From 4d074f0a1ef1d774786b4f1e1e3e827a9bf576e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?N=C3=A9stor=20Amador?= Date: Fri, 8 Jul 2022 00:34:51 +0200 Subject: [PATCH] [1.19.X] Client code cleanup, updates, and other refactors (#8786) * Revert "Allow safely registering RenderType predicates at any time (#8685)" This reverts commit be7275443fd939db9c58bcad47079c3767789ac1. * Renderable API refactors - Rename "render values" to "context" - Rename SimpleRenderable to CompositeRenderable to better reflect its use - Remove IMultipartRenderValues since it doesn't have any real use - Add extensive customization options to BakedModelRenderable * ClientRegistry and MinecraftForgeClient refactors - Add sprite loader manager and registration event - Add spectator shader manager and registration event - Add client tooltip factory manager and registration event - Add recipe book manager and registration event - Add key mapping registration event - Remove ClientRegistry, as everything has been moved out of it - Remove registration methods from MinecraftForgeClient, as they have dedicated events now * Dimension special effects refactors - Fold handlers into an extension class and remove public mutable fields - Add dimension special effects manager and registration event * HUD overlay refactors - Rename to IGuiOverlay match vanilla (instead of Ingame) - Add overlay manager and registration event - Move vanilla overlays to a standalone enum * Model loader refactors - Rename IModelLoader to IGeometryLoader - Add loader manager and registration event - Fold all model events into one - Move registration of additionally loaded models to an event - Remove ForgeModelBakery and related classes as they served no purpose anymore * Render properties refactors - Rename all render properties to client extensions and relocate accordingly - Move lookups to the respective interfaces * Model data refactors - Convert model data to a final class backed by an immutable map and document mutability requirements. This addresses several thread-safety issues in the current implementation which could result in race conditions - Transfer ownership of the data manager to the client level. This addresses several issues that arise when multiple levels are used at once * GUI and widget refactors - Move all widgets to the correct package - Rename GuiUtils and children to match vanilla naming * New vertex pipeline API - Move to vanilla's VertexConsumer - Roll back recent PR making VertexConsumer format-aware. This is the opposite of what vanilla does, and should not be relevant with the updated lighting pipeline * Lighting pipeline refactors - Move to dedicated lighting package - Separate flat and smooth lighters - Convert from a vertex pipeline transformer to a pure vertex source (input is baked quads) * Model geometry API refactors - Rename IModelGeometry to IUnbakedGeometry - Rename IModelConfiguration to IGeometryBakingContext - Rename other elements to match vanilla naming - Remove current changes to ModelState, as they do not belong there. Transforms should be specified through vanilla's system. ModelState is intended to transfer state from the blockstate JSON - Remove multipart geometries and geometry parts. After some discussion, these should not be exposed. Instead, geometries should be baked with only the necessary parts enabled * Make render types a first-class citizen in baked models - Add named render types (block + entity + fabulous entity) - Add named render type manager + registration event - Make BakedModel aware of render types and transfer control over which ones are used to it instead of ItemBlockRenderTypes (fallback) - (additional) Add concatenated list view. A wrapper for multiple lists that iterates through them in order without the cost of merging them. Useful for merging lists of baked quads * General event refactors - Several renames to either match vanilla or improve clarity - Relocate client chat event dispatching out of common code * Forge model type refactors - Rename SeparatePerspectiveModel to SeparateTransformsModel - Rename ItemModelMesherForge to ForgeItemModelShaper - Rename DynamicBucketModel to DynamicFluidContainerModel - Prefix all OBJ-related classes with "Obj" and decouple parsing from construction - Extract ElementsModel from model loader registry - Add EmptyModel (baked, unbaked and loader) - Refactor CompositeModel to take over ItemMultiLayerBakedModel - Remove FluidModel as it's not used and isn't compatible with the new fluid rendering in modern versions - Move model loader registration to a proper event handler - Update names of several JSON fields (backwards-compatible) - Update datagens to match * Miscellaneous changes and overlapping patches - Dispatch all new registration events - Convert ExtendedServerListData to a record - Add/remove hooks from ForgeHooksClient as necessary * Update test mods * Fix VertexConsumerWrapper returning parent instead of itself * Additional event cleanup pass As discussed on Discord: - Remove "@hidden" and "@see " javadoc annotations from all client events and replace them with @ApiStatus.Internal annotation - Make all events that shouldn't be fired directly into abstract classes with protected constructors - Another styling pass, just in case (caught some missed classes) * Add proper deprecation javadocs and de-dupe some vertex consumer code * Replace sets of chunk render types with a faster BitSet-backed collection This largely addresses potential performance concerns that using a plain HashSet might involve by making lookups and iteration as linear as they can likely be (aside from using a plain byte/int/long for bit storage). Further performance concerns related to the implementation may be addressed separately, as all the implementation details are hidden from the end user * Requested changes - Remove MinecraftForgeClient and move members to Minecraft, IForgeMinecraft and StencilManager - Allow non-default elements to be passed into VertexConsumer and add support to derived classes - Move array instantiation out of quad processing in lighting pipeline - Fix flipped fluid container model - Set default UV1 to the correct values in the remapping pipeline - Minor documentation changes * Add/update EXC entries and fix AT comment * Add test mod as per Orion's request * Additional requested changes * Allow custom model types to request the particle texture to be loaded * Even more requested changes * Improve generics in ConcatenatedListView and add missing fallbacks * Fix fluid render types being bound to the fluid and not its holder * Remove non-contractual nullability in ChunkRenderTypeSet and add isEmpty Additionally, introduce chunk render type checks in ItemBlockRenderTypes Co-authored-by: Dennis C --- .../blaze3d/vertex/BufferBuilder.java.patch | 5 +- .../SheetedDecalTextureGenerator.java.patch | 9 - .../blaze3d/vertex/VertexConsumer.java.patch | 18 +- .../vertex/VertexMultiConsumer.java.patch | 25 - .../client/ClientRecipeBook.java.patch | 2 +- .../minecraft/client/KeyMapping.java.patch | 40 +- .../client/KeyboardHandler.java.patch | 2 +- .../net/minecraft/client/Minecraft.java.patch | 65 ++- .../minecraft/client/MouseHandler.java.patch | 4 +- .../client/RecipeBookCategories.java.patch | 9 +- .../client/color/block/BlockColors.java.patch | 4 +- .../client/color/item/ItemColors.java.patch | 4 +- .../net/minecraft/client/gui/Gui.java.patch | 20 +- .../components/BossHealthOverlay.java.patch | 10 +- .../client/gui/screens/Screen.java.patch | 8 +- .../client/gui/screens/TitleScreen.java.patch | 4 +- .../AbstractContainerScreen.java.patch | 6 +- .../EffectRenderingInventoryScreen.java.patch | 26 +- .../tooltip/ClientTooltipComponent.java.patch | 2 +- .../client/multiplayer/ClientLevel.java.patch | 18 +- .../ClientPacketListener.java.patch | 2 +- .../particle/BreakingItemParticle.java.patch | 2 +- .../client/particle/ParticleEngine.java.patch | 11 +- .../player/AbstractClientPlayer.java.patch | 2 +- .../client/player/LocalPlayer.java.patch | 2 +- .../DimensionSpecialEffects.java.patch | 57 +- .../client/renderer/GameRenderer.java.patch | 2 +- .../renderer/ItemBlockRenderTypes.java.patch | 100 ++-- .../client/renderer/LevelRenderer.java.patch | 32 +- .../renderer/OutlineBufferSource.java.patch | 10 - .../client/renderer/RenderType.java.patch | 18 + .../renderer/ScreenEffectRenderer.java.patch | 19 +- .../SpriteCoordinateExpander.java.patch | 9 - .../block/BlockModelShaper.java.patch | 6 +- .../block/BlockRenderDispatcher.java.patch | 28 +- .../block/LiquidBlockRenderer.java.patch | 2 +- .../block/ModelBlockRenderer.java.patch | 40 +- .../renderer/block/model/BakedQuad.java.patch | 23 - .../block/model/BlockModel.java.patch | 24 +- .../block/model/ItemOverrides.java.patch | 2 +- .../block/model/ItemTransform.java.patch | 46 +- .../block/model/ItemTransforms.java.patch | 5 +- .../chunk/ChunkRenderDispatcher.java.patch | 73 +-- .../chunk/RenderChunkRegion.java.patch | 12 + .../renderer/entity/EntityRenderer.java.patch | 8 +- .../entity/FallingBlockRenderer.java.patch | 12 +- .../renderer/entity/ItemRenderer.java.patch | 25 +- .../resources/model/BakedModel.java.patch | 6 +- .../resources/model/ModelBakery.java.patch | 50 +- .../resources/model/ModelManager.java.patch | 32 +- .../resources/model/ModelState.java.patch | 11 - .../model/MultiPartBakedModel.java.patch | 39 +- .../model/SimpleBakedModel.java.patch | 76 ++- .../model/WeightedBakedModel.java.patch | 12 +- .../world/effect/MobEffect.java.patch | 2 +- .../net/minecraft/world/item/Item.java.patch | 2 +- .../world/level/BlockAndTintGetter.java.patch | 11 + .../world/level/block/Block.java.patch | 2 +- .../client/ChunkRenderTypeSet.java | 223 ++++++++ .../client/ClientCommandHandler.java | 2 +- .../client/ClientCommandSourceStack.java | 18 +- .../minecraftforge/client/ClientForgeMod.java | 54 ++ .../minecraftforge/client/ClientRegistry.java | 47 -- .../DimensionSpecialEffectsManager.java | 65 +++ .../minecraftforge/client/EffectRenderer.java | 90 --- .../client/EntitySpectatorShaderManager.java | 50 ++ .../client/ExtendedServerListData.java | 22 +- .../client/FluidContainerColorer.java | 23 - .../client/ForgeHooksClient.java | 434 +++++++------- .../client/ICloudRenderHandler.java | 20 - .../client/IItemRenderProperties.java | 102 ---- .../client/ISkyRenderHandler.java | 20 - .../client/IWeatherParticleRenderHandler.java | 21 - .../client/IWeatherRenderHandler.java | 20 - .../client/MinecraftForgeClient.java | 146 ----- .../client/NamedRenderTypeManager.java | 61 ++ .../client/RecipeBookManager.java | 76 +++ .../client/RecipeBookRegistry.java | 53 -- .../client/RenderProperties.java | 69 --- .../client/RenderTypeGroup.java | 39 ++ .../minecraftforge/client/StencilManager.java | 44 ++ .../client/event/ClientChatEvent.java | 11 +- .../client/event/ClientChatReceivedEvent.java | 13 +- .../ClientPlayerChangeGameTypeEvent.java | 11 +- .../event/ClientPlayerNetworkEvent.java | 101 ++-- ...vent.java => ComputeFovModifierEvent.java} | 44 +- .../client/event/ContainerScreenEvent.java | 112 ++-- .../event/CustomizeGuiOverlayEvent.java | 219 +++++++ .../client/event/EntityRenderersEvent.java | 45 +- .../client/event/InputEvent.java | 166 +++--- .../client/event/ModelBakeEvent.java | 71 --- .../client/event/ModelEvent.java | 139 +++++ .../client/event/ModelRegistryEvent.java | 36 -- .../event/MovementInputUpdateEvent.java | 14 +- .../client/event/RecipesUpdatedEvent.java | 20 +- .../event/RegisterClientCommandsEvent.java | 11 +- .../RegisterClientReloadListenersEvent.java | 11 +- ...rClientTooltipComponentFactoriesEvent.java | 47 ++ ...t.java => RegisterColorHandlersEvent.java} | 64 ++- .../RegisterDimensionSpecialEffectsEvent.java | 44 ++ .../RegisterEntitySpectatorShadersEvent.java | 45 ++ .../event/RegisterGuiOverlaysEvent.java | 118 ++++ .../event/RegisterKeyMappingsEvent.java | 43 ++ .../event/RegisterNamedRenderTypesEvent.java | 72 +++ ...va => RegisterParticleProvidersEvent.java} | 32 +- .../RegisterRecipeBookCategoriesEvent.java | 72 +++ .../client/event/RegisterShadersEvent.java | 13 +- ...egisterTextureAtlasSpriteLoadersEvent.java | 48 ++ .../client/event/RenderArmEvent.java | 10 +- ...java => RenderBlockScreenEffectEvent.java} | 55 +- .../client/event/RenderGameOverlayEvent.java | 436 -------------- .../client/event/RenderGuiEvent.java | 90 +++ .../client/event/RenderGuiOverlayEvent.java | 100 ++++ .../client/event/RenderHandEvent.java | 19 +- ...onEvent.java => RenderHighlightEvent.java} | 81 +-- .../client/event/RenderItemInFrameEvent.java | 17 +- .../client/event/RenderLevelLastEvent.java | 14 +- .../client/event/RenderLivingEvent.java | 74 ++- ...lateEvent.java => RenderNameTagEvent.java} | 16 +- .../client/event/RenderPlayerEvent.java | 63 +- .../client/event/RenderTooltipEvent.java | 51 +- .../client/event/ScreenEvent.java | 536 ++++++++--------- .../client/event/ScreenOpenEvent.java | 56 -- .../client/event/ScreenshotEvent.java | 17 +- .../client/event/TextureStitchEvent.java | 37 +- ...iewRenderEvent.java => ViewportEvent.java} | 160 +++--- .../client/event/sound/PlaySoundEvent.java | 9 +- .../event/sound/PlaySoundSourceEvent.java | 11 +- .../event/sound/PlayStreamingSourceEvent.java | 11 +- .../event/sound/SoundEngineLoadEvent.java | 9 +- .../client/event/sound/SoundEvent.java | 21 +- .../extensions/ForgeItemBlockRenderTypes.java | 110 ---- .../client/extensions/IForgeBakedModel.java | 85 ++- .../extensions/IForgeBlockAndTintGetter.java | 29 + .../IForgeDimensionSpecialEffects.java | 64 +++ .../client/extensions/IForgeKeyMapping.java | 2 +- .../client/extensions/IForgeMinecraft.java | 11 + .../client/extensions/IForgeModelState.java | 35 -- .../extensions/IForgeVertexConsumer.java | 113 +--- .../common/IClientBlockExtensions.java} | 25 +- .../common/IClientFluidTypeExtensions.java} | 120 ++-- .../common/IClientItemExtensions.java | 145 +++++ .../common/IClientMobEffectExtensions.java | 106 ++++ .../gui/ClientTooltipComponentManager.java | 51 ++ .../client/gui/IIngameOverlay.java | 13 - .../client/gui/ModListScreen.java | 4 +- .../gui/ModMismatchDisconnectedScreen.java | 1 + .../client/gui/OverlayRegistry.java | 186 ------ .../gui/{GuiUtils.java => ScreenUtils.java} | 47 +- ...ava => TitleScreenModUpdateIndicator.java} | 14 +- .../ForgeGui.java} | 490 +++++----------- .../client/gui/overlay/GuiOverlayManager.java | 79 +++ .../client/gui/overlay/IGuiOverlay.java | 20 + .../client/gui/overlay/NamedGuiOverlay.java | 24 + .../client/gui/overlay/VanillaGuiOverlay.java | 224 ++++++++ .../client/gui/widget/ExtendedButton.java | 4 +- .../client/gui/{ => widget}/ScrollPanel.java | 5 +- .../client/gui/widget/UnicodeGlyphButton.java | 4 +- .../client/loading/ClientModLoader.java | 3 - .../client/model/BakedItemModel.java | 120 ---- .../client/model/BakedModelWrapper.java | 58 +- .../client/model/CompositeModel.java | 537 ++++++++++-------- .../client/model/CompositeModelState.java | 71 --- .../client/model/DynamicBucketModel.java | 264 --------- .../model/DynamicFluidContainerModel.java | 304 ++++++++++ .../client/model/ElementsModel.java | 133 +++++ .../client/model/EmptyModel.java | 82 +++ .../model/ExtendedBlockModelDeserializer.java | 101 ++++ .../client/model/FluidModel.java | 476 ---------------- .../ForgeItemModelShaper.java} | 27 +- .../client/model/ForgeModelBakery.java | 263 --------- .../model/{data => }/IDynamicBakedModel.java | 19 +- .../client/model/IModelBuilder.java | 87 ++- .../client/model/IModelConfiguration.java | 93 --- .../client/model/IModelLoader.java | 16 - .../client/model/IQuadTransformer.java | 142 +++++ .../client/model/ItemLayerModel.java | 522 ++++------------- .../model/ItemMultiLayerBakedModel.java | 198 ------- .../model/ItemTextureQuadConverter.java | 323 ----------- .../client/model/ModelDataManager.java | 105 ---- .../client/model/ModelLoaderRegistry.java | 428 -------------- .../client/model/ModelLoadingException.java | 21 - .../client/model/MultiLayerModel.java | 270 --------- .../client/model/PerspectiveMapWrapper.java | 170 ------ .../client/model/QuadTransformer.java | 217 ------- .../model/SeparatePerspectiveModel.java | 217 ------- .../client/model/SeparateTransformsModel.java | 220 +++++++ .../client/model/SimpleModelState.java | 33 +- .../model/StandaloneModelConfiguration.java | 105 ---- .../client/model/b3d/package-info.java | 12 - .../client/model/data/EmptyModelData.java | 20 - .../client/model/data/IModelData.java | 30 - .../client/model/data/ModelData.java | 99 ++++ .../client/model/data/ModelDataManager.java | 102 ++++ .../client/model/data/ModelDataMap.java | 68 --- .../client/model/data/ModelProperty.java | 32 +- .../client/model/data/MultipartModelData.java | 94 ++- .../model/generators/BlockStateProvider.java | 8 +- ...ckstate.java => IGeneratedBlockState.java} | 4 +- .../client/model/generators/ModelBuilder.java | 100 ++-- .../model/generators/ModelProvider.java | 2 +- .../MultiPartBlockStateBuilder.java | 3 +- .../generators/VariantBlockStateBuilder.java | 3 +- .../loaders/CompositeModelBuilder.java | 32 +- ...=> DynamicFluidContainerModelBuilder.java} | 26 +- .../loaders/ItemLayersModelBuilder.java | 98 +++- .../loaders/MultiLayerModelBuilder.java | 57 -- .../generators/loaders/OBJLoaderBuilder.java | 103 ---- .../generators/loaders/ObjModelBuilder.java | 103 ++++ ...va => SeparateTransformsModelBuilder.java} | 15 +- .../BlockGeometryBakingContext.java} | 121 ++-- .../model/geometry/GeometryLoaderManager.java | 61 ++ .../geometry/IGeometryBakingContext.java | 94 +++ .../model/geometry/IGeometryLoader.java | 27 + .../model/geometry/IModelGeometryPart.java | 33 -- .../geometry/IMultipartModelGeometry.java | 46 -- .../model/geometry/ISimpleModelGeometry.java | 43 -- ...delGeometry.java => IUnbakedGeometry.java} | 36 +- .../model/geometry/SimpleUnbakedGeometry.java | 50 ++ .../StandaloneGeometryBakingContext.java | 233 ++++++++ .../model/geometry/UnbakedGeometryHelper.java | 233 ++++++++ .../model/lighting/FlatQuadLighter.java | 75 +++ .../lighting/ForgeModelBlockRenderer.java | 109 ++++ .../client/model/lighting/QuadLighter.java | 153 +++++ .../model/lighting/SmoothQuadLighter.java | 256 +++++++++ .../client/model/obj/OBJLoader.java | 94 --- .../client/model/obj/ObjLoader.java | 130 +++++ ...alLibrary.java => ObjMaterialLibrary.java} | 35 +- .../obj/{OBJModel.java => ObjModel.java} | 462 ++++++++------- .../{LineReader.java => ObjTokenizer.java} | 21 +- .../model/pipeline/BakedQuadBuilder.java | 181 ------ .../client/model/pipeline/BlockInfo.java | 236 -------- .../pipeline/ForgeBlockModelRenderer.java | 119 ---- .../model/pipeline/IVertexConsumer.java | 29 - .../model/pipeline/IVertexProducer.java | 15 - .../client/model/pipeline/LightUtil.java | 331 ----------- .../pipeline/QuadBakingVertexConsumer.java | 164 ++++++ .../pipeline/QuadGatheringTransformer.java | 57 -- .../pipeline/RemappingVertexPipeline.java | 153 +++++ .../model/pipeline/TRSRTransformer.java | 45 -- .../model/pipeline/TransformerConsumer.java | 32 -- .../pipeline/TransformingVertexPipeline.java | 44 ++ .../model/pipeline/VertexBufferConsumer.java | 122 ---- .../model/pipeline/VertexConsumerWrapper.java | 91 +++ .../model/pipeline/VertexLighterFlat.java | 322 ----------- .../model/pipeline/VertexLighterSmoothAo.java | 162 ------ .../model/pipeline/VertexTransformer.java | 56 -- .../renderable/BakedModelRenderable.java | 97 ++++ .../model/renderable/BakedRenderable.java | 72 --- .../model/renderable/CompositeRenderable.java | 181 ++++++ .../renderable/IMultipartRenderValues.java | 23 - .../client/model/renderable/IRenderable.java | 41 +- .../renderable/ITextureRenderTypeLookup.java | 18 + .../model/renderable/MultipartTransforms.java | 43 -- .../model/renderable/SimpleRenderable.java | 154 ----- ...yBindingMap.java => KeyMappingLookup.java} | 20 +- .../client/textures/ForgeTextureMetadata.java | 3 +- .../textures/ITextureAtlasSpriteLoader.java | 22 +- .../TextureAtlasSpriteLoaderManager.java | 48 ++ ...prite.java => UnitTextureAtlasSprite.java} | 14 +- .../net/minecraftforge/common/ForgeMod.java | 26 +- .../common/ForgeSpawnEggItem.java | 4 +- .../common/TierSortingRegistry.java | 2 +- .../common/extensions/IForgeBlockEntity.java | 14 +- .../common/extensions/IForgeBlockGetter.java | 11 + .../common/util/ConcatenatedListView.java | 148 +++++ .../{model => util}/TransformationHelper.java | 46 +- .../event/ForgeEventFactory.java | 20 - .../net/minecraftforge/fluids/FluidType.java | 4 +- .../logging/ModelLoaderErrorMessage.java | 104 ---- .../resources/META-INF/accesstransformer.cfg | 12 +- src/main/resources/forge.exc | 23 +- .../debug/block/FullPotsAccessorDemo.java | 72 ++- .../debug/client/CustomArmorModelTest.java | 14 +- .../debug/client/CustomTASTest.java | 10 +- .../debug/client/CustomTooltipTest.java | 10 +- .../debug/client/GuiLayeringTest.java | 2 +- .../debug/client/OverlayLayersTest.java | 91 --- .../debug/client/PotionSizeEventTest.java | 8 +- .../debug/client/model/MegaModelTest.java | 175 ++++++ .../client/model/NewModelLoaderTest.java | 92 +-- .../client/model/TRSRTransformerTest.java | 44 +- .../LinearTextTextureFilteringTest.java | 6 +- .../NameplateRenderingEventTest.java | 4 +- .../client/rendering/RenderableTest.java | 43 +- .../debug/client/rendering/ShaderFixTest.java | 9 +- .../debug/fluid/FluidTypeTest.java | 17 +- .../debug/fluid/NewFluidTest.java | 8 +- .../RecipeBookExtensionClientHelper.java | 11 +- .../recipebook/RecipeBookExtensionTest.java | 9 +- .../eventtest/internal/TestFramework.java | 4 +- src/test/resources/META-INF/mods.toml | 2 + .../blockstates/test_block.json | 7 + .../models/block/test_block.json | 94 +++ .../models/item/test_block.json | 3 + 295 files changed, 9819 insertions(+), 11494 deletions(-) delete mode 100644 patches/minecraft/com/mojang/blaze3d/vertex/SheetedDecalTextureGenerator.java.patch delete mode 100644 patches/minecraft/com/mojang/blaze3d/vertex/VertexMultiConsumer.java.patch delete mode 100644 patches/minecraft/net/minecraft/client/renderer/OutlineBufferSource.java.patch delete mode 100644 patches/minecraft/net/minecraft/client/renderer/SpriteCoordinateExpander.java.patch delete mode 100644 patches/minecraft/net/minecraft/client/renderer/block/model/BakedQuad.java.patch create mode 100644 patches/minecraft/net/minecraft/client/renderer/chunk/RenderChunkRegion.java.patch delete mode 100644 patches/minecraft/net/minecraft/client/resources/model/ModelState.java.patch create mode 100644 patches/minecraft/net/minecraft/world/level/BlockAndTintGetter.java.patch create mode 100644 src/main/java/net/minecraftforge/client/ChunkRenderTypeSet.java create mode 100644 src/main/java/net/minecraftforge/client/ClientForgeMod.java delete mode 100644 src/main/java/net/minecraftforge/client/ClientRegistry.java create mode 100644 src/main/java/net/minecraftforge/client/DimensionSpecialEffectsManager.java delete mode 100644 src/main/java/net/minecraftforge/client/EffectRenderer.java create mode 100644 src/main/java/net/minecraftforge/client/EntitySpectatorShaderManager.java delete mode 100644 src/main/java/net/minecraftforge/client/FluidContainerColorer.java delete mode 100644 src/main/java/net/minecraftforge/client/ICloudRenderHandler.java delete mode 100644 src/main/java/net/minecraftforge/client/IItemRenderProperties.java delete mode 100644 src/main/java/net/minecraftforge/client/ISkyRenderHandler.java delete mode 100644 src/main/java/net/minecraftforge/client/IWeatherParticleRenderHandler.java delete mode 100644 src/main/java/net/minecraftforge/client/IWeatherRenderHandler.java delete mode 100644 src/main/java/net/minecraftforge/client/MinecraftForgeClient.java create mode 100644 src/main/java/net/minecraftforge/client/NamedRenderTypeManager.java create mode 100644 src/main/java/net/minecraftforge/client/RecipeBookManager.java delete mode 100644 src/main/java/net/minecraftforge/client/RecipeBookRegistry.java delete mode 100644 src/main/java/net/minecraftforge/client/RenderProperties.java create mode 100644 src/main/java/net/minecraftforge/client/RenderTypeGroup.java create mode 100644 src/main/java/net/minecraftforge/client/StencilManager.java rename src/main/java/net/minecraftforge/client/event/{FOVModifierEvent.java => ComputeFovModifierEvent.java} (57%) create mode 100644 src/main/java/net/minecraftforge/client/event/CustomizeGuiOverlayEvent.java delete mode 100644 src/main/java/net/minecraftforge/client/event/ModelBakeEvent.java create mode 100644 src/main/java/net/minecraftforge/client/event/ModelEvent.java delete mode 100644 src/main/java/net/minecraftforge/client/event/ModelRegistryEvent.java create mode 100644 src/main/java/net/minecraftforge/client/event/RegisterClientTooltipComponentFactoriesEvent.java rename src/main/java/net/minecraftforge/client/event/{ColorHandlerEvent.java => RegisterColorHandlersEvent.java} (67%) create mode 100644 src/main/java/net/minecraftforge/client/event/RegisterDimensionSpecialEffectsEvent.java create mode 100644 src/main/java/net/minecraftforge/client/event/RegisterEntitySpectatorShadersEvent.java create mode 100644 src/main/java/net/minecraftforge/client/event/RegisterGuiOverlaysEvent.java create mode 100644 src/main/java/net/minecraftforge/client/event/RegisterKeyMappingsEvent.java create mode 100644 src/main/java/net/minecraftforge/client/event/RegisterNamedRenderTypesEvent.java rename src/main/java/net/minecraftforge/client/event/{ParticleFactoryRegisterEvent.java => RegisterParticleProvidersEvent.java} (51%) create mode 100644 src/main/java/net/minecraftforge/client/event/RegisterRecipeBookCategoriesEvent.java create mode 100644 src/main/java/net/minecraftforge/client/event/RegisterTextureAtlasSpriteLoadersEvent.java rename src/main/java/net/minecraftforge/client/event/{RenderBlockOverlayEvent.java => RenderBlockScreenEffectEvent.java} (72%) delete mode 100644 src/main/java/net/minecraftforge/client/event/RenderGameOverlayEvent.java create mode 100644 src/main/java/net/minecraftforge/client/event/RenderGuiEvent.java create mode 100644 src/main/java/net/minecraftforge/client/event/RenderGuiOverlayEvent.java rename src/main/java/net/minecraftforge/client/event/{DrawSelectionEvent.java => RenderHighlightEvent.java} (65%) rename src/main/java/net/minecraftforge/client/event/{RenderNameplateEvent.java => RenderNameTagEvent.java} (88%) delete mode 100644 src/main/java/net/minecraftforge/client/event/ScreenOpenEvent.java rename src/main/java/net/minecraftforge/client/event/{EntityViewRenderEvent.java => ViewportEvent.java} (72%) delete mode 100644 src/main/java/net/minecraftforge/client/extensions/ForgeItemBlockRenderTypes.java create mode 100644 src/main/java/net/minecraftforge/client/extensions/IForgeBlockAndTintGetter.java create mode 100644 src/main/java/net/minecraftforge/client/extensions/IForgeDimensionSpecialEffects.java delete mode 100644 src/main/java/net/minecraftforge/client/extensions/IForgeModelState.java rename src/main/java/net/minecraftforge/client/{IBlockRenderProperties.java => extensions/common/IClientBlockExtensions.java} (83%) rename src/main/java/net/minecraftforge/client/{IFluidTypeRenderProperties.java => extensions/common/IClientFluidTypeExtensions.java} (75%) create mode 100644 src/main/java/net/minecraftforge/client/extensions/common/IClientItemExtensions.java create mode 100644 src/main/java/net/minecraftforge/client/extensions/common/IClientMobEffectExtensions.java create mode 100644 src/main/java/net/minecraftforge/client/gui/ClientTooltipComponentManager.java delete mode 100644 src/main/java/net/minecraftforge/client/gui/IIngameOverlay.java delete mode 100644 src/main/java/net/minecraftforge/client/gui/OverlayRegistry.java rename src/main/java/net/minecraftforge/client/gui/{GuiUtils.java => ScreenUtils.java} (80%) rename src/main/java/net/minecraftforge/client/gui/{NotificationModUpdateScreen.java => TitleScreenModUpdateIndicator.java} (80%) rename src/main/java/net/minecraftforge/client/gui/{ForgeIngameGui.java => overlay/ForgeGui.java} (52%) create mode 100644 src/main/java/net/minecraftforge/client/gui/overlay/GuiOverlayManager.java create mode 100644 src/main/java/net/minecraftforge/client/gui/overlay/IGuiOverlay.java create mode 100644 src/main/java/net/minecraftforge/client/gui/overlay/NamedGuiOverlay.java create mode 100644 src/main/java/net/minecraftforge/client/gui/overlay/VanillaGuiOverlay.java rename src/main/java/net/minecraftforge/client/gui/{ => widget}/ScrollPanel.java (98%) delete mode 100644 src/main/java/net/minecraftforge/client/model/BakedItemModel.java delete mode 100644 src/main/java/net/minecraftforge/client/model/CompositeModelState.java delete mode 100644 src/main/java/net/minecraftforge/client/model/DynamicBucketModel.java create mode 100644 src/main/java/net/minecraftforge/client/model/DynamicFluidContainerModel.java create mode 100644 src/main/java/net/minecraftforge/client/model/ElementsModel.java create mode 100644 src/main/java/net/minecraftforge/client/model/EmptyModel.java create mode 100644 src/main/java/net/minecraftforge/client/model/ExtendedBlockModelDeserializer.java delete mode 100644 src/main/java/net/minecraftforge/client/model/FluidModel.java rename src/main/java/net/minecraftforge/client/{ItemModelMesherForge.java => model/ForgeItemModelShaper.java} (72%) delete mode 100644 src/main/java/net/minecraftforge/client/model/ForgeModelBakery.java rename src/main/java/net/minecraftforge/client/model/{data => }/IDynamicBakedModel.java (62%) delete mode 100644 src/main/java/net/minecraftforge/client/model/IModelConfiguration.java delete mode 100644 src/main/java/net/minecraftforge/client/model/IModelLoader.java create mode 100644 src/main/java/net/minecraftforge/client/model/IQuadTransformer.java delete mode 100644 src/main/java/net/minecraftforge/client/model/ItemMultiLayerBakedModel.java delete mode 100644 src/main/java/net/minecraftforge/client/model/ItemTextureQuadConverter.java delete mode 100644 src/main/java/net/minecraftforge/client/model/ModelDataManager.java delete mode 100644 src/main/java/net/minecraftforge/client/model/ModelLoaderRegistry.java delete mode 100644 src/main/java/net/minecraftforge/client/model/ModelLoadingException.java delete mode 100644 src/main/java/net/minecraftforge/client/model/MultiLayerModel.java delete mode 100644 src/main/java/net/minecraftforge/client/model/PerspectiveMapWrapper.java delete mode 100644 src/main/java/net/minecraftforge/client/model/QuadTransformer.java delete mode 100644 src/main/java/net/minecraftforge/client/model/SeparatePerspectiveModel.java create mode 100644 src/main/java/net/minecraftforge/client/model/SeparateTransformsModel.java delete mode 100644 src/main/java/net/minecraftforge/client/model/StandaloneModelConfiguration.java delete mode 100644 src/main/java/net/minecraftforge/client/model/b3d/package-info.java delete mode 100644 src/main/java/net/minecraftforge/client/model/data/EmptyModelData.java delete mode 100644 src/main/java/net/minecraftforge/client/model/data/IModelData.java create mode 100644 src/main/java/net/minecraftforge/client/model/data/ModelData.java create mode 100644 src/main/java/net/minecraftforge/client/model/data/ModelDataManager.java delete mode 100644 src/main/java/net/minecraftforge/client/model/data/ModelDataMap.java rename src/main/java/net/minecraftforge/client/model/generators/{IGeneratedBlockstate.java => IGeneratedBlockState.java} (87%) rename src/main/java/net/minecraftforge/client/model/generators/loaders/{DynamicBucketModelBuilder.java => DynamicFluidContainerModelBuilder.java} (61%) delete mode 100644 src/main/java/net/minecraftforge/client/model/generators/loaders/MultiLayerModelBuilder.java delete mode 100644 src/main/java/net/minecraftforge/client/model/generators/loaders/OBJLoaderBuilder.java create mode 100644 src/main/java/net/minecraftforge/client/model/generators/loaders/ObjModelBuilder.java rename src/main/java/net/minecraftforge/client/model/generators/loaders/{SeparatePerspectiveModelBuilder.java => SeparateTransformsModelBuilder.java} (67%) rename src/main/java/net/minecraftforge/client/model/{BlockModelConfiguration.java => geometry/BlockGeometryBakingContext.java} (57%) create mode 100644 src/main/java/net/minecraftforge/client/model/geometry/GeometryLoaderManager.java create mode 100644 src/main/java/net/minecraftforge/client/model/geometry/IGeometryBakingContext.java create mode 100644 src/main/java/net/minecraftforge/client/model/geometry/IGeometryLoader.java delete mode 100644 src/main/java/net/minecraftforge/client/model/geometry/IModelGeometryPart.java delete mode 100644 src/main/java/net/minecraftforge/client/model/geometry/IMultipartModelGeometry.java delete mode 100644 src/main/java/net/minecraftforge/client/model/geometry/ISimpleModelGeometry.java rename src/main/java/net/minecraftforge/client/model/geometry/{IModelGeometry.java => IUnbakedGeometry.java} (50%) create mode 100644 src/main/java/net/minecraftforge/client/model/geometry/SimpleUnbakedGeometry.java create mode 100644 src/main/java/net/minecraftforge/client/model/geometry/StandaloneGeometryBakingContext.java create mode 100644 src/main/java/net/minecraftforge/client/model/geometry/UnbakedGeometryHelper.java create mode 100644 src/main/java/net/minecraftforge/client/model/lighting/FlatQuadLighter.java create mode 100644 src/main/java/net/minecraftforge/client/model/lighting/ForgeModelBlockRenderer.java create mode 100644 src/main/java/net/minecraftforge/client/model/lighting/QuadLighter.java create mode 100644 src/main/java/net/minecraftforge/client/model/lighting/SmoothQuadLighter.java delete mode 100644 src/main/java/net/minecraftforge/client/model/obj/OBJLoader.java create mode 100644 src/main/java/net/minecraftforge/client/model/obj/ObjLoader.java rename src/main/java/net/minecraftforge/client/model/obj/{MaterialLibrary.java => ObjMaterialLibrary.java} (78%) rename src/main/java/net/minecraftforge/client/model/obj/{OBJModel.java => ObjModel.java} (51%) rename src/main/java/net/minecraftforge/client/model/obj/{LineReader.java => ObjTokenizer.java} (81%) delete mode 100644 src/main/java/net/minecraftforge/client/model/pipeline/BakedQuadBuilder.java delete mode 100644 src/main/java/net/minecraftforge/client/model/pipeline/BlockInfo.java delete mode 100644 src/main/java/net/minecraftforge/client/model/pipeline/ForgeBlockModelRenderer.java delete mode 100644 src/main/java/net/minecraftforge/client/model/pipeline/IVertexConsumer.java delete mode 100644 src/main/java/net/minecraftforge/client/model/pipeline/IVertexProducer.java delete mode 100644 src/main/java/net/minecraftforge/client/model/pipeline/LightUtil.java create mode 100644 src/main/java/net/minecraftforge/client/model/pipeline/QuadBakingVertexConsumer.java delete mode 100644 src/main/java/net/minecraftforge/client/model/pipeline/QuadGatheringTransformer.java create mode 100644 src/main/java/net/minecraftforge/client/model/pipeline/RemappingVertexPipeline.java delete mode 100644 src/main/java/net/minecraftforge/client/model/pipeline/TRSRTransformer.java delete mode 100644 src/main/java/net/minecraftforge/client/model/pipeline/TransformerConsumer.java create mode 100644 src/main/java/net/minecraftforge/client/model/pipeline/TransformingVertexPipeline.java delete mode 100644 src/main/java/net/minecraftforge/client/model/pipeline/VertexBufferConsumer.java create mode 100644 src/main/java/net/minecraftforge/client/model/pipeline/VertexConsumerWrapper.java delete mode 100644 src/main/java/net/minecraftforge/client/model/pipeline/VertexLighterFlat.java delete mode 100644 src/main/java/net/minecraftforge/client/model/pipeline/VertexLighterSmoothAo.java delete mode 100644 src/main/java/net/minecraftforge/client/model/pipeline/VertexTransformer.java create mode 100644 src/main/java/net/minecraftforge/client/model/renderable/BakedModelRenderable.java delete mode 100644 src/main/java/net/minecraftforge/client/model/renderable/BakedRenderable.java create mode 100644 src/main/java/net/minecraftforge/client/model/renderable/CompositeRenderable.java delete mode 100644 src/main/java/net/minecraftforge/client/model/renderable/IMultipartRenderValues.java create mode 100644 src/main/java/net/minecraftforge/client/model/renderable/ITextureRenderTypeLookup.java delete mode 100644 src/main/java/net/minecraftforge/client/model/renderable/MultipartTransforms.java delete mode 100644 src/main/java/net/minecraftforge/client/model/renderable/SimpleRenderable.java rename src/main/java/net/minecraftforge/client/settings/{KeyBindingMap.java => KeyMappingLookup.java} (84%) create mode 100644 src/main/java/net/minecraftforge/client/textures/TextureAtlasSpriteLoaderManager.java rename src/main/java/net/minecraftforge/client/textures/{UnitSprite.java => UnitTextureAtlasSprite.java} (70%) create mode 100644 src/main/java/net/minecraftforge/common/util/ConcatenatedListView.java rename src/main/java/net/minecraftforge/common/{model => util}/TransformationHelper.java (92%) delete mode 100644 src/main/java/net/minecraftforge/logging/ModelLoaderErrorMessage.java delete mode 100644 src/test/java/net/minecraftforge/debug/client/OverlayLayersTest.java create mode 100644 src/test/java/net/minecraftforge/debug/client/model/MegaModelTest.java create mode 100644 src/test/resources/assets/mega_model_test/blockstates/test_block.json create mode 100644 src/test/resources/assets/mega_model_test/models/block/test_block.json create mode 100644 src/test/resources/assets/mega_model_test/models/item/test_block.json diff --git a/patches/minecraft/com/mojang/blaze3d/vertex/BufferBuilder.java.patch b/patches/minecraft/com/mojang/blaze3d/vertex/BufferBuilder.java.patch index 31aef88a7de..10bbd9656cf 100644 --- a/patches/minecraft/com/mojang/blaze3d/vertex/BufferBuilder.java.patch +++ b/patches/minecraft/com/mojang/blaze3d/vertex/BufferBuilder.java.patch @@ -1,6 +1,6 @@ --- a/com/mojang/blaze3d/vertex/BufferBuilder.java +++ b/com/mojang/blaze3d/vertex/BufferBuilder.java -@@ -486,4 +_,16 @@ +@@ -486,4 +_,13 @@ this.f_166822_ = p_166829_; } } @@ -13,7 +13,4 @@ + this.f_85654_ += buffer.limit() / this.f_85658_.m_86020_(); + this.f_85652_ += buffer.limit(); + } -+ -+ @Override -+ public VertexFormat getVertexFormat() { return this.f_85658_; } } diff --git a/patches/minecraft/com/mojang/blaze3d/vertex/SheetedDecalTextureGenerator.java.patch b/patches/minecraft/com/mojang/blaze3d/vertex/SheetedDecalTextureGenerator.java.patch deleted file mode 100644 index d3c3e85fc42..00000000000 --- a/patches/minecraft/com/mojang/blaze3d/vertex/SheetedDecalTextureGenerator.java.patch +++ /dev/null @@ -1,9 +0,0 @@ ---- a/com/mojang/blaze3d/vertex/SheetedDecalTextureGenerator.java -+++ b/com/mojang/blaze3d/vertex/SheetedDecalTextureGenerator.java -@@ -91,4 +_,6 @@ - this.f_85878_ = p_85902_; - return this; - } -+ -+ public VertexFormat getVertexFormat() { return f_85867_.getVertexFormat(); } - } diff --git a/patches/minecraft/com/mojang/blaze3d/vertex/VertexConsumer.java.patch b/patches/minecraft/com/mojang/blaze3d/vertex/VertexConsumer.java.patch index 1f91a101924..40ad7dee0ea 100644 --- a/patches/minecraft/com/mojang/blaze3d/vertex/VertexConsumer.java.patch +++ b/patches/minecraft/com/mojang/blaze3d/vertex/VertexConsumer.java.patch @@ -9,7 +9,18 @@ VertexConsumer m_5483_(double p_85945_, double p_85946_, double p_85947_); VertexConsumer m_6122_(int p_85973_, int p_85974_, int p_85975_, int p_85976_); -@@ -101,11 +_,12 @@ +@@ -64,6 +_,10 @@ + } + + default void m_85995_(PoseStack.Pose p_85996_, BakedQuad p_85997_, float[] p_85998_, float p_85999_, float p_86000_, float p_86001_, int[] p_86002_, int p_86003_, boolean p_86004_) { ++ putBulkData(p_85996_, p_85997_, p_85998_, p_85999_, p_86000_, p_86001_, 1, p_86002_, p_86003_, p_86004_); ++ } ++ ++ default void putBulkData(PoseStack.Pose p_85996_, BakedQuad p_85997_, float[] p_85998_, float p_85999_, float p_86000_, float p_86001_, float alpha, int[] p_86002_, int p_86003_, boolean p_86004_) { + float[] afloat = new float[]{p_85998_[0], p_85998_[1], p_85998_[2], p_85998_[3]}; + int[] aint = new int[]{p_86002_[0], p_86002_[1], p_86002_[2], p_86002_[3]}; + int[] aint1 = p_85997_.m_111303_(); +@@ -101,12 +_,14 @@ f5 = afloat[k] * p_86001_; } @@ -19,7 +30,10 @@ float f10 = bytebuffer.getFloat(20); Vector4f vector4f = new Vector4f(f, f1, f2, 1.0F); vector4f.m_123607_(matrix4f); +- this.m_5954_(vector4f.m_123601_(), vector4f.m_123615_(), vector4f.m_123616_(), f3, f4, f5, 1.0F, f9, f10, p_86003_, l, vector3f.m_122239_(), vector3f.m_122260_(), vector3f.m_122269_()); + applyBakedNormals(vector3f, bytebuffer, p_85996_.m_85864_()); - this.m_5954_(vector4f.m_123601_(), vector4f.m_123615_(), vector4f.m_123616_(), f3, f4, f5, 1.0F, f9, f10, p_86003_, l, vector3f.m_122239_(), vector3f.m_122260_(), vector3f.m_122269_()); ++ float vertexAlpha = p_86004_ ? alpha * (float) (bytebuffer.get(15) & 255) / 255.0F : alpha; ++ this.m_5954_(vector4f.m_123601_(), vector4f.m_123615_(), vector4f.m_123616_(), f3, f4, f5, vertexAlpha, f9, f10, p_86003_, l, vector3f.m_122239_(), vector3f.m_122260_(), vector3f.m_122269_()); } } catch (Throwable throwable1) { + if (memorystack != null) { diff --git a/patches/minecraft/com/mojang/blaze3d/vertex/VertexMultiConsumer.java.patch b/patches/minecraft/com/mojang/blaze3d/vertex/VertexMultiConsumer.java.patch deleted file mode 100644 index bdc328e3531..00000000000 --- a/patches/minecraft/com/mojang/blaze3d/vertex/VertexMultiConsumer.java.patch +++ /dev/null @@ -1,25 +0,0 @@ ---- a/com/mojang/blaze3d/vertex/VertexMultiConsumer.java -+++ b/com/mojang/blaze3d/vertex/VertexMultiConsumer.java -@@ -91,6 +_,8 @@ - this.f_86171_.m_141991_(); - this.f_86172_.m_141991_(); - } -+ -+ public VertexFormat getVertexFormat() { return f_86171_.getVertexFormat(); } - } - - @OnlyIn(Dist.CLIENT) -@@ -176,6 +_,13 @@ - - public void m_141991_() { - this.m_167144_(VertexConsumer::m_141991_); -+ } -+ -+ public VertexFormat getVertexFormat() -+ { -+ if (f_167071_.length > 0) -+ return f_167071_[0].getVertexFormat(); -+ return DefaultVertexFormat.f_85811_; - } - } - } diff --git a/patches/minecraft/net/minecraft/client/ClientRecipeBook.java.patch b/patches/minecraft/net/minecraft/client/ClientRecipeBook.java.patch index 2855244ad43..afeb1e75c19 100644 --- a/patches/minecraft/net/minecraft/client/ClientRecipeBook.java.patch +++ b/patches/minecraft/net/minecraft/client/ClientRecipeBook.java.patch @@ -4,7 +4,7 @@ } else if (recipetype == RecipeType.f_44113_) { return RecipeBookCategories.SMITHING; } else { -+ RecipeBookCategories categories = net.minecraftforge.client.RecipeBookRegistry.findCategories(recipetype, p_90647_); ++ RecipeBookCategories categories = net.minecraftforge.client.RecipeBookManager.findCategories((RecipeType) recipetype, p_90647_); + if (categories != null) return categories; f_90618_.warn("Unknown recipe category: {}/{}", LogUtils.defer(() -> { return Registry.f_122864_.m_7981_(p_90647_.m_6671_()); diff --git a/patches/minecraft/net/minecraft/client/KeyMapping.java.patch b/patches/minecraft/net/minecraft/client/KeyMapping.java.patch index 60bec959dac..3cb1e05a531 100644 --- a/patches/minecraft/net/minecraft/client/KeyMapping.java.patch +++ b/patches/minecraft/net/minecraft/client/KeyMapping.java.patch @@ -8,48 +8,20 @@ +public class KeyMapping implements Comparable, net.minecraftforge.client.extensions.IForgeKeyMapping { private static final Map f_90809_ = Maps.newHashMap(); - private static final Map f_90810_ = Maps.newHashMap(); -+ private static final net.minecraftforge.client.settings.KeyBindingMap f_90810_ = new net.minecraftforge.client.settings.KeyBindingMap(); ++ private static final net.minecraftforge.client.settings.KeyMappingLookup f_90810_ = new net.minecraftforge.client.settings.KeyMappingLookup(); private static final Set f_90811_ = Sets.newHashSet(); public static final String f_167805_ = "key.categories.movement"; public static final String f_167806_ = "key.categories.misc"; -@@ -41,7 +_,7 @@ - private int f_90818_; - - public static void m_90835_(InputConstants.Key p_90836_) { -- KeyMapping keymapping = f_90810_.get(p_90836_); -+ KeyMapping keymapping = f_90810_.lookupActive(p_90836_); - if (keymapping != null) { - ++keymapping.f_90818_; - } @@ -49,7 +_,7 @@ } public static void m_90837_(InputConstants.Key p_90838_, boolean p_90839_) { - KeyMapping keymapping = f_90810_.get(p_90838_); -+ for (KeyMapping keymapping : f_90810_.lookupAll(p_90838_)) ++ for (KeyMapping keymapping : f_90810_.getAll(p_90838_)) if (keymapping != null) { keymapping.m_7249_(p_90839_); } -@@ -73,10 +_,10 @@ - } - - public static void m_90854_() { -- f_90810_.clear(); -+ f_90810_.clearMap(); - - for(KeyMapping keymapping : f_90809_.values()) { -- f_90810_.put(keymapping.f_90816_, keymapping); -+ f_90810_.addKey(keymapping.f_90816_, keymapping); - } - - } -@@ -91,12 +_,12 @@ - this.f_90814_ = this.f_90816_; - this.f_90815_ = p_90828_; - f_90809_.put(p_90825_, this); -- f_90810_.put(this.f_90816_, this); -+ f_90810_.addKey(this.f_90816_, this); - f_90811_.add(p_90828_); +@@ -96,7 +_,7 @@ } public boolean m_90857_() { @@ -154,7 +126,7 @@ + if (this.keyModifier.matches(keyCode)) + this.keyModifier = net.minecraftforge.client.settings.KeyModifier.NONE; + f_90809_.put(description, this); -+ f_90810_.addKey(keyCode, this); ++ f_90810_.put(keyCode, this); + f_90811_.add(category); + } + @@ -188,9 +160,9 @@ + this.f_90816_ = keyCode; + if (keyModifier.matches(keyCode)) + keyModifier = net.minecraftforge.client.settings.KeyModifier.NONE; -+ f_90810_.removeKey(this); ++ f_90810_.remove(this); + this.keyModifier = keyModifier; -+ f_90810_.addKey(keyCode, this); ++ f_90810_.put(keyCode, this); + } + /****************** Forge End *****************************/ } diff --git a/patches/minecraft/net/minecraft/client/KeyboardHandler.java.patch b/patches/minecraft/net/minecraft/client/KeyboardHandler.java.patch index 5aa624f564e..9ed330c09b8 100644 --- a/patches/minecraft/net/minecraft/client/KeyboardHandler.java.patch +++ b/patches/minecraft/net/minecraft/client/KeyboardHandler.java.patch @@ -43,7 +43,7 @@ } } - -+ net.minecraftforge.client.ForgeHooksClient.fireKeyInput(p_90895_, p_90896_, p_90897_, p_90898_); ++ net.minecraftforge.client.ForgeHooksClient.onKeyInput(p_90895_, p_90896_, p_90897_, p_90898_); } } diff --git a/patches/minecraft/net/minecraft/client/Minecraft.java.patch b/patches/minecraft/net/minecraft/client/Minecraft.java.patch index 984363caaea..6059f88bfd7 100644 --- a/patches/minecraft/net/minecraft/client/Minecraft.java.patch +++ b/patches/minecraft/net/minecraft/client/Minecraft.java.patch @@ -46,7 +46,7 @@ this.m_91271_(); this.f_91036_.m_7217_(this.f_90997_); this.f_91061_ = new ParticleEngine(this.f_91073_, this.f_90987_); -+ net.minecraftforge.fml.ModLoader.get().postEvent(new net.minecraftforge.client.event.ParticleFactoryRegisterEvent()); ++ net.minecraftforge.client.ForgeHooksClient.onRegisterParticleProviders(f_91061_); this.f_91036_.m_7217_(this.f_91061_); this.f_91053_ = new PaintingTextureManager(this.f_90987_); this.f_91036_.m_7217_(this.f_91053_); @@ -55,12 +55,12 @@ this.f_91036_.m_7217_(this.f_91047_); this.f_91036_.m_7217_(this.f_205120_); - this.f_91065_ = new Gui(this, this.f_90995_); -+ this.f_91065_ = new net.minecraftforge.client.gui.ForgeIngameGui(this); ++ this.f_91065_ = new net.minecraftforge.client.gui.overlay.ForgeGui(this); + this.f_91067_.m_91524_(this.f_90990_.m_85439_()); //Forge: Moved below ingameGUI setting to prevent NPEs in handeler. this.f_91064_ = new DebugRenderer(this); RenderSystem.m_69900_(this::m_91113_); if (this.f_91042_.f_83915_ == this.f_90990_.m_85441_() && this.f_91042_.f_83916_ == this.f_90990_.m_85442_()) { -@@ -526,6 +_,11 @@ +@@ -526,6 +_,19 @@ TinyFileDialogs.tinyfd_messageBox("Minecraft", stringbuilder.toString(), "ok", "error", false); } @@ -68,6 +68,14 @@ + net.minecraftforge.fml.ModLoader.get().postEvent(new net.minecraftforge.client.event.RegisterClientReloadListenersEvent(this.f_91036_)); + net.minecraftforge.fml.ModLoader.get().postEvent(new net.minecraftforge.client.event.EntityRenderersEvent.RegisterLayerDefinitions()); + net.minecraftforge.fml.ModLoader.get().postEvent(new net.minecraftforge.client.event.EntityRenderersEvent.RegisterRenderers()); ++ net.minecraftforge.client.textures.TextureAtlasSpriteLoaderManager.init(); ++ net.minecraftforge.client.gui.ClientTooltipComponentManager.init(); ++ net.minecraftforge.client.EntitySpectatorShaderManager.init(); ++ net.minecraftforge.client.ForgeHooksClient.onRegisterKeyMappings(f_91066_); ++ net.minecraftforge.client.RecipeBookManager.init(); ++ net.minecraftforge.client.gui.overlay.GuiOverlayManager.init(); ++ net.minecraftforge.client.DimensionSpecialEffectsManager.init(); ++ net.minecraftforge.client.NamedRenderTypeManager.init(); + this.f_90990_.m_85409_(this.f_91066_.m_231817_().m_231551_()); this.f_90990_.m_85424_(this.f_91066_.m_232123_().m_231551_()); @@ -140,33 +148,38 @@ if (p_91153_ == null && this.f_91073_ == null) { p_91153_ = new TitleScreen(); } else if (p_91153_ == null && this.f_91074_.m_21224_()) { -@@ -906,6 +_,15 @@ +@@ -906,6 +_,19 @@ } } + net.minecraftforge.client.ForgeHooksClient.clearGuiLayers(this); + Screen old = this.f_91080_; -+ net.minecraftforge.client.event.ScreenOpenEvent event = new net.minecraftforge.client.event.ScreenOpenEvent(p_91153_); -+ if (net.minecraftforge.common.MinecraftForge.EVENT_BUS.post(event)) return; ++ if (p_91153_ != null) { ++ var event = new net.minecraftforge.client.event.ScreenEvent.Opening(old, p_91153_); ++ if (net.minecraftforge.common.MinecraftForge.EVENT_BUS.post(event)) return; ++ p_91153_ = event.getScreen(); ++ } + -+ p_91153_ = event.getScreen(); -+ if (old != null && p_91153_ != old) ++ if (old != null && p_91153_ != old) { ++ net.minecraftforge.common.MinecraftForge.EVENT_BUS.post(new net.minecraftforge.client.event.ScreenEvent.Closing(old)); + old.m_7861_(); ++ } + this.f_91080_ = p_91153_; BufferUploader.m_166835_(); if (p_91153_ != null) { -@@ -1049,11 +_,13 @@ +@@ -1049,11 +_,14 @@ RenderSystem.m_69481_(); this.f_91026_.m_7238_(); if (!this.f_91079_) { -+ net.minecraftforge.event.ForgeEventFactory.onRenderTickStart(this.f_91012_ ? this.f_91013_ : this.f_90991_.f_92518_); ++ this.realPartialTick = this.f_91012_ ? this.f_91013_ : this.f_90991_.f_92518_; // Cache this since pause is volatile ++ net.minecraftforge.event.ForgeEventFactory.onRenderTickStart(this.realPartialTick); this.f_91026_.m_6182_("gameRenderer"); this.f_91063_.m_109093_(this.f_91012_ ? this.f_91013_ : this.f_90991_.f_92518_, i, p_91384_); this.f_91026_.m_6182_("toasts"); this.f_91003_.m_94920_(new PoseStack()); this.f_91026_.m_7238_(); -+ net.minecraftforge.event.ForgeEventFactory.onRenderTickEnd(this.f_91012_ ? this.f_91013_ : this.f_90991_.f_92518_); ++ net.minecraftforge.event.ForgeEventFactory.onRenderTickEnd(this.realPartialTick); } if (this.f_91056_ != null) { @@ -197,7 +210,7 @@ BlockPos blockpos = blockhitresult.m_82425_(); - if (!this.f_91073_.m_8055_(blockpos).m_60795_()) { + if (!this.f_91073_.m_46859_(blockpos)) { -+ net.minecraftforge.client.event.InputEvent.ClickInputEvent inputEvent = net.minecraftforge.client.ForgeHooksClient.onClickInput(0, this.f_91066_.f_92096_, InteractionHand.MAIN_HAND); ++ var inputEvent = net.minecraftforge.client.ForgeHooksClient.onClickInput(0, this.f_91066_.f_92096_, InteractionHand.MAIN_HAND); + if (inputEvent.isCanceled()) { + if (inputEvent.shouldSwingHand()) { + this.f_91061_.addBlockHitEffects(blockpos, blockhitresult); @@ -218,7 +231,7 @@ } else { boolean flag = false; - switch (this.f_91077_.m_6662_()) { -+ net.minecraftforge.client.event.InputEvent.ClickInputEvent inputEvent = net.minecraftforge.client.ForgeHooksClient.onClickInput(0, this.f_91066_.f_92096_, InteractionHand.MAIN_HAND); ++ var inputEvent = net.minecraftforge.client.ForgeHooksClient.onClickInput(0, this.f_91066_.f_92096_, InteractionHand.MAIN_HAND); + HitResult.Type hitType = this.f_91077_.m_6662_(); + if(this.f_91077_ instanceof EntityHitResult entityHit) { // Forge: Perform attack range checks here, instead of in GameRenderer#pick, so extended-reach interactions work. + if(!f_91074_.canHit(entityHit.m_82443_(), 0)) hitType = HitResult.Type.MISS; // No padding in client code. @@ -251,7 +264,7 @@ } for(InteractionHand interactionhand : InteractionHand.values()) { -+ net.minecraftforge.client.event.InputEvent.ClickInputEvent inputEvent = net.minecraftforge.client.ForgeHooksClient.onClickInput(1, this.f_91066_.f_92095_, interactionhand); ++ var inputEvent = net.minecraftforge.client.ForgeHooksClient.onClickInput(1, this.f_91066_.f_92095_, interactionhand); + if (inputEvent.isCanceled()) { + if (inputEvent.shouldSwingHand()) this.f_91074_.m_6674_(interactionhand); + return; @@ -441,18 +454,30 @@ } private static Supplier m_91330_(Supplier p_91331_) { -@@ -2660,6 +_,14 @@ - - public void m_91312_(int p_91313_) { +@@ -2662,6 +_,14 @@ this.f_91051_.m_119410_(p_91313_); -+ } -+ + } + + public ItemColors getItemColors() { + return this.f_91041_; + } + + public SearchRegistry getSearchTreeManager() { + return this.f_90997_; ++ } ++ + public EntityModelSet m_167973_() { + return this.f_167844_; } +@@ -2719,4 +_,11 @@ - public EntityModelSet m_167973_() { + public abstract boolean m_142594_(boolean p_168035_); + } ++ ++ // FORGE START ++ private float realPartialTick; ++ public float getPartialTick() { ++ return realPartialTick; ++ } ++ // FORGE END + } diff --git a/patches/minecraft/net/minecraft/client/MouseHandler.java.patch b/patches/minecraft/net/minecraft/client/MouseHandler.java.patch index d4266d503d7..d40024713f9 100644 --- a/patches/minecraft/net/minecraft/client/MouseHandler.java.patch +++ b/patches/minecraft/net/minecraft/client/MouseHandler.java.patch @@ -4,7 +4,7 @@ this.f_91510_ = -1; } -+ if (net.minecraftforge.client.ForgeHooksClient.onRawMouseClicked(p_91532_, p_91533_, p_91534_)) return; ++ if (net.minecraftforge.client.ForgeHooksClient.onMouseButtonPre(p_91532_, p_91533_, p_91534_)) return; boolean[] aboolean = new boolean[]{false}; if (this.f_91503_.m_91265_() == null) { if (this.f_91503_.f_91080_ == null) { @@ -35,7 +35,7 @@ } } - -+ net.minecraftforge.client.ForgeHooksClient.fireMouseInput(p_91532_, p_91533_, p_91534_); ++ net.minecraftforge.client.ForgeHooksClient.onMouseButtonPost(p_91532_, p_91533_, p_91534_); } } diff --git a/patches/minecraft/net/minecraft/client/RecipeBookCategories.java.patch b/patches/minecraft/net/minecraft/client/RecipeBookCategories.java.patch index ba40062a6ad..254604ce81d 100644 --- a/patches/minecraft/net/minecraft/client/RecipeBookCategories.java.patch +++ b/patches/minecraft/net/minecraft/client/RecipeBookCategories.java.patch @@ -14,17 +14,16 @@ public static final List f_92258_ = ImmutableList.of(FURNACE_SEARCH, FURNACE_FOOD, FURNACE_BLOCKS, FURNACE_MISC); public static final List f_92259_ = ImmutableList.of(CRAFTING_SEARCH, CRAFTING_EQUIPMENT, CRAFTING_BUILDING_BLOCKS, CRAFTING_MISC, CRAFTING_REDSTONE); - public static final Map> f_92260_ = ImmutableMap.of(CRAFTING_SEARCH, ImmutableList.of(CRAFTING_EQUIPMENT, CRAFTING_BUILDING_BLOCKS, CRAFTING_MISC, CRAFTING_REDSTONE), FURNACE_SEARCH, ImmutableList.of(FURNACE_FOOD, FURNACE_BLOCKS, FURNACE_MISC), BLAST_FURNACE_SEARCH, ImmutableList.of(BLAST_FURNACE_BLOCKS, BLAST_FURNACE_MISC), SMOKER_SEARCH, ImmutableList.of(SMOKER_FOOD)); -+ public static final Map> f_92260_ = net.minecraftforge.client.RecipeBookRegistry.AGGREGATE_CATEGORIES_VIEW; ++ public static final Map> f_92260_ = net.minecraftforge.client.RecipeBookManager.getAggregateCategories(); private final List f_92261_; private RecipeBookCategories(ItemStack... p_92267_) { -@@ -54,11 +_,17 @@ +@@ -54,11 +_,15 @@ case SMOKER: return f_92256_; default: -+ if (net.minecraftforge.client.RecipeBookRegistry.TYPE_TO_CATEGORIES_VIEW.containsKey(p_92270_)) -+ return net.minecraftforge.client.RecipeBookRegistry.TYPE_TO_CATEGORIES_VIEW.get(p_92270_); - return ImmutableList.of(); +- return ImmutableList.of(); ++ return net.minecraftforge.client.RecipeBookManager.getCustomCategoriesOrEmpty(p_92270_); } } diff --git a/patches/minecraft/net/minecraft/client/color/block/BlockColors.java.patch b/patches/minecraft/net/minecraft/client/color/block/BlockColors.java.patch index c0ca58a0b0c..4deb5b3795b 100644 --- a/patches/minecraft/net/minecraft/client/color/block/BlockColors.java.patch +++ b/patches/minecraft/net/minecraft/client/color/block/BlockColors.java.patch @@ -24,7 +24,7 @@ if (blockcolor != null) { return blockcolor.m_92566_(p_92583_, (BlockAndTintGetter)null, (BlockPos)null, 0); } else { -@@ -87,13 +_,13 @@ +@@ -87,13 +_,15 @@ } public int m_92577_(BlockState p_92578_, @Nullable BlockAndTintGetter p_92579_, @Nullable BlockPos p_92580_, int p_92581_) { @@ -33,6 +33,8 @@ return blockcolor == null ? -1 : blockcolor.m_92566_(p_92578_, p_92579_, p_92580_, p_92581_); } ++ /** @deprecated Register via {@link net.minecraftforge.client.event.RegisterColorHandlersEvent.Block} */ ++ @Deprecated public void m_92589_(BlockColor p_92590_, Block... p_92591_) { for(Block block : p_92591_) { - this.f_92571_.m_122664_(p_92590_, Registry.f_122824_.m_7447_(block)); diff --git a/patches/minecraft/net/minecraft/client/color/item/ItemColors.java.patch b/patches/minecraft/net/minecraft/client/color/item/ItemColors.java.patch index 5021f30bad0..8e62d2f28ba 100644 --- a/patches/minecraft/net/minecraft/client/color/item/ItemColors.java.patch +++ b/patches/minecraft/net/minecraft/client/color/item/ItemColors.java.patch @@ -10,7 +10,7 @@ public static ItemColors m_92683_(BlockColors p_92684_) { ItemColors itemcolors = new ItemColors(); -@@ -88,17 +_,18 @@ +@@ -88,17 +_,20 @@ itemcolors.m_92689_((p_232352_, p_232353_) -> { return p_232353_ == 0 ? -1 : MapItem.m_42918_(p_232352_); }, Items.f_42573_); @@ -24,6 +24,8 @@ return itemcolor == null ? -1 : itemcolor.m_92671_(p_92677_, p_92678_); } ++ /** @deprecated Register via {@link net.minecraftforge.client.event.RegisterColorHandlersEvent.Item} */ ++ @Deprecated public void m_92689_(ItemColor p_92690_, ItemLike... p_92691_) { for(ItemLike itemlike : p_92691_) { - this.f_92674_.m_122664_(p_92690_, Item.m_41393_(itemlike.m_5456_())); diff --git a/patches/minecraft/net/minecraft/client/gui/Gui.java.patch b/patches/minecraft/net/minecraft/client/gui/Gui.java.patch index 4cd9e4b0ce1..c5dbf80e843 100644 --- a/patches/minecraft/net/minecraft/client/gui/Gui.java.patch +++ b/patches/minecraft/net/minecraft/client/gui/Gui.java.patch @@ -12,21 +12,21 @@ for(MobEffectInstance mobeffectinstance : Ordering.natural().reverse().sortedCopy(collection)) { MobEffect mobeffect = mobeffectinstance.m_19544_(); -+ net.minecraftforge.client.EffectRenderer renderer = net.minecraftforge.client.RenderProperties.getEffectRenderer(mobeffectinstance); -+ if (!renderer.shouldRenderHUD(mobeffectinstance)) continue; ++ var renderer = net.minecraftforge.client.extensions.common.IClientMobEffectExtensions.of(mobeffectinstance); ++ if (!renderer.isVisibleInGui(mobeffectinstance)) continue; + // Rebind in case previous renderHUDEffect changed texture + RenderSystem.m_157456_(0, AbstractContainerScreen.f_97725_); if (mobeffectinstance.m_19575_()) { int i = this.f_92977_; int j = 1; -@@ -489,6 +_,7 @@ - RenderSystem.m_157429_(1.0F, 1.0F, 1.0F, f1); - m_93200_(p_93029_, l + 3, i1 + 3, this.m_93252_(), 18, 18, textureatlassprite); - }); -+ renderer.renderHUDEffect(mobeffectinstance,this, p_93029_, i, j, this.m_93252_(), f); - } - } +@@ -480,6 +_,7 @@ + } + } ++ if (renderer.renderGuiIcon(mobeffectinstance, this, p_93029_, i, j, this.m_93252_(), f)) continue; + TextureAtlasSprite textureatlassprite = mobeffecttexturemanager.m_118732_(mobeffect); + int l = i; + int i1 = j; @@ -609,12 +_,13 @@ public void m_93069_(PoseStack p_93070_) { this.f_92986_.m_91307_().m_6180_("selectedItemName"); @@ -48,7 +48,7 @@ RenderSystem.m_69453_(); m_93172_(p_93070_, j - 2, k - 2, j + i + 2, k + 9 + 2, this.f_92986_.f_91066_.m_92143_(0)); - this.m_93082_().m_92763_(p_93070_, mutablecomponent, (float)j, (float)k, 16777215 + (l << 24)); -+ Font font = net.minecraftforge.client.RenderProperties.get(f_92994_).getFont(f_92994_); ++ Font font = net.minecraftforge.client.extensions.common.IClientItemExtensions.of(f_92994_).getFont(f_92994_, net.minecraftforge.client.extensions.common.IClientItemExtensions.FontContext.SELECTED_ITEM_NAME); + if (font == null) { + this.m_93082_().m_92763_(p_93070_, highlightTip, (float)j, (float)k, 16777215 + (l << 24)); + } else { diff --git a/patches/minecraft/net/minecraft/client/gui/components/BossHealthOverlay.java.patch b/patches/minecraft/net/minecraft/client/gui/components/BossHealthOverlay.java.patch index f8aa36b2497..1fc9e58b13c 100644 --- a/patches/minecraft/net/minecraft/client/gui/components/BossHealthOverlay.java.patch +++ b/patches/minecraft/net/minecraft/client/gui/components/BossHealthOverlay.java.patch @@ -1,23 +1,19 @@ --- a/net/minecraft/client/gui/components/BossHealthOverlay.java +++ b/net/minecraft/client/gui/components/BossHealthOverlay.java -@@ -34,6 +_,9 @@ +@@ -34,6 +_,7 @@ for(LerpingBossEvent lerpingbossevent : this.f_93699_.values()) { int k = i / 2 - 91; -+ net.minecraftforge.client.event.RenderGameOverlayEvent.BossInfo event = -+ net.minecraftforge.client.ForgeHooksClient.renderBossEventPre(p_93705_, this.f_93698_.m_91268_(), lerpingbossevent, k, j, 10 + this.f_93698_.f_91062_.f_92710_); -+ if (!event.isCanceled()) { ++ var event = net.minecraftforge.client.ForgeHooksClient.onCustomizeBossEventProgress(p_93705_, this.f_93698_.m_91268_(), lerpingbossevent, k, j, 10 + this.f_93698_.f_91062_.f_92710_); RenderSystem.m_157429_(1.0F, 1.0F, 1.0F, 1.0F); RenderSystem.m_157456_(0, f_93697_); this.m_93706_(p_93705_, k, j, lerpingbossevent); -@@ -42,7 +_,9 @@ +@@ -42,7 +_,7 @@ int i1 = i / 2 - l / 2; int j1 = j - 9; this.f_93698_.f_91062_.m_92763_(p_93705_, component, (float)i1, (float)j1, 16777215); - j += 10 + 9; -+ } + j += event.getIncrement(); -+ net.minecraftforge.client.ForgeHooksClient.renderBossEventPost(p_93705_, this.f_93698_.m_91268_()); if (j >= this.f_93698_.m_91268_().m_85446_() / 3) { break; } diff --git a/patches/minecraft/net/minecraft/client/gui/screens/Screen.java.patch b/patches/minecraft/net/minecraft/client/gui/screens/Screen.java.patch index 7ea644ffa06..b177b4d2c73 100644 --- a/patches/minecraft/net/minecraft/client/gui/screens/Screen.java.patch +++ b/patches/minecraft/net/minecraft/client/gui/screens/Screen.java.patch @@ -156,12 +156,12 @@ + this.f_169368_.add(ne); + f_96540_.add(b); + }; -+ if (!net.minecraftforge.common.MinecraftForge.EVENT_BUS.post(new net.minecraftforge.client.event.ScreenEvent.InitScreenEvent.Pre(this, this.f_96540_, add, this::m_169411_))) { ++ if (!net.minecraftforge.common.MinecraftForge.EVENT_BUS.post(new net.minecraftforge.client.event.ScreenEvent.Init.Pre(this, this.f_96540_, add, this::m_169411_))) { this.m_232761_(); this.m_169407_(false); this.m_169378_(f_169370_); + } -+ net.minecraftforge.common.MinecraftForge.EVENT_BUS.post(new net.minecraftforge.client.event.ScreenEvent.InitScreenEvent.Post(this, this.f_96540_, add, this::m_169411_)); ++ net.minecraftforge.common.MinecraftForge.EVENT_BUS.post(new net.minecraftforge.client.event.ScreenEvent.Init.Post(this, this.f_96540_, add, this::m_169411_)); } protected void m_232761_() { @@ -169,7 +169,7 @@ public void m_96558_(PoseStack p_96559_, int p_96560_) { if (this.f_96541_.f_91073_ != null) { this.m_93179_(p_96559_, 0, 0, this.f_96543_, this.f_96544_, -1072689136, -804253680); -+ net.minecraftforge.common.MinecraftForge.EVENT_BUS.post(new net.minecraftforge.client.event.ScreenEvent.BackgroundDrawnEvent(this, p_96559_)); ++ net.minecraftforge.common.MinecraftForge.EVENT_BUS.post(new net.minecraftforge.client.event.ScreenEvent.BackgroundRendered(this, p_96559_)); } else { this.m_96626_(p_96560_); } @@ -177,7 +177,7 @@ bufferbuilder.m_5483_((double)this.f_96543_, 0.0D, 0.0D).m_7421_((float)this.f_96543_ / 32.0F, (float)p_96627_).m_6122_(64, 64, 64, 255).m_5752_(); bufferbuilder.m_5483_(0.0D, 0.0D, 0.0D).m_7421_(0.0F, (float)p_96627_).m_6122_(64, 64, 64, 255).m_5752_(); tesselator.m_85914_(); -+ net.minecraftforge.common.MinecraftForge.EVENT_BUS.post(new net.minecraftforge.client.event.ScreenEvent.BackgroundDrawnEvent(this, new PoseStack())); ++ net.minecraftforge.common.MinecraftForge.EVENT_BUS.post(new net.minecraftforge.client.event.ScreenEvent.BackgroundRendered(this, new PoseStack())); } public boolean m_7043_() { diff --git a/patches/minecraft/net/minecraft/client/gui/screens/TitleScreen.java.patch b/patches/minecraft/net/minecraft/client/gui/screens/TitleScreen.java.patch index 112fe416c4d..6bf2e364588 100644 --- a/patches/minecraft/net/minecraft/client/gui/screens/TitleScreen.java.patch +++ b/patches/minecraft/net/minecraft/client/gui/screens/TitleScreen.java.patch @@ -4,7 +4,7 @@ private long f_96715_; @Nullable private TitleScreen.WarningLabel f_232768_; -+ private net.minecraftforge.client.gui.NotificationModUpdateScreen modUpdateNotification; ++ private net.minecraftforge.client.gui.TitleScreenModUpdateIndicator modUpdateNotification; public TitleScreen() { this(false); @@ -21,7 +21,7 @@ + this.f_96541_.m_91152_(new net.minecraftforge.client.gui.ModListScreen(this)); + })); } -+ modUpdateNotification = net.minecraftforge.client.gui.NotificationModUpdateScreen.init(this, modButton); ++ modUpdateNotification = net.minecraftforge.client.gui.TitleScreenModUpdateIndicator.init(this, modButton); this.m_142416_(new ImageButton(this.f_96543_ / 2 - 124, l + 72 + 12, 20, 20, 0, 106, 20, Button.f_93617_, 256, 256, (p_96791_) -> { this.f_96541_.m_91152_(new LanguageSelectScreen(this, this.f_96541_.f_91066_, this.f_96541_.m_91102_())); diff --git a/patches/minecraft/net/minecraft/client/gui/screens/inventory/AbstractContainerScreen.java.patch b/patches/minecraft/net/minecraft/client/gui/screens/inventory/AbstractContainerScreen.java.patch index d49e023ae12..ba3a8b0fddf 100644 --- a/patches/minecraft/net/minecraft/client/gui/screens/inventory/AbstractContainerScreen.java.patch +++ b/patches/minecraft/net/minecraft/client/gui/screens/inventory/AbstractContainerScreen.java.patch @@ -4,7 +4,7 @@ int i = this.f_97735_; int j = this.f_97736_; this.m_7286_(p_97795_, p_97798_, p_97796_, p_97797_); -+ net.minecraftforge.common.MinecraftForge.EVENT_BUS.post(new net.minecraftforge.client.event.ContainerScreenEvent.DrawBackground(this, p_97795_, p_97796_, p_97797_)); ++ net.minecraftforge.common.MinecraftForge.EVENT_BUS.post(new net.minecraftforge.client.event.ContainerScreenEvent.Render.Background(this, p_97795_, p_97796_, p_97797_)); RenderSystem.m_69465_(); super.m_6305_(p_97795_, p_97796_, p_97797_, p_97798_); PoseStack posestack = RenderSystem.m_157191_(); @@ -18,7 +18,7 @@ } this.m_7027_(p_97795_, p_97796_, p_97797_); -+ net.minecraftforge.common.MinecraftForge.EVENT_BUS.post(new net.minecraftforge.client.event.ContainerScreenEvent.DrawForeground(this, p_97795_, p_97796_, p_97797_)); ++ net.minecraftforge.common.MinecraftForge.EVENT_BUS.post(new net.minecraftforge.client.event.ContainerScreenEvent.Render.Foreground(this, p_97795_, p_97796_, p_97797_)); ItemStack itemstack = this.f_97711_.m_41619_() ? this.f_97732_.m_142621_() : this.f_97711_; if (!itemstack.m_41619_()) { int l1 = 8; @@ -41,7 +41,7 @@ RenderSystem.m_157182_(); this.m_93250_(200); this.f_96542_.f_115093_ = 200.0F; -+ net.minecraft.client.gui.Font font = net.minecraftforge.client.RenderProperties.get(p_97783_).getFont(p_97783_); ++ var font = net.minecraftforge.client.extensions.common.IClientItemExtensions.of(p_97783_).getFont(p_97783_, net.minecraftforge.client.extensions.common.IClientItemExtensions.FontContext.ITEM_COUNT); + if (font == null) font = this.f_96547_; this.f_96542_.m_115203_(p_97783_, p_97784_, p_97785_); - this.f_96542_.m_115174_(this.f_96547_, p_97783_, p_97784_, p_97785_ - (this.f_97711_.m_41619_() ? 0 : 8), p_97786_); diff --git a/patches/minecraft/net/minecraft/client/gui/screens/inventory/EffectRenderingInventoryScreen.java.patch b/patches/minecraft/net/minecraft/client/gui/screens/inventory/EffectRenderingInventoryScreen.java.patch index 42964990f43..2f7c7f94aec 100644 --- a/patches/minecraft/net/minecraft/client/gui/screens/inventory/EffectRenderingInventoryScreen.java.patch +++ b/patches/minecraft/net/minecraft/client/gui/screens/inventory/EffectRenderingInventoryScreen.java.patch @@ -1,11 +1,12 @@ --- a/net/minecraft/client/gui/screens/inventory/EffectRenderingInventoryScreen.java +++ b/net/minecraft/client/gui/screens/inventory/EffectRenderingInventoryScreen.java -@@ -42,12 +_,15 @@ +@@ -42,12 +_,16 @@ if (!collection.isEmpty() && j >= 32) { RenderSystem.m_157429_(1.0F, 1.0F, 1.0F, 1.0F); boolean flag = j >= 120; -+ var event = net.minecraftforge.client.ForgeHooksClient.onScreenPotionSize(this); -+ if (event != net.minecraftforge.eventbus.api.Event.Result.DEFAULT) flag = event == net.minecraftforge.eventbus.api.Event.Result.DENY; // true means classic mode ++ var event = net.minecraftforge.client.ForgeHooksClient.onScreenPotionSize(this, j, !flag); ++ if (event == 0) return; // 0 = cancel rendering ++ flag = event == 2; // 2 = full-size / 1 = compact int k = 33; if (collection.size() > 5) { k = 132 / (collection.size() - 1); @@ -17,13 +18,24 @@ this.m_194002_(p_194015_, i, k, iterable, flag); this.m_194008_(p_194015_, i, k, iterable, flag); if (flag) { -@@ -108,6 +_,12 @@ +@@ -95,6 +_,11 @@ + int i = this.f_97736_; + + for(MobEffectInstance mobeffectinstance : p_194012_) { ++ var renderer = net.minecraftforge.client.extensions.common.IClientMobEffectExtensions.of(mobeffectinstance); ++ if (renderer.renderInventoryIcon(mobeffectinstance, this, p_194009_, p_194010_ + (p_194013_ ? 6 : 7), i, this.m_93252_())) { ++ i += p_194011_; ++ continue; ++ } + MobEffect mobeffect = mobeffectinstance.m_19544_(); + TextureAtlasSprite textureatlassprite = mobeffecttexturemanager.m_118732_(mobeffect); + RenderSystem.m_157456_(0, textureatlassprite.m_118414_().m_118330_()); +@@ -108,6 +_,11 @@ int i = this.f_97736_; for(MobEffectInstance mobeffectinstance : p_98726_) { -+ net.minecraftforge.client.EffectRenderer renderer = net.minecraftforge.client.RenderProperties.getEffectRenderer(mobeffectinstance); -+ renderer.renderInventoryEffect(mobeffectinstance, this, p_98723_, p_98724_, i, this.m_93252_()); -+ if (!renderer.shouldRenderInvText(mobeffectinstance)) { ++ var renderer = net.minecraftforge.client.extensions.common.IClientMobEffectExtensions.of(mobeffectinstance); ++ if (renderer.renderInventoryText(mobeffectinstance, this, p_98723_, p_98724_, i, this.m_93252_())) { + i += p_98725_; + continue; + } diff --git a/patches/minecraft/net/minecraft/client/gui/screens/inventory/tooltip/ClientTooltipComponent.java.patch b/patches/minecraft/net/minecraft/client/gui/screens/inventory/tooltip/ClientTooltipComponent.java.patch index 2cbd8c78acd..627230b0312 100644 --- a/patches/minecraft/net/minecraft/client/gui/screens/inventory/tooltip/ClientTooltipComponent.java.patch +++ b/patches/minecraft/net/minecraft/client/gui/screens/inventory/tooltip/ClientTooltipComponent.java.patch @@ -4,7 +4,7 @@ if (p_169951_ instanceof BundleTooltip) { return new ClientBundleTooltip((BundleTooltip)p_169951_); } else { -+ ClientTooltipComponent result = net.minecraftforge.client.MinecraftForgeClient.getClientTooltipComponent(p_169951_); ++ ClientTooltipComponent result = net.minecraftforge.client.gui.ClientTooltipComponentManager.createClientTooltipComponent(p_169951_); + if (result != null) return result; throw new IllegalArgumentException("Unknown TooltipComponent"); } diff --git a/patches/minecraft/net/minecraft/client/multiplayer/ClientLevel.java.patch b/patches/minecraft/net/minecraft/client/multiplayer/ClientLevel.java.patch index 96ad30329c4..4161fdeb2d6 100644 --- a/patches/minecraft/net/minecraft/client/multiplayer/ClientLevel.java.patch +++ b/patches/minecraft/net/minecraft/client/multiplayer/ClientLevel.java.patch @@ -1,10 +1,11 @@ --- a/net/minecraft/client/multiplayer/ClientLevel.java +++ b/net/minecraft/client/multiplayer/ClientLevel.java -@@ -121,6 +_,7 @@ +@@ -121,6 +_,8 @@ private int f_194123_; private final BlockStatePredictionHandler f_233599_ = new BlockStatePredictionHandler(); private static final Set f_194124_ = Set.of(Items.f_42127_, Items.f_151033_); + private final it.unimi.dsi.fastutil.ints.Int2ObjectMap> partEntities = new it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap<>(); ++ private final net.minecraftforge.client.model.data.ModelDataManager modelDataManager = new net.minecraftforge.client.model.data.ModelDataManager(this); public void m_233651_(int p_233652_) { this.f_233599_.m_233856_(p_233652_, this); @@ -70,7 +71,7 @@ this.f_104840_ = p_104852_; } -@@ -939,14 +_,33 @@ +@@ -939,14 +_,46 @@ ClientLevel.this.f_104566_.add((AbstractClientPlayer)p_171712_); } @@ -102,5 +103,18 @@ + @Override + public java.util.Collection> getPartEntities() { + return this.partEntities.values(); ++ } ++ ++ @Override ++ public net.minecraftforge.client.model.data.ModelDataManager getModelDataManager() { ++ return modelDataManager; ++ } ++ ++ @Override ++ public float getShade(float normalX, float normalY, float normalZ, boolean shade) { ++ boolean constantAmbientLight = this.m_104583_().m_108885_(); ++ if (!shade) ++ return constantAmbientLight ? 0.9F : 1.0F; ++ return net.minecraftforge.client.model.lighting.QuadLighter.calculateShade(normalX, normalY, normalZ, constantAmbientLight); } } diff --git a/patches/minecraft/net/minecraft/client/multiplayer/ClientPacketListener.java.patch b/patches/minecraft/net/minecraft/client/multiplayer/ClientPacketListener.java.patch index af2cbc14b76..a054e7e3dff 100644 --- a/patches/minecraft/net/minecraft/client/multiplayer/ClientPacketListener.java.patch +++ b/patches/minecraft/net/minecraft/client/multiplayer/ClientPacketListener.java.patch @@ -20,7 +20,7 @@ } Component component = flag ? p_233693_.f_237213_() : p_233693_.m_237220_(); -+ component = net.minecraftforge.event.ForgeEventFactory.onClientChat(p_233692_, component, p_233694_); ++ component = net.minecraftforge.client.ForgeHooksClient.onClientChat(p_233692_, component, p_233694_); + if (component == null) return; this.f_104888_.f_91065_.m_232360_(p_233692_, component, p_233694_); } diff --git a/patches/minecraft/net/minecraft/client/particle/BreakingItemParticle.java.patch b/patches/minecraft/net/minecraft/client/particle/BreakingItemParticle.java.patch index 8cd54f85dbd..38322a01733 100644 --- a/patches/minecraft/net/minecraft/client/particle/BreakingItemParticle.java.patch +++ b/patches/minecraft/net/minecraft/client/particle/BreakingItemParticle.java.patch @@ -6,7 +6,7 @@ super(p_105665_, p_105666_, p_105667_, p_105668_, 0.0D, 0.0D, 0.0D); - this.m_108337_(Minecraft.m_91087_().m_91291_().m_174264_(p_105669_, p_105665_, (LivingEntity)null, 0).m_6160_()); + var model = Minecraft.m_91087_().m_91291_().m_174264_(p_105669_, p_105665_, (LivingEntity)null, 0); -+ this.m_108337_(model.m_7343_().m_173464_(model, p_105669_, p_105665_, null, 0).getParticleIcon(net.minecraftforge.client.model.data.EmptyModelData.INSTANCE)); ++ this.m_108337_(model.m_7343_().m_173464_(model, p_105669_, p_105665_, null, 0).getParticleIcon(net.minecraftforge.client.model.data.ModelData.EMPTY)); this.f_107226_ = 1.0F; this.f_107663_ /= 2.0F; this.f_105643_ = this.f_107223_.m_188501_() * 3.0F; diff --git a/patches/minecraft/net/minecraft/client/particle/ParticleEngine.java.patch b/patches/minecraft/net/minecraft/client/particle/ParticleEngine.java.patch index d7da5ca52be..1293f024bfc 100644 --- a/patches/minecraft/net/minecraft/client/particle/ParticleEngine.java.patch +++ b/patches/minecraft/net/minecraft/client/particle/ParticleEngine.java.patch @@ -14,14 +14,19 @@ private final Queue f_107294_ = Queues.newArrayDeque(); private final Map f_107295_ = Maps.newHashMap(); private final TextureAtlas f_107296_; -@@ -178,13 +_,13 @@ +@@ -177,14 +_,18 @@ + this.m_107378_(ParticleTypes.f_235901_, ShriekParticle.Provider::new); } ++ /** @deprecated Register via {@link net.minecraftforge.client.event.RegisterParticleProvidersEvent} */ ++ @Deprecated public void m_107381_(ParticleType p_107382_, ParticleProvider p_107383_) { - this.f_107293_.put(Registry.f_122829_.m_7447_(p_107382_), p_107383_); + this.f_107293_.put(Registry.f_122829_.m_7981_(p_107382_), p_107383_); } ++ /** @deprecated Register via {@link net.minecraftforge.client.event.RegisterParticleProvidersEvent} */ ++ @Deprecated public void m_107378_(ParticleType p_107379_, ParticleEngine.SpriteParticleRegistration p_107380_) { ParticleEngine.MutableSpriteSet particleengine$mutablespriteset = new ParticleEngine.MutableSpriteSet(); this.f_107295_.put(Registry.f_122829_.m_7981_(p_107379_), particleengine$mutablespriteset); @@ -79,7 +84,7 @@ public void m_107355_(BlockPos p_107356_, BlockState p_107357_) { - if (!p_107357_.m_60795_()) { -+ if (!p_107357_.m_60795_() && !net.minecraftforge.client.RenderProperties.get(p_107357_).addDestroyEffects(p_107357_, this.f_107287_, p_107356_, this)) { ++ if (!p_107357_.m_60795_() && !net.minecraftforge.client.extensions.common.IClientBlockExtensions.of(p_107357_).addDestroyEffects(p_107357_, this.f_107287_, p_107356_, this)) { VoxelShape voxelshape = p_107357_.m_60808_(this.f_107287_, p_107356_); double d0 = 0.25D; voxelshape.m_83286_((p_172273_, p_172274_, p_172275_, p_172276_, p_172277_, p_172278_) -> { @@ -107,7 +112,7 @@ + + public void addBlockHitEffects(BlockPos pos, net.minecraft.world.phys.BlockHitResult target) { + BlockState state = f_107287_.m_8055_(pos); -+ if (!net.minecraftforge.client.RenderProperties.get(state).addHitEffects(state, f_107287_, target, this)) ++ if (!net.minecraftforge.client.extensions.common.IClientBlockExtensions.of(state).addHitEffects(state, f_107287_, target, this)) + m_107367_(pos, target.m_82434_()); } diff --git a/patches/minecraft/net/minecraft/client/player/AbstractClientPlayer.java.patch b/patches/minecraft/net/minecraft/client/player/AbstractClientPlayer.java.patch index 786d0ad6640..aeb8d98921a 100644 --- a/patches/minecraft/net/minecraft/client/player/AbstractClientPlayer.java.patch +++ b/patches/minecraft/net/minecraft/client/player/AbstractClientPlayer.java.patch @@ -5,6 +5,6 @@ } - return Mth.m_14179_(Minecraft.m_91087_().f_91066_.m_231925_().m_231551_().floatValue(), 1.0F, f); -+ return net.minecraftforge.client.ForgeHooksClient.getFieldOfView(this, f); ++ return net.minecraftforge.client.ForgeHooksClient.getFieldOfViewModifier(this, f); } } diff --git a/patches/minecraft/net/minecraft/client/player/LocalPlayer.java.patch b/patches/minecraft/net/minecraft/client/player/LocalPlayer.java.patch index 547df395136..a5559cc4414 100644 --- a/patches/minecraft/net/minecraft/client/player/LocalPlayer.java.patch +++ b/patches/minecraft/net/minecraft/client/player/LocalPlayer.java.patch @@ -13,7 +13,7 @@ public void m_234125_(String p_234126_, @Nullable Component p_234127_) { + // TODO-PATCHING: If the chat preview component is not null and the message is changed by this event, it looks like the signatures will de-sync and the server will skip the message. Fix? -SS -+ p_234126_ = net.minecraftforge.event.ForgeEventFactory.onClientSendMessage(p_234126_); ++ p_234126_ = net.minecraftforge.client.ForgeHooksClient.onClientSendMessage(p_234126_); + if (p_234126_.isEmpty()) return; MessageSigner messagesigner = MessageSigner.m_237183_(this.m_20148_()); this.m_234141_(messagesigner, p_234126_, p_234127_); diff --git a/patches/minecraft/net/minecraft/client/renderer/DimensionSpecialEffects.java.patch b/patches/minecraft/net/minecraft/client/renderer/DimensionSpecialEffects.java.patch index add11e0cef8..a29a670f209 100644 --- a/patches/minecraft/net/minecraft/client/renderer/DimensionSpecialEffects.java.patch +++ b/patches/minecraft/net/minecraft/client/renderer/DimensionSpecialEffects.java.patch @@ -1,49 +1,20 @@ --- a/net/minecraft/client/renderer/DimensionSpecialEffects.java +++ b/net/minecraft/client/renderer/DimensionSpecialEffects.java -@@ -27,6 +_,10 @@ - private final DimensionSpecialEffects.SkyType f_108861_; - private final boolean f_108862_; - private final boolean f_108863_; -+ private net.minecraftforge.client.IWeatherRenderHandler weatherRenderHandler = null; -+ private net.minecraftforge.client.IWeatherParticleRenderHandler weatherParticleRenderHandler = null; -+ private net.minecraftforge.client.ISkyRenderHandler skyRenderHandler = null; -+ private net.minecraftforge.client.ICloudRenderHandler cloudRenderHandler = null; +@@ -13,7 +_,7 @@ + import net.minecraftforge.api.distmarker.OnlyIn; - public DimensionSpecialEffects(float p_108866_, boolean p_108867_, DimensionSpecialEffects.SkyType p_108868_, boolean p_108869_, boolean p_108870_) { - this.f_108859_ = p_108866_; -@@ -81,6 +_,35 @@ + @OnlyIn(Dist.CLIENT) +-public abstract class DimensionSpecialEffects { ++public abstract class DimensionSpecialEffects implements net.minecraftforge.client.extensions.IForgeDimensionSpecialEffects { + private static final Object2ObjectMap f_108857_ = Util.m_137469_(new Object2ObjectArrayMap<>(), (p_108881_) -> { + DimensionSpecialEffects.OverworldEffects dimensionspecialeffects$overworldeffects = new DimensionSpecialEffects.OverworldEffects(); + p_108881_.defaultReturnValue(dimensionspecialeffects$overworldeffects); +@@ -37,7 +_,7 @@ + } - public boolean m_108885_() { - return this.f_108863_; -+ } -+ -+ public void setWeatherRenderHandler(net.minecraftforge.client.IWeatherRenderHandler weatherRenderHandler) { -+ this.weatherRenderHandler = weatherRenderHandler; -+ } -+ public void setWeatherParticleRenderHandler(net.minecraftforge.client.IWeatherParticleRenderHandler weatherParticleRenderHandler) { -+ this.weatherParticleRenderHandler = weatherParticleRenderHandler; -+ } -+ public void setSkyRenderHandler(net.minecraftforge.client.ISkyRenderHandler skyRenderHandler) { -+ this.skyRenderHandler = skyRenderHandler; -+ } -+ public void setCloudRenderHandler(net.minecraftforge.client.ICloudRenderHandler cloudRenderHandler) { -+ this.cloudRenderHandler = cloudRenderHandler; -+ } -+ @Nullable -+ public net.minecraftforge.client.ICloudRenderHandler getCloudRenderHandler() { -+ return cloudRenderHandler; -+ } -+ @Nullable -+ public net.minecraftforge.client.IWeatherRenderHandler getWeatherRenderHandler() { -+ return weatherRenderHandler; -+ } -+ @Nullable -+ public net.minecraftforge.client.IWeatherParticleRenderHandler getWeatherParticleRenderHandler() { -+ return weatherParticleRenderHandler; -+ } -+ @Nullable -+ public net.minecraftforge.client.ISkyRenderHandler getSkyRenderHandler() { -+ return skyRenderHandler; + public static DimensionSpecialEffects m_108876_(DimensionType p_108877_) { +- return f_108857_.get(p_108877_.f_63837_()); ++ return net.minecraftforge.client.DimensionSpecialEffectsManager.getForType(p_108877_.f_63837_()); } - @OnlyIn(Dist.CLIENT) + @Nullable diff --git a/patches/minecraft/net/minecraft/client/renderer/GameRenderer.java.patch b/patches/minecraft/net/minecraft/client/renderer/GameRenderer.java.patch index 75fbdca0b5c..67bb0daf827 100644 --- a/patches/minecraft/net/minecraft/client/renderer/GameRenderer.java.patch +++ b/patches/minecraft/net/minecraft/client/renderer/GameRenderer.java.patch @@ -88,7 +88,7 @@ this.m_109111_(matrix4f); camera.m_90575_(this.f_109059_.f_91073_, (Entity)(this.f_109059_.m_91288_() == null ? this.f_109059_.f_91074_ : this.f_109059_.m_91288_()), !this.f_109059_.f_91066_.m_92176_().m_90612_(), this.f_109059_.f_91066_.m_92176_().m_90613_(), p_109090_); + -+ net.minecraftforge.client.event.EntityViewRenderEvent.CameraSetup cameraSetup = net.minecraftforge.client.ForgeHooksClient.onCameraSetup(this, camera, p_109090_); ++ net.minecraftforge.client.event.ViewportEvent.ComputeCameraAngles cameraSetup = net.minecraftforge.client.ForgeHooksClient.onCameraSetup(this, camera, p_109090_); + camera.setAnglesInternal(cameraSetup.getYaw(), cameraSetup.getPitch()); + p_109092_.m_85845_(Vector3f.f_122227_.m_122240_(cameraSetup.getRoll())); + diff --git a/patches/minecraft/net/minecraft/client/renderer/ItemBlockRenderTypes.java.patch b/patches/minecraft/net/minecraft/client/renderer/ItemBlockRenderTypes.java.patch index 722925438f3..a5b3b1cfaa3 100644 --- a/patches/minecraft/net/minecraft/client/renderer/ItemBlockRenderTypes.java.patch +++ b/patches/minecraft/net/minecraft/client/renderer/ItemBlockRenderTypes.java.patch @@ -1,11 +1,9 @@ --- a/net/minecraft/client/renderer/ItemBlockRenderTypes.java +++ b/net/minecraft/client/renderer/ItemBlockRenderTypes.java -@@ -18,7 +_,8 @@ - import net.minecraftforge.api.distmarker.OnlyIn; +@@ -19,6 +_,7 @@ @OnlyIn(Dist.CLIENT) --public class ItemBlockRenderTypes { -+public class ItemBlockRenderTypes extends net.minecraftforge.client.extensions.ForgeItemBlockRenderTypes { + public class ItemBlockRenderTypes { + @Deprecated private static final Map f_109275_ = Util.m_137469_(Maps.newHashMap(), (p_109296_) -> { RenderType rendertype = RenderType.m_110503_(); @@ -40,76 +38,82 @@ public static RenderType m_109284_(BlockState p_109285_, boolean p_109286_) { - RenderType rendertype = m_109282_(p_109285_); - if (rendertype == RenderType.m_110466_()) { -+ if (canRenderInLayer(p_109285_, RenderType.m_110466_())) { ++ if (getRenderLayers(p_109285_).contains(RenderType.m_110466_())) { if (!Minecraft.m_91085_()) { return Sheets.m_110792_(); } else { -@@ -350,10 +_,68 @@ - } +@@ -351,8 +_,73 @@ } -+ @Deprecated // FORGE: Use canRenderInLayer public static RenderType m_109287_(FluidState p_109288_) { - RenderType rendertype = f_109276_.get(p_109288_.m_76152_()); +- RenderType rendertype = f_109276_.get(p_109288_.m_76152_()); ++ RenderType rendertype = FLUID_RENDER_TYPES.get(net.minecraftforge.registries.ForgeRegistries.FLUIDS.getDelegateOrThrow(p_109288_.m_76152_())); return rendertype != null ? rendertype : RenderType.m_110451_(); - } ++ } + + // FORGE START + -+ public static boolean canRenderInLayer(BlockState state, RenderType type) { ++ private static final net.minecraftforge.client.ChunkRenderTypeSet CUTOUT_MIPPED = net.minecraftforge.client.ChunkRenderTypeSet.of(RenderType.m_110457_()); ++ private static final net.minecraftforge.client.ChunkRenderTypeSet SOLID = net.minecraftforge.client.ChunkRenderTypeSet.of(RenderType.m_110451_()); ++ private static final Map, net.minecraftforge.client.ChunkRenderTypeSet> BLOCK_RENDER_TYPES = Util.m_137469_(new it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap<>(f_109275_.size(), 0.5F), map -> { ++ map.defaultReturnValue(SOLID); ++ for(Map.Entry entry : f_109275_.entrySet()) { ++ map.put(net.minecraftforge.registries.ForgeRegistries.BLOCKS.getDelegateOrThrow(entry.getKey()), net.minecraftforge.client.ChunkRenderTypeSet.of(entry.getValue())); ++ } ++ }); ++ private static final Map, RenderType> FLUID_RENDER_TYPES = Util.m_137469_(new it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap<>(f_109276_.size(), 0.5F), map -> { ++ map.defaultReturnValue(RenderType.m_110451_()); ++ for(Map.Entry entry : f_109276_.entrySet()) { ++ map.put(net.minecraftforge.registries.ForgeRegistries.FLUIDS.getDelegateOrThrow(entry.getKey()), entry.getValue()); ++ } ++ }); ++ ++ /** @deprecated Use {@link net.minecraft.client.resources.model.BakedModel#getRenderTypes(BlockState, net.minecraft.util.RandomSource, net.minecraftforge.client.model.data.ModelData)}. */ ++ @Deprecated(forRemoval = true, since = "1.19") ++ public static net.minecraftforge.client.ChunkRenderTypeSet getRenderLayers(BlockState state) { + Block block = state.m_60734_(); + if (block instanceof LeavesBlock) { -+ return f_109277_ ? type == RenderType.m_110457_() : type == RenderType.m_110451_(); ++ return f_109277_ ? CUTOUT_MIPPED : SOLID; + } else { -+ return getBlockLayerPredicates().get(net.minecraftforge.registries.ForgeRegistries.BLOCKS.getDelegateOrThrow(block)).test(type); ++ return BLOCK_RENDER_TYPES.get(net.minecraftforge.registries.ForgeRegistries.BLOCKS.getDelegateOrThrow(block)); + } + } + -+ public static boolean canRenderInLayer(FluidState fluid, RenderType type) { -+ return getFluidLayerPredicates().get(net.minecraftforge.registries.ForgeRegistries.FLUIDS.getDelegateOrThrow(fluid.m_76152_())).test(type); -+ } -+ ++ /** @deprecated Set your render type in your model's JSON or override {@link net.minecraft.client.resources.model.BakedModel#getRenderTypes(BlockState, net.minecraft.util.RandomSource, net.minecraftforge.client.model.data.ModelData)} */ ++ @Deprecated(forRemoval = true, since = "1.19") + public static void setRenderLayer(Block block, RenderType type) { -+ java.util.Objects.requireNonNull(type); -+ setRenderLayer(block, t -> t == type); -+ } -+ -+ public static void setRenderLayer(Block block, java.util.function.Predicate predicate) { -+ net.minecraftforge.client.extensions.ForgeItemBlockRenderTypes.setRenderLayer(block, predicate); -+ } -+ -+ public static void setRenderLayer(Fluid fluid, RenderType type) { -+ java.util.Objects.requireNonNull(type); -+ setRenderLayer(fluid, t -> t == type); ++ com.google.common.base.Preconditions.checkArgument(type.getChunkLayerId() >= 0, "The argument must be a valid chunk render type returned by RenderType#chunkBufferLayers()."); ++ setRenderLayer(block, net.minecraftforge.client.ChunkRenderTypeSet.of(type)); + } + -+ public static void setRenderLayer(Fluid fluid, java.util.function.Predicate predicate) { -+ net.minecraftforge.client.extensions.ForgeItemBlockRenderTypes.setRenderLayer(fluid, predicate); ++ /** @deprecated Set your render type in your model's JSON or override {@link net.minecraft.client.resources.model.BakedModel#getRenderTypes(BlockState, net.minecraft.util.RandomSource, net.minecraftforge.client.model.data.ModelData)} */ ++ @Deprecated(forRemoval = true, since = "1.19") ++ public static synchronized void setRenderLayer(Block block, java.util.function.Predicate predicate) { ++ setRenderLayer(block, createSetFromPredicate(predicate)); + } + -+ /** -+ * Returns an unmodifiable view of the current block -> render type predicate map. -+ * The returned view should not be cached, as its backing map will become outdated as soon as -+ * something registers a new render type predicate -+ */ -+ public static Map, java.util.function.Predicate> getBlockLayerPredicatesView() { -+ return java.util.Collections.unmodifiableMap(getBlockLayerPredicates()); ++ /** @deprecated Set your render type in your model's JSON or override {@link net.minecraft.client.resources.model.BakedModel#getRenderTypes(BlockState, net.minecraft.util.RandomSource, net.minecraftforge.client.model.data.ModelData)} */ ++ @Deprecated(forRemoval = true, since = "1.19") ++ public static synchronized void setRenderLayer(Block block, net.minecraftforge.client.ChunkRenderTypeSet layers) { ++ checkClientLoading(); ++ BLOCK_RENDER_TYPES.put(net.minecraftforge.registries.ForgeRegistries.BLOCKS.getDelegateOrThrow(block), layers); + } + -+ /** -+ * Returns an unmodifiable view of the current fluid -> render type predicate map. -+ * The returned view should not be cached, as its backing map will become outdated as soon as -+ * something registers a new render type predicate -+ */ -+ public static Map, java.util.function.Predicate> getFluidLayerPredicatesView() { -+ return java.util.Collections.unmodifiableMap(getFluidLayerPredicates()); ++ public static void setRenderLayer(Fluid fluid, RenderType type) { ++ com.google.common.base.Preconditions.checkArgument(type.getChunkLayerId() >= 0, "The argument must be a valid chunk render type returned by RenderType#chunkBufferLayers()."); ++ checkClientLoading(); ++ FLUID_RENDER_TYPES.put(net.minecraftforge.registries.ForgeRegistries.FLUIDS.getDelegateOrThrow(fluid), type); + } + -+ static { -+ net.minecraftforge.client.extensions.ForgeItemBlockRenderTypes.initFromVanillaMaps(f_109275_, f_109276_); ++ private static void checkClientLoading() { ++ com.google.common.base.Preconditions.checkState(net.minecraftforge.client.loading.ClientModLoader.isLoading(), ++ "Render layers can only be set during client loading! " + ++ "This might ideally be done from `FMLClientSetupEvent`." ++ ); + } + -+ // FORGE END ++ private static net.minecraftforge.client.ChunkRenderTypeSet createSetFromPredicate(java.util.function.Predicate predicate) { ++ return net.minecraftforge.client.ChunkRenderTypeSet.of(RenderType.m_110506_().stream().filter(predicate).toArray(RenderType[]::new)); + } public static void m_109291_(boolean p_109292_) { - f_109277_ = p_109292_; diff --git a/patches/minecraft/net/minecraft/client/renderer/LevelRenderer.java.patch b/patches/minecraft/net/minecraft/client/renderer/LevelRenderer.java.patch index fc1d5f7c6a5..f75f65f9fe2 100644 --- a/patches/minecraft/net/minecraft/client/renderer/LevelRenderer.java.patch +++ b/patches/minecraft/net/minecraft/client/renderer/LevelRenderer.java.patch @@ -1,26 +1,20 @@ --- a/net/minecraft/client/renderer/LevelRenderer.java +++ b/net/minecraft/client/renderer/LevelRenderer.java -@@ -263,6 +_,11 @@ +@@ -263,6 +_,8 @@ } private void m_109703_(LightTexture p_109704_, float p_109705_, double p_109706_, double p_109707_, double p_109708_) { -+ net.minecraftforge.client.IWeatherRenderHandler renderHandler = f_109465_.m_104583_().getWeatherRenderHandler(); -+ if (renderHandler != null) { -+ renderHandler.render(f_109477_, p_109705_, f_109465_, f_109461_, p_109704_, p_109706_, p_109707_, p_109708_); ++ if (f_109465_.m_104583_().renderSnowAndRain(f_109465_, f_109477_, p_109705_, p_109704_, p_109706_, p_109707_, p_109708_)) + return; -+ } float f = this.f_109461_.f_91073_.m_46722_(p_109705_); if (!(f <= 0.0F)) { p_109704_.m_109896_(); -@@ -383,6 +_,11 @@ +@@ -383,6 +_,8 @@ } public void m_109693_(Camera p_109694_) { -+ net.minecraftforge.client.IWeatherParticleRenderHandler renderHandler = f_109465_.m_104583_().getWeatherParticleRenderHandler(); -+ if (renderHandler != null) { -+ renderHandler.render(f_109477_, f_109465_, f_109461_, p_109694_); ++ if (f_109465_.m_104583_().tickRain(f_109465_, f_109477_, p_109694_)) + return; -+ } float f = this.f_109461_.f_91073_.m_46722_(1.0F) / (Minecraft.m_91405_() ? 1.0F : 2.0F); if (!(f <= 0.0F)) { RandomSource randomsource = RandomSource.m_216335_((long)this.f_109477_ * 312987231L); @@ -99,27 +93,21 @@ } posestack.m_85836_(); -@@ -1781,6 +_,11 @@ +@@ -1780,6 +_,8 @@ + } public void m_202423_(PoseStack p_202424_, Matrix4f p_202425_, float p_202426_, Camera p_202427_, boolean p_202428_, Runnable p_202429_) { - p_202429_.run(); -+ net.minecraftforge.client.ISkyRenderHandler renderHandler = f_109465_.m_104583_().getSkyRenderHandler(); -+ if (renderHandler != null) { -+ renderHandler.render(f_109477_, p_202426_, p_202424_, f_109465_, f_109461_); ++ if (f_109465_.m_104583_().renderSky(f_109465_, f_109477_, p_202426_, p_202424_, p_202427_, p_202425_, p_202428_, p_202429_)) + return; -+ } + p_202429_.run(); if (!p_202428_) { FogType fogtype = p_202427_.m_167685_(); - if (fogtype != FogType.POWDER_SNOW && fogtype != FogType.LAVA && !this.m_234310_(p_202427_)) { -@@ -1912,6 +_,11 @@ +@@ -1912,6 +_,8 @@ } public void m_172954_(PoseStack p_172955_, Matrix4f p_172956_, float p_172957_, double p_172958_, double p_172959_, double p_172960_) { -+ net.minecraftforge.client.ICloudRenderHandler renderHandler = f_109465_.m_104583_().getCloudRenderHandler(); -+ if (renderHandler != null) { -+ renderHandler.render(f_109477_, p_172957_, p_172955_, f_109465_, f_109461_, p_172958_, p_172959_, p_172960_); ++ if (f_109465_.m_104583_().renderClouds(f_109465_, f_109477_, p_172957_, p_172955_, p_172958_, p_172959_, p_172960_, p_172956_)) + return; -+ } float f = this.f_109465_.m_104583_().m_108871_(); if (!Float.isNaN(f)) { RenderSystem.m_69464_(); diff --git a/patches/minecraft/net/minecraft/client/renderer/OutlineBufferSource.java.patch b/patches/minecraft/net/minecraft/client/renderer/OutlineBufferSource.java.patch deleted file mode 100644 index 40475315792..00000000000 --- a/patches/minecraft/net/minecraft/client/renderer/OutlineBufferSource.java.patch +++ /dev/null @@ -1,10 +0,0 @@ ---- a/net/minecraft/client/renderer/OutlineBufferSource.java -+++ b/net/minecraft/client/renderer/OutlineBufferSource.java -@@ -105,5 +_,7 @@ - public void m_5752_() { - this.f_109936_.m_5483_(this.f_109937_, this.f_109938_, this.f_109939_).m_6122_(this.f_85825_, this.f_85826_, this.f_85827_, this.f_85828_).m_7421_(this.f_109940_, this.f_109941_).m_5752_(); - } -+ -+ public com.mojang.blaze3d.vertex.VertexFormat getVertexFormat() { return f_109936_.getVertexFormat(); } - } - } diff --git a/patches/minecraft/net/minecraft/client/renderer/RenderType.java.patch b/patches/minecraft/net/minecraft/client/renderer/RenderType.java.patch index 464f302330c..82cb85d5404 100644 --- a/patches/minecraft/net/minecraft/client/renderer/RenderType.java.patch +++ b/patches/minecraft/net/minecraft/client/renderer/RenderType.java.patch @@ -34,3 +34,21 @@ } public static RenderType m_110502_() { +@@ -608,4 +_,17 @@ + return this.f_110696_; + } + } ++ ++ // FORGE START ++ private int chunkLayerId = -1; ++ /** {@return the unique ID of this {@link RenderType} for chunk rendering purposes, or {@literal -1} if this is not a chunk {@link RenderType}} */ ++ public final int getChunkLayerId() { ++ return chunkLayerId; ++ } ++ static { ++ int i = 0; ++ for (var layer : m_110506_()) ++ layer.chunkLayerId = i++; ++ } ++ // FORGE END + } diff --git a/patches/minecraft/net/minecraft/client/renderer/ScreenEffectRenderer.java.patch b/patches/minecraft/net/minecraft/client/renderer/ScreenEffectRenderer.java.patch index 1a20ccee000..8cb221d2ff1 100644 --- a/patches/minecraft/net/minecraft/client/renderer/ScreenEffectRenderer.java.patch +++ b/patches/minecraft/net/minecraft/client/renderer/ScreenEffectRenderer.java.patch @@ -9,7 +9,7 @@ - m_173296_(p_110719_.m_91289_().m_110907_().m_110882_(blockstate), p_110720_); + org.apache.commons.lang3.tuple.Pair overlay = getOverlayBlock(player); + if (overlay != null) { -+ if (!net.minecraftforge.client.ForgeHooksClient.renderBlockOverlay(player, p_110720_, net.minecraftforge.client.event.RenderBlockOverlayEvent.OverlayType.BLOCK, overlay.getLeft(), overlay.getRight())) ++ if (!net.minecraftforge.client.ForgeHooksClient.renderBlockOverlay(player, p_110720_, net.minecraftforge.client.event.RenderBlockScreenEffectEvent.OverlayType.BLOCK, overlay.getLeft(), overlay.getRight())) + m_173296_(p_110719_.m_91289_().m_110907_().getTexture(overlay.getLeft(), p_110719_.f_91073_, overlay.getRight()), p_110720_); } } @@ -19,7 +19,7 @@ + if (!net.minecraftforge.client.ForgeHooksClient.renderWaterOverlay(player, p_110720_)) m_110725_(p_110719_, p_110720_); } -+ else if (!player.getEyeInFluidType().isAir()) net.minecraftforge.client.RenderProperties.get(player.getEyeInFluidType()).renderOverlay(p_110719_, p_110720_); ++ else if (!player.getEyeInFluidType().isAir()) net.minecraftforge.client.extensions.common.IClientFluidTypeExtensions.of(player.getEyeInFluidType()).renderOverlay(p_110719_, p_110720_); if (p_110719_.f_91074_.m_6060_()) { + if (!net.minecraftforge.client.ForgeHooksClient.renderFireOverlay(player, p_110720_)) @@ -47,3 +47,18 @@ } } +@@ -90,9 +_,13 @@ + } + + private static void m_110725_(Minecraft p_110726_, PoseStack p_110727_) { ++ renderFluid(p_110726_, p_110727_, f_110714_); ++ } ++ ++ public static void renderFluid(Minecraft p_110726_, PoseStack p_110727_, ResourceLocation texture) { + RenderSystem.m_157427_(GameRenderer::m_172817_); + RenderSystem.m_69493_(); +- RenderSystem.m_157456_(0, f_110714_); ++ RenderSystem.m_157456_(0, texture); + BufferBuilder bufferbuilder = Tesselator.m_85913_().m_85915_(); + BlockPos blockpos = new BlockPos(p_110726_.f_91074_.m_20185_(), p_110726_.f_91074_.m_20188_(), p_110726_.f_91074_.m_20189_()); + float f = LightTexture.m_234316_(p_110726_.f_91074_.f_19853_.m_6042_(), p_110726_.f_91074_.f_19853_.m_46803_(blockpos)); diff --git a/patches/minecraft/net/minecraft/client/renderer/SpriteCoordinateExpander.java.patch b/patches/minecraft/net/minecraft/client/renderer/SpriteCoordinateExpander.java.patch deleted file mode 100644 index 9525fda5e5c..00000000000 --- a/patches/minecraft/net/minecraft/client/renderer/SpriteCoordinateExpander.java.patch +++ /dev/null @@ -1,9 +0,0 @@ ---- a/net/minecraft/client/renderer/SpriteCoordinateExpander.java -+++ b/net/minecraft/client/renderer/SpriteCoordinateExpander.java -@@ -54,4 +_,6 @@ - public void m_5954_(float p_110808_, float p_110809_, float p_110810_, float p_110811_, float p_110812_, float p_110813_, float p_110814_, float p_110815_, float p_110816_, int p_110817_, int p_110818_, float p_110819_, float p_110820_, float p_110821_) { - this.f_110795_.m_5954_(p_110808_, p_110809_, p_110810_, p_110811_, p_110812_, p_110813_, p_110814_, this.f_110796_.m_118367_((double)(p_110815_ * 16.0F)), this.f_110796_.m_118393_((double)(p_110816_ * 16.0F)), p_110817_, p_110818_, p_110819_, p_110820_, p_110821_); - } -+ -+ public com.mojang.blaze3d.vertex.VertexFormat getVertexFormat() { return f_110795_.getVertexFormat(); } - } diff --git a/patches/minecraft/net/minecraft/client/renderer/block/BlockModelShaper.java.patch b/patches/minecraft/net/minecraft/client/renderer/block/BlockModelShaper.java.patch index 1e1b84cc0f4..4a3f2e2da9e 100644 --- a/patches/minecraft/net/minecraft/client/renderer/block/BlockModelShaper.java.patch +++ b/patches/minecraft/net/minecraft/client/renderer/block/BlockModelShaper.java.patch @@ -7,13 +7,13 @@ + @Deprecated public TextureAtlasSprite m_110882_(BlockState p_110883_) { - return this.m_110893_(p_110883_).m_6160_(); -+ return this.m_110893_(p_110883_).getParticleIcon(net.minecraftforge.client.model.data.EmptyModelData.INSTANCE); ++ return this.m_110893_(p_110883_).getParticleIcon(net.minecraftforge.client.model.data.ModelData.EMPTY); + } + + public TextureAtlasSprite getTexture(BlockState p_110883_, net.minecraft.world.level.Level level, net.minecraft.core.BlockPos pos) { -+ net.minecraftforge.client.model.data.IModelData data = net.minecraftforge.client.model.ModelDataManager.getModelData(level, pos); ++ var data = level.getModelDataManager().getAt(pos); + BakedModel model = this.m_110893_(p_110883_); -+ return model.getParticleIcon(model.getModelData(level, pos, p_110883_, data == null ? net.minecraftforge.client.model.data.EmptyModelData.INSTANCE : data)); ++ return model.getParticleIcon(model.getModelData(level, pos, p_110883_, data == null ? net.minecraftforge.client.model.data.ModelData.EMPTY : data)); } public BakedModel m_110893_(BlockState p_110894_) { diff --git a/patches/minecraft/net/minecraft/client/renderer/block/BlockRenderDispatcher.java.patch b/patches/minecraft/net/minecraft/client/renderer/block/BlockRenderDispatcher.java.patch index ac76163e5a6..08b1521a3c1 100644 --- a/patches/minecraft/net/minecraft/client/renderer/block/BlockRenderDispatcher.java.patch +++ b/patches/minecraft/net/minecraft/client/renderer/block/BlockRenderDispatcher.java.patch @@ -5,7 +5,7 @@ this.f_173397_ = p_173400_; this.f_110903_ = p_173401_; - this.f_110900_ = new ModelBlockRenderer(this.f_110903_); -+ this.f_110900_ = new net.minecraftforge.client.model.pipeline.ForgeBlockModelRenderer(this.f_110903_); ++ this.f_110900_ = new net.minecraftforge.client.model.lighting.ForgeModelBlockRenderer(this.f_110903_); this.f_110901_ = new LiquidBlockRenderer(); } @@ -13,29 +13,29 @@ return this.f_110899_; } -+ @Deprecated //Forge: Model parameter ++ @Deprecated //Forge: Model data parameter public void m_110918_(BlockState p_110919_, BlockPos p_110920_, BlockAndTintGetter p_110921_, PoseStack p_110922_, VertexConsumer p_110923_) { -+ renderBreakingTexture(p_110919_, p_110920_, p_110921_, p_110922_, p_110923_, net.minecraftforge.client.model.data.EmptyModelData.INSTANCE); ++ renderBreakingTexture(p_110919_, p_110920_, p_110921_, p_110922_, p_110923_, net.minecraftforge.client.model.data.ModelData.EMPTY); + } -+ public void renderBreakingTexture(BlockState p_110919_, BlockPos p_110920_, BlockAndTintGetter p_110921_, PoseStack p_110922_, VertexConsumer p_110923_, net.minecraftforge.client.model.data.IModelData modelData) { ++ public void renderBreakingTexture(BlockState p_110919_, BlockPos p_110920_, BlockAndTintGetter p_110921_, PoseStack p_110922_, VertexConsumer p_110923_, net.minecraftforge.client.model.data.ModelData modelData) { if (p_110919_.m_60799_() == RenderShape.MODEL) { BakedModel bakedmodel = this.f_110899_.m_110893_(p_110919_); long i = p_110919_.m_60726_(p_110920_); - this.f_110900_.m_234379_(p_110921_, bakedmodel, p_110919_, p_110920_, p_110922_, p_110923_, true, this.f_110902_, i, OverlayTexture.f_118083_); -+ this.f_110900_.tesselateBlock(p_110921_, bakedmodel, p_110919_, p_110920_, p_110922_, p_110923_, true, this.f_110902_, i, OverlayTexture.f_118083_, modelData); ++ this.f_110900_.tesselateBlock(p_110921_, bakedmodel, p_110919_, p_110920_, p_110922_, p_110923_, true, this.f_110902_, i, OverlayTexture.f_118083_, modelData, null); } } -+ @Deprecated //Forge: Model parameter ++ @Deprecated //Forge: Model data and render type parameter public void m_234355_(BlockState p_234356_, BlockPos p_234357_, BlockAndTintGetter p_234358_, PoseStack p_234359_, VertexConsumer p_234360_, boolean p_234361_, RandomSource p_234362_) { -+ renderBatched(p_234356_, p_234357_, p_234358_, p_234359_, p_234360_, p_234361_, p_234362_, net.minecraftforge.client.model.data.EmptyModelData.INSTANCE); ++ renderBatched(p_234356_, p_234357_, p_234358_, p_234359_, p_234360_, p_234361_, p_234362_, net.minecraftforge.client.model.data.ModelData.EMPTY, null); + } -+ public void renderBatched(BlockState p_234356_, BlockPos p_234357_, BlockAndTintGetter p_234358_, PoseStack p_234359_, VertexConsumer p_234360_, boolean p_234361_, RandomSource p_234362_, net.minecraftforge.client.model.data.IModelData modelData) { ++ public void renderBatched(BlockState p_234356_, BlockPos p_234357_, BlockAndTintGetter p_234358_, PoseStack p_234359_, VertexConsumer p_234360_, boolean p_234361_, RandomSource p_234362_, net.minecraftforge.client.model.data.ModelData modelData, net.minecraft.client.renderer.RenderType renderType) { try { RenderShape rendershape = p_234356_.m_60799_(); if (rendershape == RenderShape.MODEL) { - this.f_110900_.m_234379_(p_234358_, this.m_110910_(p_234356_), p_234356_, p_234357_, p_234359_, p_234360_, p_234361_, p_234362_, p_234356_.m_60726_(p_234357_), OverlayTexture.f_118083_); -+ this.f_110900_.tesselateBlock(p_234358_, this.m_110910_(p_234356_), p_234356_, p_234357_, p_234359_, p_234360_, p_234361_, p_234362_, p_234356_.m_60726_(p_234357_), OverlayTexture.f_118083_, modelData); ++ this.f_110900_.tesselateBlock(p_234358_, this.m_110910_(p_234356_), p_234356_, p_234357_, p_234359_, p_234360_, p_234361_, p_234362_, p_234356_.m_60726_(p_234357_), OverlayTexture.f_118083_, modelData, renderType); } } catch (Throwable throwable) { @@ -43,11 +43,11 @@ return this.f_110899_.m_110893_(p_110911_); } -+ @Deprecated //Forge: Model parameter ++ @Deprecated //Forge: Model data and render type parameter public void m_110912_(BlockState p_110913_, PoseStack p_110914_, MultiBufferSource p_110915_, int p_110916_, int p_110917_) { -+ renderSingleBlock(p_110913_, p_110914_, p_110915_, p_110916_, p_110917_, net.minecraftforge.client.model.data.EmptyModelData.INSTANCE); ++ renderSingleBlock(p_110913_, p_110914_, p_110915_, p_110916_, p_110917_, net.minecraftforge.client.model.data.ModelData.EMPTY, null); + } -+ public void renderSingleBlock(BlockState p_110913_, PoseStack p_110914_, MultiBufferSource p_110915_, int p_110916_, int p_110917_, net.minecraftforge.client.model.data.IModelData modelData) { ++ public void renderSingleBlock(BlockState p_110913_, PoseStack p_110914_, MultiBufferSource p_110915_, int p_110916_, int p_110917_, net.minecraftforge.client.model.data.ModelData modelData, net.minecraft.client.renderer.RenderType renderType) { RenderShape rendershape = p_110913_.m_60799_(); if (rendershape != RenderShape.INVISIBLE) { switch (rendershape) { @@ -56,12 +56,12 @@ float f1 = (float)(i >> 8 & 255) / 255.0F; float f2 = (float)(i & 255) / 255.0F; - this.f_110900_.m_111067_(p_110914_.m_85850_(), p_110915_.m_6299_(ItemBlockRenderTypes.m_109284_(p_110913_, false)), p_110913_, bakedmodel, f, f1, f2, p_110916_, p_110917_); -+ this.f_110900_.renderModel(p_110914_.m_85850_(), p_110915_.m_6299_(ItemBlockRenderTypes.m_109284_(p_110913_, false)), p_110913_, bakedmodel, f, f1, f2, p_110916_, p_110917_, modelData); ++ this.f_110900_.renderModel(p_110914_.m_85850_(), p_110915_.m_6299_(ItemBlockRenderTypes.m_109284_(p_110913_, false)), p_110913_, bakedmodel, f, f1, f2, p_110916_, p_110917_, modelData, renderType); break; case ENTITYBLOCK_ANIMATED: - this.f_173397_.m_108829_(new ItemStack(p_110913_.m_60734_()), ItemTransforms.TransformType.NONE, p_110914_, p_110915_, p_110916_, p_110917_); + ItemStack stack = new ItemStack(p_110913_.m_60734_()); -+ net.minecraftforge.client.RenderProperties.get(stack).getItemStackRenderer().m_108829_(stack, ItemTransforms.TransformType.NONE, p_110914_, p_110915_, p_110916_, p_110917_); ++ net.minecraftforge.client.extensions.common.IClientItemExtensions.of(stack).getCustomRenderer().m_108829_(stack, ItemTransforms.TransformType.NONE, p_110914_, p_110915_, p_110916_, p_110917_); } } diff --git a/patches/minecraft/net/minecraft/client/renderer/block/LiquidBlockRenderer.java.patch b/patches/minecraft/net/minecraft/client/renderer/block/LiquidBlockRenderer.java.patch index 37f9a0f709b..14419b0ec61 100644 --- a/patches/minecraft/net/minecraft/client/renderer/block/LiquidBlockRenderer.java.patch +++ b/patches/minecraft/net/minecraft/client/renderer/block/LiquidBlockRenderer.java.patch @@ -7,7 +7,7 @@ - TextureAtlasSprite[] atextureatlassprite = flag ? this.f_110940_ : this.f_110941_; - int i = flag ? 16777215 : BiomeColors.m_108811_(p_234370_, p_234371_); + TextureAtlasSprite[] atextureatlassprite = net.minecraftforge.client.ForgeHooksClient.getFluidSprites(p_234370_, p_234371_, p_234374_); -+ int i = net.minecraftforge.client.RenderProperties.get(p_234374_).getColorTint(p_234374_, p_234370_, p_234371_); ++ int i = net.minecraftforge.client.extensions.common.IClientFluidTypeExtensions.of(p_234374_).getTintColor(p_234374_, p_234370_, p_234371_); + float alpha = (float)(i >> 24 & 255) / 255.0F; float f = (float)(i >> 16 & 255) / 255.0F; float f1 = (float)(i >> 8 & 255) / 255.0F; diff --git a/patches/minecraft/net/minecraft/client/renderer/block/ModelBlockRenderer.java.patch b/patches/minecraft/net/minecraft/client/renderer/block/ModelBlockRenderer.java.patch index d81ca1cb16b..ac56c6bdd0b 100644 --- a/patches/minecraft/net/minecraft/client/renderer/block/ModelBlockRenderer.java.patch +++ b/patches/minecraft/net/minecraft/client/renderer/block/ModelBlockRenderer.java.patch @@ -4,14 +4,14 @@ this.f_110995_ = p_110999_; } -+ @Deprecated //Forge: Model data argument ++ @Deprecated //Forge: Model data and render type parameter public void m_234379_(BlockAndTintGetter p_234380_, BakedModel p_234381_, BlockState p_234382_, BlockPos p_234383_, PoseStack p_234384_, VertexConsumer p_234385_, boolean p_234386_, RandomSource p_234387_, long p_234388_, int p_234389_) { - boolean flag = Minecraft.m_91086_() && p_234382_.m_60791_() == 0 && p_234381_.m_7541_(); - Vec3 vec3 = p_234382_.m_60824_(p_234380_, p_234383_); - p_234384_.m_85837_(vec3.f_82479_, vec3.f_82480_, vec3.f_82481_); -+ tesselateBlock(p_234380_, p_234381_, p_234382_, p_234383_, p_234384_, p_234385_, p_234386_, p_234387_, p_234388_, p_234389_, net.minecraftforge.client.model.data.EmptyModelData.INSTANCE); ++ tesselateBlock(p_234380_, p_234381_, p_234382_, p_234383_, p_234384_, p_234385_, p_234386_, p_234387_, p_234388_, p_234389_, net.minecraftforge.client.model.data.ModelData.EMPTY, null); + } -+ public void tesselateBlock(BlockAndTintGetter p_111048_, BakedModel p_111049_, BlockState p_111050_, BlockPos p_111051_, PoseStack p_111052_, VertexConsumer p_111053_, boolean p_111054_, RandomSource p_111055_, long p_111056_, int p_111057_, net.minecraftforge.client.model.data.IModelData modelData) { ++ public void tesselateBlock(BlockAndTintGetter p_111048_, BakedModel p_111049_, BlockState p_111050_, BlockPos p_111051_, PoseStack p_111052_, VertexConsumer p_111053_, boolean p_111054_, RandomSource p_111055_, long p_111056_, int p_111057_, net.minecraftforge.client.model.data.ModelData modelData, net.minecraft.client.renderer.RenderType renderType) { + boolean flag = Minecraft.m_91086_() && p_111050_.getLightEmission(p_111048_, p_111051_) == 0 && p_111049_.m_7541_(); + Vec3 vec3 = p_111050_.m_60824_(p_111048_, p_111051_); + p_111052_.m_85837_(vec3.f_82479_, vec3.f_82480_, vec3.f_82481_); @@ -20,10 +20,10 @@ try { if (flag) { - this.m_234390_(p_234380_, p_234381_, p_234382_, p_234383_, p_234384_, p_234385_, p_234386_, p_234387_, p_234388_, p_234389_); -+ this.tesselateWithAO(p_111048_, p_111049_, p_111050_, p_111051_, p_111052_, p_111053_, p_111054_, p_111055_, p_111056_, p_111057_, modelData); ++ this.tesselateWithAO(p_111048_, p_111049_, p_111050_, p_111051_, p_111052_, p_111053_, p_111054_, p_111055_, p_111056_, p_111057_, modelData, renderType); } else { - this.m_234401_(p_234380_, p_234381_, p_234382_, p_234383_, p_234384_, p_234385_, p_234386_, p_234387_, p_234388_, p_234389_); -+ this.tesselateWithoutAO(p_111048_, p_111049_, p_111050_, p_111051_, p_111052_, p_111053_, p_111054_, p_111055_, p_111056_, p_111057_, modelData); ++ this.tesselateWithoutAO(p_111048_, p_111049_, p_111050_, p_111051_, p_111052_, p_111053_, p_111054_, p_111055_, p_111056_, p_111057_, modelData, renderType); } } catch (Throwable throwable) { @@ -36,11 +36,11 @@ } } -+ @Deprecated //Forge: Model data argument ++ @Deprecated //Forge: Model data and render type parameter public void m_234390_(BlockAndTintGetter p_234391_, BakedModel p_234392_, BlockState p_234393_, BlockPos p_234394_, PoseStack p_234395_, VertexConsumer p_234396_, boolean p_234397_, RandomSource p_234398_, long p_234399_, int p_234400_) { -+ tesselateWithAO(p_234391_, p_234392_, p_234393_, p_234394_, p_234395_, p_234396_, p_234397_, p_234398_, p_234399_, p_234400_, net.minecraftforge.client.model.data.EmptyModelData.INSTANCE); ++ tesselateWithAO(p_234391_, p_234392_, p_234393_, p_234394_, p_234395_, p_234396_, p_234397_, p_234398_, p_234399_, p_234400_, net.minecraftforge.client.model.data.ModelData.EMPTY, null); + } -+ public void tesselateWithAO(BlockAndTintGetter p_111079_, BakedModel p_111080_, BlockState p_111081_, BlockPos p_111082_, PoseStack p_111083_, VertexConsumer p_111084_, boolean p_111085_, RandomSource p_111086_, long p_111087_, int p_111088_, net.minecraftforge.client.model.data.IModelData modelData) { ++ public void tesselateWithAO(BlockAndTintGetter p_111079_, BakedModel p_111080_, BlockState p_111081_, BlockPos p_111082_, PoseStack p_111083_, VertexConsumer p_111084_, boolean p_111085_, RandomSource p_111086_, long p_111087_, int p_111088_, net.minecraftforge.client.model.data.ModelData modelData, net.minecraft.client.renderer.RenderType renderType) { float[] afloat = new float[f_173405_.length * 2]; BitSet bitset = new BitSet(3); ModelBlockRenderer.AmbientOcclusionFace modelblockrenderer$ambientocclusionface = new ModelBlockRenderer.AmbientOcclusionFace(); @@ -51,7 +51,7 @@ - p_234398_.m_188584_(p_234399_); - List list = p_234392_.m_213637_(p_234393_, direction, p_234398_); + p_111086_.m_188584_(p_111087_); -+ List list = p_111080_.getQuads(p_111081_, direction, p_111086_, modelData); ++ List list = p_111080_.getQuads(p_111081_, direction, p_111086_, modelData, renderType); if (!list.isEmpty()) { - blockpos$mutableblockpos.m_122159_(p_234394_, direction); - if (!p_234397_ || Block.m_152444_(p_234393_, p_234391_, p_234394_, direction, blockpos$mutableblockpos)) { @@ -66,7 +66,7 @@ - p_234398_.m_188584_(p_234399_); - List list1 = p_234392_.m_213637_(p_234393_, (Direction)null, p_234398_); + p_111086_.m_188584_(p_111087_); -+ List list1 = p_111080_.getQuads(p_111081_, (Direction)null, p_111086_, modelData); ++ List list1 = p_111080_.getQuads(p_111081_, (Direction)null, p_111086_, modelData, renderType); if (!list1.isEmpty()) { - this.m_111012_(p_234391_, p_234393_, p_234394_, p_234395_, p_234396_, list1, afloat, bitset, modelblockrenderer$ambientocclusionface, p_234400_); + this.m_111012_(p_111079_, p_111081_, p_111082_, p_111083_, p_111084_, list1, afloat, bitset, modelblockrenderer$ambientocclusionface, p_111088_); @@ -74,11 +74,11 @@ } -+ @Deprecated //Forge: Model data argument ++ @Deprecated //Forge: Model data and render type parameter public void m_234401_(BlockAndTintGetter p_234402_, BakedModel p_234403_, BlockState p_234404_, BlockPos p_234405_, PoseStack p_234406_, VertexConsumer p_234407_, boolean p_234408_, RandomSource p_234409_, long p_234410_, int p_234411_) { -+ tesselateWithoutAO(p_234402_, p_234403_, p_234404_, p_234405_, p_234406_, p_234407_, p_234408_, p_234409_, p_234410_, p_234411_, net.minecraftforge.client.model.data.EmptyModelData.INSTANCE); ++ tesselateWithoutAO(p_234402_, p_234403_, p_234404_, p_234405_, p_234406_, p_234407_, p_234408_, p_234409_, p_234410_, p_234411_, net.minecraftforge.client.model.data.ModelData.EMPTY, null); + } -+ public void tesselateWithoutAO(BlockAndTintGetter p_111091_, BakedModel p_111092_, BlockState p_111093_, BlockPos p_111094_, PoseStack p_111095_, VertexConsumer p_111096_, boolean p_111097_, RandomSource p_111098_, long p_111099_, int p_111100_, net.minecraftforge.client.model.data.IModelData modelData) { ++ public void tesselateWithoutAO(BlockAndTintGetter p_111091_, BakedModel p_111092_, BlockState p_111093_, BlockPos p_111094_, PoseStack p_111095_, VertexConsumer p_111096_, boolean p_111097_, RandomSource p_111098_, long p_111099_, int p_111100_, net.minecraftforge.client.model.data.ModelData modelData, net.minecraft.client.renderer.RenderType renderType) { BitSet bitset = new BitSet(3); - BlockPos.MutableBlockPos blockpos$mutableblockpos = p_234405_.m_122032_(); + BlockPos.MutableBlockPos blockpos$mutableblockpos = p_111094_.m_122032_(); @@ -87,7 +87,7 @@ - p_234409_.m_188584_(p_234410_); - List list = p_234403_.m_213637_(p_234404_, direction, p_234409_); + p_111098_.m_188584_(p_111099_); -+ List list = p_111092_.getQuads(p_111093_, direction, p_111098_, modelData); ++ List list = p_111092_.getQuads(p_111093_, direction, p_111098_, modelData, renderType); if (!list.isEmpty()) { - blockpos$mutableblockpos.m_122159_(p_234405_, direction); - if (!p_234408_ || Block.m_152444_(p_234404_, p_234402_, p_234405_, direction, blockpos$mutableblockpos)) { @@ -104,7 +104,7 @@ - p_234409_.m_188584_(p_234410_); - List list1 = p_234403_.m_213637_(p_234404_, (Direction)null, p_234409_); + p_111098_.m_188584_(p_111099_); -+ List list1 = p_111092_.getQuads(p_111093_, (Direction)null, p_111098_, modelData); ++ List list1 = p_111092_.getQuads(p_111093_, (Direction)null, p_111098_, modelData, renderType); if (!list1.isEmpty()) { - this.m_111001_(p_234402_, p_234404_, p_234405_, -1, p_234411_, true, p_234406_, p_234407_, list1, bitset); + this.m_111001_(p_111091_, p_111093_, p_111094_, -1, p_111100_, true, p_111095_, p_111096_, list1, bitset); @@ -115,23 +115,23 @@ } -+ @Deprecated //Forge: Model data argument ++ @Deprecated //Forge: Model data and render type parameter public void m_111067_(PoseStack.Pose p_111068_, VertexConsumer p_111069_, @Nullable BlockState p_111070_, BakedModel p_111071_, float p_111072_, float p_111073_, float p_111074_, int p_111075_, int p_111076_) { -+ renderModel(p_111068_, p_111069_, p_111070_, p_111071_, p_111072_, p_111073_, p_111074_, p_111075_, p_111076_, net.minecraftforge.client.model.data.EmptyModelData.INSTANCE); ++ renderModel(p_111068_, p_111069_, p_111070_, p_111071_, p_111072_, p_111073_, p_111074_, p_111075_, p_111076_, net.minecraftforge.client.model.data.ModelData.EMPTY, null); + } -+ public void renderModel(PoseStack.Pose p_111068_, VertexConsumer p_111069_, @Nullable BlockState p_111070_, BakedModel p_111071_, float p_111072_, float p_111073_, float p_111074_, int p_111075_, int p_111076_, net.minecraftforge.client.model.data.IModelData modelData) { ++ public void renderModel(PoseStack.Pose p_111068_, VertexConsumer p_111069_, @Nullable BlockState p_111070_, BakedModel p_111071_, float p_111072_, float p_111073_, float p_111074_, int p_111075_, int p_111076_, net.minecraftforge.client.model.data.ModelData modelData, net.minecraft.client.renderer.RenderType renderType) { RandomSource randomsource = RandomSource.m_216327_(); long i = 42L; for(Direction direction : f_173405_) { randomsource.m_188584_(42L); - m_111058_(p_111068_, p_111069_, p_111072_, p_111073_, p_111074_, p_111071_.m_213637_(p_111070_, direction, randomsource), p_111075_, p_111076_); -+ m_111058_(p_111068_, p_111069_, p_111072_, p_111073_, p_111074_, p_111071_.getQuads(p_111070_, direction, randomsource, modelData), p_111075_, p_111076_); ++ m_111058_(p_111068_, p_111069_, p_111072_, p_111073_, p_111074_, p_111071_.getQuads(p_111070_, direction, randomsource, modelData, renderType), p_111075_, p_111076_); } randomsource.m_188584_(42L); - m_111058_(p_111068_, p_111069_, p_111072_, p_111073_, p_111074_, p_111071_.m_213637_(p_111070_, (Direction)null, randomsource), p_111075_, p_111076_); -+ m_111058_(p_111068_, p_111069_, p_111072_, p_111073_, p_111074_, p_111071_.getQuads(p_111070_, (Direction)null, randomsource, modelData), p_111075_, p_111076_); ++ m_111058_(p_111068_, p_111069_, p_111072_, p_111073_, p_111074_, p_111071_.getQuads(p_111070_, (Direction)null, randomsource, modelData, renderType), p_111075_, p_111076_); } private static void m_111058_(PoseStack.Pose p_111059_, VertexConsumer p_111060_, float p_111061_, float p_111062_, float p_111063_, List p_111064_, int p_111065_, int p_111066_) { diff --git a/patches/minecraft/net/minecraft/client/renderer/block/model/BakedQuad.java.patch b/patches/minecraft/net/minecraft/client/renderer/block/model/BakedQuad.java.patch deleted file mode 100644 index e1183a0c426..00000000000 --- a/patches/minecraft/net/minecraft/client/renderer/block/model/BakedQuad.java.patch +++ /dev/null @@ -1,23 +0,0 @@ ---- a/net/minecraft/client/renderer/block/model/BakedQuad.java -+++ b/net/minecraft/client/renderer/block/model/BakedQuad.java -@@ -6,7 +_,7 @@ - import net.minecraftforge.api.distmarker.OnlyIn; - - @OnlyIn(Dist.CLIENT) --public class BakedQuad { -+public class BakedQuad implements net.minecraftforge.client.model.pipeline.IVertexProducer { - protected final int[] f_111292_; - protected final int f_111293_; - protected final Direction f_111294_; -@@ -39,6 +_,11 @@ - - public Direction m_111306_() { - return this.f_111294_; -+ } -+ -+ @Override -+ public void pipe(net.minecraftforge.client.model.pipeline.IVertexConsumer consumer) { -+ net.minecraftforge.client.model.pipeline.LightUtil.putBakedQuad(consumer, this); - } - - public boolean m_111307_() { diff --git a/patches/minecraft/net/minecraft/client/renderer/block/model/BlockModel.java.patch b/patches/minecraft/net/minecraft/client/renderer/block/model/BlockModel.java.patch index 3d6b06f8e53..f32751039ac 100644 --- a/patches/minecraft/net/minecraft/client/renderer/block/model/BlockModel.java.patch +++ b/patches/minecraft/net/minecraft/client/renderer/block/model/BlockModel.java.patch @@ -4,11 +4,11 @@ public BlockModel f_111418_; @Nullable protected ResourceLocation f_111419_; -+ public final net.minecraftforge.client.model.BlockModelConfiguration customData = new net.minecraftforge.client.model.BlockModelConfiguration(this); ++ public final net.minecraftforge.client.model.geometry.BlockGeometryBakingContext customData = new net.minecraftforge.client.model.geometry.BlockGeometryBakingContext(this); public static BlockModel m_111461_(Reader p_111462_) { - return GsonHelper.m_13776_(f_111415_, p_111462_, BlockModel.class); -+ return GsonHelper.m_13776_(net.minecraftforge.client.model.ModelLoaderRegistry.ExpandedBlockModelDeserializer.INSTANCE, p_111462_, BlockModel.class); ++ return GsonHelper.m_13776_(net.minecraftforge.client.model.ExtendedBlockModelDeserializer.INSTANCE, p_111462_, BlockModel.class); } public static BlockModel m_111463_(String p_111464_) { @@ -59,25 +59,23 @@ } public BakedModel m_111449_(ModelBakery p_111450_, BlockModel p_111451_, Function p_111452_, ModelState p_111453_, ResourceLocation p_111454_, boolean p_111455_) { -+ return net.minecraftforge.client.model.ModelLoaderRegistry.bakeHelper(this, p_111450_, p_111451_, p_111452_, p_111453_, p_111454_, p_111455_); ++ return net.minecraftforge.client.model.geometry.UnbakedGeometryHelper.bake(this, p_111450_, p_111451_, p_111452_, p_111453_, p_111454_, p_111455_); + } + + @Deprecated //Forge: exposed for our callbacks only. Use the above function. -+ public BakedModel bakeVanilla(ModelBakery p_111450_, BlockModel p_111451_, Function p_111452_, ModelState p_111453_, ResourceLocation p_111454_, boolean p_111455_) { ++ public BakedModel bakeVanilla(ModelBakery p_111450_, BlockModel p_111451_, Function p_111452_, ModelState p_111453_, ResourceLocation p_111454_, boolean p_111455_, net.minecraftforge.client.RenderTypeGroup renderTypes) { TextureAtlasSprite textureatlassprite = p_111452_.apply(this.m_111480_("particle")); if (this.m_111490_() == ModelBakery.f_119233_) { return new BuiltInModel(this.m_111491_(), this.m_111446_(p_111450_, p_111451_), textureatlassprite, this.m_111479_().m_111526_()); -@@ -212,6 +_,10 @@ - return f_111421_.m_111600_(p_111438_.f_111308_, p_111438_.f_111309_, p_111439_, p_111440_, p_111441_, p_111442_, p_111438_.f_111311_, p_111438_.f_111312_, p_111443_); - } +@@ -204,7 +_,7 @@ + } + } -+ public static BakedQuad makeBakedQuad(BlockElement p_111438_, BlockElementFace p_111439_, TextureAtlasSprite p_111440_, Direction p_111441_, ModelState p_111442_, ResourceLocation p_111443_) { -+ return m_111437_(p_111438_, p_111439_, p_111440_, p_111441_, p_111442_, p_111443_); -+ } -+ - public boolean m_111477_(String p_111478_) { - return !MissingTextureAtlasSprite.m_118071_().equals(this.m_111480_(p_111478_).m_119203_()); +- return simplebakedmodel$builder.m_119533_(); ++ return simplebakedmodel$builder.build(renderTypes); + } } + @@ -268,7 +_,18 @@ ItemTransform itemtransform5 = this.m_111444_(ItemTransforms.TransformType.GUI); ItemTransform itemtransform6 = this.m_111444_(ItemTransforms.TransformType.GROUND); diff --git a/patches/minecraft/net/minecraft/client/renderer/block/model/ItemOverrides.java.patch b/patches/minecraft/net/minecraft/client/renderer/block/model/ItemOverrides.java.patch index d8a5f951cb9..b0628e59120 100644 --- a/patches/minecraft/net/minecraft/client/renderer/block/model/ItemOverrides.java.patch +++ b/patches/minecraft/net/minecraft/client/renderer/block/model/ItemOverrides.java.patch @@ -6,7 +6,7 @@ + @Deprecated //Forge: Use IUnbakedModel, add texture getter public ItemOverrides(ModelBakery p_111740_, BlockModel p_111741_, Function p_111742_, List p_111743_) { -+ this(p_111740_, p_111741_, p_111742_, p_111740_.getSpriteMap()::m_117971_, p_111743_); ++ this(p_111740_, p_111741_, p_111742_, p_111740_.getAtlasSet()::m_117971_, p_111743_); + } + public ItemOverrides(ModelBakery p_111740_, UnbakedModel p_111741_, Function p_111742_, Function textureGetter, List p_111743_) { this.f_173461_ = p_111743_.stream().flatMap(ItemOverride::m_173449_).map(ItemOverride.Predicate::m_173459_).distinct().toArray((p_173479_) -> { diff --git a/patches/minecraft/net/minecraft/client/renderer/block/model/ItemTransform.java.patch b/patches/minecraft/net/minecraft/client/renderer/block/model/ItemTransform.java.patch index ea9a2ca9d09..cdfc8f9f00c 100644 --- a/patches/minecraft/net/minecraft/client/renderer/block/model/ItemTransform.java.patch +++ b/patches/minecraft/net/minecraft/client/renderer/block/model/ItemTransform.java.patch @@ -1,14 +1,38 @@ --- a/net/minecraft/client/renderer/block/model/ItemTransform.java +++ b/net/minecraft/client/renderer/block/model/ItemTransform.java -@@ -14,7 +_,11 @@ - import net.minecraftforge.api.distmarker.Dist; - import net.minecraftforge.api.distmarker.OnlyIn; - -+/** -+ * @deprecated use {@link com.mojang.math.Transformation} through {@link net.minecraftforge.client.extensions.IForgeBakedModel#handlePerspective} -+ */ - @OnlyIn(Dist.CLIENT) -+@Deprecated - public class ItemTransform { - public static final ItemTransform f_111754_ = new ItemTransform(new Vector3f(), new Vector3f(), new Vector3f(1.0F, 1.0F, 1.0F)); +@@ -20,11 +_,17 @@ public final Vector3f f_111755_; + public final Vector3f f_111756_; + public final Vector3f f_111757_; ++ public final Vector3f rightRotation; + + public ItemTransform(Vector3f p_111760_, Vector3f p_111761_, Vector3f p_111762_) { ++ this(p_111760_, p_111761_, p_111762_, Vector3f.f_176763_); ++ } ++ ++ public ItemTransform(Vector3f p_111760_, Vector3f p_111761_, Vector3f p_111762_, Vector3f rightRotation) { + this.f_111755_ = p_111760_.m_122281_(); + this.f_111756_ = p_111761_.m_122281_(); + this.f_111757_ = p_111762_.m_122281_(); ++ this.rightRotation = rightRotation.m_122281_(); + } + + public void m_111763_(boolean p_111764_, PoseStack p_111765_) { +@@ -41,6 +_,7 @@ + p_111765_.m_85837_((double)((float)i * this.f_111756_.m_122239_()), (double)this.f_111756_.m_122260_(), (double)this.f_111756_.m_122269_()); + p_111765_.m_85845_(new Quaternion(f, f1, f2, true)); + p_111765_.m_85841_(this.f_111757_.m_122239_(), this.f_111757_.m_122260_(), this.f_111757_.m_122269_()); ++ p_111765_.m_85845_(new Quaternion(rightRotation.m_122239_(), rightRotation.m_122260_() * (p_111764_ ? -1 : 1), rightRotation.m_122269_() * (p_111764_ ? -1 : 1), true)); + } + } + +@@ -77,7 +_,8 @@ + vector3f1.m_122242_(-5.0F, 5.0F); + Vector3f vector3f2 = this.m_111778_(jsonobject, "scale", f_111771_); + vector3f2.m_122242_(-4.0F, 4.0F); +- return new ItemTransform(vector3f, vector3f1, vector3f2); ++ Vector3f rightRotation = this.m_111778_(jsonobject, "right_rotation", f_111769_); ++ return new ItemTransform(vector3f, vector3f1, vector3f2, rightRotation); + } + + private Vector3f m_111778_(JsonObject p_111779_, String p_111780_, Vector3f p_111781_) { diff --git a/patches/minecraft/net/minecraft/client/renderer/block/model/ItemTransforms.java.patch b/patches/minecraft/net/minecraft/client/renderer/block/model/ItemTransforms.java.patch index 8a6ab9112a2..ea27ebe179f 100644 --- a/patches/minecraft/net/minecraft/client/renderer/block/model/ItemTransforms.java.patch +++ b/patches/minecraft/net/minecraft/client/renderer/block/model/ItemTransforms.java.patch @@ -31,17 +31,14 @@ this.f_111787_ = p_111798_; this.f_111788_ = p_111799_; this.f_111789_ = p_111800_; -@@ -45,8 +_,10 @@ +@@ -45,6 +_,7 @@ this.f_111792_ = p_111803_; this.f_111793_ = p_111804_; this.f_111794_ = p_111805_; + this.moddedTransforms = moddedTransforms; } -+ @Deprecated public ItemTransform m_111808_(ItemTransforms.TransformType p_111809_) { - switch (p_111809_) { - case THIRD_PERSON_LEFT_HAND: @@ -66,7 +_,7 @@ case FIXED: return this.f_111794_; diff --git a/patches/minecraft/net/minecraft/client/renderer/chunk/ChunkRenderDispatcher.java.patch b/patches/minecraft/net/minecraft/client/renderer/chunk/ChunkRenderDispatcher.java.patch index 6e91ef0c887..68844d532d6 100644 --- a/patches/minecraft/net/minecraft/client/renderer/chunk/ChunkRenderDispatcher.java.patch +++ b/patches/minecraft/net/minecraft/client/renderer/chunk/ChunkRenderDispatcher.java.patch @@ -39,7 +39,7 @@ protected final double f_112847_; protected final AtomicBoolean f_112848_ = new AtomicBoolean(false); protected final boolean f_194420_; -+ protected java.util.Map modelData; ++ protected java.util.Map modelData; public ChunkCompileTask(double p_194423_, boolean p_194424_) { + this(null, p_194423_, p_194424_); @@ -51,7 +51,7 @@ + if (pos == null) { + this.modelData = java.util.Collections.emptyMap(); + } else { -+ this.modelData = net.minecraftforge.client.model.ModelDataManager.getModelData(net.minecraft.client.Minecraft.m_91087_().f_91073_, pos); ++ this.modelData = net.minecraft.client.Minecraft.m_91087_().f_91073_.getModelDataManager().getAt(pos); + } } @@ -61,8 +61,8 @@ return Doubles.compare(this.f_112847_, p_112855_.f_112847_); } + -+ public net.minecraftforge.client.model.data.IModelData getModelData(net.minecraft.core.BlockPos pos) { -+ return modelData.getOrDefault(pos, net.minecraftforge.client.model.data.EmptyModelData.INSTANCE); ++ public net.minecraftforge.client.model.data.ModelData getModelData(net.minecraft.core.BlockPos pos) { ++ return modelData.getOrDefault(pos, net.minecraftforge.client.model.data.ModelData.EMPTY); + } } @@ -82,62 +82,29 @@ this.f_112858_ = p_194428_; } -@@ -592,29 +_,34 @@ +@@ -603,7 +_,10 @@ + } - BlockState blockstate1 = renderchunkregion.m_8055_(blockpos2); - FluidState fluidstate = blockstate1.m_60819_(); -- if (!fluidstate.m_76178_()) { -- RenderType rendertype = ItemBlockRenderTypes.m_109287_(fluidstate); -- BufferBuilder bufferbuilder = p_234471_.m_108839_(rendertype); -- if (set.add(rendertype)) { -- RenderChunk.this.m_112805_(bufferbuilder); -- } -- -- blockrenderdispatcher.m_234363_(blockpos2, renderchunkregion, bufferbuilder, blockstate1, fluidstate); -- } -- -- if (blockstate.m_60799_() != RenderShape.INVISIBLE) { + if (blockstate.m_60799_() != RenderShape.INVISIBLE) { - RenderType rendertype2 = ItemBlockRenderTypes.m_109282_(blockstate); -- BufferBuilder bufferbuilder2 = p_234471_.m_108839_(rendertype2); -- if (set.add(rendertype2)) { -- RenderChunk.this.m_112805_(bufferbuilder2); -- } -- -- posestack.m_85836_(); -- posestack.m_85837_((double)(blockpos2.m_123341_() & 15), (double)(blockpos2.m_123342_() & 15), (double)(blockpos2.m_123343_() & 15)); ++ var model = blockrenderdispatcher.m_110910_(blockstate); ++ var modelData = getModelData(blockpos2); ++ randomsource.m_188584_(blockstate.m_60726_(blockpos2)); ++ for (RenderType rendertype2 : model.getRenderTypes(blockstate, randomsource, modelData)) { + BufferBuilder bufferbuilder2 = p_234471_.m_108839_(rendertype2); + if (set.add(rendertype2)) { + RenderChunk.this.m_112805_(bufferbuilder2); +@@ -611,8 +_,9 @@ + + posestack.m_85836_(); + posestack.m_85837_((double)(blockpos2.m_123341_() & 15), (double)(blockpos2.m_123342_() & 15), (double)(blockpos2.m_123343_() & 15)); - blockrenderdispatcher.m_234355_(blockstate, blockpos2, renderchunkregion, posestack, bufferbuilder2, true, randomsource); -- posestack.m_85849_(); -+ net.minecraftforge.client.model.data.IModelData modelData = getModelData(blockpos2); -+ for (RenderType rendertype : RenderType.m_110506_()) { -+ net.minecraftforge.client.ForgeHooksClient.setRenderType(rendertype); -+ -+ if (!fluidstate.m_76178_() && ItemBlockRenderTypes.canRenderInLayer(fluidstate, rendertype)) { -+ BufferBuilder bufferbuilder = p_234471_.m_108839_(rendertype); -+ if (set.add(rendertype)) { -+ RenderChunk.this.m_112805_(bufferbuilder); -+ } -+ -+ blockrenderdispatcher.m_234363_(blockpos2, renderchunkregion, bufferbuilder, blockstate1, fluidstate); -+ } -+ -+ if (blockstate.m_60799_() != RenderShape.INVISIBLE && ItemBlockRenderTypes.canRenderInLayer(blockstate, rendertype)) { -+ RenderType rendertype1 = rendertype; -+ BufferBuilder bufferbuilder2 = p_234471_.m_108839_(rendertype1); -+ if (set.add(rendertype1)) { -+ RenderChunk.this.m_112805_(bufferbuilder2); -+ } -+ -+ posestack.m_85836_(); -+ posestack.m_85837_((double) (blockpos2.m_123341_() & 15), (double) (blockpos2.m_123342_() & 15), (double) (blockpos2.m_123343_() & 15)); -+ blockrenderdispatcher.renderBatched(blockstate, blockpos2, renderchunkregion, posestack, bufferbuilder2, true, randomsource, modelData); -+ posestack.m_85849_(); ++ blockrenderdispatcher.renderBatched(blockstate, blockpos2, renderchunkregion, posestack, bufferbuilder2, true, randomsource, modelData, rendertype2); + posestack.m_85849_(); + } } } -+ net.minecraftforge.client.ForgeHooksClient.setRenderType(null); - if (set.contains(RenderType.m_110466_())) { - BufferBuilder bufferbuilder1 = p_234471_.m_108839_(RenderType.m_110466_()); @@ -641,10 +_,10 @@ private void m_234476_(ChunkRenderDispatcher.RenderChunk.RebuildTask.CompileResults p_234477_, E p_234478_) { BlockEntityRenderer blockentityrenderer = Minecraft.m_91087_().m_167982_().m_112265_(p_234478_); diff --git a/patches/minecraft/net/minecraft/client/renderer/chunk/RenderChunkRegion.java.patch b/patches/minecraft/net/minecraft/client/renderer/chunk/RenderChunkRegion.java.patch new file mode 100644 index 00000000000..e8b4b230aaf --- /dev/null +++ b/patches/minecraft/net/minecraft/client/renderer/chunk/RenderChunkRegion.java.patch @@ -0,0 +1,12 @@ +--- a/net/minecraft/client/renderer/chunk/RenderChunkRegion.java ++++ b/net/minecraft/client/renderer/chunk/RenderChunkRegion.java +@@ -66,4 +_,9 @@ + public int m_141928_() { + return this.f_112908_.m_141928_(); + } ++ ++ @Override ++ public float getShade(float normalX, float normalY, float normalZ, boolean shade) { ++ return this.f_112908_.getShade(normalX, normalY, normalZ, shade); ++ } + } diff --git a/patches/minecraft/net/minecraft/client/renderer/entity/EntityRenderer.java.patch b/patches/minecraft/net/minecraft/client/renderer/entity/EntityRenderer.java.patch index e9ea8b88c03..36d5b167d17 100644 --- a/patches/minecraft/net/minecraft/client/renderer/entity/EntityRenderer.java.patch +++ b/patches/minecraft/net/minecraft/client/renderer/entity/EntityRenderer.java.patch @@ -6,10 +6,10 @@ public void m_7392_(T p_114485_, float p_114486_, float p_114487_, PoseStack p_114488_, MultiBufferSource p_114489_, int p_114490_) { - if (this.m_6512_(p_114485_)) { - this.m_7649_(p_114485_, p_114485_.m_5446_(), p_114488_, p_114489_, p_114490_); -+ net.minecraftforge.client.event.RenderNameplateEvent renderNameplateEvent = new net.minecraftforge.client.event.RenderNameplateEvent(p_114485_, p_114485_.m_5446_(), this, p_114488_, p_114489_, p_114490_, p_114487_); -+ net.minecraftforge.common.MinecraftForge.EVENT_BUS.post(renderNameplateEvent); -+ if (renderNameplateEvent.getResult() != net.minecraftforge.eventbus.api.Event.Result.DENY && (renderNameplateEvent.getResult() == net.minecraftforge.eventbus.api.Event.Result.ALLOW || this.m_6512_(p_114485_))) { -+ this.m_7649_(p_114485_, renderNameplateEvent.getContent(), p_114488_, p_114489_, p_114490_); ++ var renderNameTagEvent = new net.minecraftforge.client.event.RenderNameTagEvent(p_114485_, p_114485_.m_5446_(), this, p_114488_, p_114489_, p_114490_, p_114487_); ++ net.minecraftforge.common.MinecraftForge.EVENT_BUS.post(renderNameTagEvent); ++ if (renderNameTagEvent.getResult() != net.minecraftforge.eventbus.api.Event.Result.DENY && (renderNameTagEvent.getResult() == net.minecraftforge.eventbus.api.Event.Result.ALLOW || this.m_6512_(p_114485_))) { ++ this.m_7649_(p_114485_, renderNameTagEvent.getContent(), p_114488_, p_114489_, p_114490_); } } diff --git a/patches/minecraft/net/minecraft/client/renderer/entity/FallingBlockRenderer.java.patch b/patches/minecraft/net/minecraft/client/renderer/entity/FallingBlockRenderer.java.patch index d2a7dabc237..6602e74b449 100644 --- a/patches/minecraft/net/minecraft/client/renderer/entity/FallingBlockRenderer.java.patch +++ b/patches/minecraft/net/minecraft/client/renderer/entity/FallingBlockRenderer.java.patch @@ -1,17 +1,13 @@ --- a/net/minecraft/client/renderer/entity/FallingBlockRenderer.java +++ b/net/minecraft/client/renderer/entity/FallingBlockRenderer.java -@@ -34,7 +_,13 @@ +@@ -34,7 +_,9 @@ p_114637_.m_85836_(); BlockPos blockpos = new BlockPos(p_114634_.m_20185_(), p_114634_.m_20191_().f_82292_, p_114634_.m_20189_()); p_114637_.m_85837_(-0.5D, 0.0D, -0.5D); - this.f_234617_.m_110937_().m_234379_(level, this.f_234617_.m_110910_(blockstate), blockstate, blockpos, p_114637_, p_114638_.m_6299_(ItemBlockRenderTypes.m_109293_(blockstate)), false, RandomSource.m_216327_(), blockstate.m_60726_(p_114634_.m_31978_()), OverlayTexture.f_118083_); -+ for (net.minecraft.client.renderer.RenderType type : net.minecraft.client.renderer.RenderType.m_110506_()) { -+ if (ItemBlockRenderTypes.canRenderInLayer(blockstate, type)) { -+ net.minecraftforge.client.ForgeHooksClient.setRenderType(type); -+ this.f_234617_.m_110937_().m_234379_(level, this.f_234617_.m_110910_(blockstate), blockstate, blockpos, p_114637_, p_114638_.m_6299_(type), false, RandomSource.m_216327_(), blockstate.m_60726_(p_114634_.m_31978_()), OverlayTexture.f_118083_); -+ } -+ } -+ net.minecraftforge.client.ForgeHooksClient.setRenderType(null); ++ var model = this.f_234617_.m_110910_(blockstate); ++ for (var renderType : model.getRenderTypes(blockstate, RandomSource.m_216335_(blockstate.m_60726_(p_114634_.m_31978_())), net.minecraftforge.client.model.data.ModelData.EMPTY)) ++ this.f_234617_.m_110937_().tesselateBlock(level, model, blockstate, blockpos, p_114637_, p_114638_.m_6299_(renderType), false, RandomSource.m_216327_(), blockstate.m_60726_(p_114634_.m_31978_()), OverlayTexture.f_118083_, net.minecraftforge.client.model.data.ModelData.EMPTY, renderType); p_114637_.m_85849_(); super.m_7392_(p_114634_, p_114635_, p_114636_, p_114637_, p_114638_, p_114639_); } diff --git a/patches/minecraft/net/minecraft/client/renderer/entity/ItemRenderer.java.patch b/patches/minecraft/net/minecraft/client/renderer/entity/ItemRenderer.java.patch index 419758f5a3b..24693e7c546 100644 --- a/patches/minecraft/net/minecraft/client/renderer/entity/ItemRenderer.java.patch +++ b/patches/minecraft/net/minecraft/client/renderer/entity/ItemRenderer.java.patch @@ -1,15 +1,14 @@ --- a/net/minecraft/client/renderer/entity/ItemRenderer.java +++ b/net/minecraft/client/renderer/entity/ItemRenderer.java -@@ -77,8 +_,8 @@ +@@ -77,7 +_,7 @@ public ItemRenderer(TextureManager p_174225_, ModelManager p_174226_, ItemColors p_174227_, BlockEntityWithoutLevelRenderer p_174228_) { this.f_115096_ = p_174225_; - this.f_115095_ = new ItemModelShaper(p_174226_); ++ this.f_115095_ = new net.minecraftforge.client.model.ForgeItemModelShaper(p_174226_); this.f_174223_ = p_174228_; -+ this.f_115095_ = new net.minecraftforge.client.ItemModelMesherForge(p_174226_); for(Item item : Registry.f_122827_) { - if (!f_115094_.contains(item)) { @@ -118,7 +_,7 @@ } } @@ -19,24 +18,28 @@ p_115147_.m_85837_(-0.5D, -0.5D, -0.5D); if (!p_115151_.m_7521_() && (!p_115144_.m_150930_(Items.f_42713_) || flag)) { boolean flag1; -@@ -128,7 +_,8 @@ +@@ -128,8 +_,8 @@ } else { flag1 = true; } - -+ if (p_115151_.isLayered()) { net.minecraftforge.client.ForgeHooksClient.drawItemLayered(this, p_115151_, p_115144_, p_115147_, p_115148_, p_115149_, p_115150_, flag1); } -+ else { - RenderType rendertype = ItemBlockRenderTypes.m_109279_(p_115144_, flag1); +- RenderType rendertype = ItemBlockRenderTypes.m_109279_(p_115144_, flag1); ++ for (var model : p_115151_.getRenderPasses(p_115144_, flag1)) { ++ for (var rendertype : model.getRenderTypes(p_115144_, flag1)) { VertexConsumer vertexconsumer; if (p_115144_.m_204117_(ItemTags.f_215866_) && p_115144_.m_41790_()) { -@@ -154,8 +_,9 @@ + p_115147_.m_85836_(); +@@ -153,9 +_,11 @@ + vertexconsumer = m_115211_(p_115148_, rendertype, true, p_115144_.m_41790_()); } - this.m_115189_(p_115151_, p_115144_, p_115149_, p_115150_, p_115147_, vertexconsumer); +- this.m_115189_(p_115151_, p_115144_, p_115149_, p_115150_, p_115147_, vertexconsumer); ++ this.m_115189_(model, p_115144_, p_115149_, p_115150_, p_115147_, vertexconsumer); ++ } + } } else { - this.f_174223_.m_108829_(p_115144_, p_115145_, p_115147_, p_115148_, p_115149_, p_115150_); -+ net.minecraftforge.client.RenderProperties.get(p_115144_).getItemStackRenderer().m_108829_(p_115144_, p_115145_, p_115147_, p_115148_, p_115149_, p_115150_); ++ net.minecraftforge.client.extensions.common.IClientItemExtensions.of(p_115144_).getCustomRenderer().m_108829_(p_115144_, p_115145_, p_115147_, p_115148_, p_115149_, p_115150_); } p_115147_.m_85849_(); @@ -45,7 +48,7 @@ float f1 = (float)(i >> 8 & 255) / 255.0F; float f2 = (float)(i & 255) / 255.0F; - p_115164_.m_85987_(posestack$pose, bakedquad, f, f1, f2, p_115167_, p_115168_); -+ p_115164_.putBulkData(posestack$pose, bakedquad, f, f1, f2, p_115167_, p_115168_, true); ++ p_115164_.putBulkData(posestack$pose, bakedquad, f, f1, f2, 1.0F, p_115167_, p_115168_, true); } } diff --git a/patches/minecraft/net/minecraft/client/resources/model/BakedModel.java.patch b/patches/minecraft/net/minecraft/client/resources/model/BakedModel.java.patch index b00cbf36243..aa068367d69 100644 --- a/patches/minecraft/net/minecraft/client/resources/model/BakedModel.java.patch +++ b/patches/minecraft/net/minecraft/client/resources/model/BakedModel.java.patch @@ -6,7 +6,7 @@ @OnlyIn(Dist.CLIENT) -public interface BakedModel { +public interface BakedModel extends net.minecraftforge.client.extensions.IForgeBakedModel { -+ /**@deprecated Forge: Use {@link net.minecraftforge.client.extensions.IForgeBakedModel#getQuads(BlockState, Direction, Random, net.minecraftforge.client.model.data.IModelData)}*/ ++ /**@deprecated Forge: Use {@link net.minecraftforge.client.extensions.IForgeBakedModel#getQuads(BlockState, Direction, RandomSource, net.minecraftforge.client.model.data.ModelData, net.minecraft.client.renderer.RenderType)}*/ + @Deprecated List m_213637_(@Nullable BlockState p_235039_, @Nullable Direction p_235040_, RandomSource p_235041_); @@ -15,12 +15,12 @@ boolean m_7521_(); -+ /**@deprecated Forge: Use {@link net.minecraftforge.client.extensions.IForgeBakedModel#getParticleIcon(net.minecraftforge.client.model.data.IModelData)}*/ ++ /**@deprecated Forge: Use {@link net.minecraftforge.client.extensions.IForgeBakedModel#getParticleIcon(net.minecraftforge.client.model.data.ModelData)}*/ + @Deprecated TextureAtlasSprite m_6160_(); - ItemTransforms m_7442_(); -+ /**@deprecated Forge: Use {@link net.minecraftforge.client.extensions.IForgeBakedModel#handlePerspective(ItemTransforms.TransformType, com.mojang.blaze3d.vertex.PoseStack)} instead */ ++ /**@deprecated Forge: Use {@link net.minecraftforge.client.extensions.IForgeBakedModel#applyTransform(ItemTransforms.TransformType, com.mojang.blaze3d.vertex.PoseStack, boolean)} instead */ + @Deprecated + default ItemTransforms m_7442_() { return ItemTransforms.f_111786_; } diff --git a/patches/minecraft/net/minecraft/client/resources/model/ModelBakery.java.patch b/patches/minecraft/net/minecraft/client/resources/model/ModelBakery.java.patch index 3af88fac7b9..4edd2529298 100644 --- a/patches/minecraft/net/minecraft/client/resources/model/ModelBakery.java.patch +++ b/patches/minecraft/net/minecraft/client/resources/model/ModelBakery.java.patch @@ -1,29 +1,24 @@ --- a/net/minecraft/client/resources/model/ModelBakery.java +++ b/net/minecraft/client/resources/model/ModelBakery.java -@@ -149,8 +_,17 @@ - }); - +@@ -151,6 +_,8 @@ public ModelBakery(ResourceManager p_119247_, BlockColors p_119248_, ProfilerFiller p_119249_, int p_119250_) { -+ this(p_119247_, p_119248_, true); -+ processLoading(p_119249_, p_119250_); -+ } -+ -+ protected ModelBakery(ResourceManager p_119247_, BlockColors p_119248_, boolean vanillaBakery) { this.f_119243_ = p_119247_; this.f_119209_ = p_119248_; -+ } + -+ protected void processLoading(ProfilerFiller p_119249_, int p_119250_) { -+ net.minecraftforge.client.model.ModelLoaderRegistry.onModelLoadingStart(); ++ net.minecraftforge.client.model.geometry.GeometryLoaderManager.init(); p_119249_.m_6180_("missing_model"); try { -@@ -184,12 +_,16 @@ +@@ -184,12 +_,20 @@ p_119249_.m_6182_("special"); this.m_119306_(new ModelResourceLocation("minecraft:trident_in_hand#inventory")); this.m_119306_(new ModelResourceLocation("minecraft:spyglass_in_hand#inventory")); -+ for (ResourceLocation rl : getSpecialModels()) { -+ addModelToCache(rl); ++ Set additionalModels = Sets.newHashSet(); ++ net.minecraftforge.client.ForgeHooksClient.onRegisterAdditionalModels(additionalModels); ++ for (ResourceLocation rl : additionalModels) { ++ UnbakedModel unbakedmodel = this.m_119341_(rl); // loadTopLevel(...), but w/o ModelResourceLocation limitation ++ this.f_119212_.put(rl, unbakedmodel); ++ this.f_119214_.put(rl, unbakedmodel); + } p_119249_.m_6182_("textures"); Set> set = Sets.newLinkedHashSet(); @@ -43,20 +38,6 @@ f_119235_.warn("Unable to bake model: '{}': {}", p_119369_, exception); } -@@ -458,6 +_,13 @@ - this.f_119210_.addAll(p_119354_.m_7970_()); - } - -+ // Same as loadTopLevel but without restricting to MRL's -+ private void addModelToCache(ResourceLocation p_217843_1_) { -+ UnbakedModel unbakedmodel = this.m_119341_(p_217843_1_); -+ this.f_119212_.put(p_217843_1_, unbakedmodel); -+ this.f_119214_.put(p_217843_1_, unbakedmodel); -+ } -+ - private void m_119306_(ModelResourceLocation p_119307_) { - UnbakedModel unbakedmodel = this.m_119341_(p_119307_); - this.f_119212_.put(p_119307_, unbakedmodel); @@ -472,7 +_,13 @@ } @@ -85,22 +66,13 @@ this.f_119213_.put(triple, bakedmodel); return bakedmodel; } -@@ -537,11 +_,19 @@ - return this.f_119218_; - } - -+ public Set getSpecialModels() { -+ return java.util.Collections.emptySet(); -+ } -+ - @OnlyIn(Dist.CLIENT) - static class BlockStateDefinitionException extends RuntimeException { +@@ -542,6 +_,10 @@ public BlockStateDefinitionException(String p_119373_) { super(p_119373_); } + } + -+ public AtlasSet getSpriteMap() { ++ public AtlasSet getAtlasSet() { + return this.f_119244_; } diff --git a/patches/minecraft/net/minecraft/client/resources/model/ModelManager.java.patch b/patches/minecraft/net/minecraft/client/resources/model/ModelManager.java.patch index a20d434860b..464b916b65d 100644 --- a/patches/minecraft/net/minecraft/client/resources/model/ModelManager.java.patch +++ b/patches/minecraft/net/minecraft/client/resources/model/ModelManager.java.patch @@ -9,6 +9,14 @@ @Nullable private AtlasSet f_119398_; private final BlockModelShaper f_119399_; +@@ -28,6 +_,7 @@ + private int f_119402_; + private BakedModel f_119403_; + private Object2IntMap f_119404_; ++ private ModelBakery modelBakery; + + public ModelManager(TextureManager p_119406_, BlockColors p_119407_, int p_119408_) { + this.f_119400_ = p_119406_; @@ -36,6 +_,10 @@ this.f_119399_ = new BlockModelShaper(this); } @@ -20,20 +28,12 @@ public BakedModel m_119422_(ModelResourceLocation p_119423_) { return this.f_119397_.getOrDefault(p_119423_, this.f_119403_); } -@@ -50,7 +_,7 @@ - - protected ModelBakery m_5944_(ResourceManager p_119413_, ProfilerFiller p_119414_) { - p_119414_.m_7242_(); -- ModelBakery modelbakery = new ModelBakery(p_119413_, this.f_119401_, p_119414_, this.f_119402_); -+ net.minecraftforge.client.model.ForgeModelBakery modelbakery = new net.minecraftforge.client.model.ForgeModelBakery(p_119413_, this.f_119401_, p_119414_, this.f_119402_); - p_119414_.m_7241_(); - return modelbakery; - } -@@ -66,6 +_,7 @@ +@@ -66,6 +_,8 @@ this.f_119397_ = p_119419_.m_119251_(); this.f_119404_ = p_119419_.m_119355_(); this.f_119403_ = this.f_119397_.get(ModelBakery.f_119230_); -+ net.minecraftforge.client.ForgeHooksClient.onModelBake(this, this.f_119397_, (net.minecraftforge.client.model.ForgeModelBakery) p_119419_); ++ this.modelBakery = p_119419_; ++ net.minecraftforge.client.ForgeHooksClient.onModelBake(this, this.f_119397_, p_119419_); p_119421_.m_6182_("cache"); this.f_119399_.m_110892_(); p_119421_.m_7238_(); @@ -45,3 +45,13 @@ return this.f_119398_.m_117973_(p_119429_); } +@@ -103,5 +_,9 @@ + + public void m_119410_(int p_119411_) { + this.f_119402_ = p_119411_; ++ } ++ ++ public ModelBakery getModelBakery() { ++ return com.google.common.base.Preconditions.checkNotNull(modelBakery, "Attempted to query model bakery before it has been initialized."); + } + } diff --git a/patches/minecraft/net/minecraft/client/resources/model/ModelState.java.patch b/patches/minecraft/net/minecraft/client/resources/model/ModelState.java.patch deleted file mode 100644 index d3aebed4bdb..00000000000 --- a/patches/minecraft/net/minecraft/client/resources/model/ModelState.java.patch +++ /dev/null @@ -1,11 +0,0 @@ ---- a/net/minecraft/client/resources/model/ModelState.java -+++ b/net/minecraft/client/resources/model/ModelState.java -@@ -5,7 +_,7 @@ - import net.minecraftforge.api.distmarker.OnlyIn; - - @OnlyIn(Dist.CLIENT) --public interface ModelState { -+public interface ModelState extends net.minecraftforge.client.extensions.IForgeModelState { - default Transformation m_6189_() { - return Transformation.m_121093_(); - } diff --git a/patches/minecraft/net/minecraft/client/resources/model/MultiPartBakedModel.java.patch b/patches/minecraft/net/minecraft/client/resources/model/MultiPartBakedModel.java.patch index 2dd3f8847ee..223fbae8985 100644 --- a/patches/minecraft/net/minecraft/client/resources/model/MultiPartBakedModel.java.patch +++ b/patches/minecraft/net/minecraft/client/resources/model/MultiPartBakedModel.java.patch @@ -5,7 +5,7 @@ @OnlyIn(Dist.CLIENT) -public class MultiPartBakedModel implements BakedModel { -+public class MultiPartBakedModel implements net.minecraftforge.client.model.data.IDynamicBakedModel { ++public class MultiPartBakedModel implements net.minecraftforge.client.model.IDynamicBakedModel { private final List, BakedModel>> f_119459_; protected final boolean f_119453_; protected final boolean f_119454_; @@ -28,19 +28,31 @@ - public List m_213637_(@Nullable BlockState p_235050_, @Nullable Direction p_235051_, RandomSource p_235052_) { + // FORGE: Implement our overloads (here and below) so child models can have custom logic -+ public List getQuads(@Nullable BlockState p_235050_, @Nullable Direction p_235051_, RandomSource p_235052_, net.minecraftforge.client.model.data.IModelData modelData) { ++ public List getQuads(@Nullable BlockState p_235050_, @Nullable Direction p_235051_, RandomSource p_235052_, net.minecraftforge.client.model.data.ModelData modelData, @org.jetbrains.annotations.Nullable net.minecraft.client.renderer.RenderType renderType) { if (p_235050_ == null) { return Collections.emptyList(); } else { -@@ -65,7 +_,7 @@ +@@ -60,16 +_,17 @@ + this.f_119460_.put(p_235050_, bitset); + } + +- List list = Lists.newArrayList(); ++ List> list = Lists.newArrayList(); + long k = p_235052_.m_188505_(); for(int j = 0; j < bitset.length(); ++j) { if (bitset.get(j)) { - list.addAll(this.f_119459_.get(j).getRight().m_213637_(p_235050_, p_235051_, RandomSource.m_216335_(k))); -+ list.addAll(this.f_119459_.get(j).getRight().getQuads(p_235050_, p_235051_, RandomSource.m_216335_(k), net.minecraftforge.client.model.data.MultipartModelData.resolve(this.f_119459_.get(j).getRight(), modelData))); ++ var model = this.f_119459_.get(j).getRight(); ++ list.add(model.getQuads(p_235050_, p_235051_, RandomSource.m_216335_(k), net.minecraftforge.client.model.data.MultipartModelData.resolve(modelData, model), renderType)); } } +- return list; ++ return net.minecraftforge.common.util.ConcatenatedListView.of(list); + } + } + @@ -77,6 +_,10 @@ return this.f_119453_; } @@ -52,7 +64,7 @@ public boolean m_7539_() { return this.f_119454_; } -@@ -89,16 +_,31 @@ +@@ -89,12 +_,22 @@ return false; } @@ -61,26 +73,17 @@ return this.f_119456_; } -+ public TextureAtlasSprite getParticleIcon(net.minecraftforge.client.model.data.IModelData modelData) { ++ public TextureAtlasSprite getParticleIcon(net.minecraftforge.client.model.data.ModelData modelData) { + return this.defaultModel.getParticleIcon(modelData); + } + + @Deprecated public ItemTransforms m_7442_() { return this.f_119457_; - } - -+ public BakedModel handlePerspective(net.minecraft.client.renderer.block.model.ItemTransforms.TransformType transformType, com.mojang.blaze3d.vertex.PoseStack poseStack) { -+ return this.defaultModel.handlePerspective(transformType, poseStack); + } + - public ItemOverrides m_7343_() { - return this.f_119458_; -+ } -+ -+ @Override -+ public net.minecraftforge.client.model.data.IModelData getModelData(net.minecraft.world.level.BlockAndTintGetter world, net.minecraft.core.BlockPos pos, BlockState state, net.minecraftforge.client.model.data.IModelData tileData) { -+ return net.minecraftforge.client.model.data.MultipartModelData.create(f_119459_, world, pos, state, tileData); ++ public BakedModel applyTransform(net.minecraft.client.renderer.block.model.ItemTransforms.TransformType transformType, com.mojang.blaze3d.vertex.PoseStack poseStack, boolean applyLeftHandTransform) { ++ return this.defaultModel.applyTransform(transformType, poseStack, applyLeftHandTransform); } - @OnlyIn(Dist.CLIENT) + public ItemOverrides m_7343_() { diff --git a/patches/minecraft/net/minecraft/client/resources/model/SimpleBakedModel.java.patch b/patches/minecraft/net/minecraft/client/resources/model/SimpleBakedModel.java.patch index 7a9bad2fc90..2af85d284cb 100644 --- a/patches/minecraft/net/minecraft/client/resources/model/SimpleBakedModel.java.patch +++ b/patches/minecraft/net/minecraft/client/resources/model/SimpleBakedModel.java.patch @@ -1,13 +1,75 @@ --- a/net/minecraft/client/resources/model/SimpleBakedModel.java +++ b/net/minecraft/client/resources/model/SimpleBakedModel.java -@@ -81,6 +_,10 @@ - private final boolean f_119514_; - private final ItemTransforms f_119515_; +@@ -26,8 +_,17 @@ + protected final TextureAtlasSprite f_119485_; + protected final ItemTransforms f_119486_; + protected final ItemOverrides f_119487_; ++ protected final net.minecraftforge.client.ChunkRenderTypeSet blockRenderTypes; ++ protected final List itemRenderTypes; ++ protected final List fabulousItemRenderTypes; -+ public Builder(net.minecraftforge.client.model.IModelConfiguration model, ItemOverrides overrides) { -+ this(model.useSmoothLighting(), model.isSideLit(), model.isShadedInGui(), model.getCameraTransforms(), overrides); ++ /** @deprecated Forge: Use {@linkplain #SimpleBakedModel(List, Map, boolean, boolean, boolean, TextureAtlasSprite, ItemTransforms, ItemOverrides, net.minecraftforge.client.RenderTypeGroup) variant with RenderTypeGroup} **/ ++ @Deprecated + public SimpleBakedModel(List p_119489_, Map> p_119490_, boolean p_119491_, boolean p_119492_, boolean p_119493_, TextureAtlasSprite p_119494_, ItemTransforms p_119495_, ItemOverrides p_119496_) { ++ this(p_119489_, p_119490_, p_119491_, p_119492_, p_119493_, p_119494_, p_119495_, p_119496_, net.minecraftforge.client.RenderTypeGroup.EMPTY); ++ } ++ ++ public SimpleBakedModel(List p_119489_, Map> p_119490_, boolean p_119491_, boolean p_119492_, boolean p_119493_, TextureAtlasSprite p_119494_, ItemTransforms p_119495_, ItemOverrides p_119496_, net.minecraftforge.client.RenderTypeGroup renderTypes) { + this.f_119480_ = p_119489_; + this.f_119481_ = p_119490_; + this.f_119482_ = p_119491_; +@@ -36,6 +_,9 @@ + this.f_119485_ = p_119494_; + this.f_119486_ = p_119495_; + this.f_119487_ = p_119496_; ++ this.blockRenderTypes = !renderTypes.isEmpty() ? net.minecraftforge.client.ChunkRenderTypeSet.of(renderTypes.block()) : null; ++ this.itemRenderTypes = !renderTypes.isEmpty() ? List.of(renderTypes.entity()) : null; ++ this.fabulousItemRenderTypes = !renderTypes.isEmpty() ? List.of(renderTypes.entityFabulous()) : null; + } + + public List m_213637_(@Nullable BlockState p_235054_, @Nullable Direction p_235055_, RandomSource p_235056_) { +@@ -70,6 +_,25 @@ + return this.f_119487_; + } + ++ @Override ++ public net.minecraftforge.client.ChunkRenderTypeSet getRenderTypes(@org.jetbrains.annotations.NotNull BlockState state, @org.jetbrains.annotations.NotNull RandomSource rand, @org.jetbrains.annotations.NotNull net.minecraftforge.client.model.data.ModelData data) { ++ if (blockRenderTypes != null) ++ return blockRenderTypes; ++ return BakedModel.super.getRenderTypes(state, rand, data); ++ } ++ ++ @Override ++ public List getRenderTypes(net.minecraft.world.item.ItemStack itemStack, boolean fabulous) { ++ if (fabulous) { ++ if (itemRenderTypes != null) ++ return itemRenderTypes; ++ } else { ++ if (fabulousItemRenderTypes != null) ++ return fabulousItemRenderTypes; ++ } ++ return BakedModel.super.getRenderTypes(itemStack, fabulous); ++ } ++ + @OnlyIn(Dist.CLIENT) + public static class Builder { + private final List f_119508_ = Lists.newArrayList(); +@@ -116,11 +_,17 @@ + return this; + } + ++ /** @deprecated Forge: Use {@linkplain #build(net.minecraftforge.client.RenderTypeGroup) variant with RenderTypeGroup} **/ ++ @Deprecated + public BakedModel m_119533_() { ++ return build(net.minecraftforge.client.RenderTypeGroup.EMPTY); + } + - public Builder(BlockModel p_119517_, ItemOverrides p_119518_, boolean p_119519_) { - this(p_119517_.m_111476_(), p_119517_.m_111479_().m_111526_(), p_119519_, p_119517_.m_111491_(), p_119518_); ++ public BakedModel build(net.minecraftforge.client.RenderTypeGroup renderTypes) { + if (this.f_119512_ == null) { + throw new RuntimeException("Missing particle!"); + } else { +- return new SimpleBakedModel(this.f_119508_, this.f_119509_, this.f_119511_, this.f_119513_, this.f_119514_, this.f_119512_, this.f_119515_, this.f_119510_); ++ return new SimpleBakedModel(this.f_119508_, this.f_119509_, this.f_119511_, this.f_119513_, this.f_119514_, this.f_119512_, this.f_119515_, this.f_119510_, renderTypes); + } } + } diff --git a/patches/minecraft/net/minecraft/client/resources/model/WeightedBakedModel.java.patch b/patches/minecraft/net/minecraft/client/resources/model/WeightedBakedModel.java.patch index 32d6a51f826..3330088a5b0 100644 --- a/patches/minecraft/net/minecraft/client/resources/model/WeightedBakedModel.java.patch +++ b/patches/minecraft/net/minecraft/client/resources/model/WeightedBakedModel.java.patch @@ -5,7 +5,7 @@ @OnlyIn(Dist.CLIENT) -public class WeightedBakedModel implements BakedModel { -+public class WeightedBakedModel implements net.minecraftforge.client.model.data.IDynamicBakedModel { ++public class WeightedBakedModel implements net.minecraftforge.client.model.IDynamicBakedModel { private final int f_119540_; private final List> f_119541_; private final BakedModel f_119542_; @@ -15,10 +15,10 @@ - public List m_213637_(@Nullable BlockState p_235058_, @Nullable Direction p_235059_, RandomSource p_235060_) { + // FORGE: Implement our overloads (here and below) so child models can have custom logic -+ public List getQuads(@Nullable BlockState p_235058_, @Nullable Direction p_235059_, RandomSource p_235060_, net.minecraftforge.client.model.data.IModelData modelData) { ++ public List getQuads(@Nullable BlockState p_235058_, @Nullable Direction p_235059_, RandomSource p_235060_, net.minecraftforge.client.model.data.ModelData modelData, @org.jetbrains.annotations.Nullable net.minecraft.client.renderer.RenderType renderType) { return WeightedRandom.m_146314_(this.f_119541_, Math.abs((int)p_235060_.m_188505_()) % this.f_119540_).map((p_235065_) -> { - return p_235065_.m_146310_().m_213637_(p_235058_, p_235059_, p_235060_); -+ return p_235065_.m_146310_().getQuads(p_235058_, p_235059_, p_235060_, modelData); ++ return p_235065_.m_146310_().getQuads(p_235058_, p_235059_, p_235060_, modelData, renderType); }).orElse(Collections.emptyList()); } @@ -38,7 +38,7 @@ return this.f_119542_.m_6160_(); } -+ public TextureAtlasSprite getParticleIcon(net.minecraftforge.client.model.data.IModelData modelData) { ++ public TextureAtlasSprite getParticleIcon(net.minecraftforge.client.model.data.ModelData modelData) { + return this.f_119542_.getParticleIcon(modelData); + } + @@ -46,8 +46,8 @@ return this.f_119542_.m_7442_(); + } + -+ public BakedModel handlePerspective(net.minecraft.client.renderer.block.model.ItemTransforms.TransformType transformType, com.mojang.blaze3d.vertex.PoseStack poseStack) { -+ return this.f_119542_.handlePerspective(transformType, poseStack); ++ public BakedModel applyTransform(net.minecraft.client.renderer.block.model.ItemTransforms.TransformType transformType, com.mojang.blaze3d.vertex.PoseStack poseStack, boolean applyLeftHandTransform) { ++ return this.f_119542_.applyTransform(transformType, poseStack, applyLeftHandTransform); } public ItemOverrides m_7343_() { diff --git a/patches/minecraft/net/minecraft/world/effect/MobEffect.java.patch b/patches/minecraft/net/minecraft/world/effect/MobEffect.java.patch index 4779cd2b5b2..63a0d87255e 100644 --- a/patches/minecraft/net/minecraft/world/effect/MobEffect.java.patch +++ b/patches/minecraft/net/minecraft/world/effect/MobEffect.java.patch @@ -42,7 +42,7 @@ + } + } + -+ public void initializeClient(java.util.function.Consumer consumer) { ++ public void initializeClient(java.util.function.Consumer consumer) { + } + // END FORGE + diff --git a/patches/minecraft/net/minecraft/world/item/Item.java.patch b/patches/minecraft/net/minecraft/world/item/Item.java.patch index 5ee6263bc32..5f17e38215d 100644 --- a/patches/minecraft/net/minecraft/world/item/Item.java.patch +++ b/patches/minecraft/net/minecraft/world/item/Item.java.patch @@ -179,7 +179,7 @@ + } + } + -+ public void initializeClient(java.util.function.Consumer consumer) { ++ public void initializeClient(java.util.function.Consumer consumer) { + } + // END FORGE + diff --git a/patches/minecraft/net/minecraft/world/level/BlockAndTintGetter.java.patch b/patches/minecraft/net/minecraft/world/level/BlockAndTintGetter.java.patch new file mode 100644 index 00000000000..2f630164156 --- /dev/null +++ b/patches/minecraft/net/minecraft/world/level/BlockAndTintGetter.java.patch @@ -0,0 +1,11 @@ +--- a/net/minecraft/world/level/BlockAndTintGetter.java ++++ b/net/minecraft/world/level/BlockAndTintGetter.java +@@ -4,7 +_,7 @@ + import net.minecraft.core.Direction; + import net.minecraft.world.level.lighting.LevelLightEngine; + +-public interface BlockAndTintGetter extends BlockGetter { ++public interface BlockAndTintGetter extends BlockGetter, net.minecraftforge.client.extensions.IForgeBlockAndTintGetter { + float m_7717_(Direction p_45522_, boolean p_45523_); + + LevelLightEngine m_5518_(); diff --git a/patches/minecraft/net/minecraft/world/level/block/Block.java.patch b/patches/minecraft/net/minecraft/world/level/block/Block.java.patch index d0ada9a746b..47be29cd50d 100644 --- a/patches/minecraft/net/minecraft/world/level/block/Block.java.patch +++ b/patches/minecraft/net/minecraft/world/level/block/Block.java.patch @@ -119,7 +119,7 @@ + } + } + -+ public void initializeClient(java.util.function.Consumer consumer) { ++ public void initializeClient(java.util.function.Consumer consumer) { + } + + @Override diff --git a/src/main/java/net/minecraftforge/client/ChunkRenderTypeSet.java b/src/main/java/net/minecraftforge/client/ChunkRenderTypeSet.java new file mode 100644 index 00000000000..c8359cdbe3e --- /dev/null +++ b/src/main/java/net/minecraftforge/client/ChunkRenderTypeSet.java @@ -0,0 +1,223 @@ +/* + * Copyright (c) Forge Development LLC and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.minecraftforge.client; + +import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableList; +import net.minecraft.Util; +import net.minecraft.client.renderer.RenderType; +import org.jetbrains.annotations.NotNull; + +import java.util.Arrays; +import java.util.BitSet; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; + +/** + * An immutable ordered set (not implementing {@link java.util.Set}) of chunk {@linkplain RenderType render types}. + *

+ * Considerably speeds up lookups and merges of sets of chunk {@linkplain RenderType render types}. + * Users should cache their instances of this class whenever possible, as instantiating it is cheap, but not free. + */ +public sealed class ChunkRenderTypeSet implements Iterable +{ + private static final List CHUNK_RENDER_TYPES_LIST = RenderType.chunkBufferLayers(); + private static final RenderType[] CHUNK_RENDER_TYPES = CHUNK_RENDER_TYPES_LIST.toArray(new RenderType[0]); + + private static final ChunkRenderTypeSet NONE = new None(); + private static final ChunkRenderTypeSet ALL = new All(); + + public static ChunkRenderTypeSet none() + { + return NONE; + } + + public static ChunkRenderTypeSet all() + { + return ALL; + } + + public static ChunkRenderTypeSet of(RenderType... renderTypes) + { + return of(Arrays.asList(renderTypes)); + } + + public static ChunkRenderTypeSet of(Collection renderTypes) + { + if (renderTypes.isEmpty()) + return none(); + return of((Iterable) renderTypes); + } + + private static ChunkRenderTypeSet of(Iterable renderTypes) + { + var bits = new BitSet(); + for (RenderType renderType : renderTypes) + { + int index = renderType.getChunkLayerId(); + Preconditions.checkArgument(index >= 0, "Attempted to create chunk render type set with a non-chunk render type: " + renderType); + bits.set(index); + } + return new ChunkRenderTypeSet(bits); + } + + public static ChunkRenderTypeSet union(ChunkRenderTypeSet... sets) + { + return union(Arrays.asList(sets)); + } + + public static ChunkRenderTypeSet union(Collection sets) + { + if (sets.isEmpty()) + return none(); + return union((Iterable) sets); + } + + public static ChunkRenderTypeSet union(Iterable sets) + { + var bits = new BitSet(); + for (var set : sets) + bits.or(set.bits); + return new ChunkRenderTypeSet(bits); + } + + public static ChunkRenderTypeSet intersection(ChunkRenderTypeSet... sets) + { + return intersection(Arrays.asList(sets)); + } + + public static ChunkRenderTypeSet intersection(Collection sets) + { + if (sets.isEmpty()) + return all(); + return intersection((Iterable) sets); + } + + public static ChunkRenderTypeSet intersection(Iterable sets) + { + var bits = new BitSet(); + bits.set(0, CHUNK_RENDER_TYPES.length); + for (var set : sets) + bits.and(set.bits); + return new ChunkRenderTypeSet(bits); + } + + private final BitSet bits; + + private ChunkRenderTypeSet(BitSet bits) + { + this.bits = bits; + } + + public boolean isEmpty() + { + return bits.isEmpty(); + } + + public boolean contains(RenderType renderType) + { + int id = renderType.getChunkLayerId(); + return id >= 0 && bits.get(id); + } + + @NotNull + @Override + public Iterator iterator() + { + return new IteratorImpl(); + } + + public List asList() + { + return ImmutableList.copyOf(this); + } + + private final class IteratorImpl implements Iterator + { + private int index = bits.nextSetBit(0); + + @Override + public boolean hasNext() + { + return index >= 0; + } + + @Override + public RenderType next() + { + var renderType = CHUNK_RENDER_TYPES[index]; + index = bits.nextSetBit(index + 1); + return renderType; + } + } + + private static final class None extends ChunkRenderTypeSet + { + private None() + { + super(new BitSet()); + } + + @Override + public boolean isEmpty() + { + return true; + } + + @Override + public boolean contains(RenderType renderType) + { + return false; + } + + @NotNull + @Override + public Iterator iterator() + { + return Collections.emptyIterator(); + } + + @Override + public List asList() + { + return List.of(); + } + } + + private static final class All extends ChunkRenderTypeSet + { + private All() + { + super(Util.make(new BitSet(), bits -> bits.set(0, CHUNK_RENDER_TYPES.length))); + } + + @Override + public boolean isEmpty(){ + return false; + } + + @Override + public boolean contains(RenderType renderType) + { + return renderType.getChunkLayerId() >= 0; // Could just return true for efficiency purposes, but checking is near-free + } + + @NotNull + @Override + public Iterator iterator() + { + return CHUNK_RENDER_TYPES_LIST.iterator(); + } + + @Override + public List asList() + { + return CHUNK_RENDER_TYPES_LIST; + } + } +} diff --git a/src/main/java/net/minecraftforge/client/ClientCommandHandler.java b/src/main/java/net/minecraftforge/client/ClientCommandHandler.java index b59587fbe6c..f68c283df5a 100644 --- a/src/main/java/net/minecraftforge/client/ClientCommandHandler.java +++ b/src/main/java/net/minecraftforge/client/ClientCommandHandler.java @@ -43,7 +43,7 @@ public static void init() MinecraftForge.EVENT_BUS.addListener(ClientCommandHandler::handleClientPlayerLogin); } - private static void handleClientPlayerLogin(ClientPlayerNetworkEvent.LoggedInEvent event) + private static void handleClientPlayerLogin(ClientPlayerNetworkEvent.LoggingIn event) { // some custom server implementations do not send ClientboundCommandsPacket, provide a fallback var suggestionDispatcher = mergeServerCommands(new CommandDispatcher<>(), new CommandBuildContext(event.getPlayer().connection.registryAccess())); diff --git a/src/main/java/net/minecraftforge/client/ClientCommandSourceStack.java b/src/main/java/net/minecraftforge/client/ClientCommandSourceStack.java index 514c4259023..0fca05ba420 100644 --- a/src/main/java/net/minecraftforge/client/ClientCommandSourceStack.java +++ b/src/main/java/net/minecraftforge/client/ClientCommandSourceStack.java @@ -50,7 +50,7 @@ public void sendSuccess(Component message, boolean sendToAdmins) } /** - * Gets the list of teams from the client side + * {@return the list of teams from the client side} */ @Override public Collection getAllTeams() @@ -59,7 +59,7 @@ public Collection getAllTeams() } /** - * Gets the list of online player names from the client side + * {@return the list of online player names from the client side} */ @Override public Collection getOnlinePlayerNames() @@ -68,7 +68,7 @@ public Collection getOnlinePlayerNames() } /** - * Gets a {@link Stream} of recipe ids that are available on the client + * {@return a {@link Stream} of recipe ids that are available on the client} */ @Override public Stream getRecipeNames() @@ -77,7 +77,7 @@ public Stream getRecipeNames() } /** - * Gets a set of {@link ResourceKey} for levels from the client side + * {@return a set of {@link ResourceKey} for levels from the client side} */ @Override public Set> levels() @@ -86,7 +86,7 @@ public Set> levels() } /** - * Gets the {@link RegistryAccess} from the client side + * {@return the {@link RegistryAccess} from the client side} */ @Override public RegistryAccess registryAccess() @@ -95,7 +95,7 @@ public RegistryAccess registryAccess() } /** - * Gets the scoreboard from the client side + * {@return the scoreboard from the client side} */ @Override public Scoreboard getScoreboard() @@ -104,7 +104,7 @@ public Scoreboard getScoreboard() } /** - * Gets the advancement from the id from the client side where the advancement needs to be visible to the player + * {@return the advancement from the id from the client side where the advancement needs to be visible to the player} */ @Override public Advancement getAdvancement(ResourceLocation id) @@ -113,7 +113,7 @@ public Advancement getAdvancement(ResourceLocation id) } /** - * Gets the {@link RecipeManager} from the client side + * {@return the {@link RecipeManager} from the client side} */ @Override public RecipeManager getRecipeManager() @@ -122,7 +122,7 @@ public RecipeManager getRecipeManager() } /** - * Gets the level from the client side + * {@return the level from the client side} */ @Override public Level getUnsidedLevel() diff --git a/src/main/java/net/minecraftforge/client/ClientForgeMod.java b/src/main/java/net/minecraftforge/client/ClientForgeMod.java new file mode 100644 index 00000000000..945a74d4eeb --- /dev/null +++ b/src/main/java/net/minecraftforge/client/ClientForgeMod.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) Forge Development LLC and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.minecraftforge.client; + +import net.minecraft.client.renderer.RenderType; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.client.event.ModelEvent; +import net.minecraftforge.client.event.RegisterClientReloadListenersEvent; +import net.minecraftforge.client.event.RegisterNamedRenderTypesEvent; +import net.minecraftforge.client.model.CompositeModel; +import net.minecraftforge.client.model.DynamicFluidContainerModel; +import net.minecraftforge.client.model.ElementsModel; +import net.minecraftforge.client.model.EmptyModel; +import net.minecraftforge.client.model.ItemLayerModel; +import net.minecraftforge.client.model.SeparateTransformsModel; +import net.minecraftforge.client.model.obj.ObjLoader; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.common.Mod; + +@Mod.EventBusSubscriber(value = Dist.CLIENT, bus = Mod.EventBusSubscriber.Bus.MOD, modid = "forge") +public class ClientForgeMod +{ + @SubscribeEvent + public static void onRegisterGeometryLoaders(ModelEvent.RegisterGeometryLoaders event) + { + event.register("empty", EmptyModel.LOADER); + event.register("elements", ElementsModel.Loader.INSTANCE); + event.register("obj", ObjLoader.INSTANCE); + event.register("fluid_container", DynamicFluidContainerModel.Loader.INSTANCE); + event.register("composite", CompositeModel.Loader.INSTANCE); + event.register("item_layers", ItemLayerModel.Loader.INSTANCE); + event.register("separate_transforms", SeparateTransformsModel.Loader.INSTANCE); + + // TODO: Deprecated. To be removed in 1.20 + event.register("bucket", DynamicFluidContainerModel.Loader.INSTANCE_DEPRECATED); + event.register("item-layers", ItemLayerModel.Loader.INSTANCE_DEPRECATED); + event.register("separate-perspective", SeparateTransformsModel.Loader.INSTANCE_DEPRECATED); + } + + @SubscribeEvent + public static void onRegisterReloadListeners(RegisterClientReloadListenersEvent event) + { + event.registerReloadListener(ObjLoader.INSTANCE); + } + + @SubscribeEvent + public static void onRegisterNamedRenderTypes(RegisterNamedRenderTypesEvent event) + { + event.register("item_unlit", RenderType.translucent(), ForgeRenderTypes.ITEM_UNSORTED_UNLIT_TRANSLUCENT.get()); + } +} diff --git a/src/main/java/net/minecraftforge/client/ClientRegistry.java b/src/main/java/net/minecraftforge/client/ClientRegistry.java deleted file mode 100644 index 845c59df825..00000000000 --- a/src/main/java/net/minecraftforge/client/ClientRegistry.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (c) Forge Development LLC and contributors - * SPDX-License-Identifier: LGPL-2.1-only - */ - -package net.minecraftforge.client; - -import net.minecraft.world.entity.Entity; -import net.minecraft.resources.ResourceLocation; -import org.apache.commons.lang3.ArrayUtils; - -import net.minecraft.client.Minecraft; -import net.minecraft.client.KeyMapping; - -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -public class ClientRegistry -{ - private static Map, ResourceLocation> entityShaderMap = new ConcurrentHashMap<>(); - - /** - * Registers a KeyBinding. - * Call this during {@link net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent}. - * This method is safe to call during parallel mod loading. - */ - public static synchronized void registerKeyBinding(KeyMapping key) - { - Minecraft.getInstance().options.keyMappings = ArrayUtils.add(Minecraft.getInstance().options.keyMappings, key); - } - - /** - * Register a shader for an entity. This shader gets activated when a spectator begins spectating an entity. - * Vanilla examples of this are the green effect for creepers and the invert effect for endermen. - * Call this during {@link net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent}. - * This method is safe to call during parallel mod loading. - */ - public static void registerEntityShader(Class entityClass, ResourceLocation shader) - { - entityShaderMap.put(entityClass, shader); - } - - public static ResourceLocation getEntityShader(Class entityClass) - { - return entityShaderMap.get(entityClass); - } -} diff --git a/src/main/java/net/minecraftforge/client/DimensionSpecialEffectsManager.java b/src/main/java/net/minecraftforge/client/DimensionSpecialEffectsManager.java new file mode 100644 index 00000000000..bfd3cd2e77c --- /dev/null +++ b/src/main/java/net/minecraftforge/client/DimensionSpecialEffectsManager.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) Forge Development LLC and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.minecraftforge.client; + +import com.google.common.collect.ImmutableMap; +import net.minecraft.client.renderer.DimensionSpecialEffects; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.dimension.BuiltinDimensionTypes; +import net.minecraftforge.client.event.RegisterDimensionSpecialEffectsEvent; +import net.minecraftforge.fml.ModLoader; +import net.minecraftforge.fml.ModLoadingContext; +import org.jetbrains.annotations.ApiStatus; + +import java.util.HashMap; +import java.util.Map; + +/** + * Manager for {@link DimensionSpecialEffects} instances. + *

+ * Provides a lookup by dimension type. + */ +public final class DimensionSpecialEffectsManager +{ + private static ImmutableMap EFFECTS; + private static DimensionSpecialEffects DEFAULT_EFFECTS; + + /** + * Finds the {@link DimensionSpecialEffects} for a given dimension type, or the default if none is registered. + */ + public static DimensionSpecialEffects getForType(ResourceLocation type) + { + return EFFECTS.getOrDefault(type, DEFAULT_EFFECTS); + } + + @ApiStatus.Internal + public static void init() + { + var effects = new HashMap(); + DEFAULT_EFFECTS = preRegisterVanillaEffects(effects); + var event = new RegisterDimensionSpecialEffectsEvent(effects); + ModLoader.get().postEventWithWrapInModOrder(event, (mc, e) -> ModLoadingContext.get().setActiveContainer(mc), (mc, e) -> ModLoadingContext.get().setActiveContainer(null)); + EFFECTS = ImmutableMap.copyOf(effects); + } + + /** + * Pre-registers vanilla dimension effects and returns the default fallback effects instance. + *

+ * Borrowed from {@link DimensionSpecialEffects#EFFECTS}. + */ + private static DimensionSpecialEffects preRegisterVanillaEffects(Map effects) + { + var overworldEffects = new DimensionSpecialEffects.OverworldEffects(); + effects.put(BuiltinDimensionTypes.OVERWORLD_EFFECTS, overworldEffects); + effects.put(BuiltinDimensionTypes.NETHER_EFFECTS, new DimensionSpecialEffects.NetherEffects()); + effects.put(BuiltinDimensionTypes.END_EFFECTS, new DimensionSpecialEffects.EndEffects()); + return overworldEffects; + } + + private DimensionSpecialEffectsManager() + { + } +} diff --git a/src/main/java/net/minecraftforge/client/EffectRenderer.java b/src/main/java/net/minecraftforge/client/EffectRenderer.java deleted file mode 100644 index f09de312876..00000000000 --- a/src/main/java/net/minecraftforge/client/EffectRenderer.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (c) Forge Development LLC and contributors - * SPDX-License-Identifier: LGPL-2.1-only - */ - -package net.minecraftforge.client; - -import com.mojang.blaze3d.vertex.PoseStack; -import net.minecraft.client.gui.GuiComponent; -import net.minecraft.client.gui.screens.inventory.EffectRenderingInventoryScreen; -import net.minecraft.world.effect.MobEffectInstance; - - -public abstract class EffectRenderer -{ - public static final EffectRenderer DUMMY = new EffectRenderer() - { - @Override - public void renderInventoryEffect(MobEffectInstance effectInstance, EffectRenderingInventoryScreen gui, PoseStack poseStack, int x, int y, float z) - { - - } - - @Override - public void renderHUDEffect(MobEffectInstance effectInstance, GuiComponent gui, PoseStack poseStack, int x, int y, float z, float alpha) - { - - } - }; - - /** - * If the Potion effect should be displayed in the players inventory - * - * @param effect the active PotionEffect - * @return true to display it (default), false to hide it. - */ - public boolean shouldRender(MobEffectInstance effect) - { - return true; - } - - /** - * If the standard PotionEffect text (name and duration) should be drawn when this potion is active. - * - * @param effect the active PotionEffect - * @return true to draw the standard text - */ - public boolean shouldRenderInvText(MobEffectInstance effect) - { - return true; - } - - /** - * If the Potion effect should be displayed in the player's ingame HUD - * - * @param effect the active PotionEffect - * @return true to display it (default), false to hide it. - */ - public boolean shouldRenderHUD(MobEffectInstance effect) - { - return true; - } - - /** - * Called to draw the this Potion onto the player's inventory when it's active. - * This can be used to e.g. render Potion icons from your own texture. - * - * @param effectInstance the effect instance - * @param gui the gui instance - * @param poseStack the pose stack - * @param x the x coordinate - * @param y the y coordinate - * @param z the z level - */ - public abstract void renderInventoryEffect(MobEffectInstance effectInstance, EffectRenderingInventoryScreen gui, PoseStack poseStack, int x, int y, float z); - - /** - * Called to draw the this Potion onto the player's ingame HUD when it's active. - * This can be used to e.g. render Potion icons from your own texture. - * - * @param effectInstance the active PotionEffect - * @param gui the gui instance - * @param poseStack the pose stack - * @param x the x coordinate - * @param y the y coordinate - * @param z the z level - * @param alpha the alpha value, blinks when the potion is about to run out - */ - public abstract void renderHUDEffect(MobEffectInstance effectInstance, GuiComponent gui, PoseStack poseStack, int x, int y, float z, float alpha); -} diff --git a/src/main/java/net/minecraftforge/client/EntitySpectatorShaderManager.java b/src/main/java/net/minecraftforge/client/EntitySpectatorShaderManager.java new file mode 100644 index 00000000000..f15d7dc9e45 --- /dev/null +++ b/src/main/java/net/minecraftforge/client/EntitySpectatorShaderManager.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) Forge Development LLC and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.minecraftforge.client; + +import com.google.common.collect.ImmutableMap; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.entity.EntityType; +import net.minecraftforge.client.event.RegisterEntitySpectatorShadersEvent; +import net.minecraftforge.fml.ModLoader; +import net.minecraftforge.fml.ModLoadingContext; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.Nullable; + +import java.util.HashMap; +import java.util.Map; + +/** + * Manager for entity spectator mode shaders. + *

+ * Provides a lookup. + */ +public final class EntitySpectatorShaderManager +{ + private static Map, ResourceLocation> SHADERS; + + /** + * Finds the path to the spectator mode shader used for the specified entity type, or null if none is registered. + */ + @Nullable + public static ResourceLocation get(EntityType entityType) + { + return SHADERS.get(entityType); + } + + @ApiStatus.Internal + public static void init() + { + var shaders = new HashMap, ResourceLocation>(); + var event = new RegisterEntitySpectatorShadersEvent(shaders); + ModLoader.get().postEventWithWrapInModOrder(event, (mc, e) -> ModLoadingContext.get().setActiveContainer(mc), (mc, e) -> ModLoadingContext.get().setActiveContainer(null)); + SHADERS = ImmutableMap.copyOf(shaders); + } + + private EntitySpectatorShaderManager() + { + } +} diff --git a/src/main/java/net/minecraftforge/client/ExtendedServerListData.java b/src/main/java/net/minecraftforge/client/ExtendedServerListData.java index f4ff2a7eb06..2ca175b05a0 100644 --- a/src/main/java/net/minecraftforge/client/ExtendedServerListData.java +++ b/src/main/java/net/minecraftforge/client/ExtendedServerListData.java @@ -5,24 +5,10 @@ package net.minecraftforge.client; -public class ExtendedServerListData { - public final String type; - public final boolean isCompatible; - public int numberOfMods; - public String extraReason; - public final boolean truncated; - - public ExtendedServerListData(String type, boolean isCompatible, int num, String extraReason) - { - this(type, isCompatible, num, extraReason, false); - } - - public ExtendedServerListData(String type, boolean isCompatible, int num, String extraReason, boolean truncated) +public record ExtendedServerListData(String type, boolean isCompatible, int numberOfMods, String extraReason, boolean truncated) +{ + public ExtendedServerListData(String type, boolean isCompatible, int numberOfMods, String extraReason) { - this.type = type; - this.isCompatible = isCompatible; - this.numberOfMods = num; - this.extraReason = extraReason; - this.truncated = truncated; + this(type, isCompatible, numberOfMods, extraReason, false); } } diff --git a/src/main/java/net/minecraftforge/client/FluidContainerColorer.java b/src/main/java/net/minecraftforge/client/FluidContainerColorer.java deleted file mode 100644 index 65850f0971c..00000000000 --- a/src/main/java/net/minecraftforge/client/FluidContainerColorer.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (c) Forge Development LLC and contributors - * SPDX-License-Identifier: LGPL-2.1-only - */ - -package net.minecraftforge.client; - -import net.minecraft.client.color.item.ItemColor; -import net.minecraft.world.item.ItemStack; -import net.minecraftforge.fluids.FluidUtil; -import org.jetbrains.annotations.NotNull; - -public class FluidContainerColorer implements ItemColor -{ - @Override - public int getColor(@NotNull ItemStack stack, int tintIndex) - { - if (tintIndex != 1) return 0xFFFFFFFF; - return FluidUtil.getFluidContained(stack) - .map(fstack -> RenderProperties.get(fstack.getFluid()).getColorTint(fstack)) - .orElse(0xFFFFFFFF); - } -} diff --git a/src/main/java/net/minecraftforge/client/ForgeHooksClient.java b/src/main/java/net/minecraftforge/client/ForgeHooksClient.java index 7b0a20fa36c..05815b2375b 100755 --- a/src/main/java/net/minecraftforge/client/ForgeHooksClient.java +++ b/src/main/java/net/minecraftforge/client/ForgeHooksClient.java @@ -6,100 +6,143 @@ package net.minecraftforge.client; import com.google.common.collect.ImmutableMap; - +import com.mojang.blaze3d.platform.NativeImage; +import com.mojang.blaze3d.platform.Window; import com.mojang.blaze3d.shaders.FogShape; import com.mojang.blaze3d.systems.RenderSystem; -import com.mojang.blaze3d.vertex.*; +import com.mojang.blaze3d.vertex.DefaultVertexFormat; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; import com.mojang.datafixers.util.Either; +import com.mojang.math.Matrix4f; +import com.mojang.math.Vector3f; +import net.minecraft.ChatFormatting; +import net.minecraft.client.Camera; +import net.minecraft.client.KeyMapping; +import net.minecraft.client.Minecraft; +import net.minecraft.client.MouseHandler; +import net.minecraft.client.Options; +import net.minecraft.client.color.block.BlockColors; +import net.minecraft.client.color.item.ItemColors; +import net.minecraft.client.gui.Font; +import net.minecraft.client.gui.GuiComponent; import net.minecraft.client.gui.chat.NarratorChatListener; +import net.minecraft.client.gui.components.LerpingBossEvent; import net.minecraft.client.gui.screens.ConfirmScreen; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.gui.screens.TitleScreen; import net.minecraft.client.gui.screens.inventory.tooltip.ClientTooltipComponent; import net.minecraft.client.gui.screens.multiplayer.JoinMultiplayerScreen; +import net.minecraft.client.model.HumanoidModel; import net.minecraft.client.model.Model; import net.minecraft.client.model.geom.ModelLayerLocation; import net.minecraft.client.model.geom.builders.LayerDefinition; import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.client.multiplayer.MultiPlayerGameMode; +import net.minecraft.client.multiplayer.PlayerInfo; import net.minecraft.client.multiplayer.ServerData; +import net.minecraft.client.particle.ParticleEngine; import net.minecraft.client.particle.ParticleRenderType; import net.minecraft.client.player.AbstractClientPlayer; +import net.minecraft.client.player.Input; import net.minecraft.client.player.LocalPlayer; +import net.minecraft.client.renderer.FogRenderer; +import net.minecraft.client.renderer.GameRenderer; +import net.minecraft.client.renderer.LevelRenderer; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.ShaderInstance; +import net.minecraft.client.renderer.Sheets; +import net.minecraft.client.renderer.block.BlockRenderDispatcher; +import net.minecraft.client.renderer.block.model.ItemTransforms; +import net.minecraft.client.renderer.texture.TextureAtlas; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.resources.language.I18n; +import net.minecraft.client.resources.model.BakedModel; +import net.minecraft.client.resources.model.Material; +import net.minecraft.client.resources.model.ModelBakery; +import net.minecraft.client.resources.model.ModelManager; +import net.minecraft.client.resources.sounds.SoundInstance; +import net.minecraft.client.sounds.SoundEngine; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; import net.minecraft.locale.Language; import net.minecraft.network.Connection; -import net.minecraft.network.chat.*; +import net.minecraft.network.chat.ChatSender; +import net.minecraft.network.chat.ChatType; +import net.minecraft.network.chat.CommonComponents; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.FormattedText; import net.minecraft.network.protocol.status.ServerStatus; -import net.minecraft.util.RandomSource; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.packs.resources.Resource; +import net.minecraft.server.packs.resources.ResourceManager; import net.minecraft.util.Mth; +import net.minecraft.util.RandomSource; +import net.minecraft.world.InteractionHand; import net.minecraft.world.effect.MobEffectInstance; -import net.minecraft.world.entity.HumanoidArm; -import net.minecraft.world.inventory.tooltip.TooltipComponent; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.state.BlockState; -import com.mojang.blaze3d.platform.Window; -import net.minecraft.client.Minecraft; -import net.minecraft.client.MouseHandler; -import net.minecraft.client.resources.sounds.SoundInstance; -import net.minecraft.client.sounds.SoundEngine; -import net.minecraft.client.gui.GuiComponent; -import net.minecraft.client.gui.components.LerpingBossEvent; -import net.minecraft.client.gui.Font; -import net.minecraft.client.gui.screens.TitleScreen; -import net.minecraft.client.gui.screens.Screen; -import net.minecraft.client.multiplayer.PlayerInfo; -import net.minecraft.client.renderer.*; -import net.minecraft.client.color.block.BlockColors; -import net.minecraft.client.color.item.ItemColors; -import net.minecraft.client.model.HumanoidModel; -import net.minecraft.client.resources.model.BakedModel; -import net.minecraft.client.renderer.block.model.ItemTransforms; -import net.minecraft.client.resources.model.ModelManager; -import net.minecraft.client.resources.model.Material; -import net.minecraft.client.renderer.texture.TextureAtlas; -import com.mojang.blaze3d.platform.NativeImage; -import net.minecraft.client.renderer.texture.TextureAtlasSprite; -import net.minecraft.client.resources.language.I18n; -import net.minecraft.client.KeyMapping; import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.entity.HumanoidArm; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.ai.attributes.AttributeInstance; import net.minecraft.world.entity.player.Player; -import net.minecraft.world.level.material.Fluid; -import net.minecraft.world.level.material.FluidState; -import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.inventory.tooltip.TooltipComponent; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.crafting.RecipeManager; -import net.minecraft.server.packs.resources.Resource; -import net.minecraft.server.packs.resources.ResourceManager; -import net.minecraft.core.Direction; -import net.minecraft.world.InteractionHand; -import net.minecraft.client.player.Input; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.core.BlockPos; +import net.minecraft.world.level.BlockAndTintGetter; +import net.minecraft.world.level.GameType; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.material.Fluid; +import net.minecraft.world.level.material.FluidState; import net.minecraft.world.level.material.FogType; import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.EntityHitResult; import net.minecraft.world.phys.HitResult; -import com.mojang.math.Matrix3f; -import com.mojang.math.Matrix4f; -import com.mojang.math.Transformation; -import com.mojang.math.Vector3f; -import net.minecraft.ChatFormatting; -import net.minecraft.world.level.GameType; -import net.minecraft.world.level.BlockAndTintGetter; -import net.minecraft.world.level.Level; import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.client.event.*; +import net.minecraftforge.client.event.ClientChatEvent; +import net.minecraftforge.client.event.ClientChatReceivedEvent; +import net.minecraftforge.client.event.ClientPlayerChangeGameTypeEvent; +import net.minecraftforge.client.event.ClientPlayerNetworkEvent; +import net.minecraftforge.client.event.ComputeFovModifierEvent; +import net.minecraftforge.client.event.CustomizeGuiOverlayEvent; +import net.minecraftforge.client.event.InputEvent; +import net.minecraftforge.client.event.ModelEvent; +import net.minecraftforge.client.event.MovementInputUpdateEvent; +import net.minecraftforge.client.event.RecipesUpdatedEvent; +import net.minecraftforge.client.event.RegisterColorHandlersEvent; +import net.minecraftforge.client.event.RegisterKeyMappingsEvent; +import net.minecraftforge.client.event.RegisterParticleProvidersEvent; +import net.minecraftforge.client.event.RegisterShadersEvent; +import net.minecraftforge.client.event.RenderArmEvent; +import net.minecraftforge.client.event.RenderBlockScreenEffectEvent; +import net.minecraftforge.client.event.RenderHandEvent; +import net.minecraftforge.client.event.RenderHighlightEvent; +import net.minecraftforge.client.event.RenderLevelLastEvent; +import net.minecraftforge.client.event.RenderTooltipEvent; +import net.minecraftforge.client.event.ScreenEvent; +import net.minecraftforge.client.event.ScreenshotEvent; +import net.minecraftforge.client.event.TextureStitchEvent; +import net.minecraftforge.client.event.ViewportEvent; import net.minecraftforge.client.event.sound.PlaySoundEvent; -import net.minecraftforge.client.model.ForgeModelBakery; +import net.minecraftforge.client.extensions.common.IClientFluidTypeExtensions; +import net.minecraftforge.client.extensions.common.IClientItemExtensions; +import net.minecraftforge.client.extensions.common.IClientMobEffectExtensions; +import net.minecraftforge.client.model.data.ModelData; import net.minecraftforge.client.textures.ForgeTextureMetadata; +import net.minecraftforge.common.ForgeI18n; import net.minecraftforge.common.ForgeMod; import net.minecraftforge.common.MinecraftForge; -import net.minecraftforge.common.model.TransformationHelper; import net.minecraftforge.eventbus.api.Event; import net.minecraftforge.eventbus.api.SubscribeEvent; -import net.minecraftforge.fml.*; +import net.minecraftforge.fml.IExtensionPoint; +import net.minecraftforge.fml.ModList; +import net.minecraftforge.fml.ModLoader; +import net.minecraftforge.fml.StartupMessageManager; +import net.minecraftforge.fml.VersionChecker; import net.minecraftforge.fml.common.Mod; -import net.minecraftforge.common.ForgeI18n; import net.minecraftforge.network.NetworkConstants; import net.minecraftforge.network.NetworkRegistry; import net.minecraftforge.registries.ForgeRegistries; @@ -110,6 +153,9 @@ import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Marker; import org.apache.logging.log4j.MarkerManager; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.io.File; import java.io.IOException; @@ -129,16 +175,10 @@ import java.util.stream.Collectors; import java.util.stream.Stream; -import static net.minecraftforge.client.event.RenderGameOverlayEvent.ElementType.BOSSINFO; import static net.minecraftforge.fml.VersionChecker.Status.BETA; import static net.minecraftforge.fml.VersionChecker.Status.BETA_OUTDATED; -import net.minecraft.client.Camera; -import net.minecraft.client.renderer.block.BlockRenderDispatcher; -import net.minecraft.client.renderer.entity.ItemRenderer; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - +@ApiStatus.Internal public class ForgeHooksClient { private static final Logger LOGGER = LogManager.getLogger(); @@ -210,12 +250,12 @@ public static boolean onDrawHighlight(LevelRenderer context, Camera camera, HitR switch (target.getType()) { case BLOCK: if (!(target instanceof BlockHitResult blockTarget)) return false; - return MinecraftForge.EVENT_BUS.post(new DrawSelectionEvent.HighlightBlock(context, camera, blockTarget, partialTick, poseStack, bufferSource)); + return MinecraftForge.EVENT_BUS.post(new RenderHighlightEvent.Block(context, camera, blockTarget, partialTick, poseStack, bufferSource)); case ENTITY: if (!(target instanceof EntityHitResult entityTarget)) return false; - return MinecraftForge.EVENT_BUS.post(new DrawSelectionEvent.HighlightEntity(context, camera, entityTarget, partialTick, poseStack, bufferSource)); + return MinecraftForge.EVENT_BUS.post(new RenderHighlightEvent.Entity(context, camera, entityTarget, partialTick, poseStack, bufferSource)); default: - return MinecraftForge.EVENT_BUS.post(new DrawSelectionEvent(context, camera, target, partialTick, poseStack, bufferSource)); + return false; // NO-OP - This doesn't even get called for anything other than blocks and entities } } @@ -251,24 +291,17 @@ public static void onTextureStitchedPost(TextureAtlas map) public static void onBlockColorsInit(BlockColors blockColors) { - ModLoader.get().postEvent(new ColorHandlerEvent.Block(blockColors)); + ModLoader.get().postEvent(new RegisterColorHandlersEvent.Block(blockColors)); } public static void onItemColorsInit(ItemColors itemColors, BlockColors blockColors) { - ModLoader.get().postEvent(new ColorHandlerEvent.Item(itemColors, blockColors)); - } - - static final ThreadLocal renderType = new ThreadLocal(); - - public static void setRenderType(RenderType layer) - { - renderType.set(layer); + ModLoader.get().postEvent(new RegisterColorHandlersEvent.Item(itemColors, blockColors)); } public static Model getArmorModel(LivingEntity entityLiving, ItemStack itemStack, EquipmentSlot slot, HumanoidModel _default) { - return RenderProperties.get(itemStack).getBaseArmorModel(entityLiving, itemStack, slot, _default); + return IClientItemExtensions.of(itemStack).getGenericArmorModel(entityLiving, itemStack, slot, _default); } /** Copies humanoid model properties from the original model to another, used for armor models */ @@ -307,15 +340,15 @@ public static String fixDomain(String base, String complex) } } - public static float getFieldOfView(Player entity, float fov) + public static float getFieldOfViewModifier(Player entity, float fovModifier) { - FOVModifierEvent fovModifierEvent = new FOVModifierEvent(entity, fov); + ComputeFovModifierEvent fovModifierEvent = new ComputeFovModifierEvent(entity, fovModifier); MinecraftForge.EVENT_BUS.post(fovModifierEvent); - return fovModifierEvent.getNewFov(); + return fovModifierEvent.getNewFovModifier(); } public static double getFieldOfView(GameRenderer renderer, Camera camera, double partialTick, double fov) { - EntityViewRenderEvent.FieldOfView event = new EntityViewRenderEvent.FieldOfView(renderer, camera, partialTick, fov); + ViewportEvent.ComputeFov event = new ViewportEvent.ComputeFov(renderer, camera, partialTick, fov); MinecraftForge.EVENT_BUS.post(event); return event.getFOV(); } @@ -378,9 +411,9 @@ public static void drawScreen(Screen screen, PoseStack poseStack, int mouseX, in private static void drawScreenInternal(Screen screen, PoseStack poseStack, int mouseX, int mouseY, float partialTick) { - if (!MinecraftForge.EVENT_BUS.post(new ScreenEvent.DrawScreenEvent.Pre(screen, poseStack, mouseX, mouseY, partialTick))) + if (!MinecraftForge.EVENT_BUS.post(new ScreenEvent.Render.Pre(screen, poseStack, mouseX, mouseY, partialTick))) screen.render(poseStack, mouseX, mouseY, partialTick); - MinecraftForge.EVENT_BUS.post(new ScreenEvent.DrawScreenEvent.Post(screen, poseStack, mouseX, mouseY, partialTick)); + MinecraftForge.EVENT_BUS.post(new ScreenEvent.Render.Post(screen, poseStack, mouseX, mouseY, partialTick)); } public static Vector3f getFogColor(Camera camera, float partialTick, ClientLevel level, int renderDistance, float darkenWorldAmount, float fogRed, float fogGreen, float fogBlue) @@ -389,9 +422,9 @@ public static Vector3f getFogColor(Camera camera, float partialTick, ClientLevel FluidState state = level.getFluidState(camera.getBlockPosition()); Vector3f fluidFogColor = new Vector3f(fogRed, fogGreen, fogBlue); if (camera.getPosition().y < (double)((float)camera.getBlockPosition().getY() + state.getHeight(level, camera.getBlockPosition()))) - fluidFogColor = RenderProperties.get(state).modifyFogColor(camera, partialTick, level, renderDistance, darkenWorldAmount, fluidFogColor); + fluidFogColor = IClientFluidTypeExtensions.of(state).modifyFogColor(camera, partialTick, level, renderDistance, darkenWorldAmount, fluidFogColor); - EntityViewRenderEvent.FogColors event = new net.minecraftforge.client.event.EntityViewRenderEvent.FogColors(camera, partialTick, fluidFogColor.x(), fluidFogColor.y(), fluidFogColor.z()); + ViewportEvent.ComputeFogColor event = new ViewportEvent.ComputeFogColor(camera, partialTick, fluidFogColor.x(), fluidFogColor.y(), fluidFogColor.z()); MinecraftForge.EVENT_BUS.post(event); fluidFogColor.set(event.getRed(), event.getGreen(), event.getBlue()); @@ -403,9 +436,9 @@ public static void onFogRender(FogRenderer.FogMode mode, FogType type, Camera ca // Modify fog rendering depending on the fluid FluidState state = camera.getEntity().level.getFluidState(camera.getBlockPosition()); if (camera.getPosition().y < (double)((float)camera.getBlockPosition().getY() + state.getHeight(camera.getEntity().level, camera.getBlockPosition()))) - RenderProperties.get(state).modifyFogRender(camera, mode, renderDistance, partialTick, nearDistance, farDistance, shape); + IClientFluidTypeExtensions.of(state).modifyFogRender(camera, mode, renderDistance, partialTick, nearDistance, farDistance, shape); - EntityViewRenderEvent.RenderFogEvent event = new EntityViewRenderEvent.RenderFogEvent(type, camera, partialTick, nearDistance, farDistance, shape); + ViewportEvent.RenderFog event = new ViewportEvent.RenderFog(type, camera, partialTick, nearDistance, farDistance, shape); if (MinecraftForge.EVENT_BUS.post(event)) { RenderSystem.setShaderFogStart(event.getNearPlaneDistance()); @@ -414,54 +447,28 @@ public static void onFogRender(FogRenderer.FogMode mode, FogType type, Camera ca } } - public static EntityViewRenderEvent.CameraSetup onCameraSetup(GameRenderer renderer, Camera camera, float partial) + public static ViewportEvent.ComputeCameraAngles onCameraSetup(GameRenderer renderer, Camera camera, float partial) { - EntityViewRenderEvent.CameraSetup event = new EntityViewRenderEvent.CameraSetup(renderer, camera, partial, camera.getYRot(), camera.getXRot(), 0); + ViewportEvent.ComputeCameraAngles event = new ViewportEvent.ComputeCameraAngles(renderer, camera, partial, camera.getYRot(), camera.getXRot(), 0); MinecraftForge.EVENT_BUS.post(event); return event; } - public static void onModelBake(ModelManager modelManager, Map modelRegistry, ForgeModelBakery modelLoader) + public static void onModelBake(ModelManager modelManager, Map models, ModelBakery modelBakery) { - ModLoader.get().postEvent(new ModelBakeEvent(modelManager, modelRegistry, modelLoader)); - modelLoader.onPostBakeEvent(modelRegistry); - } - - private static final Matrix4f flipX; - private static final Matrix3f flipXNormal; - static { - flipX = Matrix4f.createScaleMatrix(-1,1,1); - flipXNormal = new Matrix3f(flipX); + ModLoader.get().postEvent(new ModelEvent.BakingCompleted(modelManager, models, modelBakery)); } - public static BakedModel handleCameraTransforms(PoseStack poseStack, BakedModel model, ItemTransforms.TransformType cameraTransformType, boolean leftHandHackery) + public static BakedModel handleCameraTransforms(PoseStack poseStack, BakedModel model, ItemTransforms.TransformType cameraTransformType, boolean applyLeftHandTransform) { - PoseStack stack = new PoseStack(); - model = model.handlePerspective(cameraTransformType, stack); - - // If the stack is not empty, the code has added a matrix for us to use. - if (!stack.clear()) - { - // Apply the transformation to the real matrix stack, flipping for left hand - Matrix4f tMat = stack.last().pose(); - Matrix3f nMat = stack.last().normal(); - if (leftHandHackery) - { - tMat.multiplyBackward(flipX); - tMat.multiply(flipX); - nMat.multiplyBackward(flipXNormal); - nMat.mul(flipXNormal); - } - poseStack.last().pose().multiply(tMat); - poseStack.last().normal().mul(nMat); - } + model = model.applyTransform(cameraTransformType, poseStack, applyLeftHandTransform); return model; } @SuppressWarnings("deprecation") public static TextureAtlasSprite[] getFluidSprites(BlockAndTintGetter level, BlockPos pos, FluidState fluidStateIn) { - IFluidTypeRenderProperties props = RenderProperties.get(fluidStateIn); + IClientFluidTypeExtensions props = IClientFluidTypeExtensions.of(fluidStateIn); ResourceLocation overlayTexture = props.getOverlayTexture(fluidStateIn, level, pos); return new TextureAtlasSprite[] { Minecraft.getInstance().getTextureAtlas(TextureAtlas.LOCATION_BLOCKS).apply(props.getStillTexture(fluidStateIn, level, pos)), @@ -481,9 +488,9 @@ public static void gatherFluidTextures(Set textures) public static Stream getFluidMaterials(Fluid fluid) { - return RenderProperties.get(fluid).getTextures() - .filter(Objects::nonNull) - .map(ForgeHooksClient::getBlockMaterial); + return IClientFluidTypeExtensions.of(fluid).getTextures() + .filter(Objects::nonNull) + .map(ForgeHooksClient::getBlockMaterial); } @SuppressWarnings("deprecation") @@ -534,7 +541,7 @@ public static void loadEntityShader(Entity entity, GameRenderer entityRenderer) { if (entity != null) { - ResourceLocation shader = ClientRegistry.getEntityShader(entity.getClass()); + ResourceLocation shader = EntitySpectatorShaderManager.get(entity.getType()); if (shader != null) { entityRenderer.loadEffect(shader); @@ -561,19 +568,14 @@ public static boolean shouldCauseReequipAnimation(@NotNull ItemStack from, @NotN return from.getItem().shouldCauseReequipAnimation(from, to, changed); } - public static RenderGameOverlayEvent.BossInfo renderBossEventPre(PoseStack poseStack, Window res, LerpingBossEvent bossInfo, int x, int y, int increment) + public static CustomizeGuiOverlayEvent.BossEventProgress onCustomizeBossEventProgress(PoseStack poseStack, Window window, LerpingBossEvent bossInfo, int x, int y, int increment) { - RenderGameOverlayEvent.BossInfo evt = new RenderGameOverlayEvent.BossInfo(poseStack, new RenderGameOverlayEvent(poseStack, MinecraftForgeClient.getPartialTick(), res), - BOSSINFO, bossInfo, x, y, increment); + CustomizeGuiOverlayEvent.BossEventProgress evt = new CustomizeGuiOverlayEvent.BossEventProgress(window, poseStack, + Minecraft.getInstance().getPartialTick(), bossInfo, x, y, increment); MinecraftForge.EVENT_BUS.post(evt); return evt; } - public static void renderBossEventPost(PoseStack poseStack, Window res) - { - MinecraftForge.EVENT_BUS.post(new RenderGameOverlayEvent.Post(poseStack, new RenderGameOverlayEvent(poseStack, MinecraftForgeClient.getPartialTick(), res), BOSSINFO)); - } - public static ScreenshotEvent onScreenshot(NativeImage image, File screenshotFile) { ScreenshotEvent event = new ScreenshotEvent(image, screenshotFile); @@ -590,16 +592,6 @@ public static void onClientChangeGameType(PlayerInfo info, GameType currentGameM } } - @SuppressWarnings("deprecation") - public static BakedModel handlePerspective(BakedModel model, ItemTransforms.TransformType type, PoseStack stack) - { - Transformation tr = TransformationHelper.toTransformation(model.getTransforms().getTransform(type)); - if(!tr.isIdentity()) { - tr.push(stack); - } - return model; - } - public static void onMovementInputUpdate(Player player, Input movementInput) { MinecraftForge.EVENT_BUS.post(new MovementInputUpdateEvent(player, movementInput)); @@ -607,40 +599,40 @@ public static void onMovementInputUpdate(Player player, Input movementInput) public static boolean onScreenMouseClickedPre(Screen guiScreen, double mouseX, double mouseY, int button) { - Event event = new ScreenEvent.MouseClickedEvent.Pre(guiScreen, mouseX, mouseY, button); + Event event = new ScreenEvent.MouseButtonPressed.Pre(guiScreen, mouseX, mouseY, button); return MinecraftForge.EVENT_BUS.post(event); } public static boolean onScreenMouseClickedPost(Screen guiScreen, double mouseX, double mouseY, int button, boolean handled) { - Event event = new ScreenEvent.MouseClickedEvent.Post(guiScreen, mouseX, mouseY, button, handled); + Event event = new ScreenEvent.MouseButtonPressed.Post(guiScreen, mouseX, mouseY, button, handled); MinecraftForge.EVENT_BUS.post(event); return event.getResult() == Event.Result.DEFAULT ? handled : event.getResult() == Event.Result.ALLOW; } public static boolean onScreenMouseReleasedPre(Screen guiScreen, double mouseX, double mouseY, int button) { - Event event = new ScreenEvent.MouseReleasedEvent.Pre(guiScreen, mouseX, mouseY, button); + Event event = new ScreenEvent.MouseButtonReleased.Pre(guiScreen, mouseX, mouseY, button); return MinecraftForge.EVENT_BUS.post(event); } public static boolean onScreenMouseReleasedPost(Screen guiScreen, double mouseX, double mouseY, int button, boolean handled) { - Event event = new ScreenEvent.MouseReleasedEvent.Post(guiScreen, mouseX, mouseY, button, handled); + Event event = new ScreenEvent.MouseButtonReleased.Post(guiScreen, mouseX, mouseY, button, handled); MinecraftForge.EVENT_BUS.post(event); return event.getResult() == Event.Result.DEFAULT ? handled : event.getResult() == Event.Result.ALLOW; } public static boolean onScreenMouseDragPre(Screen guiScreen, double mouseX, double mouseY, int mouseButton, double dragX, double dragY) { - Event event = new ScreenEvent.MouseDragEvent.Pre(guiScreen, mouseX, mouseY, mouseButton, dragX, dragY); + Event event = new ScreenEvent.MouseDragged.Pre(guiScreen, mouseX, mouseY, mouseButton, dragX, dragY); return MinecraftForge.EVENT_BUS.post(event); } - public static boolean onScreenMouseDragPost(Screen guiScreen, double mouseX, double mouseY, int mouseButton, double dragX, double dragY) + public static void onScreenMouseDragPost(Screen guiScreen, double mouseX, double mouseY, int mouseButton, double dragX, double dragY) { - Event event = new ScreenEvent.MouseDragEvent.Post(guiScreen, mouseX, mouseY, mouseButton, dragX, dragY); - return MinecraftForge.EVENT_BUS.post(event); + Event event = new ScreenEvent.MouseDragged.Post(guiScreen, mouseX, mouseY, mouseButton, dragX, dragY); + MinecraftForge.EVENT_BUS.post(event); } public static boolean onScreenMouseScrollPre(MouseHandler mouseHelper, Screen guiScreen, double scrollDelta) @@ -648,53 +640,53 @@ public static boolean onScreenMouseScrollPre(MouseHandler mouseHelper, Screen gu Window mainWindow = guiScreen.getMinecraft().getWindow(); double mouseX = mouseHelper.xpos() * (double) mainWindow.getGuiScaledWidth() / (double) mainWindow.getScreenWidth(); double mouseY = mouseHelper.ypos() * (double) mainWindow.getGuiScaledHeight() / (double) mainWindow.getScreenHeight(); - Event event = new ScreenEvent.MouseScrollEvent.Pre(guiScreen, mouseX, mouseY, scrollDelta); + Event event = new ScreenEvent.MouseScrolled.Pre(guiScreen, mouseX, mouseY, scrollDelta); return MinecraftForge.EVENT_BUS.post(event); } - public static boolean onScreenMouseScrollPost(MouseHandler mouseHelper, Screen guiScreen, double scrollDelta) + public static void onScreenMouseScrollPost(MouseHandler mouseHelper, Screen guiScreen, double scrollDelta) { Window mainWindow = guiScreen.getMinecraft().getWindow(); double mouseX = mouseHelper.xpos() * (double) mainWindow.getGuiScaledWidth() / (double) mainWindow.getScreenWidth(); double mouseY = mouseHelper.ypos() * (double) mainWindow.getGuiScaledHeight() / (double) mainWindow.getScreenHeight(); - Event event = new ScreenEvent.MouseScrollEvent.Post(guiScreen, mouseX, mouseY, scrollDelta); - return MinecraftForge.EVENT_BUS.post(event); + Event event = new ScreenEvent.MouseScrolled.Post(guiScreen, mouseX, mouseY, scrollDelta); + MinecraftForge.EVENT_BUS.post(event); } public static boolean onScreenKeyPressedPre(Screen guiScreen, int keyCode, int scanCode, int modifiers) { - Event event = new ScreenEvent.KeyboardKeyPressedEvent.Pre(guiScreen, keyCode, scanCode, modifiers); + Event event = new ScreenEvent.KeyPressed.Pre(guiScreen, keyCode, scanCode, modifiers); return MinecraftForge.EVENT_BUS.post(event); } public static boolean onScreenKeyPressedPost(Screen guiScreen, int keyCode, int scanCode, int modifiers) { - Event event = new ScreenEvent.KeyboardKeyPressedEvent.Post(guiScreen, keyCode, scanCode, modifiers); + Event event = new ScreenEvent.KeyPressed.Post(guiScreen, keyCode, scanCode, modifiers); return MinecraftForge.EVENT_BUS.post(event); } public static boolean onScreenKeyReleasedPre(Screen guiScreen, int keyCode, int scanCode, int modifiers) { - Event event = new ScreenEvent.KeyboardKeyReleasedEvent.Pre(guiScreen, keyCode, scanCode, modifiers); + Event event = new ScreenEvent.KeyReleased.Pre(guiScreen, keyCode, scanCode, modifiers); return MinecraftForge.EVENT_BUS.post(event); } public static boolean onScreenKeyReleasedPost(Screen guiScreen, int keyCode, int scanCode, int modifiers) { - Event event = new ScreenEvent.KeyboardKeyReleasedEvent.Post(guiScreen, keyCode, scanCode, modifiers); + Event event = new ScreenEvent.KeyReleased.Post(guiScreen, keyCode, scanCode, modifiers); return MinecraftForge.EVENT_BUS.post(event); } public static boolean onScreenCharTypedPre(Screen guiScreen, char codePoint, int modifiers) { - Event event = new ScreenEvent.KeyboardCharTypedEvent.Pre(guiScreen, codePoint, modifiers); + Event event = new ScreenEvent.CharacterTyped.Pre(guiScreen, codePoint, modifiers); return MinecraftForge.EVENT_BUS.post(event); } - public static boolean onScreenCharTypedPost(Screen guiScreen, char codePoint, int modifiers) + public static void onScreenCharTypedPost(Screen guiScreen, char codePoint, int modifiers) { - Event event = new ScreenEvent.KeyboardCharTypedEvent.Post(guiScreen, codePoint, modifiers); - return MinecraftForge.EVENT_BUS.post(event); + Event event = new ScreenEvent.CharacterTyped.Post(guiScreen, codePoint, modifiers); + MinecraftForge.EVENT_BUS.post(event); } public static void onRecipesUpdated(RecipeManager mgr) @@ -703,54 +695,34 @@ public static void onRecipesUpdated(RecipeManager mgr) MinecraftForge.EVENT_BUS.post(event); } - public static void fireMouseInput(int button, int action, int mods) + public static boolean onMouseButtonPre(int button, int action, int mods) { - MinecraftForge.EVENT_BUS.post(new InputEvent.MouseInputEvent(button, action, mods)); + return MinecraftForge.EVENT_BUS.post(new InputEvent.MouseButton.Pre(button, action, mods)); } - public static void fireKeyInput(int key, int scanCode, int action, int modifiers) + public static void onMouseButtonPost(int button, int action, int mods) { - MinecraftForge.EVENT_BUS.post(new InputEvent.KeyInputEvent(key, scanCode, action, modifiers)); + MinecraftForge.EVENT_BUS.post(new InputEvent.MouseButton.Post(button, action, mods)); } public static boolean onMouseScroll(MouseHandler mouseHelper, double scrollDelta) { - Event event = new InputEvent.MouseScrollEvent(scrollDelta, mouseHelper.isLeftPressed(), mouseHelper.isMiddlePressed(), mouseHelper.isRightPressed(), mouseHelper.xpos(), mouseHelper.ypos()); + Event event = new InputEvent.MouseScrollingEvent(scrollDelta, mouseHelper.isLeftPressed(), mouseHelper.isMiddlePressed(), mouseHelper.isRightPressed(), mouseHelper.xpos(), mouseHelper.ypos()); return MinecraftForge.EVENT_BUS.post(event); } - public static boolean onRawMouseClicked(int button, int action, int mods) + public static void onKeyInput(int key, int scanCode, int action, int modifiers) { - return MinecraftForge.EVENT_BUS.post(new InputEvent.RawMouseEvent(button, action, mods)); + MinecraftForge.EVENT_BUS.post(new InputEvent.Key(key, scanCode, action, modifiers)); } - public static InputEvent.ClickInputEvent onClickInput(int button, KeyMapping keyBinding, InteractionHand hand) + public static InputEvent.InteractionKeyMappingTriggered onClickInput(int button, KeyMapping keyBinding, InteractionHand hand) { - InputEvent.ClickInputEvent event = new InputEvent.ClickInputEvent(button, keyBinding, hand); + InputEvent.InteractionKeyMappingTriggered event = new InputEvent.InteractionKeyMappingTriggered(button, keyBinding, hand); MinecraftForge.EVENT_BUS.post(event); return event; } - public static void drawItemLayered(ItemRenderer renderer, BakedModel modelIn, ItemStack itemStackIn, PoseStack poseStack, - MultiBufferSource bufferSource, int packedLight, int packedOverlay, boolean fabulous) - { - for(com.mojang.datafixers.util.Pair layerModel : modelIn.getLayerModels(itemStackIn, fabulous)) - { - BakedModel layer = layerModel.getFirst(); - RenderType rendertype = layerModel.getSecond(); - net.minecraftforge.client.ForgeHooksClient.setRenderType(rendertype); // neded for compatibility with MultiLayerModels - VertexConsumer ivertexbuilder; - if (fabulous) - { - ivertexbuilder = ItemRenderer.getFoilBufferDirect(bufferSource, rendertype, true, itemStackIn.hasFoil()); - } else { - ivertexbuilder = ItemRenderer.getFoilBuffer(bufferSource, rendertype, true, itemStackIn.hasFoil()); - } - renderer.renderModelLists(layer, itemStackIn, packedLight, packedOverlay, poseStack, ivertexbuilder); - } - net.minecraftforge.client.ForgeHooksClient.setRenderType(null); - } - public static boolean isNameplateInRenderDistance(Entity entity, double squareDistance) { if (entity instanceof LivingEntity) { final AttributeInstance attribute = ((LivingEntity) entity).getAttribute(ForgeMod.NAMETAG_DISTANCE.get()); @@ -762,20 +734,17 @@ public static boolean isNameplateInRenderDistance(Entity entity, double squareDi } public static void renderPistonMovedBlocks(BlockPos pos, BlockState state, PoseStack stack, MultiBufferSource bufferSource, Level level, boolean checkSides, int packedOverlay, BlockRenderDispatcher blockRenderer) { - RenderType.chunkBufferLayers().stream() - .filter(t -> ItemBlockRenderTypes.canRenderInLayer(state, t)) - .forEach(rendertype -> - { - setRenderType(rendertype); - VertexConsumer ivertexbuilder = bufferSource.getBuffer(rendertype == RenderType.translucent() ? RenderType.translucentMovingBlock() : rendertype); - blockRenderer.getModelRenderer().tesselateBlock(level, blockRenderer.getBlockModel(state), state, pos, stack, ivertexbuilder, checkSides, RandomSource.create(), state.getSeed(pos), packedOverlay); - }); - setRenderType(null); + var model = blockRenderer.getBlockModel(state); + for (var renderType : model.getRenderTypes(state, RandomSource.create(state.getSeed(pos)), ModelData.EMPTY)) + { + VertexConsumer vertexConsumer = bufferSource.getBuffer(renderType == RenderType.translucent() ? RenderType.translucentMovingBlock() : renderType); + blockRenderer.getModelRenderer().tesselateBlock(level, model, state, pos, stack, vertexConsumer, checkSides, RandomSource.create(), state.getSeed(pos), packedOverlay, ModelData.EMPTY, renderType); + } } public static boolean shouldRenderEffect(MobEffectInstance effectInstance) { - return RenderProperties.getEffectRenderer(effectInstance).shouldRender(effectInstance); + return IClientMobEffectExtensions.of(effectInstance).isVisibleInInventory(effectInstance); } @Nullable @@ -868,27 +837,27 @@ public static void drawForgePingInfo(JoinMultiplayerScreen gui, ServerData targe String tooltip; if (target.forgeData == null) return; - switch (target.forgeData.type) { + switch (target.forgeData.type()) { case "FML": - if (target.forgeData.isCompatible) { + if (target.forgeData.isCompatible()) { idx = 0; - tooltip = ForgeI18n.parseMessage("fml.menu.multiplayer.compatible", target.forgeData.numberOfMods); + tooltip = ForgeI18n.parseMessage("fml.menu.multiplayer.compatible", target.forgeData.numberOfMods()); } else { idx = 16; - if(target.forgeData.extraReason != null) { - String extraReason = ForgeI18n.parseMessage(target.forgeData.extraReason); + if(target.forgeData.extraReason() != null) { + String extraReason = ForgeI18n.parseMessage(target.forgeData.extraReason()); tooltip = ForgeI18n.parseMessage("fml.menu.multiplayer.incompatible.extra", extraReason); } else { tooltip = ForgeI18n.parseMessage("fml.menu.multiplayer.incompatible"); } } - if (target.forgeData.truncated) + if (target.forgeData.truncated()) { tooltip += "\n" + ForgeI18n.parseMessage("fml.menu.multiplayer.truncated"); } break; case "VANILLA": - if (target.forgeData.isCompatible) { + if (target.forgeData.isCompatible()) { idx = 48; tooltip = ForgeI18n.parseMessage("fml.menu.multiplayer.vanilla"); } else { @@ -898,7 +867,7 @@ public static void drawForgePingInfo(JoinMultiplayerScreen gui, ServerData targe break; default: idx = 64; - tooltip = ForgeI18n.parseMessage("fml.menu.multiplayer.unknown", target.forgeData.type); + tooltip = ForgeI18n.parseMessage("fml.menu.multiplayer.unknown", target.forgeData.type()); } RenderSystem.setShaderTexture(0, ICON_SHEET); @@ -927,17 +896,42 @@ public static void handleClientLevelClosing(ClientLevel level) } public static void firePlayerLogin(MultiPlayerGameMode pc, LocalPlayer player, Connection networkManager) { - MinecraftForge.EVENT_BUS.post(new ClientPlayerNetworkEvent.LoggedInEvent(pc, player, networkManager)); + MinecraftForge.EVENT_BUS.post(new ClientPlayerNetworkEvent.LoggingIn(pc, player, networkManager)); } public static void firePlayerLogout(@Nullable MultiPlayerGameMode pc, @Nullable LocalPlayer player) { - MinecraftForge.EVENT_BUS.post(new ClientPlayerNetworkEvent.LoggedOutEvent(pc, player, player != null ? player.connection != null ? player.connection.getConnection() : null : null)); + MinecraftForge.EVENT_BUS.post(new ClientPlayerNetworkEvent.LoggingOut(pc, player, player != null ? player.connection != null ? player.connection.getConnection() : null : null)); } public static void firePlayerRespawn(MultiPlayerGameMode pc, LocalPlayer oldPlayer, LocalPlayer newPlayer, Connection networkManager) { - MinecraftForge.EVENT_BUS.post(new ClientPlayerNetworkEvent.RespawnEvent(pc, oldPlayer, newPlayer, networkManager)); + MinecraftForge.EVENT_BUS.post(new ClientPlayerNetworkEvent.Clone(pc, oldPlayer, newPlayer, networkManager)); + } + + public static void onRegisterParticleProviders(ParticleEngine particleEngine) { + ModLoader.get().postEvent(new RegisterParticleProvidersEvent(particleEngine)); + } + + public static void onRegisterKeyMappings(Options options) { + ModLoader.get().postEvent(new RegisterKeyMappingsEvent(options)); } + public static void onRegisterAdditionalModels(Set additionalModels) { + ModLoader.get().postEvent(new ModelEvent.RegisterAdditional(additionalModels)); + } + + @Nullable + public static Component onClientChat(ChatType type, Component message, ChatSender chatSender) + { + ClientChatReceivedEvent event = new ClientChatReceivedEvent(type, message, chatSender); + return MinecraftForge.EVENT_BUS.post(event) ? null : event.getMessage(); + } + + @NotNull + public static String onClientSendMessage(String message) + { + ClientChatEvent event = new ClientChatEvent(message); + return MinecraftForge.EVENT_BUS.post(event) ? "" : event.getMessage(); + } @Mod.EventBusSubscriber(value = Dist.CLIENT, modid="forge", bus= Mod.EventBusSubscriber.Bus.MOD) public static class ClientEvents @@ -965,7 +959,7 @@ public static Font getTooltipFont(@Nullable Font forcedFont, @NotNull ItemStack { return forcedFont; } - Font stackFont = RenderProperties.get(stack).getFont(stack); + Font stackFont = IClientItemExtensions.of(stack).getFont(stack, IClientItemExtensions.FontContext.TOOLTIP); return stackFont == null ? fallbackFont : stackFont; } @@ -1066,16 +1060,16 @@ public static Comparator makeParticleRenderTypeComparator(Li }; } - public static Event.Result onScreenPotionSize(Screen screen) + public static int onScreenPotionSize(Screen screen, int availableSpace, boolean compact) { - final ScreenEvent.PotionSizeEvent event = new ScreenEvent.PotionSizeEvent(screen); - MinecraftForge.EVENT_BUS.post(event); - return event.getResult(); + final ScreenEvent.RenderInventoryMobEffects event = new ScreenEvent.RenderInventoryMobEffects(screen, availableSpace, compact); + return MinecraftForge.EVENT_BUS.post(event) ? 0 : (event.isCompact() ? 1 : 2); } public static boolean isBlockInSolidLayer(BlockState state) { - return ItemBlockRenderTypes.canRenderInLayer(state, RenderType.solid()); + var model = Minecraft.getInstance().getBlockRenderer().getBlockModel(state); + return model.getRenderTypes(state, RandomSource.create(), ModelData.EMPTY).contains(RenderType.solid()); } public static void createWorldConfirmationScreen(Runnable doConfirmedWorldLoad) @@ -1102,17 +1096,17 @@ public static void createWorldConfirmationScreen(Runnable doConfirmedWorldLoad) public static boolean renderFireOverlay(Player player, PoseStack mat) { - return renderBlockOverlay(player, mat, RenderBlockOverlayEvent.OverlayType.FIRE, Blocks.FIRE.defaultBlockState(), player.blockPosition()); + return renderBlockOverlay(player, mat, RenderBlockScreenEffectEvent.OverlayType.FIRE, Blocks.FIRE.defaultBlockState(), player.blockPosition()); } public static boolean renderWaterOverlay(Player player, PoseStack mat) { - return renderBlockOverlay(player, mat, RenderBlockOverlayEvent.OverlayType.WATER, Blocks.WATER.defaultBlockState(), player.blockPosition()); + return renderBlockOverlay(player, mat, RenderBlockScreenEffectEvent.OverlayType.WATER, Blocks.WATER.defaultBlockState(), player.blockPosition()); } - public static boolean renderBlockOverlay(Player player, PoseStack mat, RenderBlockOverlayEvent.OverlayType type, BlockState block, BlockPos pos) + public static boolean renderBlockOverlay(Player player, PoseStack mat, RenderBlockScreenEffectEvent.OverlayType type, BlockState block, BlockPos pos) { - return MinecraftForge.EVENT_BUS.post(new RenderBlockOverlayEvent(player, mat, type, block, pos)); + return MinecraftForge.EVENT_BUS.post(new RenderBlockScreenEffectEvent(player, mat, type, block, pos)); } public static int getMaxMipmapLevel(int width, int height) diff --git a/src/main/java/net/minecraftforge/client/ICloudRenderHandler.java b/src/main/java/net/minecraftforge/client/ICloudRenderHandler.java deleted file mode 100644 index e0679d8131f..00000000000 --- a/src/main/java/net/minecraftforge/client/ICloudRenderHandler.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) Forge Development LLC and contributors - * SPDX-License-Identifier: LGPL-2.1-only - */ - -package net.minecraftforge.client; - -import com.mojang.blaze3d.vertex.PoseStack; -import net.minecraft.client.Minecraft; -import net.minecraft.client.multiplayer.ClientLevel; - -/** - * Call {@link net.minecraft.client.renderer.DimensionSpecialEffects#setCloudRenderHandler(ICloudRenderHandler)}, - * obtained from a {@link ClientLevel} with an implementation of this to override all cloud rendering with your own. - * This is only responsible for rendering clouds. - */ -@FunctionalInterface -public interface ICloudRenderHandler { - void render(int ticks, float partialTick, PoseStack poseStack, ClientLevel level, Minecraft minecraft, double camX, double camY, double camZ); -} diff --git a/src/main/java/net/minecraftforge/client/IItemRenderProperties.java b/src/main/java/net/minecraftforge/client/IItemRenderProperties.java deleted file mode 100644 index 19c1574876e..00000000000 --- a/src/main/java/net/minecraftforge/client/IItemRenderProperties.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright (c) Forge Development LLC and contributors - * SPDX-License-Identifier: LGPL-2.1-only - */ - -package net.minecraftforge.client; - -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.Font; -import net.minecraft.client.model.HumanoidModel; -import net.minecraft.client.model.Model; -import net.minecraft.client.renderer.BlockEntityWithoutLevelRenderer; -import net.minecraft.world.entity.EquipmentSlot; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.item.ItemStack; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -public interface IItemRenderProperties -{ - IItemRenderProperties DUMMY = new IItemRenderProperties() - { - }; - - /** - * Returns the font renderer used to render tooltips and overlays for this item. - * Returning null will use the standard font renderer. - * - * @param stack The current item stack - * @return A instance of FontRenderer or null to use default - */ - default Font getFont(ItemStack stack) - { - return null; - } - - /** - * Override this method to have an item handle its own armor rendering. - * - * @param entityLiving The entity wearing the armor - * @param itemStack The itemStack to render the model of - * @param armorSlot The slot the armor is in - * @param _default Original armor model. Will have attributes set. - * @return A HumanoidModel to render instead of the default, will have the relevant properties copied in {@link #getBaseArmorModel(LivingEntity, ItemStack, EquipmentSlot, HumanoidModel)}. - * Returning null will cause the default to render. - * @see #getBaseArmorModel(LivingEntity, ItemStack, EquipmentSlot, HumanoidModel) - */ - @Nullable - default HumanoidModel getArmorModel(LivingEntity entityLiving, ItemStack itemStack, EquipmentSlot armorSlot, HumanoidModel _default) - { - return null; - } - - /** - * Override this method to return a generic model rather than a {@link HumanoidModel}. More ideal for wrapping the original model or returning non-standard models like elytra wings. - * By default, this hook copies in the model properties from the default into the model returned by {@link #getArmorModel(LivingEntity, ItemStack, EquipmentSlot, HumanoidModel)}, - * so if you override this method you are responsible for copying properties you care about - * - * @param entityLiving The entity wearing the armor - * @param itemStack The itemStack to render the model of - * @param armorSlot The slot the armor is in - * @param _default Original armor model. Will have attributes set. - * @return A Model to render instead of the default - * @see #getArmorModel(LivingEntity, ItemStack, EquipmentSlot, HumanoidModel) - */ - @NotNull - default Model getBaseArmorModel(LivingEntity entityLiving, ItemStack itemStack, EquipmentSlot armorSlot, HumanoidModel _default) - { - HumanoidModel replacement = getArmorModel(entityLiving, itemStack, armorSlot, _default); - if (replacement != null && replacement != _default) - { - ForgeHooksClient.copyModelProperties(_default, replacement); - return replacement; - } - return _default; - } - - /** - * Called when the client starts rendering the HUD, for whatever item the player - * currently has as a helmet. This is where pumpkins would render there overlay. - * - * @param stack The ItemStack that is equipped - * @param player Reference to the current client entity - * @param width Viewport width - * @param height Viewport height - * @param partialTick Partial tick for the renderer, useful for interpolation - */ - default void renderHelmetOverlay(ItemStack stack, Player player, int width, int height, float partialTick) - { - - } - - /** - * @return This Item's renderer, or the default instance if it does not have - * one. - */ - default BlockEntityWithoutLevelRenderer getItemStackRenderer() - { - return Minecraft.getInstance().getItemRenderer().getBlockEntityRenderer(); - } -} diff --git a/src/main/java/net/minecraftforge/client/ISkyRenderHandler.java b/src/main/java/net/minecraftforge/client/ISkyRenderHandler.java deleted file mode 100644 index f793d580091..00000000000 --- a/src/main/java/net/minecraftforge/client/ISkyRenderHandler.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) Forge Development LLC and contributors - * SPDX-License-Identifier: LGPL-2.1-only - */ - -package net.minecraftforge.client; - -import com.mojang.blaze3d.vertex.PoseStack; -import net.minecraft.client.Minecraft; -import net.minecraft.client.multiplayer.ClientLevel; - -/** - * Call {@link net.minecraft.client.renderer.DimensionSpecialEffects#setSkyRenderHandler(ISkyRenderHandler)}, obtained - * from a {@link ClientLevel} with an implementation of this to override all sky rendering with your own. - * This includes the sun, moon, stars, and sky-coloring. - */ -@FunctionalInterface -public interface ISkyRenderHandler { - void render(int ticks, float partialTick, PoseStack poseStack, ClientLevel level, Minecraft minecraft); -} diff --git a/src/main/java/net/minecraftforge/client/IWeatherParticleRenderHandler.java b/src/main/java/net/minecraftforge/client/IWeatherParticleRenderHandler.java deleted file mode 100644 index f4cbab16f79..00000000000 --- a/src/main/java/net/minecraftforge/client/IWeatherParticleRenderHandler.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright (c) Forge Development LLC and contributors - * SPDX-License-Identifier: LGPL-2.1-only - */ - -package net.minecraftforge.client; - -import net.minecraft.client.Minecraft; -import net.minecraft.client.Camera; -import net.minecraft.client.multiplayer.ClientLevel; - -/** - * Call {@link net.minecraft.client.renderer.DimensionSpecialEffects#setWeatherParticleRenderHandler(IWeatherParticleRenderHandler)}, - * obtained from a {@link ClientLevel} with an implementation of this to override all weather particle rendering with your own. - * This handles ground particles that can be seen when it's raining (splash/smoke particles). - * This also includes playing rain sounds. - */ -@FunctionalInterface -public interface IWeatherParticleRenderHandler { - void render(int ticks, ClientLevel level, Minecraft minecraft, Camera camera); -} diff --git a/src/main/java/net/minecraftforge/client/IWeatherRenderHandler.java b/src/main/java/net/minecraftforge/client/IWeatherRenderHandler.java deleted file mode 100644 index 160a57891f0..00000000000 --- a/src/main/java/net/minecraftforge/client/IWeatherRenderHandler.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) Forge Development LLC and contributors - * SPDX-License-Identifier: LGPL-2.1-only - */ - -package net.minecraftforge.client; - -import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.LightTexture; -import net.minecraft.client.multiplayer.ClientLevel; - -/** - * Call {@link net.minecraft.client.renderer.DimensionSpecialEffects#setWeatherRenderHandler(IWeatherRenderHandler)}, - * obtained from a {@link ClientLevel} with an implementation of this to override all weather rendering with your own. - * This includes rain and snow. - */ -@FunctionalInterface -public interface IWeatherRenderHandler { - void render(int ticks, float partialTick, ClientLevel level, Minecraft minecraft, LightTexture lightTexture, double camX, double camY, double camZ); -} diff --git a/src/main/java/net/minecraftforge/client/MinecraftForgeClient.java b/src/main/java/net/minecraftforge/client/MinecraftForgeClient.java deleted file mode 100644 index b678540c50f..00000000000 --- a/src/main/java/net/minecraftforge/client/MinecraftForgeClient.java +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Copyright (c) Forge Development LLC and contributors - * SPDX-License-Identifier: LGPL-2.1-only - */ - -package net.minecraftforge.client; - -import java.io.IOException; -import java.util.BitSet; -import java.util.HashMap; -import java.util.Locale; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.function.Function; -import java.util.function.Supplier; - -import net.minecraft.client.gui.screens.inventory.tooltip.ClientTooltipComponent; -import net.minecraft.client.renderer.RenderType; -import net.minecraft.world.inventory.tooltip.TooltipComponent; - -import net.minecraft.client.Minecraft; -import com.mojang.blaze3d.platform.NativeImage; -import net.minecraft.server.packs.resources.Resource; -import net.minecraft.server.packs.resources.ResourceManager; -import net.minecraft.resources.ResourceLocation; -import net.minecraftforge.client.textures.ITextureAtlasSpriteLoader; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -public class MinecraftForgeClient -{ - public static RenderType getRenderType() - { - return ForgeHooksClient.renderType.get(); - } - - private static float partialTick; - - public static float getPartialTick() { - return partialTick; - } - - public static void setPartialTick(float partialTick) { - MinecraftForgeClient.partialTick = partialTick; - } - - /** - * returns the Locale set by the player in Minecraft. - * Useful for creating string and number formatters. - */ - public static Locale getLocale() - { - return Minecraft.getInstance().getLanguageManager().getSelected().getJavaLocale(); - } - - private static BitSet stencilBits = new BitSet(8); - static - { - stencilBits.set(0,8); - } - - /** - * Reserve a stencil bit for use in rendering - * - * Note: you must check the Framebuffer you are working with to - * determine if stencil bits are enabled on it before use. - * - * @return A bit or -1 if no further stencil bits are available - */ - public static int reserveStencilBit() - { - int bit = stencilBits.nextSetBit(0); - if (bit >= 0) - { - stencilBits.clear(bit); - } - return bit; - } - - /** - * Release the stencil bit for other use - * - * @param bit The bit from {@link #reserveStencilBit()} - */ - public static void releaseStencilBit(int bit) - { - if (bit >= 0 && bit < stencilBits.length()) - { - stencilBits.set(bit); - } - } - - private static HashMap> bufferedImageSuppliers = new HashMap>(); - public static void registerImageLayerSupplier(ResourceLocation resourceLocation, Supplier supplier) - { - bufferedImageSuppliers.put(resourceLocation, supplier); - } - - @NotNull - public static NativeImage getImageLayer(ResourceLocation resourceLocation, ResourceManager resourceManager) throws IOException - { - Supplier supplier = bufferedImageSuppliers.get(resourceLocation); - if (supplier != null) - return supplier.get(); - - Resource iresource1 = resourceManager.getResource(resourceLocation).orElseThrow(); - return NativeImage.read(iresource1.open()); - } - - private static final Map textureAtlasSpriteLoaders = new ConcurrentHashMap<>(); - - /** - * Register a custom ITextureAtlasSprite loader. Call this method during {@link net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent}. - */ - public static void registerTextureAtlasSpriteLoader(ResourceLocation name, ITextureAtlasSpriteLoader loader) - { - textureAtlasSpriteLoaders.put(name, loader); - } - - @Nullable - public static ITextureAtlasSpriteLoader getTextureAtlasSpriteLoader(ResourceLocation name) - { - return textureAtlasSpriteLoaders.get(name); - } - - private static final Map, Function> tooltipComponentFactories = new ConcurrentHashMap<>(); - - /** - * Register a factory for ClientTooltipComponents. - * @param cls the class for the component - * @param factory the factory for the ClientTooltipComponent - */ - @SuppressWarnings("unchecked") - public static void registerTooltipComponentFactory(Class cls, Function factory) - { - tooltipComponentFactories.put(cls, (Function) factory); - } - - @Nullable - public static ClientTooltipComponent getClientTooltipComponent(TooltipComponent component) - { - var factory = tooltipComponentFactories.get(component.getClass()); - return factory == null ? null : factory.apply(component); - } - -} diff --git a/src/main/java/net/minecraftforge/client/NamedRenderTypeManager.java b/src/main/java/net/minecraftforge/client/NamedRenderTypeManager.java new file mode 100644 index 00000000000..00e7b8d2d6f --- /dev/null +++ b/src/main/java/net/minecraftforge/client/NamedRenderTypeManager.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) Forge Development LLC and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.minecraftforge.client; + +import com.google.common.collect.ImmutableMap; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.resources.ResourceLocation; +import net.minecraftforge.client.event.RegisterNamedRenderTypesEvent; +import net.minecraftforge.fml.ModLoader; +import net.minecraftforge.fml.ModLoadingContext; +import org.jetbrains.annotations.ApiStatus; + +import java.util.HashMap; +import java.util.Map; + +/** + * Manager for named {@link RenderType render types}. + *

+ * Provides a lookup. + */ +public final class NamedRenderTypeManager +{ + private static ImmutableMap RENDER_TYPES; + + /** + * Finds the {@link RenderTypeGroup} for a given name, or the {@link RenderTypeGroup#EMPTY empty group} if not found. + */ + public static RenderTypeGroup get(ResourceLocation name) + { + return RENDER_TYPES.getOrDefault(name, RenderTypeGroup.EMPTY); + } + + @ApiStatus.Internal + public static void init() + { + var renderTypes = new HashMap(); + preRegisterVanillaRenderTypes(renderTypes); + var event = new RegisterNamedRenderTypesEvent(renderTypes); + ModLoader.get().postEventWithWrapInModOrder(event, (mc, e) -> ModLoadingContext.get().setActiveContainer(mc), (mc, e) -> ModLoadingContext.get().setActiveContainer(null)); + RENDER_TYPES = ImmutableMap.copyOf(renderTypes); + } + + /** + * Pre-registers vanilla render types. + */ + private static void preRegisterVanillaRenderTypes(Map blockRenderTypes) + { + blockRenderTypes.put(new ResourceLocation("solid"), new RenderTypeGroup(RenderType.solid(), ForgeRenderTypes.ITEM_LAYERED_SOLID.get())); + blockRenderTypes.put(new ResourceLocation("cutout"), new RenderTypeGroup(RenderType.cutout(), ForgeRenderTypes.ITEM_LAYERED_CUTOUT.get())); + blockRenderTypes.put(new ResourceLocation("cutout_mipped"), new RenderTypeGroup(RenderType.cutoutMipped(), ForgeRenderTypes.ITEM_LAYERED_CUTOUT_MIPPED.get())); + blockRenderTypes.put(new ResourceLocation("translucent"), new RenderTypeGroup(RenderType.translucent(), ForgeRenderTypes.ITEM_LAYERED_TRANSLUCENT.get())); + blockRenderTypes.put(new ResourceLocation("tripwire"), new RenderTypeGroup(RenderType.tripwire(), ForgeRenderTypes.ITEM_LAYERED_TRANSLUCENT.get())); + } + + private NamedRenderTypeManager() + { + } +} diff --git a/src/main/java/net/minecraftforge/client/RecipeBookManager.java b/src/main/java/net/minecraftforge/client/RecipeBookManager.java new file mode 100644 index 00000000000..f7da8d958c8 --- /dev/null +++ b/src/main/java/net/minecraftforge/client/RecipeBookManager.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) Forge Development LLC and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.minecraftforge.client; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import net.minecraft.client.RecipeBookCategories; +import net.minecraft.world.inventory.RecipeBookType; +import net.minecraft.world.item.crafting.Recipe; +import net.minecraft.world.item.crafting.RecipeType; +import net.minecraftforge.client.event.RegisterRecipeBookCategoriesEvent; +import net.minecraftforge.fml.ModLoader; +import net.minecraftforge.fml.ModLoadingContext; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.Nullable; + +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Function; + +import static net.minecraft.client.RecipeBookCategories.*; + +/** + * Manager for {@link RecipeBookType recipe book types} and {@link RecipeBookCategories categories}. + *

+ * Provides a recipe category lookup. + */ +public final class RecipeBookManager +{ + // Not using ConcurrentHashMap here because it's slower for lookups, so we only use it during init + private static final Map> AGGREGATE_CATEGORIES = new HashMap<>(); + private static final Map> TYPE_CATEGORIES = new HashMap<>(); + private static final Map, Function, RecipeBookCategories>> RECIPE_CATEGORY_LOOKUPS = new HashMap<>(); + private static final Map> AGGREGATE_CATEGORIES_VIEW = Collections.unmodifiableMap(AGGREGATE_CATEGORIES); + + /** + * Finds the category the specified recipe should display in, or null if none. + */ + @Nullable + public static > RecipeBookCategories findCategories(RecipeType type, T recipe) + { + var lookup = RECIPE_CATEGORY_LOOKUPS.get(type); + return lookup != null ? lookup.apply(recipe) : null; + } + + @ApiStatus.Internal + public static Map> getAggregateCategories() + { + return AGGREGATE_CATEGORIES_VIEW; + } + + @ApiStatus.Internal + public static List getCustomCategoriesOrEmpty(RecipeBookType recipeBookType) + { + return TYPE_CATEGORIES.getOrDefault(recipeBookType, List.of()); + } + + @ApiStatus.Internal + public static void init() + { + // The ImmutableMap is the patched out value of AGGREGATE_CATEGORIES + var aggregateCategories = new HashMap<>(ImmutableMap.of(CRAFTING_SEARCH, ImmutableList.of(CRAFTING_EQUIPMENT, CRAFTING_BUILDING_BLOCKS, CRAFTING_MISC, CRAFTING_REDSTONE), FURNACE_SEARCH, ImmutableList.of(FURNACE_FOOD, FURNACE_BLOCKS, FURNACE_MISC), BLAST_FURNACE_SEARCH, ImmutableList.of(BLAST_FURNACE_BLOCKS, BLAST_FURNACE_MISC), SMOKER_SEARCH, ImmutableList.of(SMOKER_FOOD))); + var typeCategories = new HashMap>(); + var recipeCategoryLookups = new HashMap, Function, RecipeBookCategories>>(); + var event = new RegisterRecipeBookCategoriesEvent(aggregateCategories, typeCategories, recipeCategoryLookups); + ModLoader.get().postEventWithWrapInModOrder(event, (mc, e) -> ModLoadingContext.get().setActiveContainer(mc), (mc, e) -> ModLoadingContext.get().setActiveContainer(null)); + AGGREGATE_CATEGORIES.putAll(aggregateCategories); + TYPE_CATEGORIES.putAll(typeCategories); + RECIPE_CATEGORY_LOOKUPS.putAll(recipeCategoryLookups); + } +} diff --git a/src/main/java/net/minecraftforge/client/RecipeBookRegistry.java b/src/main/java/net/minecraftforge/client/RecipeBookRegistry.java deleted file mode 100644 index a70a936f56f..00000000000 --- a/src/main/java/net/minecraftforge/client/RecipeBookRegistry.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (c) Forge Development LLC and contributors - * SPDX-License-Identifier: LGPL-2.1-only - */ - -package net.minecraftforge.client; - -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMap; -import net.minecraft.client.RecipeBookCategories; -import net.minecraft.world.inventory.RecipeBookType; -import net.minecraft.world.item.crafting.Recipe; -import net.minecraft.world.item.crafting.RecipeType; -import org.jetbrains.annotations.Nullable; - -import java.util.*; -import java.util.function.Function; - -import static net.minecraft.client.RecipeBookCategories.*; - -public class RecipeBookRegistry -{ - // The ImmutableMap is the patched out value of AGGREGATE_CATEGORIES - private static final Map> MUTABLE_AGGREGATE_CATEGORIES = new HashMap<>(ImmutableMap.of(CRAFTING_SEARCH, ImmutableList.of(CRAFTING_EQUIPMENT, CRAFTING_BUILDING_BLOCKS, CRAFTING_MISC, CRAFTING_REDSTONE), FURNACE_SEARCH, ImmutableList.of(FURNACE_FOOD, FURNACE_BLOCKS, FURNACE_MISC), BLAST_FURNACE_SEARCH, ImmutableList.of(BLAST_FURNACE_BLOCKS, BLAST_FURNACE_MISC), SMOKER_SEARCH, ImmutableList.of(SMOKER_FOOD))); - - private static final Map> TYPE_TO_CATEGORIES = new HashMap<>(); - private static final Map, Function, RecipeBookCategories>> FIND_CATEGORIES_FOR_TYPE = new HashMap<>(); - - //Unmodifiable view, the nested lists are immutable - public static final Map> AGGREGATE_CATEGORIES_VIEW = Collections.unmodifiableMap(MUTABLE_AGGREGATE_CATEGORIES); - public static final Map> TYPE_TO_CATEGORIES_VIEW = Collections.unmodifiableMap(TYPE_TO_CATEGORIES); - - public static void addCategoriesToType(RecipeBookType type, List categories) - { - TYPE_TO_CATEGORIES.put(type, categories instanceof ImmutableList ? categories : Collections.unmodifiableList(categories)); - } - - public static void addAggregateCategories(RecipeBookCategories search, List aggregate) - { - MUTABLE_AGGREGATE_CATEGORIES.put(search, aggregate instanceof ImmutableList ? aggregate : Collections.unmodifiableList(aggregate)); - } - - public static void addCategoriesFinder(RecipeType type, Function, RecipeBookCategories> finder) - { - FIND_CATEGORIES_FOR_TYPE.put(type, finder); - } - - @Nullable - public static RecipeBookCategories findCategories(RecipeType type, Recipe recipe) - { - return Optional.ofNullable(FIND_CATEGORIES_FOR_TYPE.get(type)).map(f -> f.apply(recipe)).orElse(null); - } -} diff --git a/src/main/java/net/minecraftforge/client/RenderProperties.java b/src/main/java/net/minecraftforge/client/RenderProperties.java deleted file mode 100644 index 05cea4a7324..00000000000 --- a/src/main/java/net/minecraftforge/client/RenderProperties.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (c) Forge Development LLC and contributors - * SPDX-License-Identifier: LGPL-2.1-only - */ - -package net.minecraftforge.client; - -import net.minecraft.world.effect.MobEffect; -import net.minecraft.world.effect.MobEffectInstance; -import net.minecraft.world.item.Item; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.material.Fluid; -import net.minecraft.world.level.material.FluidState; -import net.minecraftforge.fluids.FluidType; - -public class RenderProperties -{ - public static EffectRenderer getEffectRenderer(MobEffectInstance effectInstance) - { - return getEffectRenderer(effectInstance.getEffect()); - } - - public static EffectRenderer getEffectRenderer(MobEffect effect) - { - return effect.getEffectRendererInternal() instanceof EffectRenderer r ? r : EffectRenderer.DUMMY; - } - - public static IItemRenderProperties get(ItemStack stack) - { - return get(stack.getItem()); - } - - public static IItemRenderProperties get(Item item) - { - return item.getRenderPropertiesInternal() instanceof IItemRenderProperties props ? props : IItemRenderProperties.DUMMY; - } - - public static IBlockRenderProperties get(BlockState state) - { - return get(state.getBlock()); - } - - public static IBlockRenderProperties get(Block block) - { - return block.getRenderPropertiesInternal() instanceof IBlockRenderProperties props ? props : IBlockRenderProperties.DUMMY; - } - - public static IFluidTypeRenderProperties get(FluidState state) - { - return get(state.getFluidType()); - } - - public static IFluidTypeRenderProperties get(Fluid fluid) - { - return get(fluid.getFluidType()); - } - - public static IFluidTypeRenderProperties get(FluidType type) - { - return type.getRenderPropertiesInternal() instanceof IFluidTypeRenderProperties props ? props : IFluidTypeRenderProperties.DUMMY; - } - - private RenderProperties() - { - // Not instantiable. - } -} diff --git a/src/main/java/net/minecraftforge/client/RenderTypeGroup.java b/src/main/java/net/minecraftforge/client/RenderTypeGroup.java new file mode 100644 index 00000000000..4f5e10826a1 --- /dev/null +++ b/src/main/java/net/minecraftforge/client/RenderTypeGroup.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) Forge Development LLC and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.minecraftforge.client; + +import net.minecraft.client.renderer.RenderType; + +/** + * A set of functionally equivalent shaders. One using {@link com.mojang.blaze3d.vertex.DefaultVertexFormat#BLOCK}, + * and the other two using {@link com.mojang.blaze3d.vertex.DefaultVertexFormat#NEW_ENTITY}. + * {@code entityFabulous} may support custom render targets and other aspects of the fabulous pipeline, or can otherwise + * be the same as {@code entity}. + */ +public record RenderTypeGroup(RenderType block, RenderType entity, RenderType entityFabulous) +{ + public static RenderTypeGroup EMPTY = new RenderTypeGroup(null, null, null); + + public RenderTypeGroup + { + if ((block == null) != (entity == null) || (block == null) != (entityFabulous == null)) + throw new IllegalArgumentException("The render types in a group must either be all null, or all non-null."); + } + + public RenderTypeGroup(RenderType block, RenderType entity) + { + this(block, entity, entity); + } + + /** + * {@return true if this group has render types or not. It either has all, or none} + */ + public boolean isEmpty() + { + // We throw an exception in the constructor if nullability doesn't match, so checking this is enough + return block == null; + } +} diff --git a/src/main/java/net/minecraftforge/client/StencilManager.java b/src/main/java/net/minecraftforge/client/StencilManager.java new file mode 100644 index 00000000000..6807f6bdb4a --- /dev/null +++ b/src/main/java/net/minecraftforge/client/StencilManager.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) Forge Development LLC and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.minecraftforge.client; + +import java.util.BitSet; + +public final class StencilManager +{ + private static final BitSet BITS = new BitSet(8); + + /** + * Reserve a stencil bit for use in rendering + *

+ * Note: you must check the {@link com.mojang.blaze3d.pipeline.RenderTarget} you are working with to + * determine if stencil bits are enabled on it before use. + * + * @return A bit, or -1 if no further stencil bits are available + */ + public static int reserveBit() + { + int bit = BITS.nextClearBit(0); + if (bit >= 0) + BITS.set(bit); + return bit; + } + + /** + * Release the stencil bit for other use + * + * @param bit The bit obtained from {@link #reserveBit()} + */ + public static void releaseBit(int bit) + { + if (bit >= 0 && bit < BITS.length()) + BITS.clear(bit); + } + + private StencilManager() + { + } +} diff --git a/src/main/java/net/minecraftforge/client/event/ClientChatEvent.java b/src/main/java/net/minecraftforge/client/event/ClientChatEvent.java index c19d3b32811..1b5ac721c2f 100644 --- a/src/main/java/net/minecraftforge/client/event/ClientChatEvent.java +++ b/src/main/java/net/minecraftforge/client/event/ClientChatEvent.java @@ -7,19 +7,19 @@ import com.google.common.base.Strings; import net.minecraftforge.common.MinecraftForge; -import net.minecraftforge.event.ForgeEventFactory; import net.minecraftforge.eventbus.api.Cancelable; import net.minecraftforge.eventbus.api.Event; import net.minecraftforge.fml.LogicalSide; +import org.jetbrains.annotations.ApiStatus; /** * Fired when the client is about to send a chat message to the server. * *

This event is {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}. - * If the event is cancelled, the chat message or command will not be sent to the server.

+ * If the event is cancelled, the chat message or command will not be sent to the server.

* *

This event is fired on the {@linkplain MinecraftForge#EVENT_BUS main Forge event bus}, - * only on the {@linkplain LogicalSide#CLIENT logical client}.

+ * only on the {@linkplain LogicalSide#CLIENT logical client}.

**/ @Cancelable public class ClientChatEvent extends Event @@ -27,10 +27,7 @@ public class ClientChatEvent extends Event private String message; private final String originalMessage; - /** - * @hidden - * @see ForgeEventFactory#onClientSendMessage(String) - */ + @ApiStatus.Internal public ClientChatEvent(String message) { this.setMessage(message); diff --git a/src/main/java/net/minecraftforge/client/event/ClientChatReceivedEvent.java b/src/main/java/net/minecraftforge/client/event/ClientChatReceivedEvent.java index 9c033933feb..02888be61bc 100644 --- a/src/main/java/net/minecraftforge/client/event/ClientChatReceivedEvent.java +++ b/src/main/java/net/minecraftforge/client/event/ClientChatReceivedEvent.java @@ -5,25 +5,25 @@ package net.minecraftforge.client.event; -import net.minecraft.network.chat.ChatSender; import net.minecraft.Util; +import net.minecraft.network.chat.ChatSender; import net.minecraft.network.chat.ChatType; import net.minecraft.network.chat.Component; import net.minecraftforge.common.MinecraftForge; -import net.minecraftforge.event.ForgeEventFactory; import net.minecraftforge.eventbus.api.Cancelable; import net.minecraftforge.eventbus.api.Event; import net.minecraftforge.fml.LogicalSide; +import org.jetbrains.annotations.ApiStatus; /** * Fired when a chat message is received on the client. * This can be used for filtering and detecting messages with specific words or phrases, and suppressing them. * *

This event is {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}. - * If the event is cancelled, the message is not displayed in the chat message window.

+ * If the event is cancelled, the message is not displayed in the chat message window.

* *

This event is fired on the {@linkplain MinecraftForge#EVENT_BUS main Forge event bus}, - * only on the {@linkplain LogicalSide#CLIENT logical client}.

+ * only on the {@linkplain LogicalSide#CLIENT logical client}.

* * @see ChatType */ @@ -34,10 +34,7 @@ public class ClientChatReceivedEvent extends Event private final ChatType type; private final ChatSender chatSender; - /** - * @hidden - * @see ForgeEventFactory#onClientChat(ChatType, Component, ChatSender) - */ + @ApiStatus.Internal public ClientChatReceivedEvent(ChatType type, Component message, ChatSender chatSender) { this.type = type; diff --git a/src/main/java/net/minecraftforge/client/event/ClientPlayerChangeGameTypeEvent.java b/src/main/java/net/minecraftforge/client/event/ClientPlayerChangeGameTypeEvent.java index d286011f6cb..7c0e94b73cd 100644 --- a/src/main/java/net/minecraftforge/client/event/ClientPlayerChangeGameTypeEvent.java +++ b/src/main/java/net/minecraftforge/client/event/ClientPlayerChangeGameTypeEvent.java @@ -7,19 +7,19 @@ import net.minecraft.client.multiplayer.PlayerInfo; import net.minecraft.world.level.GameType; -import net.minecraftforge.client.ForgeHooksClient; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.eventbus.api.Cancelable; import net.minecraftforge.eventbus.api.Event; import net.minecraftforge.fml.LogicalSide; +import org.jetbrains.annotations.ApiStatus; /** * Fired when the client player is notified of a change of {@link GameType} from the server. * - *

This event is not {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}.

+ *

This event is not {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}.

* *

This event is fired on the {@linkplain MinecraftForge#EVENT_BUS main Forge event bus}, - * only on the {@linkplain LogicalSide#CLIENT logical client}.

+ * only on the {@linkplain LogicalSide#CLIENT logical client}.

*/ public class ClientPlayerChangeGameTypeEvent extends Event { @@ -27,10 +27,7 @@ public class ClientPlayerChangeGameTypeEvent extends Event private final GameType currentGameType; private final GameType newGameType; - /** - * @hidden - * @see ForgeHooksClient#onClientChangeGameType(PlayerInfo, GameType, GameType) - */ + @ApiStatus.Internal public ClientPlayerChangeGameTypeEvent(PlayerInfo info, GameType currentGameType, GameType newGameType) { this.info = info; diff --git a/src/main/java/net/minecraftforge/client/event/ClientPlayerNetworkEvent.java b/src/main/java/net/minecraftforge/client/event/ClientPlayerNetworkEvent.java index 2b83186b702..f19f9a4f33f 100644 --- a/src/main/java/net/minecraftforge/client/event/ClientPlayerNetworkEvent.java +++ b/src/main/java/net/minecraftforge/client/event/ClientPlayerNetworkEvent.java @@ -5,14 +5,14 @@ package net.minecraftforge.client.event; -import net.minecraft.client.player.LocalPlayer; import net.minecraft.client.multiplayer.MultiPlayerGameMode; +import net.minecraft.client.player.LocalPlayer; import net.minecraft.network.Connection; -import net.minecraftforge.client.ForgeHooksClient; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.eventbus.api.Cancelable; import net.minecraftforge.eventbus.api.Event; import net.minecraftforge.fml.LogicalSide; +import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; /** @@ -20,62 +20,63 @@ * See the various subclasses to listen for specific events. * *

These events are fired on the {@linkplain MinecraftForge#EVENT_BUS main Forge event bus}, - * only on the {@linkplain LogicalSide#CLIENT logical client}.

+ * only on the {@linkplain LogicalSide#CLIENT logical client}.

* - * @see ClientPlayerNetworkEvent.LoggedInEvent - * @see ClientPlayerNetworkEvent.LoggedOutEvent - * @see ClientPlayerNetworkEvent.RespawnEvent + * @see LoggingIn + * @see LoggingOut + * @see Clone **/ -public class ClientPlayerNetworkEvent extends Event { +public abstract class ClientPlayerNetworkEvent extends Event +{ private final MultiPlayerGameMode multiPlayerGameMode; private final LocalPlayer player; private final Connection connection; + @ApiStatus.Internal + protected ClientPlayerNetworkEvent(final MultiPlayerGameMode multiPlayerGameMode, final LocalPlayer player, final Connection connection) + { + this.multiPlayerGameMode = multiPlayerGameMode; + this.player = player; + this.connection = connection; + } + /** * {@return the multiplayer game mode controller for the player} */ - public MultiPlayerGameMode getMultiPlayerGameMode() { + public MultiPlayerGameMode getMultiPlayerGameMode() + { return multiPlayerGameMode; } /** * {@return the player instance} */ - public LocalPlayer getPlayer() { + public LocalPlayer getPlayer() + { return player; } /** * {@return the network connection for the player} */ - public Connection getConnection() { + public Connection getConnection() + { return connection; } - /** - * @hidden - */ - ClientPlayerNetworkEvent(final MultiPlayerGameMode multiPlayerGameMode, final LocalPlayer player, final Connection connection) { - this.multiPlayerGameMode = multiPlayerGameMode; - this.player = player; - this.connection = connection; - } - /** * Fired when the client player logs in to the server. The player should be initialized. * - *

This event is not {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}.

+ *

This event is not {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}.

* *

This event is fired on the {@linkplain MinecraftForge#EVENT_BUS main Forge event bus}, - * only on the {@linkplain LogicalSide#CLIENT logical client}.

+ * only on the {@linkplain LogicalSide#CLIENT logical client}.

*/ - public static class LoggedInEvent extends ClientPlayerNetworkEvent { - - /** - * @hidden - * @see ForgeHooksClient#firePlayerLogin(MultiPlayerGameMode, LocalPlayer, Connection) - */ - public LoggedInEvent(final MultiPlayerGameMode controller, final LocalPlayer player, final Connection networkManager) { + public static class LoggingIn extends ClientPlayerNetworkEvent + { + @ApiStatus.Internal + public LoggingIn(final MultiPlayerGameMode controller, final LocalPlayer player, final Connection networkManager) + { super(controller, player, networkManager); } } @@ -83,19 +84,18 @@ public LoggedInEvent(final MultiPlayerGameMode controller, final LocalPlayer pla /** * Fired when the client player logs out. This event may also fire when a new integrated server is being created. * - *

This event is not {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}.

+ *

This event is not {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}.

* *

This event is fired on the {@linkplain MinecraftForge#EVENT_BUS main Forge event bus}, - * only on the {@linkplain LogicalSide#CLIENT logical client}.

+ * only on the {@linkplain LogicalSide#CLIENT logical client}.

*/ - @SuppressWarnings("NullableProblems") // Shush IntelliJ, we override non-nullables as nullables in this specific event; see later comment - public static class LoggedOutEvent extends ClientPlayerNetworkEvent { - - /** - * @hidden - * @see ForgeHooksClient#firePlayerLogout(MultiPlayerGameMode, LocalPlayer) - */ - public LoggedOutEvent(@Nullable final MultiPlayerGameMode controller, @Nullable final LocalPlayer player, @Nullable final Connection networkManager) { + @SuppressWarnings("NullableProblems") + // Shush IntelliJ, we override non-nullables as nullables in this specific event; see later comment + public static class LoggingOut extends ClientPlayerNetworkEvent + { + @ApiStatus.Internal + public LoggingOut(@Nullable final MultiPlayerGameMode controller, @Nullable final LocalPlayer player, @Nullable final Connection networkManager) + { //noinspection ConstantConditions we know these are nullable, but we don't want to annotate the super as nullable since this is the only event with nullables super(controller, player, networkManager); } @@ -140,19 +140,18 @@ public Connection getConnection() /** * Fired when the client player respawns, creating a new player instance to replace the old player instance. * - *

This event is not {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}.

+ *

This event is not {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}.

* *

This event is fired on the {@linkplain MinecraftForge#EVENT_BUS main Forge event bus}, - * only on the {@linkplain LogicalSide#CLIENT logical client}.

+ * only on the {@linkplain LogicalSide#CLIENT logical client}.

*/ - public static class RespawnEvent extends ClientPlayerNetworkEvent { + public static class Clone extends ClientPlayerNetworkEvent + { private final LocalPlayer oldPlayer; - /** - * @hidden - * @see ForgeHooksClient#firePlayerRespawn(MultiPlayerGameMode, LocalPlayer, LocalPlayer, Connection) - */ - public RespawnEvent(final MultiPlayerGameMode pc, final LocalPlayer oldPlayer, final LocalPlayer newPlayer, final Connection networkManager) { + @ApiStatus.Internal + public Clone(final MultiPlayerGameMode pc, final LocalPlayer oldPlayer, final LocalPlayer newPlayer, final Connection networkManager) + { super(pc, newPlayer, networkManager); this.oldPlayer = oldPlayer; } @@ -160,23 +159,27 @@ public RespawnEvent(final MultiPlayerGameMode pc, final LocalPlayer oldPlayer, f /** * {@return the previous player instance} */ - public LocalPlayer getOldPlayer() { + public LocalPlayer getOldPlayer() + { return oldPlayer; } /** * {@return the newly created player instance} */ - public LocalPlayer getNewPlayer() { + public LocalPlayer getNewPlayer() + { return super.getPlayer(); } /** * {@return the newly created player instance} + * * @see #getNewPlayer() */ @Override - public LocalPlayer getPlayer() { + public LocalPlayer getPlayer() + { return super.getPlayer(); } } diff --git a/src/main/java/net/minecraftforge/client/event/FOVModifierEvent.java b/src/main/java/net/minecraftforge/client/event/ComputeFovModifierEvent.java similarity index 57% rename from src/main/java/net/minecraftforge/client/event/FOVModifierEvent.java rename to src/main/java/net/minecraftforge/client/event/ComputeFovModifierEvent.java index 2e3c1bba3b9..396ab736187 100644 --- a/src/main/java/net/minecraftforge/client/event/FOVModifierEvent.java +++ b/src/main/java/net/minecraftforge/client/event/ComputeFovModifierEvent.java @@ -6,40 +6,36 @@ package net.minecraftforge.client.event; import net.minecraft.client.Minecraft; -import net.minecraft.world.entity.player.Player; import net.minecraft.util.Mth; -import net.minecraftforge.client.ForgeHooksClient; +import net.minecraft.world.entity.player.Player; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.eventbus.api.Cancelable; import net.minecraftforge.eventbus.api.Event; import net.minecraftforge.fml.LogicalSide; +import org.jetbrains.annotations.ApiStatus; /** - * Fired after the field of vision (FOV) modifier for the player is calculated. - * This can be used to modify the FOV before the FOV settings are applied. + * Fired after the field of vision (FOV) modifier for the player is calculated to allow developers to adjust it further. * - *

This event is not {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}.

+ *

This event is not {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}.

* *

This event is fired on the {@linkplain MinecraftForge#EVENT_BUS main Forge event bus}, - * only on the {@linkplain LogicalSide#CLIENT logical client}.

+ * only on the {@linkplain LogicalSide#CLIENT logical client}.

* - * @see EntityViewRenderEvent.FieldOfView + * @see ViewportEvent.ComputeFov */ -public class FOVModifierEvent extends Event +public class ComputeFovModifierEvent extends Event { private final Player player; - private final float fov; - private float newFov; + private final float fovModifier; + private float newFovModifier; - /** - * @hidden - * @see ForgeHooksClient#getFieldOfView(Player, float) - */ - public FOVModifierEvent(Player player, float fov) + @ApiStatus.Internal + public ComputeFovModifierEvent(Player player, float fovModifier) { this.player = player; - this.fov = fov; - this.setNewFov((float) Mth.lerp(Minecraft.getInstance().options.fovEffectScale().get(), 1.0F, fov)); + this.fovModifier = fovModifier; + this.setNewFovModifier((float) Mth.lerp(Minecraft.getInstance().options.fovEffectScale().get(), 1.0F, fovModifier)); } /** @@ -53,26 +49,26 @@ public Player getPlayer() /** * {@return the original field of vision (FOV) of the player, before any modifications or interpolation} */ - public float getFov() + public float getFovModifier() { - return fov; + return fovModifier; } /** * {@return the current field of vision (FOV) of the player} */ - public float getNewFov() + public float getNewFovModifier() { - return newFov; + return newFovModifier; } /** * Sets the new field of vision (FOV) of the player. * - * @param newFov the new field of vision (FOV) + * @param newFovModifier the new field of vision (FOV) */ - public void setNewFov(float newFov) + public void setNewFovModifier(float newFovModifier) { - this.newFov = newFov; + this.newFovModifier = newFovModifier; } } diff --git a/src/main/java/net/minecraftforge/client/event/ContainerScreenEvent.java b/src/main/java/net/minecraftforge/client/event/ContainerScreenEvent.java index e1a5b7f1221..e0f3d092056 100644 --- a/src/main/java/net/minecraftforge/client/event/ContainerScreenEvent.java +++ b/src/main/java/net/minecraftforge/client/event/ContainerScreenEvent.java @@ -11,26 +11,24 @@ import net.minecraftforge.eventbus.api.Cancelable; import net.minecraftforge.eventbus.api.Event; import net.minecraftforge.fml.LogicalSide; +import org.jetbrains.annotations.ApiStatus; /** - * Fired for hooking into {@link AbstractContainerScreen} rendering. - * See the two subclasses to listen for foreground or background rendering. + * Fired for hooking into {@link AbstractContainerScreen} events. + * See the subclasses to listen for specific events. * *

These events are fired on the {@linkplain MinecraftForge#EVENT_BUS main Forge event bus}, - * only on the {@linkplain LogicalSide#CLIENT logical client}.

+ * only on the {@linkplain LogicalSide#CLIENT logical client}.

* - * @see ContainerScreenEvent.DrawForeground - * @see ContainerScreenEvent.DrawBackground + * @see Render.Foreground + * @see Render.Background */ -public class ContainerScreenEvent extends Event +public abstract class ContainerScreenEvent extends Event { - private final AbstractContainerScreen containerScreen; - /** - * @hidden - */ - public ContainerScreenEvent(AbstractContainerScreen containerScreen) + @ApiStatus.Internal + protected ContainerScreenEvent(AbstractContainerScreen containerScreen) { this.containerScreen = containerScreen; } @@ -44,27 +42,23 @@ public AbstractContainerScreen getContainerScreen() } /** - * Fired after the container screen's foreground layer and elements are drawn, but - * before rendering the tooltips and the item stack being dragged by the player. + * Fired every time an {@link AbstractContainerScreen} renders. + * See the two subclasses to listen for foreground or background rendering. * - *

This can be used for rendering elements that must be above other screen elements, but - * below tooltips and the dragged stack, such as slot or item stack specific overlays.

+ *

These events are fired on the {@linkplain MinecraftForge#EVENT_BUS main Forge event bus}, + * only on the {@linkplain LogicalSide#CLIENT logical client}.

* - *

This event is not {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}.

- * - *

This event is fired on the {@linkplain MinecraftForge#EVENT_BUS main Forge event bus}, - * only on the {@linkplain LogicalSide#CLIENT logical client}.

+ * @see Foreground + * @see Background */ - public static class DrawForeground extends ContainerScreenEvent + public static abstract class Render extends ContainerScreenEvent { private final PoseStack poseStack; private final int mouseX; private final int mouseY; - /** - * @hidden - */ - public DrawForeground(AbstractContainerScreen guiContainer, PoseStack poseStack, int mouseX, int mouseY) + @ApiStatus.Internal + protected Render(AbstractContainerScreen guiContainer, PoseStack poseStack, int mouseX, int mouseY) { super(guiContainer); this.poseStack = poseStack; @@ -95,56 +89,44 @@ public int getMouseY() { return mouseY; } - } - - /** - * Fired after the container screen's background layer and elements are drawn. - * This can be used for rendering new background elements. - * - *

This event is not {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}.

- * - *

This event is fired on the {@linkplain MinecraftForge#EVENT_BUS main Forge event bus}, - * only on the {@linkplain LogicalSide#CLIENT logical client}.

- */ - public static class DrawBackground extends ContainerScreenEvent - { - private final PoseStack poseStack; - private final int mouseX; - private final int mouseY; /** - * @hidden + * Fired after the container screen's foreground layer and elements are drawn, but + * before rendering the tooltips and the item stack being dragged by the player. + * + *

This can be used for rendering elements that must be above other screen elements, but + * below tooltips and the dragged stack, such as slot or item stack specific overlays.

+ * + *

This event is not {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}.

+ * + *

This event is fired on the {@linkplain MinecraftForge#EVENT_BUS main Forge event bus}, + * only on the {@linkplain LogicalSide#CLIENT logical client}.

*/ - public DrawBackground(AbstractContainerScreen guiContainer, PoseStack poseStack, int mouseX, int mouseY) + public static class Foreground extends Render { - super(guiContainer); - this.poseStack = poseStack; - this.mouseX = mouseX; - this.mouseY = mouseY; + @ApiStatus.Internal + public Foreground(AbstractContainerScreen guiContainer, PoseStack poseStack, int mouseX, int mouseY) + { + super(guiContainer, poseStack, mouseX, mouseY); + } } /** - * {@return the pose stack used for rendering} - */ - public PoseStack getPoseStack() - { - return poseStack; - } - - /** - * {@return the X coordinate of the mouse pointer} + * Fired after the container screen's background layer and elements are drawn. + * This can be used for rendering new background elements. + * + *

This event is not {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}.

+ * + *

This event is fired on the {@linkplain MinecraftForge#EVENT_BUS main Forge event bus}, + * only on the {@linkplain LogicalSide#CLIENT logical client}.

*/ - public int getMouseX() + public static class Background extends Render { - return mouseX; - } - - /** - * {@return the Y coordinate of the mouse pointer} - */ - public int getMouseY() - { - return mouseY; + @ApiStatus.Internal + public Background(AbstractContainerScreen guiContainer, PoseStack poseStack, int mouseX, int mouseY) + { + super(guiContainer, poseStack, mouseX, mouseY); + } } } } diff --git a/src/main/java/net/minecraftforge/client/event/CustomizeGuiOverlayEvent.java b/src/main/java/net/minecraftforge/client/event/CustomizeGuiOverlayEvent.java new file mode 100644 index 00000000000..9056325acfb --- /dev/null +++ b/src/main/java/net/minecraftforge/client/event/CustomizeGuiOverlayEvent.java @@ -0,0 +1,219 @@ +/* + * Copyright (c) Forge Development LLC and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.minecraftforge.client.event; + +import com.mojang.blaze3d.platform.Window; +import com.mojang.blaze3d.vertex.PoseStack; +import net.minecraft.client.gui.components.LerpingBossEvent; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.eventbus.api.Cancelable; +import net.minecraftforge.eventbus.api.Event; +import net.minecraftforge.fml.LogicalSide; +import org.jetbrains.annotations.ApiStatus; + +import java.util.ArrayList; + +/** + * Fired when an overlay is about to be rendered to the screen to allow the user to modify it. + * + * @see BossEventProgress + * @see DebugText + * @see Chat + */ +public abstract class CustomizeGuiOverlayEvent extends Event +{ + private final Window window; + private final PoseStack poseStack; + private final float partialTick; + + @ApiStatus.Internal + protected CustomizeGuiOverlayEvent(Window window, PoseStack poseStack, float partialTick) + { + this.window = window; + this.poseStack = poseStack; + this.partialTick = partialTick; + } + + public Window getWindow() + { + return window; + } + + public PoseStack getPoseStack() + { + return poseStack; + } + + public float getPartialTick() + { + return partialTick; + } + + /** + * Fired before a boss health bar is rendered to the screen. + * + *

This event is not {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}. + * + *

This event is fired on the {@linkplain MinecraftForge#EVENT_BUS main Forge event bus}, + * only on the {@linkplain LogicalSide#CLIENT logical client}.

+ */ + public static class BossEventProgress extends CustomizeGuiOverlayEvent + { + private final LerpingBossEvent bossEvent; + private final int x; + private final int y; + private int increment; + + @ApiStatus.Internal + public BossEventProgress(Window window, PoseStack poseStack, float partialTick, LerpingBossEvent bossEvent, int x, int y, int increment) + { + super(window, poseStack, partialTick); + this.bossEvent = bossEvent; + this.x = x; + this.y = y; + this.increment = increment; + } + + /** + * @return the boss health bar currently being rendered + */ + public LerpingBossEvent getBossEvent() + { + return bossEvent; + } + + /** + * {@return the X position of the boss health bar} + */ + public int getX() + { + return x; + } + + /** + * {@return the Y position of the boss health bar} + */ + public int getY() + { + return y; + } + + /** + * {@return the Y position increment before rendering the next boss health bar} + */ + public int getIncrement() + { + return increment; + } + + /** + * Sets the Y position increment before rendering the next boss health bar. + * + * @param increment the new Y position increment + */ + public void setIncrement(int increment) + { + this.increment = increment; + } + } + + /** + * Fired before textual information is rendered to the debug screen. + * This can be used to add or remove text information. + * + *

This event is not {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}. + * + *

This event is fired on the {@linkplain MinecraftForge#EVENT_BUS main Forge event bus}, + * only on the {@linkplain LogicalSide#CLIENT logical client}.

+ */ + public static class DebugText extends CustomizeGuiOverlayEvent + { + private final ArrayList left; + private final ArrayList right; + + @ApiStatus.Internal + public DebugText(Window window, PoseStack poseStack, float partialTick, ArrayList left, ArrayList right) + { + super(window, poseStack, partialTick); + this.left = left; + this.right = right; + } + + /** + * @return the modifiable list of text to render on the left side + */ + public ArrayList getLeft() + { + return left; + } + + /** + * @return the modifiable list of text to render on the right side + */ + public ArrayList getRight() + { + return right; + } + } + + /** + * Fired before the chat messages overlay is rendered to the screen. + * + *

This event is not {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}. + * + *

This event is fired on the {@linkplain MinecraftForge#EVENT_BUS main Forge event bus}, + * only on the {@linkplain LogicalSide#CLIENT logical client}.

+ */ + public static class Chat extends CustomizeGuiOverlayEvent + { + private int posX; + private int posY; + + @ApiStatus.Internal + public Chat(Window window, PoseStack poseStack, float partialTick, int posX, int posY) + { + super(window, poseStack, partialTick); + this.setPosX(posX); + this.setPosY(posY); + } + + /** + * @return the X position of the chat messages overlay + */ + public int getPosX() + { + return posX; + } + + /** + * Sets the new X position for rendering the chat messages overlay + * + * @param posX the new X position + */ + public void setPosX(int posX) + { + this.posX = posX; + } + + /** + * @return the Y position of the chat messages overlay + */ + public int getPosY() + { + return posY; + } + + /** + * Sets the new Y position for rendering the chat messages overlay + * + * @param posY the new y position + */ + public void setPosY(int posY) + { + this.posY = posY; + } + } +} diff --git a/src/main/java/net/minecraftforge/client/event/EntityRenderersEvent.java b/src/main/java/net/minecraftforge/client/event/EntityRenderersEvent.java index 0cce80ffe54..4a1d74dbff0 100644 --- a/src/main/java/net/minecraftforge/client/event/EntityRenderersEvent.java +++ b/src/main/java/net/minecraftforge/client/event/EntityRenderersEvent.java @@ -35,6 +35,7 @@ import net.minecraftforge.fml.LogicalSide; import net.minecraftforge.fml.event.IModBusEvent; import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; +import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; import java.util.Map; @@ -46,34 +47,30 @@ * See the various subclasses for listening to different events. * *

These events are fired on the {@linkplain FMLJavaModLoadingContext#getModEventBus() mod-specific event bus}, - * only on the {@linkplain LogicalSide#CLIENT logical client}.

+ * only on the {@linkplain LogicalSide#CLIENT logical client}.

* * @see EntityRenderersEvent.RegisterLayerDefinitions * @see EntityRenderersEvent.RegisterRenderers * @see EntityRenderersEvent.AddLayers */ -public class EntityRenderersEvent extends Event implements IModBusEvent +public abstract class EntityRenderersEvent extends Event implements IModBusEvent { - /** - * @hidden - */ - public EntityRenderersEvent() + @ApiStatus.Internal + protected EntityRenderersEvent() { } /** * Fired for registering layer definitions at the appropriate time. * - *

This event is not {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}.

+ *

This event is not {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}.

* *

This event is fired on the {@linkplain FMLJavaModLoadingContext#getModEventBus() mod-specific event bus}, - * only on the {@linkplain LogicalSide#CLIENT logical client}.

+ * only on the {@linkplain LogicalSide#CLIENT logical client}.

*/ public static class RegisterLayerDefinitions extends EntityRenderersEvent { - /** - * @hidden - */ + @ApiStatus.Internal public RegisterLayerDefinitions() { } @@ -98,16 +95,14 @@ public void registerLayerDefinition(ModelLayerLocation layerLocation, SupplierThis event is not {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}.

+ *

This event is not {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}.

* *

This event is fired on the {@linkplain FMLJavaModLoadingContext#getModEventBus() mod-specific event bus}, - * only on the {@linkplain LogicalSide#CLIENT logical client}.

+ * only on the {@linkplain LogicalSide#CLIENT logical client}.

*/ public static class RegisterRenderers extends EntityRenderersEvent { - /** - * @hidden - */ + @ApiStatus.Internal public RegisterRenderers() { } @@ -139,10 +134,10 @@ public void registerBlockEntityRenderer(BlockEntityType< * Fired for registering entity renderer layers at the appropriate time, after the entity and player renderers maps * have been created. * - *

This event is not {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}.

+ *

This event is not {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}.

* *

This event is fired on the {@linkplain FMLJavaModLoadingContext#getModEventBus() mod-specific event bus}, - * only on the {@linkplain LogicalSide#CLIENT logical client}.

+ * only on the {@linkplain LogicalSide#CLIENT logical client}.

*/ public static class AddLayers extends EntityRenderersEvent { @@ -150,9 +145,7 @@ public static class AddLayers extends EntityRenderersEvent private final Map> skinMap; private final EntityModelSet entityModels = Minecraft.getInstance().getEntityModels(); - /** - * @hidden - */ + @ApiStatus.Internal public AddLayers(Map, EntityRenderer> renderers, Map> playerRenderers) { this.renderers = renderers; @@ -161,7 +154,7 @@ public AddLayers(Map, EntityRenderer> renderers, Map * Minecraft provides two default skin names: {@code default} for the * {@linkplain ModelLayers#PLAYER regular player model} and {@code slim} for the * {@linkplain ModelLayers#PLAYER_SLIM slim player model}. @@ -196,7 +189,8 @@ public Set getSkins() */ @Nullable @SuppressWarnings("unchecked") - public >> R getRenderer(EntityType entityType) { + public >> R getRenderer(EntityType entityType) + { return (R) renderers.get(entityType); } @@ -212,16 +206,17 @@ public EntityModelSet getEntityModels() /** * Fired for registering additional {@linkplain net.minecraft.client.model.SkullModelBase skull models} at the appropriate time. * - *

This event is not {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}.

+ *

This event is not {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}.

* *

This event is fired on the {@linkplain FMLJavaModLoadingContext#getModEventBus() mod-specific event bus}, - * only on the {@linkplain LogicalSide#CLIENT logical client}.

+ * only on the {@linkplain LogicalSide#CLIENT logical client}.

*/ public static class CreateSkullModels extends EntityRenderersEvent { private final ImmutableMap.Builder builder; private final EntityModelSet entityModelSet; + @ApiStatus.Internal public CreateSkullModels(ImmutableMap.Builder builder, EntityModelSet entityModelSet) { this.builder = builder; diff --git a/src/main/java/net/minecraftforge/client/event/InputEvent.java b/src/main/java/net/minecraftforge/client/event/InputEvent.java index 6a7e7efbdea..f07c7fa468f 100644 --- a/src/main/java/net/minecraftforge/client/event/InputEvent.java +++ b/src/main/java/net/minecraftforge/client/event/InputEvent.java @@ -7,50 +7,48 @@ import com.mojang.blaze3d.platform.InputConstants; import net.minecraft.client.KeyMapping; -import net.minecraft.client.MouseHandler; import net.minecraft.world.InteractionHand; -import net.minecraftforge.client.ForgeHooksClient; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.eventbus.api.Cancelable; import net.minecraftforge.eventbus.api.Event; import net.minecraftforge.fml.LogicalSide; +import org.jetbrains.annotations.ApiStatus; import org.lwjgl.glfw.GLFW; /** * Fired when an input is detected from the user's input devices. * See the various subclasses to listen for specific devices and inputs. * - * @see InputEvent.RawMouseEvent - * @see InputEvent.MouseInputEvent - * @see InputEvent.MouseScrollEvent - * @see InputEvent.KeyInputEvent - * @see InputEvent.ClickInputEvent + * @see InputEvent.MouseButton + * @see MouseScrollingEvent + * @see Key + * @see InteractionKeyMappingTriggered */ -public class InputEvent extends Event +public abstract class InputEvent extends Event { + @ApiStatus.Internal + protected InputEvent() + { + } + /** - * Fired when a mouse button is clicked, before being processed by vanilla. + * Fired when a mouse button is pressed/released. Sub-events get fired {@link Pre before} and {@link Post after} this happens. * - *

This event is {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}. - * If the event is cancelled, then the mouse event will not be processed by vanilla (e.g. keymappings and screens)

- * - *

This event is fired on the {@linkplain MinecraftForge#EVENT_BUS main Forge event bus}, - * only on the {@linkplain LogicalSide#CLIENT logical client}.

+ *

These events are fired on the {@linkplain MinecraftForge#EVENT_BUS main Forge event bus}, + * only on the {@linkplain LogicalSide#CLIENT logical client}.

* * @see the online GLFW documentation + * @see Pre + * @see Post */ - @Cancelable - public static class RawMouseEvent extends InputEvent + public static abstract class MouseButton extends InputEvent { private final int button; private final int action; private final int modifiers; - /** - * @hidden - * @see ForgeHooksClient#onRawMouseClicked(int, int, int) - */ - public RawMouseEvent(int button, int action, int modifiers) + @ApiStatus.Internal + protected MouseButton(int button, int action, int modifiers) { this.button = button; this.action = action; @@ -60,8 +58,7 @@ public RawMouseEvent(int button, int action, int modifiers) /** * {@return the mouse button's input code} * - * @see InputConstants input constants starting with {@code MOUSE_BUTTON_} - * @see GLFW mouse constants starting with {@code GLFW_MOUSE_BUTTON_} + * @see GLFW mouse constants starting with 'GLFW_MOUSE_BUTTON_' * @see the online GLFW documentation */ public int getButton() @@ -95,71 +92,45 @@ public int getModifiers() { return this.modifiers; } - } - - /** - * Fired when a mouse button is clicked, after processing. - * - *

This event is not {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}.

- * - *

This event is fired on the {@linkplain MinecraftForge#EVENT_BUS main Forge event bus}, - * only on the {@linkplain LogicalSide#CLIENT logical client}.

- * - * @see the online GLFW documentation - */ - public static class MouseInputEvent extends InputEvent - { - private final int button; - private final int action; - private final int modifiers; - - /** - * @hidden - * @see ForgeHooksClient#onRawMouseClicked(int, int, int) - */ - public MouseInputEvent(int button, int action, int modifiers) - { - this.button = button; - this.action = action; - this.modifiers = modifiers; - } /** - * {@return the mouse button's input code} + * Fired when a mouse button is pressed/released, before being processed by vanilla. * - * @see GLFW mouse constants starting with 'GLFW_MOUSE_BUTTON_' - * @see the online GLFW documentation - */ - public int getButton() - { - return this.button; - } - - /** - * {@return the mouse button's action} + *

This event is {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}. + * If the event is cancelled, then the mouse event will not be processed by vanilla (e.g. keymappings and screens)

* - * @see InputConstants#PRESS - * @see InputConstants#RELEASE + *

This event is fired on the {@linkplain MinecraftForge#EVENT_BUS main Forge event bus}, + * only on the {@linkplain LogicalSide#CLIENT logical client}.

+ * + * @see the online GLFW documentation */ - public int getAction() + @Cancelable + public static class Pre extends MouseButton { - return this.action; + @ApiStatus.Internal + public Pre(int button, int action, int modifiers) + { + super(button, action, modifiers); + } } /** - * {@return a bit field representing the active modifier keys} + * Fired when a mouse button is pressed/released, after processing. * - * @see InputConstants#MOD_CONTROL CTRL modifier key bit - * @see GLFW#GLFW_MOD_SHIFT SHIFT modifier key bit - * @see GLFW#GLFW_MOD_ALT ALT modifier key bit - * @see GLFW#GLFW_MOD_SUPER SUPER modifier key bit - * @see GLFW#GLFW_KEY_CAPS_LOCK CAPS LOCK modifier key bit - * @see GLFW#GLFW_KEY_NUM_LOCK NUM LOCK modifier key bit - * @see the online GLFW documentation + *

This event is not {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}.

+ * + *

This event is fired on the {@linkplain MinecraftForge#EVENT_BUS main Forge event bus}, + * only on the {@linkplain LogicalSide#CLIENT logical client}.

+ * + * @see the online GLFW documentation */ - public int getModifiers() + public static class Post extends MouseButton { - return this.modifiers; + @ApiStatus.Internal + public Post(int button, int action, int modifiers) + { + super(button, action, modifiers); + } } } @@ -168,15 +139,15 @@ public int getModifiers() * processed by vanilla. * *

This event is {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}. - * If the event is cancelled, then the mouse scroll event will not be processed further.

+ * If the event is cancelled, then the mouse scroll event will not be processed further.

* *

This event is fired on the {@linkplain MinecraftForge#EVENT_BUS main Forge event bus}, - * only on the {@linkplain LogicalSide#CLIENT logical client}.

+ * only on the {@linkplain LogicalSide#CLIENT logical client}.

* * @see the online GLFW documentation */ @Cancelable - public static class MouseScrollEvent extends InputEvent + public static class MouseScrollingEvent extends InputEvent { private final double scrollDelta; private final double mouseX; @@ -185,11 +156,8 @@ public static class MouseScrollEvent extends InputEvent private final boolean middleDown; private final boolean rightDown; - /** - * @hidden - * @see ForgeHooksClient#onMouseScroll(MouseHandler, double) - */ - public MouseScrollEvent(double scrollDelta, boolean leftDown, boolean middleDown, boolean rightDown, double mouseX, double mouseY) + @ApiStatus.Internal + public MouseScrollingEvent(double scrollDelta, boolean leftDown, boolean middleDown, boolean rightDown, double mouseX, double mouseY) { this.scrollDelta = scrollDelta; this.leftDown = leftDown; @@ -251,23 +219,20 @@ public double getMouseY() /** * Fired when a keyboard key input occurs, such as pressing, releasing, or repeating a key. * - *

This event is not {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}.

+ *

This event is not {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}.

* *

This event is fired on the {@linkplain MinecraftForge#EVENT_BUS main Forge event bus}, - * only on the {@linkplain LogicalSide#CLIENT logical client}.

+ * only on the {@linkplain LogicalSide#CLIENT logical client}.

*/ - public static class KeyInputEvent extends InputEvent + public static class Key extends InputEvent { private final int key; private final int scanCode; private final int action; private final int modifiers; - /** - * @hidden - * @see ForgeHooksClient#fireKeyInput(int, int, int, int) - */ - public KeyInputEvent(int key, int scanCode, int action, int modifiers) + @ApiStatus.Internal + public Key(int key, int scanCode, int action, int modifiers) { this.key = key; this.scanCode = scanCode; @@ -289,7 +254,7 @@ public int getKey() /** * {@return the platform-specific scan code} - * + *

* The scan code is unique for every key, regardless of whether it has a key code. * Scan codes are platform-specific but consistent over time, so keys will have different scan codes depending * on the platform but they are safe to save to disk as custom key bindings. @@ -342,24 +307,21 @@ public int getModifiers() * *

This event is {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}. * If this event is cancelled, then the keymapping's action is not processed further, and the hand will be swung - * according to {@link #shouldSwingHand()}.

+ * according to {@link #shouldSwingHand()}.

* *

This event is fired on the {@linkplain MinecraftForge#EVENT_BUS main Forge event bus}, - * only on the {@linkplain LogicalSide#CLIENT logical client}.

+ * only on the {@linkplain LogicalSide#CLIENT logical client}.

*/ @Cancelable - public static class ClickInputEvent extends InputEvent + public static class InteractionKeyMappingTriggered extends InputEvent { private final int button; private final KeyMapping keyMapping; private final InteractionHand hand; private boolean handSwing = true; - /** - * @hidden - * @see ForgeHooksClient#onClickInput(int, KeyMapping, InteractionHand) - */ - public ClickInputEvent(int button, KeyMapping keyMapping, InteractionHand hand) + @ApiStatus.Internal + public InteractionKeyMappingTriggered(int button, KeyMapping keyMapping, InteractionHand hand) { this.button = button; this.keyMapping = keyMapping; @@ -386,7 +348,7 @@ public boolean shouldSwingHand() /** * {@return the hand that caused the input} - * + *

* The event will be called for both hands if this is a use item input regardless * of both event's cancellation. * Will always be {@link InteractionHand#MAIN_HAND} if this is an attack or pick block input. diff --git a/src/main/java/net/minecraftforge/client/event/ModelBakeEvent.java b/src/main/java/net/minecraftforge/client/event/ModelBakeEvent.java deleted file mode 100644 index 52d747a9f1f..00000000000 --- a/src/main/java/net/minecraftforge/client/event/ModelBakeEvent.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (c) Forge Development LLC and contributors - * SPDX-License-Identifier: LGPL-2.1-only - */ - -package net.minecraftforge.client.event; - -import java.util.Map; - -import net.minecraft.client.resources.model.BakedModel; -import net.minecraft.client.resources.model.ModelManager; -import net.minecraft.resources.ResourceLocation; -import net.minecraftforge.client.ForgeHooksClient; -import net.minecraftforge.client.model.ForgeModelBakery; -import net.minecraftforge.eventbus.api.Cancelable; -import net.minecraftforge.eventbus.api.Event; -import net.minecraftforge.fml.LogicalSide; -import net.minecraftforge.fml.event.IModBusEvent; -import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; - -/** - * Fired when the ModelManager is notified of the resource manager reloading. - * Called after model registry is setup, but before it's passed to BlockModelShapes. - * - *

This event is not {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}.

- * - *

These events are fired on the {@linkplain FMLJavaModLoadingContext#getModEventBus() mod-specific event bus}, - * only on the {@linkplain LogicalSide#CLIENT logical client}.

- */ -// TODO: try to merge with ICustomModelLoader -public class ModelBakeEvent extends Event implements IModBusEvent -{ - private final ModelManager modelManager; - private final Map modelRegistry; - private final ForgeModelBakery modelLoader; - - /** - * @hidden - * @see ForgeHooksClient#onModelBake(ModelManager, Map, ForgeModelBakery) - */ - public ModelBakeEvent(ModelManager modelManager, Map modelRegistry, ForgeModelBakery modelLoader) - { - this.modelManager = modelManager; - this.modelRegistry = modelRegistry; - this.modelLoader = modelLoader; - } - - /** - * {@return the model manager} - */ - public ModelManager getModelManager() - { - return modelManager; - } - - /** - * {@return the modifiable registry map of models and their model names} - */ - public Map getModelRegistry() - { - return modelRegistry; - } - - /** - * {@return the model loader} - */ - public ForgeModelBakery getModelLoader() - { - return modelLoader; - } -} diff --git a/src/main/java/net/minecraftforge/client/event/ModelEvent.java b/src/main/java/net/minecraftforge/client/event/ModelEvent.java new file mode 100644 index 00000000000..7c576394caf --- /dev/null +++ b/src/main/java/net/minecraftforge/client/event/ModelEvent.java @@ -0,0 +1,139 @@ +/* + * Copyright (c) Forge Development LLC and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.minecraftforge.client.event; + +import com.google.common.base.Preconditions; +import net.minecraft.client.resources.model.BakedModel; +import net.minecraft.client.resources.model.ModelBakery; +import net.minecraft.client.resources.model.ModelManager; +import net.minecraft.resources.ResourceLocation; +import net.minecraftforge.client.model.geometry.IGeometryLoader; +import net.minecraftforge.eventbus.api.Cancelable; +import net.minecraftforge.eventbus.api.Event; +import net.minecraftforge.fml.LogicalSide; +import net.minecraftforge.fml.ModLoadingContext; +import net.minecraftforge.fml.event.IModBusEvent; +import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; +import org.jetbrains.annotations.ApiStatus; + +import java.util.Map; +import java.util.Set; + +/** + * Houses events related to models. + */ +public abstract class ModelEvent extends Event +{ + @ApiStatus.Internal + protected ModelEvent() + { + } + + /** + * Fired when the {@link ModelManager} is notified of the resource manager reloading. + * Called after model registry is set up, but before it's passed to {@link net.minecraft.client.renderer.block.BlockModelShaper}. + * + *

This event is not {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}.

+ * + *

This event is fired on the {@linkplain FMLJavaModLoadingContext#getModEventBus() mod-specific event bus}, + * only on the {@linkplain LogicalSide#CLIENT logical client}.

+ */ + public static class BakingCompleted extends ModelEvent implements IModBusEvent + { + private final ModelManager modelManager; + private final Map models; + private final ModelBakery modelBakery; + + @ApiStatus.Internal + public BakingCompleted(ModelManager modelManager, Map models, ModelBakery modelBakery) + { + this.modelManager = modelManager; + this.models = models; + this.modelBakery = modelBakery; + } + + /** + * @return the model manager + */ + public ModelManager getModelManager() + { + return modelManager; + } + + /** + * @return the modifiable registry map of models and their model names + */ + public Map getModels() + { + return models; + } + + /** + * @return the model loader + */ + public ModelBakery getModelBakery() + { + return modelBakery; + } + } + + /** + * Fired when the {@link net.minecraft.client.resources.model.ModelBakery} is notified of the resource manager reloading. + * Allows developers to register models to be loaded, along with their dependencies. + * + *

This event is not {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}.

+ * + *

This event is fired on the {@linkplain FMLJavaModLoadingContext#getModEventBus() mod-specific event bus}, + * only on the {@linkplain LogicalSide#CLIENT logical client}.

+ */ + public static class RegisterAdditional extends ModelEvent implements IModBusEvent + { + private final Set models; + + @ApiStatus.Internal + public RegisterAdditional(Set models) + { + this.models = models; + } + + /** + * Registers a model to be loaded, along with its dependencies. + */ + public void register(ResourceLocation model) + { + models.add(model); + } + } + + /** + * Allows users to register their own {@link IGeometryLoader geometry loaders} for use in block/item models. + * + *

This event is not {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}.

+ * + *

This event is fired on the {@linkplain FMLJavaModLoadingContext#getModEventBus() mod-specific event bus}, + * only on the {@linkplain LogicalSide#CLIENT logical client}.

+ */ + public static class RegisterGeometryLoaders extends ModelEvent implements IModBusEvent + { + private final Map> loaders; + + @ApiStatus.Internal + public RegisterGeometryLoaders(Map> loaders) + { + this.loaders = loaders; + } + + /** + * Registers a new geometry loader. + */ + public void register(String name, IGeometryLoader loader) + { + var key = new ResourceLocation(ModLoadingContext.get().getActiveNamespace(), name); + Preconditions.checkArgument(!loaders.containsKey(key), "Geometry loader already registered: " + key); + loaders.put(key, loader); + } + } +} diff --git a/src/main/java/net/minecraftforge/client/event/ModelRegistryEvent.java b/src/main/java/net/minecraftforge/client/event/ModelRegistryEvent.java deleted file mode 100644 index fe90c537375..00000000000 --- a/src/main/java/net/minecraftforge/client/event/ModelRegistryEvent.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) Forge Development LLC and contributors - * SPDX-License-Identifier: LGPL-2.1-only - */ - -package net.minecraftforge.client.event; - -import net.minecraft.resources.ResourceLocation; -import net.minecraftforge.client.model.IModelLoader; -import net.minecraftforge.client.model.ModelLoaderRegistry; -import net.minecraftforge.eventbus.api.Cancelable; -import net.minecraftforge.eventbus.api.Event; -import net.minecraftforge.fml.LogicalSide; -import net.minecraftforge.fml.event.IModBusEvent; -import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; - -/** - * Fired when the {@link ModelLoaderRegistry} is ready for model loader registrations. - * - *

This event is not {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}.

- * - *

This event is fired on the {@linkplain FMLJavaModLoadingContext#getModEventBus() mod-specific event bus}, - * only on the {@linkplain LogicalSide#CLIENT logical client}.

- * - * @see ModelLoaderRegistry#registerLoader(ResourceLocation, IModelLoader) - */ -public class ModelRegistryEvent extends Event implements IModBusEvent -{ - /** - * @hidden - * @see ModelLoaderRegistry#onModelLoadingStart() - */ - public ModelRegistryEvent() - { - } -} diff --git a/src/main/java/net/minecraftforge/client/event/MovementInputUpdateEvent.java b/src/main/java/net/minecraftforge/client/event/MovementInputUpdateEvent.java index 7ae53c391b4..a1d8a5f2339 100644 --- a/src/main/java/net/minecraftforge/client/event/MovementInputUpdateEvent.java +++ b/src/main/java/net/minecraftforge/client/event/MovementInputUpdateEvent.java @@ -5,30 +5,27 @@ package net.minecraftforge.client.event; -import net.minecraft.world.entity.player.Player; import net.minecraft.client.player.Input; -import net.minecraftforge.client.ForgeHooksClient; +import net.minecraft.world.entity.player.Player; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.event.entity.player.PlayerEvent; import net.minecraftforge.eventbus.api.Cancelable; import net.minecraftforge.fml.LogicalSide; +import org.jetbrains.annotations.ApiStatus; /** *

Fired after the player's movement inputs are updated.

* - *

This event is not {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}.

+ *

This event is not {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}.

* *

This event is fired on the {@linkplain MinecraftForge#EVENT_BUS main Forge event bus}, - * only on the {@linkplain LogicalSide#CLIENT logical client}.

+ * only on the {@linkplain LogicalSide#CLIENT logical client}.

*/ public class MovementInputUpdateEvent extends PlayerEvent { private final Input input; - /** - * @hidden - * @see ForgeHooksClient#onMovementInputUpdate(Player, Input) - */ + @ApiStatus.Internal public MovementInputUpdateEvent(Player player, Input input) { super(player); @@ -42,5 +39,4 @@ public Input getInput() { return input; } - } diff --git a/src/main/java/net/minecraftforge/client/event/RecipesUpdatedEvent.java b/src/main/java/net/minecraftforge/client/event/RecipesUpdatedEvent.java index 5b0b29ee72c..0337d6c4ac9 100644 --- a/src/main/java/net/minecraftforge/client/event/RecipesUpdatedEvent.java +++ b/src/main/java/net/minecraftforge/client/event/RecipesUpdatedEvent.java @@ -6,32 +6,28 @@ package net.minecraftforge.client.event; import net.minecraft.world.item.crafting.RecipeManager; -import net.minecraftforge.client.ForgeHooksClient; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.eventbus.api.Cancelable; import net.minecraftforge.eventbus.api.Event; import net.minecraftforge.fml.LogicalSide; +import org.jetbrains.annotations.ApiStatus; /** * Fired when the {@link RecipeManager} has received and synced the recipes from the server to the client. * - *

This event is not {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}.

+ *

This event is not {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}.

* *

This event is fired on the {@linkplain MinecraftForge#EVENT_BUS main Forge event bus}, - * only on the {@linkplain LogicalSide#CLIENT logical client}.

+ * only on the {@linkplain LogicalSide#CLIENT logical client}.

*/ public class RecipesUpdatedEvent extends Event { + private final RecipeManager recipeManager; - private final RecipeManager mgr; - - /** - * @hidden - * @see ForgeHooksClient#onRecipesUpdated(RecipeManager) - */ - public RecipesUpdatedEvent(RecipeManager mgr) + @ApiStatus.Internal + public RecipesUpdatedEvent(RecipeManager recipeManager) { - this.mgr = mgr; + this.recipeManager = recipeManager; } /** @@ -39,6 +35,6 @@ public RecipesUpdatedEvent(RecipeManager mgr) */ public RecipeManager getRecipeManager() { - return mgr; + return recipeManager; } } diff --git a/src/main/java/net/minecraftforge/client/event/RegisterClientCommandsEvent.java b/src/main/java/net/minecraftforge/client/event/RegisterClientCommandsEvent.java index 12d00d9f4fb..4dc3e7a4964 100644 --- a/src/main/java/net/minecraftforge/client/event/RegisterClientCommandsEvent.java +++ b/src/main/java/net/minecraftforge/client/event/RegisterClientCommandsEvent.java @@ -14,6 +14,7 @@ import net.minecraftforge.eventbus.api.Cancelable; import net.minecraftforge.eventbus.api.Event; import net.minecraftforge.fml.LogicalSide; +import org.jetbrains.annotations.ApiStatus; /** * Fired to allow mods to register client commands. @@ -26,23 +27,19 @@ * objectives that are displayed to the player. * * - *

This event is not {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}.

+ *

This event is not {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}.

* *

This event is fired on the {@linkplain MinecraftForge#EVENT_BUS main Forge event bus}, - * only on the {@linkplain LogicalSide#CLIENT logical client}.

+ * only on the {@linkplain LogicalSide#CLIENT logical client}.

* * @see net.minecraftforge.event.RegisterCommandsEvent */ public class RegisterClientCommandsEvent extends Event { - private final CommandDispatcher dispatcher; private final CommandBuildContext context; - /** - * @hidden - * @see net.minecraftforge.client.ClientCommandHandler#mergeServerCommands(CommandDispatcher, CommandBuildContext) - */ + @ApiStatus.Internal public RegisterClientCommandsEvent(CommandDispatcher dispatcher, CommandBuildContext context) { this.dispatcher = dispatcher; diff --git a/src/main/java/net/minecraftforge/client/event/RegisterClientReloadListenersEvent.java b/src/main/java/net/minecraftforge/client/event/RegisterClientReloadListenersEvent.java index 2324cfba690..0e641cc2ba6 100644 --- a/src/main/java/net/minecraftforge/client/event/RegisterClientReloadListenersEvent.java +++ b/src/main/java/net/minecraftforge/client/event/RegisterClientReloadListenersEvent.java @@ -14,25 +14,24 @@ import net.minecraftforge.fml.LogicalSide; import net.minecraftforge.fml.event.IModBusEvent; import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; +import org.jetbrains.annotations.ApiStatus; /** * Fired to allow mods to register their reload listeners on the client-side resource manager. * This event is fired once during the construction of the {@link Minecraft} instance. * - *

For registering reload listeners on the server-side resource manager, see {@link AddReloadListenerEvent}.

+ *

For registering reload listeners on the server-side resource manager, see {@link AddReloadListenerEvent}.

* - *

This event is not {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}.

+ *

This event is not {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}.

* *

This event is fired on the {@linkplain FMLJavaModLoadingContext#getModEventBus() mod-specific event bus}, - * only on the {@linkplain LogicalSide#CLIENT logical client}.

+ * only on the {@linkplain LogicalSide#CLIENT logical client}.

*/ public class RegisterClientReloadListenersEvent extends Event implements IModBusEvent { private final ReloadableResourceManager resourceManager; - /** - * @hidden - */ + @ApiStatus.Internal public RegisterClientReloadListenersEvent(ReloadableResourceManager resourceManager) { this.resourceManager = resourceManager; diff --git a/src/main/java/net/minecraftforge/client/event/RegisterClientTooltipComponentFactoriesEvent.java b/src/main/java/net/minecraftforge/client/event/RegisterClientTooltipComponentFactoriesEvent.java new file mode 100644 index 00000000000..564ff815e3d --- /dev/null +++ b/src/main/java/net/minecraftforge/client/event/RegisterClientTooltipComponentFactoriesEvent.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) Forge Development LLC and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.minecraftforge.client.event; + +import net.minecraft.client.gui.screens.inventory.tooltip.ClientTooltipComponent; +import net.minecraft.world.inventory.tooltip.TooltipComponent; +import net.minecraftforge.eventbus.api.Cancelable; +import net.minecraftforge.eventbus.api.Event; +import net.minecraftforge.fml.LogicalSide; +import net.minecraftforge.fml.event.IModBusEvent; +import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; +import org.jetbrains.annotations.ApiStatus; + +import java.util.Map; +import java.util.function.Function; + +/** + * Allows users to register custom {@link net.minecraft.client.gui.screens.inventory.tooltip.ClientTooltipComponent} + * factories for their {@link net.minecraft.world.inventory.tooltip.TooltipComponent} types. + * + *

This event is not {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}. + * + *

This event is fired on the {@linkplain FMLJavaModLoadingContext#getModEventBus() mod-specific event bus}, + * only on the {@linkplain LogicalSide#CLIENT logical client}.

+ */ +public class RegisterClientTooltipComponentFactoriesEvent extends Event implements IModBusEvent +{ + private final Map, Function> factories; + + @ApiStatus.Internal + public RegisterClientTooltipComponentFactoriesEvent(Map, Function> factories) + { + this.factories = factories; + } + + /** + * Registers a {@link ClientTooltipComponent} factory for a {@link TooltipComponent}. + */ + @SuppressWarnings("unchecked") + public void register(Class type, Function factory) + { + factories.put(type, (Function) factory); + } +} diff --git a/src/main/java/net/minecraftforge/client/event/ColorHandlerEvent.java b/src/main/java/net/minecraftforge/client/event/RegisterColorHandlersEvent.java similarity index 67% rename from src/main/java/net/minecraftforge/client/event/ColorHandlerEvent.java rename to src/main/java/net/minecraftforge/client/event/RegisterColorHandlersEvent.java index fb232fea84e..29444c54c36 100644 --- a/src/main/java/net/minecraftforge/client/event/ColorHandlerEvent.java +++ b/src/main/java/net/minecraftforge/client/event/RegisterColorHandlersEvent.java @@ -10,48 +10,43 @@ import net.minecraft.client.color.item.ItemColor; import net.minecraft.client.color.item.ItemColors; import net.minecraft.world.level.ItemLike; -import net.minecraftforge.client.ForgeHooksClient; import net.minecraftforge.eventbus.api.Cancelable; import net.minecraftforge.eventbus.api.Event; import net.minecraftforge.fml.LogicalSide; import net.minecraftforge.fml.event.IModBusEvent; import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; +import org.jetbrains.annotations.ApiStatus; /** * Fired for registering block and item color handlers at the appropriate time. * See the two subclasses for registering block or item color handlers. * *

These events are fired on the {@linkplain FMLJavaModLoadingContext#getModEventBus() mod-specific event bus}, - * only on the {@linkplain LogicalSide#CLIENT logical client}.

+ * only on the {@linkplain LogicalSide#CLIENT logical client}.

* - * @see ColorHandlerEvent.Block - * @see ColorHandlerEvent.Item + * @see RegisterColorHandlersEvent.Block + * @see RegisterColorHandlersEvent.Item */ -public abstract class ColorHandlerEvent extends Event implements IModBusEvent +public abstract class RegisterColorHandlersEvent extends Event implements IModBusEvent { - /** - * @hidden This should only be invoked by subclasses. - */ - public ColorHandlerEvent() + @ApiStatus.Internal + protected RegisterColorHandlersEvent() { } /** * Fired for registering block color handlers. * - *

This event is not {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}.

+ *

This event is not {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}.

* *

This event is fired on the {@linkplain FMLJavaModLoadingContext#getModEventBus() mod-specific event bus}, - * only on the {@linkplain LogicalSide#CLIENT logical client}.

+ * only on the {@linkplain LogicalSide#CLIENT logical client}.

*/ - public static class Block extends ColorHandlerEvent + public static class Block extends RegisterColorHandlersEvent { private final BlockColors blockColors; - /** - * @hidden This should only be invoked by the client hook. - * @see ForgeHooksClient#onBlockColorsInit(BlockColors) - */ + @ApiStatus.Internal public Block(BlockColors blockColors) { this.blockColors = blockColors; @@ -59,34 +54,43 @@ public Block(BlockColors blockColors) /** * {@return the block colors registry} + * * @see BlockColors#register(BlockColor, net.minecraft.world.level.block.Block...) */ public BlockColors getBlockColors() { return blockColors; } + + /** + * Registers a {@link BlockColor} instance for a set of blocks. + * + * @param blockColor The color provider + * @param blocks The blocks + */ + public void register(BlockColor blockColor, net.minecraft.world.level.block.Block... blocks) + { + blockColors.register(blockColor, blocks); + } } /** * Fired for registering item color handlers. * *

The block colors should only be used for referencing or delegating item colors to their respective block - * colors. Use {@link ColorHandlerEvent.Block} for registering your block color handlers.

+ * colors. Use {@link RegisterColorHandlersEvent.Block} for registering your block color handlers.

* - *

This event is not {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}.

+ *

This event is not {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}.

* *

This event is fired on the {@linkplain FMLJavaModLoadingContext#getModEventBus() mod-specific event bus}, - * only on the {@linkplain LogicalSide#CLIENT logical client}.

+ * only on the {@linkplain LogicalSide#CLIENT logical client}.

*/ - public static class Item extends ColorHandlerEvent + public static class Item extends RegisterColorHandlersEvent { private final ItemColors itemColors; private final BlockColors blockColors; - /** - * @hidden - * @see ForgeHooksClient#onItemColorsInit(ItemColors, BlockColors) - */ + @ApiStatus.Internal public Item(ItemColors itemColors, BlockColors blockColors) { this.itemColors = itemColors; @@ -95,6 +99,7 @@ public Item(ItemColors itemColors, BlockColors blockColors) /** * {@return the item colors registry} + * * @see ItemColors#register(ItemColor, ItemLike...) */ public ItemColors getItemColors() @@ -110,5 +115,16 @@ public BlockColors getBlockColors() { return blockColors; } + + /** + * Registers a {@link ItemColor} instance for a set of blocks. + * + * @param itemColor The color provider + * @param items The items + */ + public void register(ItemColor itemColor, ItemLike... items) + { + itemColors.register(itemColor, items); + } } } diff --git a/src/main/java/net/minecraftforge/client/event/RegisterDimensionSpecialEffectsEvent.java b/src/main/java/net/minecraftforge/client/event/RegisterDimensionSpecialEffectsEvent.java new file mode 100644 index 00000000000..65c792bd5f0 --- /dev/null +++ b/src/main/java/net/minecraftforge/client/event/RegisterDimensionSpecialEffectsEvent.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) Forge Development LLC and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.minecraftforge.client.event; + +import net.minecraft.client.renderer.DimensionSpecialEffects; +import net.minecraft.resources.ResourceLocation; +import net.minecraftforge.eventbus.api.Cancelable; +import net.minecraftforge.eventbus.api.Event; +import net.minecraftforge.fml.LogicalSide; +import net.minecraftforge.fml.event.IModBusEvent; +import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; +import org.jetbrains.annotations.ApiStatus; + +import java.util.Map; + +/** + * Allows users to register custom {@link DimensionSpecialEffects} for their dimensions. + * + *

This event is not {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}. + * + *

This event is fired on the {@linkplain FMLJavaModLoadingContext#getModEventBus() mod-specific event bus}, + * only on the {@linkplain LogicalSide#CLIENT logical client}.

+ */ +public class RegisterDimensionSpecialEffectsEvent extends Event implements IModBusEvent +{ + private final Map effects; + + @ApiStatus.Internal + public RegisterDimensionSpecialEffectsEvent(Map effects) + { + this.effects = effects; + } + + /** + * Registers the effects for a given dimension type. + */ + public void register(ResourceLocation dimensionType, DimensionSpecialEffects effects) + { + this.effects.put(dimensionType, effects); + } +} diff --git a/src/main/java/net/minecraftforge/client/event/RegisterEntitySpectatorShadersEvent.java b/src/main/java/net/minecraftforge/client/event/RegisterEntitySpectatorShadersEvent.java new file mode 100644 index 00000000000..911367820bf --- /dev/null +++ b/src/main/java/net/minecraftforge/client/event/RegisterEntitySpectatorShadersEvent.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) Forge Development LLC and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.minecraftforge.client.event; + +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.entity.EntityType; +import net.minecraftforge.eventbus.api.Cancelable; +import net.minecraftforge.eventbus.api.Event; +import net.minecraftforge.fml.LogicalSide; +import net.minecraftforge.fml.event.IModBusEvent; +import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; +import org.jetbrains.annotations.ApiStatus; + +import java.util.Map; + +/** + * Allows users to register custom shaders to be used when the player spectates a certain kind of entity. + * Vanilla examples of this are the green effect for creepers and the invert effect for endermen. + * + *

This event is not {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}. + * + *

This event is fired on the {@linkplain FMLJavaModLoadingContext#getModEventBus() mod-specific event bus}, + * only on the {@linkplain LogicalSide#CLIENT logical client}.

+ */ +public class RegisterEntitySpectatorShadersEvent extends Event implements IModBusEvent +{ + private final Map, ResourceLocation> shaders; + + @ApiStatus.Internal + public RegisterEntitySpectatorShadersEvent(Map, ResourceLocation> shaders) + { + this.shaders = shaders; + } + + /** + * Registers a spectator shader for a given entity type. + */ + public void register(EntityType entityType, ResourceLocation shader) + { + shaders.put(entityType, shader); + } +} diff --git a/src/main/java/net/minecraftforge/client/event/RegisterGuiOverlaysEvent.java b/src/main/java/net/minecraftforge/client/event/RegisterGuiOverlaysEvent.java new file mode 100644 index 00000000000..dba0ddeb148 --- /dev/null +++ b/src/main/java/net/minecraftforge/client/event/RegisterGuiOverlaysEvent.java @@ -0,0 +1,118 @@ +/* + * Copyright (c) Forge Development LLC and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.minecraftforge.client.event; + +import com.google.common.base.Preconditions; +import net.minecraft.resources.ResourceLocation; +import net.minecraftforge.client.gui.overlay.IGuiOverlay; +import net.minecraftforge.client.gui.overlay.VanillaGuiOverlay; +import net.minecraftforge.eventbus.api.Cancelable; +import net.minecraftforge.eventbus.api.Event; +import net.minecraftforge.fml.LogicalSide; +import net.minecraftforge.fml.ModLoadingContext; +import net.minecraftforge.fml.event.IModBusEvent; +import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; +import java.util.Map; + +/** + * Allows users to register custom {@link IGuiOverlay GUI overlays}. + * + *

This event is not {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}. + * + *

This event is fired on the {@linkplain FMLJavaModLoadingContext#getModEventBus() mod-specific event bus}, + * only on the {@linkplain LogicalSide#CLIENT logical client}.

+ */ +public class RegisterGuiOverlaysEvent extends Event implements IModBusEvent +{ + private final Map overlays; + private final List orderedOverlays; + + @ApiStatus.Internal + public RegisterGuiOverlaysEvent(Map overlays, List orderedOverlays) + { + this.overlays = overlays; + this.orderedOverlays = orderedOverlays; + } + + /** + * Registers an overlay that renders below all others. + * + * @param id A unique resource id for this overlay + * @param overlay The overlay + */ + public void registerBelowAll(@NotNull String id, @NotNull IGuiOverlay overlay) + { + register(Ordering.BEFORE, null, id, overlay); + } + + /** + * Registers an overlay that renders below another. + * + * @param other The id of the overlay to render below. This must be an overlay you have already registered or a + * {@link VanillaGuiOverlay vanilla overlay}. Do not use other mods' overlays. + * @param id A unique resource id for this overlay + * @param overlay The overlay + */ + public void registerBelow(@NotNull ResourceLocation other, @NotNull String id, @NotNull IGuiOverlay overlay) + { + register(Ordering.BEFORE, other, id, overlay); + } + + /** + * Registers an overlay that renders above another. + * + * @param other The id of the overlay to render above. This must be an overlay you have already registered or a + * {@link VanillaGuiOverlay vanilla overlay}. Do not use other mods' overlays. + * @param id A unique resource id for this overlay + * @param overlay The overlay + */ + public void registerAbove(@NotNull ResourceLocation other, @NotNull String id, @NotNull IGuiOverlay overlay) + { + register(Ordering.AFTER, other, id, overlay); + } + + /** + * Registers an overlay that renders above all others. + * + * @param id A unique resource id for this overlay + * @param overlay The overlay + */ + public void registerAboveAll(@NotNull String id, @NotNull IGuiOverlay overlay) + { + register(Ordering.AFTER, null, id, overlay); + } + + private void register(@NotNull Ordering ordering, @Nullable ResourceLocation other, @NotNull String id, @NotNull IGuiOverlay overlay) + { + var key = new ResourceLocation(ModLoadingContext.get().getActiveNamespace(), id); + Preconditions.checkArgument(!overlays.containsKey(key), "Overlay already registered: " + key); + + int insertPosition; + if (other == null) + { + insertPosition = ordering == Ordering.BEFORE ? 0 : overlays.size(); + } + else + { + int otherIndex = orderedOverlays.indexOf(other); + Preconditions.checkState(otherIndex >= 0, "Attempted to order against an unregistered overlay. Only order against vanilla's and your own."); + insertPosition = otherIndex + (ordering == Ordering.BEFORE ? 0 : 1); + } + + overlays.put(key, overlay); + orderedOverlays.add(insertPosition, key); + } + + private enum Ordering + { + BEFORE, AFTER + } +} diff --git a/src/main/java/net/minecraftforge/client/event/RegisterKeyMappingsEvent.java b/src/main/java/net/minecraftforge/client/event/RegisterKeyMappingsEvent.java new file mode 100644 index 00000000000..4d0d08588dd --- /dev/null +++ b/src/main/java/net/minecraftforge/client/event/RegisterKeyMappingsEvent.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) Forge Development LLC and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.minecraftforge.client.event; + +import net.minecraft.client.KeyMapping; +import net.minecraft.client.Options; +import net.minecraftforge.eventbus.api.Cancelable; +import net.minecraftforge.eventbus.api.Event; +import net.minecraftforge.fml.LogicalSide; +import net.minecraftforge.fml.event.IModBusEvent; +import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; +import org.apache.commons.lang3.ArrayUtils; +import org.jetbrains.annotations.ApiStatus; + +/** + * Allows users to register custom {@link net.minecraft.client.KeyMapping key mappings}. + * + *

This event is not {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}. + * + *

This event is fired on the {@linkplain FMLJavaModLoadingContext#getModEventBus() mod-specific event bus}, + * only on the {@linkplain LogicalSide#CLIENT logical client}.

+ */ +public class RegisterKeyMappingsEvent extends Event implements IModBusEvent +{ + private final Options options; + + @ApiStatus.Internal + public RegisterKeyMappingsEvent(Options options) + { + this.options = options; + } + + /** + * Registers a new key mapping. + */ + public void register(KeyMapping key) + { + options.keyMappings = ArrayUtils.add(options.keyMappings, key); + } +} diff --git a/src/main/java/net/minecraftforge/client/event/RegisterNamedRenderTypesEvent.java b/src/main/java/net/minecraftforge/client/event/RegisterNamedRenderTypesEvent.java new file mode 100644 index 00000000000..145eb44dd52 --- /dev/null +++ b/src/main/java/net/minecraftforge/client/event/RegisterNamedRenderTypesEvent.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) Forge Development LLC and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.minecraftforge.client.event; + +import com.google.common.base.Preconditions; +import com.mojang.blaze3d.vertex.DefaultVertexFormat; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.resources.ResourceLocation; +import net.minecraftforge.client.RenderTypeGroup; +import net.minecraftforge.eventbus.api.Cancelable; +import net.minecraftforge.eventbus.api.Event; +import net.minecraftforge.fml.LogicalSide; +import net.minecraftforge.fml.ModLoadingContext; +import net.minecraftforge.fml.event.IModBusEvent; +import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; +import org.jetbrains.annotations.ApiStatus; + +import java.util.Map; + +/** + * Allows users to register custom named {@link RenderType render types}. + * + *

This event is not {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}. + * + *

This event is fired on the {@linkplain FMLJavaModLoadingContext#getModEventBus() mod-specific event bus}, + * only on the {@linkplain LogicalSide#CLIENT logical client}.

+ */ +public class RegisterNamedRenderTypesEvent extends Event implements IModBusEvent +{ + private final Map renderTypes; + + @ApiStatus.Internal + public RegisterNamedRenderTypesEvent(Map renderTypes) + { + this.renderTypes = renderTypes; + } + + /** + * Registers a named {@link RenderTypeGroup}. + * + * @param name The name + * @param blockRenderType One of the values returned by {@link RenderType#chunkBufferLayers()} + * @param entityRenderType A {@link RenderType} using {@link DefaultVertexFormat#NEW_ENTITY} + */ + public void register(String name, RenderType blockRenderType, RenderType entityRenderType) + { + register(name, blockRenderType, entityRenderType, entityRenderType); + } + + /** + * Registers a named {@link RenderTypeGroup}. + * + * @param name The name + * @param blockRenderType One of the values returned by {@link RenderType#chunkBufferLayers()} + * @param entityRenderType A {@link RenderType} using {@link DefaultVertexFormat#NEW_ENTITY} + * @param fabulousEntityRenderType A {@link RenderType} using {@link DefaultVertexFormat#NEW_ENTITY} for use when + * "fabulous" rendering is enabled + */ + public void register(String name, RenderType blockRenderType, RenderType entityRenderType, RenderType fabulousEntityRenderType) + { + var key = new ResourceLocation(ModLoadingContext.get().getActiveNamespace(), name); + Preconditions.checkArgument(!renderTypes.containsKey(key), "Render type already registered: " + key); + Preconditions.checkArgument(blockRenderType.format() == DefaultVertexFormat.BLOCK, "The block render type must use the BLOCK vertex format."); + Preconditions.checkArgument(blockRenderType.getChunkLayerId() >= 0, "Only chunk render types can be used for block rendering. Query RenderType#chunkBufferLayers() for a list."); + Preconditions.checkArgument(entityRenderType.format() == DefaultVertexFormat.NEW_ENTITY, "The entity render type must use the NEW_ENTITY vertex format."); + Preconditions.checkArgument(fabulousEntityRenderType.format() == DefaultVertexFormat.NEW_ENTITY, "The fabulous entity render type must use the NEW_ENTITY vertex format."); + renderTypes.put(key, new RenderTypeGroup(blockRenderType, entityRenderType, fabulousEntityRenderType)); + } +} diff --git a/src/main/java/net/minecraftforge/client/event/ParticleFactoryRegisterEvent.java b/src/main/java/net/minecraftforge/client/event/RegisterParticleProvidersEvent.java similarity index 51% rename from src/main/java/net/minecraftforge/client/event/ParticleFactoryRegisterEvent.java rename to src/main/java/net/minecraftforge/client/event/RegisterParticleProvidersEvent.java index db5c8bf8b04..974e39a65e2 100644 --- a/src/main/java/net/minecraftforge/client/event/ParticleFactoryRegisterEvent.java +++ b/src/main/java/net/minecraftforge/client/event/RegisterParticleProvidersEvent.java @@ -7,6 +7,7 @@ import net.minecraft.client.particle.ParticleEngine; import net.minecraft.client.particle.ParticleProvider; +import net.minecraft.core.particles.ParticleOptions; import net.minecraft.core.particles.ParticleType; import net.minecraftforge.eventbus.api.Cancelable; import net.minecraftforge.eventbus.api.Event; @@ -14,25 +15,36 @@ import net.minecraftforge.fml.event.IModBusEvent; import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; import net.minecraftforge.registries.RegisterEvent; +import org.jetbrains.annotations.ApiStatus; /** * Fired for registering particle providers at the appropriate time. * *

{@link ParticleType}s must be registered during {@link RegisterEvent} as usual; - * this event is only for the {@link ParticleProvider}s.

+ * this event is only for the {@link ParticleProvider}s.

* - *

This event is not {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}.

+ *

This event is not {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}.

* *

This event is fired on the {@linkplain FMLJavaModLoadingContext#getModEventBus() mod-specific event bus}, - * only on the {@linkplain LogicalSide#CLIENT logical client}.

- * - * @see ParticleEngine#register(ParticleType, ParticleProvider) + * only on the {@linkplain LogicalSide#CLIENT logical client}.

*/ -public class ParticleFactoryRegisterEvent extends Event implements IModBusEvent { - /** - * @hidden - */ - public ParticleFactoryRegisterEvent() +public class RegisterParticleProvidersEvent extends Event implements IModBusEvent +{ + private final ParticleEngine particleEngine; + + @ApiStatus.Internal + public RegisterParticleProvidersEvent(ParticleEngine particleEngine) + { + this.particleEngine = particleEngine; + } + + public void register(ParticleType type, ParticleProvider provider) + { + particleEngine.register(type, provider); + } + + public void register(ParticleType type, ParticleEngine.SpriteParticleRegistration registration) { + particleEngine.register(type, registration); } } diff --git a/src/main/java/net/minecraftforge/client/event/RegisterRecipeBookCategoriesEvent.java b/src/main/java/net/minecraftforge/client/event/RegisterRecipeBookCategoriesEvent.java new file mode 100644 index 00000000000..4c8a7aabe2d --- /dev/null +++ b/src/main/java/net/minecraftforge/client/event/RegisterRecipeBookCategoriesEvent.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) Forge Development LLC and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.minecraftforge.client.event; + +import com.google.common.collect.ImmutableList; +import net.minecraft.client.RecipeBookCategories; +import net.minecraft.world.inventory.RecipeBookType; +import net.minecraft.world.item.crafting.Recipe; +import net.minecraft.world.item.crafting.RecipeType; +import net.minecraftforge.eventbus.api.Cancelable; +import net.minecraftforge.eventbus.api.Event; +import net.minecraftforge.fml.LogicalSide; +import net.minecraftforge.fml.event.IModBusEvent; +import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; +import org.jetbrains.annotations.ApiStatus; + +import java.util.List; +import java.util.Map; +import java.util.function.Function; + +/** + * Allows users to register custom categories for the vanilla recipe book, making it usable in modded GUIs. + * + *

This event is not {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}. + * + *

This event is fired on the {@linkplain FMLJavaModLoadingContext#getModEventBus() mod-specific event bus}, + * only on the {@linkplain LogicalSide#CLIENT logical client}.

+ */ +public class RegisterRecipeBookCategoriesEvent extends Event implements IModBusEvent +{ + private final Map> aggregateCategories; + private final Map> typeCategories; + private final Map, Function, RecipeBookCategories>> recipeCategoryLookups; + + @ApiStatus.Internal + public RegisterRecipeBookCategoriesEvent( + Map> aggregateCategories, + Map> typeCategories, + Map, Function, RecipeBookCategories>> recipeCategoryLookups) + { + this.aggregateCategories = aggregateCategories; + this.typeCategories = typeCategories; + this.recipeCategoryLookups = recipeCategoryLookups; + } + + /** + * Registers the list of categories that compose an aggregate category. + */ + public void registerAggregateCategory(RecipeBookCategories category, List others) + { + aggregateCategories.put(category, ImmutableList.copyOf(others)); + } + + /** + * Registers the list of categories that compose a recipe book. + */ + public void registerBookCategories(RecipeBookType type, List categories) + { + typeCategories.put(type, ImmutableList.copyOf(categories)); + } + + /** + * Registers a category lookup for a certain recipe type. + */ + public void registerRecipeCategoryFinder(RecipeType type, Function, RecipeBookCategories> lookup) + { + recipeCategoryLookups.put(type, lookup); + } +} diff --git a/src/main/java/net/minecraftforge/client/event/RegisterShadersEvent.java b/src/main/java/net/minecraftforge/client/event/RegisterShadersEvent.java index 9c97904d70a..7b7079a56c1 100644 --- a/src/main/java/net/minecraftforge/client/event/RegisterShadersEvent.java +++ b/src/main/java/net/minecraftforge/client/event/RegisterShadersEvent.java @@ -13,6 +13,7 @@ import net.minecraftforge.fml.LogicalSide; import net.minecraftforge.fml.event.IModBusEvent; import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; +import org.jetbrains.annotations.ApiStatus; import java.util.List; import java.util.function.Consumer; @@ -21,19 +22,17 @@ * Fired to allow mods to register custom {@linkplain ShaderInstance shaders}. * This event is fired after the default Minecraft shaders have been registered. * - *

This event is not {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}.

+ *

This event is not {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}.

* *

This event is fired on the {@linkplain FMLJavaModLoadingContext#getModEventBus() mod-specific event bus}, - * only on the {@linkplain LogicalSide#CLIENT logical client}.

+ * only on the {@linkplain LogicalSide#CLIENT logical client}.

*/ public class RegisterShadersEvent extends Event implements IModBusEvent { private final ResourceManager resourceManager; private final List>> shaderList; - /** - * @hidden - */ + @ApiStatus.Internal public RegisterShadersEvent(ResourceManager resourceManager, List>> shaderList) { this.resourceManager = resourceManager; @@ -52,10 +51,10 @@ public ResourceManager getResourceManager() * Registers a shader, and a callback for when the shader is loaded. * *

When creating a {@link ShaderInstance}, pass in the {@linkplain #getResourceManager() - * client-side resource manager} as the resource provider.

+ * client-side resource manager} as the resource provider.

* *

Mods should not store the shader instance passed into this method. Instead, mods should store the shader - * passed into the registered load callback.

+ * passed into the registered load callback.

* * @param shaderInstance a shader * @param onLoaded a callback for when the shader is loaded diff --git a/src/main/java/net/minecraftforge/client/event/RegisterTextureAtlasSpriteLoadersEvent.java b/src/main/java/net/minecraftforge/client/event/RegisterTextureAtlasSpriteLoadersEvent.java new file mode 100644 index 00000000000..8014c512a81 --- /dev/null +++ b/src/main/java/net/minecraftforge/client/event/RegisterTextureAtlasSpriteLoadersEvent.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) Forge Development LLC and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.minecraftforge.client.event; + +import com.google.common.base.Preconditions; +import net.minecraft.resources.ResourceLocation; +import net.minecraftforge.client.textures.ITextureAtlasSpriteLoader; +import net.minecraftforge.eventbus.api.Cancelable; +import net.minecraftforge.eventbus.api.Event; +import net.minecraftforge.fml.LogicalSide; +import net.minecraftforge.fml.ModLoadingContext; +import net.minecraftforge.fml.event.IModBusEvent; +import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; +import org.jetbrains.annotations.ApiStatus; + +import java.util.Map; + +/** + * Allows users to register custom {@link ITextureAtlasSpriteLoader texture atlas sprite loaders}. + * + *

This event is not {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}. + * + *

This event is fired on the {@linkplain FMLJavaModLoadingContext#getModEventBus() mod-specific event bus}, + * only on the {@linkplain LogicalSide#CLIENT logical client}.

+ */ +public class RegisterTextureAtlasSpriteLoadersEvent extends Event implements IModBusEvent +{ + private final Map loaders; + + @ApiStatus.Internal + public RegisterTextureAtlasSpriteLoadersEvent(Map loaders) + { + this.loaders = loaders; + } + + /** + * Registers a custom {@link ITextureAtlasSpriteLoader sprite loader}. + */ + public void register(String name, ITextureAtlasSpriteLoader loader) + { + var key = new ResourceLocation(ModLoadingContext.get().getActiveNamespace(), name); + Preconditions.checkArgument(!loaders.containsKey(key), "Sprite loader already registered: " + key); + loaders.put(key, loader); + } +} diff --git a/src/main/java/net/minecraftforge/client/event/RenderArmEvent.java b/src/main/java/net/minecraftforge/client/event/RenderArmEvent.java index 247fb56fd84..a8c28ec119e 100644 --- a/src/main/java/net/minecraftforge/client/event/RenderArmEvent.java +++ b/src/main/java/net/minecraftforge/client/event/RenderArmEvent.java @@ -14,6 +14,7 @@ import net.minecraftforge.eventbus.api.Cancelable; import net.minecraftforge.eventbus.api.Event; import net.minecraftforge.fml.LogicalSide; +import org.jetbrains.annotations.ApiStatus; /** * Fired before the player's arm is rendered in first person. This is a more targeted version of {@link RenderHandEvent}, @@ -21,10 +22,10 @@ * replacing the arm with armor. * *

This event is {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}. - * If this event is cancelled, then the arm will not be rendered.

+ * If this event is cancelled, then the arm will not be rendered.

* *

This event is fired on the {@linkplain MinecraftForge#EVENT_BUS main Forge event bus}, - * only on the {@linkplain LogicalSide#CLIENT logical client}.

+ * only on the {@linkplain LogicalSide#CLIENT logical client}.

*/ @Cancelable public class RenderArmEvent extends Event @@ -35,10 +36,7 @@ public class RenderArmEvent extends Event private final AbstractClientPlayer player; private final HumanoidArm arm; - /** - * @hidden - * @see net.minecraftforge.client.ForgeHooksClient#renderSpecificFirstPersonArm(PoseStack, MultiBufferSource, int, AbstractClientPlayer, HumanoidArm) - */ + @ApiStatus.Internal public RenderArmEvent(PoseStack poseStack, MultiBufferSource multiBufferSource, int packedLight, AbstractClientPlayer player, HumanoidArm arm) { this.poseStack = poseStack; diff --git a/src/main/java/net/minecraftforge/client/event/RenderBlockOverlayEvent.java b/src/main/java/net/minecraftforge/client/event/RenderBlockScreenEffectEvent.java similarity index 72% rename from src/main/java/net/minecraftforge/client/event/RenderBlockOverlayEvent.java rename to src/main/java/net/minecraftforge/client/event/RenderBlockScreenEffectEvent.java index 352ec7fddde..e526f13df09 100644 --- a/src/main/java/net/minecraftforge/client/event/RenderBlockOverlayEvent.java +++ b/src/main/java/net/minecraftforge/client/event/RenderBlockScreenEffectEvent.java @@ -6,35 +6,34 @@ package net.minecraftforge.client.event; import com.mojang.blaze3d.vertex.PoseStack; - -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.entity.player.Player; import net.minecraft.core.BlockPos; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.block.state.BlockState; import net.minecraftforge.common.MinecraftForge; -import net.minecraftforge.event.ForgeEventFactory; import net.minecraftforge.eventbus.api.Cancelable; import net.minecraftforge.eventbus.api.Event; import net.minecraftforge.fml.LogicalSide; +import org.jetbrains.annotations.ApiStatus; /** * Fired before a block texture will be overlaid on the player's view. * *

This event is {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}. - * If this event is cancelled, then the overlay will not be rendered.

+ * If this event is cancelled, then the overlay will not be rendered.

* *

This event is fired on the {@linkplain MinecraftForge#EVENT_BUS main Forge event bus}, - * only on the {@linkplain LogicalSide#CLIENT logical client}.

+ * only on the {@linkplain LogicalSide#CLIENT logical client}.

*/ @Cancelable -public class RenderBlockOverlayEvent extends Event +public class RenderBlockScreenEffectEvent extends Event { - /** * The type of the block overlay to be rendered. * - * @see RenderBlockOverlayEvent + * @see RenderBlockScreenEffectEvent */ - public enum OverlayType { + public enum OverlayType + { /** * The type of the overlay when the player is burning / on fire. */ @@ -55,37 +54,53 @@ public enum OverlayType { private final BlockState blockState; private final BlockPos blockPos; - /** - * @hidden - */ - public RenderBlockOverlayEvent(Player player, PoseStack poseStack, OverlayType type, BlockState block, BlockPos blockPos) + @ApiStatus.Internal + public RenderBlockScreenEffectEvent(Player player, PoseStack poseStack, OverlayType type, BlockState block, BlockPos blockPos) { this.player = player; this.poseStack = poseStack; this.overlayType = type; this.blockState = block; this.blockPos = blockPos; - } /** * {@return the player which the overlay will apply to} */ - public Player getPlayer() { return player; } + public Player getPlayer() + { + return player; + } + /** * {@return the pose stack used for rendering} */ - public PoseStack getPoseStack() { return poseStack; } + public PoseStack getPoseStack() + { + return poseStack; + } + /** * {@return the type of the overlay} */ - public OverlayType getOverlayType() { return overlayType; } + public OverlayType getOverlayType() + { + return overlayType; + } + /** * {@return the block which the overlay is gotten from} */ - public BlockState getBlockState() { return blockState; } + public BlockState getBlockState() + { + return blockState; + } + /** * {@return the position of the block which the overlay is gotten from} */ - public BlockPos getBlockPos() { return blockPos; } + public BlockPos getBlockPos() + { + return blockPos; + } } diff --git a/src/main/java/net/minecraftforge/client/event/RenderGameOverlayEvent.java b/src/main/java/net/minecraftforge/client/event/RenderGameOverlayEvent.java deleted file mode 100644 index 2f52c177513..00000000000 --- a/src/main/java/net/minecraftforge/client/event/RenderGameOverlayEvent.java +++ /dev/null @@ -1,436 +0,0 @@ -/* - * Copyright (c) Forge Development LLC and contributors - * SPDX-License-Identifier: LGPL-2.1-only - */ - -package net.minecraftforge.client.event; - -import java.util.ArrayList; - -import com.mojang.blaze3d.vertex.PoseStack; -import net.minecraftforge.client.gui.ForgeIngameGui; -import net.minecraftforge.client.gui.IIngameOverlay; -import net.minecraftforge.common.MinecraftForge; -import net.minecraftforge.eventbus.api.Cancelable; -import net.minecraftforge.eventbus.api.Event; -import com.mojang.blaze3d.platform.Window; -import net.minecraft.client.gui.components.LerpingBossEvent; -import net.minecraftforge.fml.LogicalSide; - -/** - * Fired when an overlay element is rendered to the game window. - * See the two subclasses for listening to before and after rendering. - * - *

An overlay that is not normally active cannot be forced to render, and this event will not fire.

- * - * @see RenderGameOverlayEvent.Pre - * @see RenderGameOverlayEvent.Post - * @see ForgeIngameGui - */ -@Cancelable -public class RenderGameOverlayEvent extends Event -{ - /** - * {@return the pose stack used for rendering} - */ - public PoseStack getPoseStack() - { - return poseStack; - } - - /** - * {@return the partial tick} - */ - public float getPartialTick() - { - return partialTick; - } - - /** - * {@return the game window} - */ - public Window getWindow() - { - return window; - } - - /** - * {@return the type of the overlay element being rendered} - */ - public ElementType getType() - { - return type; - } - - /** - * The types of the different overlay elements that can be rendered - */ - public enum ElementType - { - /** - * Represents all of the overlay elements; cancelling the {@link RenderGameOverlayEvent.Pre} with this type - * will suppress rendering of all overlay elements. - */ - ALL, - /** - * An in-game overlay layer. - * - * @see IIngameOverlay - * @see RenderGameOverlayEvent.PreLayer - * @see RenderGameOverlayEvent.PostLayer - */ - LAYER, - /** - * An individual boss event bar. - * - * @see RenderGameOverlayEvent.BossInfo - */ - BOSSINFO, - /** - * For adding text to be rendered on the screen (after the debug screen text, if visible). - * - * @see RenderGameOverlayEvent.Text - */ - TEXT, - /** - * The chat message window overlay. - * - * @see RenderGameOverlayEvent.Chat - */ - CHAT, - /** - * The player list overlay, shown when the TAB key (or other keybind) is pressed. - * - * See {@code ForgeIngameGui#renderPlayerList} - */ - PLAYER_LIST, - /** - * The debug overlay. - * - * See {@code ForgeIngameGui#renderHUDText.} - */ - DEBUG - } - - private final PoseStack poseStack; - private final float partialTick; - private final Window window; - private final ElementType type; - - /** - * @hidden - */ - public RenderGameOverlayEvent(PoseStack poseStack, float partialTick, Window window) - { - this.poseStack = poseStack; - this.partialTick = partialTick; - this.window = window; - this.type = null; - } - - /** - * @hidden - */ - private RenderGameOverlayEvent(PoseStack poseStack, RenderGameOverlayEvent parent, ElementType type) - { - this.poseStack = poseStack; - this.partialTick = parent.getPartialTick(); - this.window = parent.getWindow(); - this.type = type; - } - - /** - * Fired before an active overlay element is rendered to the screen. - * See the three sub-classes for specific special overlay elements. - * - *

This event is {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}. - * If this event is cancelled, then the overlay corresponding to this event will not be rendered, and the - * corresponding {@link RenderGameOverlayEvent.Post} event is not fired.

- * - *

This event is fired on the {@linkplain MinecraftForge#EVENT_BUS main Forge event bus}, - * only on the {@linkplain LogicalSide#CLIENT logical client}.

- * - * @see RenderGameOverlayEvent.PreLayer - * @see RenderGameOverlayEvent.BossInfo - * @see RenderGameOverlayEvent.Text - * @see RenderGameOverlayEvent.Chat - */ - public static class Pre extends RenderGameOverlayEvent - { - /** - * @hidden - */ - public Pre(PoseStack poseStack, RenderGameOverlayEvent parent, ElementType type) - { - super(poseStack, parent, type); - } - } - - /** - * Fired after an active overlay element is rendered to the screen, if the corresponding - * {@link RenderGameOverlayEvent.Pre} is not cancelled. - * See the specialized {@link RenderGameOverlayEvent.PostLayer} for individual overlay layer. - * - *

This event is not {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}.

- * - *

This event is fired on the {@linkplain MinecraftForge#EVENT_BUS main Forge event bus}, - * only on the {@linkplain LogicalSide#CLIENT logical client}.

- */ - public static class Post extends RenderGameOverlayEvent - { - /** - * @hidden - */ - public Post(PoseStack poseStack, RenderGameOverlayEvent parent, ElementType type) - { - super(poseStack, parent, type); - } - @Override public boolean isCancelable(){ return false; } - } - - /** - * Fired before an in-game overlay layer is rendered to the screen. - * - *

This event is {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}. - * If this event is cancelled, then the overlay layer in this event will not be rendered, and the - * corresponding {@link RenderGameOverlayEvent.PostLayer} event is not fired.

- * - *

This event is fired on the {@linkplain MinecraftForge#EVENT_BUS main Forge event bus}, - * only on the {@linkplain LogicalSide#CLIENT logical client}.

- * - * @see RenderGameOverlayEvent.PostLayer - */ - public static class PreLayer extends Pre - { - private final IIngameOverlay overlay; - - /** - * @hidden - */ - public PreLayer(PoseStack mStack, RenderGameOverlayEvent parent, IIngameOverlay overlay) - { - super(mStack, parent, ElementType.LAYER); - this.overlay = overlay; - } - - /** - * {@return the in-game overlay layer being rendered} - */ - public IIngameOverlay getOverlay() - { - return overlay; - } - } - - /** - * Fired after an in-game overlay layer is rendered to the screen, if the corresponding - * {@link RenderGameOverlayEvent.PreLayer} is not cancelled. - * - *

This event is not {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}.

- * - *

This event is fired on the {@linkplain MinecraftForge#EVENT_BUS main Forge event bus}, - * only on the {@linkplain LogicalSide#CLIENT logical client}.

- */ - public static class PostLayer extends Post - { - private final IIngameOverlay overlay; - - /** - * @hidden - */ - public PostLayer(PoseStack mStack, RenderGameOverlayEvent parent, IIngameOverlay overlay) - { - super(mStack, parent, ElementType.LAYER); - this.overlay = overlay; - } - - /** - * {@return the in-game overlay layer being rendered} - */ - public IIngameOverlay getOverlay() - { - return overlay; - } - } - - /** - * Fired before a boss health bar is rendered to the screen. - * - *

This event is {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}. - * If this event is cancelled, then the boss health bar corresponding to this event will not be rendered, and the - * corresponding {@link RenderGameOverlayEvent.Post} is not fired.

- * - *

This event is fired on the {@linkplain MinecraftForge#EVENT_BUS main Forge event bus}, - * only on the {@linkplain LogicalSide#CLIENT logical client}.

- * - * @see ElementType#BOSSINFO - */ - public static class BossInfo extends Pre - { - private final LerpingBossEvent bossEvent; - private final int x; - private final int y; - private int increment; - - /** - * @hidden - */ - public BossInfo(PoseStack mStack, RenderGameOverlayEvent parent, ElementType type, LerpingBossEvent bossEvent, int x, int y, int increment) - { - super(mStack, parent, type); - this.bossEvent = bossEvent; - this.x = x; - this.y = y; - this.increment = increment; - } - - /** - * {@return the boss health bar currently being rendered} - */ - public LerpingBossEvent getBossEvent() - { - return bossEvent; - } - - /** - * {@return the X position of the boss health bar} - */ - public int getX() - { - return x; - } - - /** - * {@return the Y position of the boss health bar} - */ - public int getY() - { - return y; - } - - /** - * {@return the Y position increment before rendering the next boss health bar} - */ - public int getIncrement() - { - return increment; - } - - /** - * Sets the Y position increment before rendering the next boss health bar. - * - * @param increment the new Y position increment - */ - public void setIncrement(int increment) - { - this.increment = increment; - } - } - - /** - * Fired before textual information is rendered to the debug screen. - * This can be used to add or remove text information. - * - *

This event is {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}. - * If this event is cancelled, then the text will not be rendered; this includes the debug overlay text.

- * - *

This event is fired on the {@linkplain MinecraftForge#EVENT_BUS main Forge event bus}, - * only on the {@linkplain LogicalSide#CLIENT logical client}.

- * - * @see ElementType#TEXT - */ - public static class Text extends Pre - { - private final ArrayList left; - private final ArrayList right; - - /** - * @hidden - */ - public Text(PoseStack mStack, RenderGameOverlayEvent parent, ArrayList left, ArrayList right) - { - super(mStack, parent, ElementType.TEXT); - this.left = left; - this.right = right; - } - - /** - * {@return the modifiable list of text to render on the left side} - */ - public ArrayList getLeft() - { - return left; - } - - /** - * {@return the modifiable list of text to render on the right side} - */ - public ArrayList getRight() - { - return right; - } - } - - /** - * Fired before the chat messages overlay is rendered to the screen. - * - *

This event is {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}. - * If this event is cancelled, then the chat messages overlay will not be rendered.

- * - *

This event is fired on the {@linkplain MinecraftForge#EVENT_BUS main Forge event bus}, - * only on the {@linkplain LogicalSide#CLIENT logical client}.

- * - * @see ElementType#CHAT - */ - public static class Chat extends Pre - { - private int posX; - private int posY; - - /** - * @hidden - */ - public Chat(PoseStack mStack, RenderGameOverlayEvent parent, int posX, int posY) - { - super(mStack, parent, ElementType.CHAT); - this.setPosX(posX); - this.setPosY(posY); - } - - /** - * {@return the X position of the chat messages overlay} - */ - public int getPosX() - { - return posX; - } - - /** - * Sets the new X position for rendering the chat messages overlay - * - * @param posX the new X position - */ - public void setPosX(int posX) - { - this.posX = posX; - } - - /** - * {@return the Y position of the chat messages overlay} - */ - public int getPosY() - { - return posY; - } - - /** - * Sets the new Y position for rendering the chat messages overlay - * - * @param posY the new y position - */ - public void setPosY(int posY) - { - this.posY = posY; - } - } -} diff --git a/src/main/java/net/minecraftforge/client/event/RenderGuiEvent.java b/src/main/java/net/minecraftforge/client/event/RenderGuiEvent.java new file mode 100644 index 00000000000..c83ace69694 --- /dev/null +++ b/src/main/java/net/minecraftforge/client/event/RenderGuiEvent.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) Forge Development LLC and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.minecraftforge.client.event; + +import com.mojang.blaze3d.platform.Window; +import com.mojang.blaze3d.vertex.PoseStack; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.eventbus.api.Cancelable; +import net.minecraftforge.eventbus.api.Event; +import net.minecraftforge.fml.LogicalSide; +import org.jetbrains.annotations.ApiStatus; + +/** + * Fired when the HUD is rendered to the screen. + * See the two subclasses for listening to the two possible phases. + * + * @see Pre + * @see Post + */ +public abstract class RenderGuiEvent extends Event +{ + private final Window window; + private final PoseStack poseStack; + private final float partialTick; + + @ApiStatus.Internal + protected RenderGuiEvent(Window window, PoseStack poseStack, float partialTick) + { + this.window = window; + this.poseStack = poseStack; + this.partialTick = partialTick; + } + + public Window getWindow() + { + return window; + } + + public PoseStack getPoseStack() + { + return poseStack; + } + + public float getPartialTick() + { + return partialTick; + } + + /** + * Fired before the HUD is rendered to the screen. + * + *

This event is {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}. + * If this event is cancelled, then the overlay will not be rendered, and the corresponding {@link Post} event will + * not be fired.

+ * + *

This event is fired on the {@linkplain MinecraftForge#EVENT_BUS main Forge event bus}, + * only on the {@linkplain LogicalSide#CLIENT logical client}.

+ * + * @see Post + */ + @Cancelable + public static class Pre extends RenderGuiEvent + { + @ApiStatus.Internal + public Pre(Window window, PoseStack poseStack, float partialTick) + { + super(window, poseStack, partialTick); + } + } + + /** + * Fired after the HUD is rendered to the screen, if the corresponding {@link Pre} is not cancelled. + * + *

This event is not {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}.

+ * + *

This event is fired on the {@linkplain MinecraftForge#EVENT_BUS main Forge event bus}, + * only on the {@linkplain LogicalSide#CLIENT logical client}.

+ */ + public static class Post extends RenderGuiEvent + { + @ApiStatus.Internal + public Post(Window window, PoseStack poseStack, float partialTick) + { + super(window, poseStack, partialTick); + } + } +} diff --git a/src/main/java/net/minecraftforge/client/event/RenderGuiOverlayEvent.java b/src/main/java/net/minecraftforge/client/event/RenderGuiOverlayEvent.java new file mode 100644 index 00000000000..78bd0a05bef --- /dev/null +++ b/src/main/java/net/minecraftforge/client/event/RenderGuiOverlayEvent.java @@ -0,0 +1,100 @@ +/* + * Copyright (c) Forge Development LLC and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.minecraftforge.client.event; + +import com.mojang.blaze3d.platform.Window; +import com.mojang.blaze3d.vertex.PoseStack; +import net.minecraftforge.client.gui.overlay.NamedGuiOverlay; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.eventbus.api.Cancelable; +import net.minecraftforge.eventbus.api.Event; +import net.minecraftforge.fml.LogicalSide; +import org.jetbrains.annotations.ApiStatus; + +/** + * Fired when an overlay is rendered to the screen. + * See the two subclasses for listening to the two possible phases. + * + *

An overlay that is not normally active cannot be forced to render. In such cases, this event will not fire.

+ * + * @see Pre + * @see Post + */ +public abstract class RenderGuiOverlayEvent extends Event +{ + private final Window window; + private final PoseStack poseStack; + private final float partialTick; + private final NamedGuiOverlay overlay; + + @ApiStatus.Internal + protected RenderGuiOverlayEvent(Window window, PoseStack poseStack, float partialTick, NamedGuiOverlay overlay) + { + this.overlay = overlay; + this.window = window; + this.poseStack = poseStack; + this.partialTick = partialTick; + } + + public Window getWindow() + { + return window; + } + + public PoseStack getPoseStack() + { + return poseStack; + } + + public float getPartialTick() + { + return partialTick; + } + + public NamedGuiOverlay getOverlay() + { + return overlay; + } + + /** + * Fired before a GUI overlay is rendered to the screen. + * + *

This event is {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}. + * If this event is cancelled, then the overlay will not be rendered, and the corresponding {@link Post} event will + * not be fired.

+ * + *

This event is fired on the {@linkplain MinecraftForge#EVENT_BUS main Forge event bus}, + * only on the {@linkplain LogicalSide#CLIENT logical client}.

+ * + * @see Post + */ + @Cancelable + public static class Pre extends RenderGuiOverlayEvent + { + @ApiStatus.Internal + public Pre(Window window, PoseStack poseStack, float partialTick, NamedGuiOverlay overlay) + { + super(window, poseStack, partialTick, overlay); + } + } + + /** + * Fired after an GUI overlay is rendered to the screen, if the corresponding {@link Pre} is not cancelled. + * + *

This event is not {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}.

+ * + *

This event is fired on the {@linkplain MinecraftForge#EVENT_BUS main Forge event bus}, + * only on the {@linkplain LogicalSide#CLIENT logical client}.

+ */ + public static class Post extends RenderGuiOverlayEvent + { + @ApiStatus.Internal + public Post(Window window, PoseStack poseStack, float partialTick, NamedGuiOverlay overlay) + { + super(window, poseStack, partialTick, overlay); + } + } +} diff --git a/src/main/java/net/minecraftforge/client/event/RenderHandEvent.java b/src/main/java/net/minecraftforge/client/event/RenderHandEvent.java index 235316eb8fe..e67267dce4b 100644 --- a/src/main/java/net/minecraftforge/client/event/RenderHandEvent.java +++ b/src/main/java/net/minecraftforge/client/event/RenderHandEvent.java @@ -6,24 +6,24 @@ package net.minecraftforge.client.event; import com.mojang.blaze3d.vertex.PoseStack; - import net.minecraft.client.renderer.LightTexture; import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.world.item.ItemStack; import net.minecraft.world.InteractionHand; +import net.minecraft.world.item.ItemStack; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.eventbus.api.Cancelable; import net.minecraftforge.eventbus.api.Event; import net.minecraftforge.fml.LogicalSide; +import org.jetbrains.annotations.ApiStatus; /** * Fired before a hand is rendered in the first person view. * *

This event is {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}. - * If this event is cancelled, then the hand will not be rendered.

+ * If this event is cancelled, then the hand will not be rendered.

* *

This event is fired on the {@linkplain MinecraftForge#EVENT_BUS main Forge event bus}, - * only on the {@linkplain LogicalSide#CLIENT logical client}.

+ * only on the {@linkplain LogicalSide#CLIENT logical client}.

* * @see RenderArmEvent */ @@ -40,10 +40,7 @@ public class RenderHandEvent extends Event private final float equipProgress; private final ItemStack stack; - /** - * @hidden - * @see net.minecraftforge.client.ForgeHooksClient#renderSpecificFirstPersonHand(InteractionHand, PoseStack, MultiBufferSource, int, float, float, float, float, ItemStack) - */ + @ApiStatus.Internal public RenderHandEvent(InteractionHand hand, PoseStack poseStack, MultiBufferSource multiBufferSource, int packedLight, float partialTick, float interpolatedPitch, float swingProgress, float equipProgress, ItemStack stack) @@ -78,7 +75,8 @@ public PoseStack getPoseStack() /** * {@return the source of rendering buffers} */ - public MultiBufferSource getMultiBufferSource() { + public MultiBufferSource getMultiBufferSource() + { return multiBufferSource; } @@ -87,7 +85,8 @@ public MultiBufferSource getMultiBufferSource() { * * @see LightTexture */ - public int getPackedLight() { + public int getPackedLight() + { return packedLight; } diff --git a/src/main/java/net/minecraftforge/client/event/DrawSelectionEvent.java b/src/main/java/net/minecraftforge/client/event/RenderHighlightEvent.java similarity index 65% rename from src/main/java/net/minecraftforge/client/event/DrawSelectionEvent.java rename to src/main/java/net/minecraftforge/client/event/RenderHighlightEvent.java index 01d7feccb3c..325e8d5e9ed 100644 --- a/src/main/java/net/minecraftforge/client/event/DrawSelectionEvent.java +++ b/src/main/java/net/minecraftforge/client/event/RenderHighlightEvent.java @@ -6,26 +6,27 @@ package net.minecraftforge.client.event; import com.mojang.blaze3d.vertex.PoseStack; +import net.minecraft.client.Camera; +import net.minecraft.client.renderer.LevelRenderer; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.EntityHitResult; +import net.minecraft.world.phys.HitResult; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.eventbus.api.Cancelable; import net.minecraftforge.eventbus.api.Event; -import net.minecraft.world.phys.HitResult; -import net.minecraft.client.Camera; -import net.minecraft.client.renderer.LevelRenderer; import net.minecraftforge.fml.LogicalSide; +import org.jetbrains.annotations.ApiStatus; /** * Fired before a selection highlight is rendered. * See the two subclasses to listen for blocks or entities. * - * @see DrawSelectionEvent.HighlightBlock - * @see DrawSelectionEvent.HighlightEntity + * @see Block + * @see Entity */ @Cancelable -public class DrawSelectionEvent extends Event +public abstract class RenderHighlightEvent extends Event { private final LevelRenderer levelRenderer; private final Camera camera; @@ -34,11 +35,8 @@ public class DrawSelectionEvent extends Event private final PoseStack poseStack; private final MultiBufferSource multiBufferSource; - /** - * @hidden - * @see net.minecraftforge.client.ForgeHooksClient#onDrawHighlight(LevelRenderer, Camera, HitResult, float, PoseStack, MultiBufferSource) - */ - public DrawSelectionEvent(LevelRenderer levelRenderer, Camera camera, HitResult target, float partialTick, PoseStack poseStack, MultiBufferSource multiBufferSource) + @ApiStatus.Internal + protected RenderHighlightEvent(LevelRenderer levelRenderer, Camera camera, HitResult target, float partialTick, PoseStack poseStack, MultiBufferSource multiBufferSource) { this.levelRenderer = levelRenderer; this.camera = camera; @@ -51,44 +49,65 @@ public DrawSelectionEvent(LevelRenderer levelRenderer, Camera camera, HitResult /** * {@return the level renderer} */ - public LevelRenderer getLevelRenderer() { return levelRenderer; } + public LevelRenderer getLevelRenderer() + { + return levelRenderer; + } + /** * {@return the camera information} */ - public Camera getCamera() { return camera; } + public Camera getCamera() + { + return camera; + } + /** * {@return the hit result which triggered the selection highlight} */ - public HitResult getTarget() { return target; } + public HitResult getTarget() + { + return target; + } + /** * {@return the partial tick} */ - public float getPartialTick() { return partialTick; } + public float getPartialTick() + { + return partialTick; + } + /** * {@return the pose stack used for rendering} */ - public PoseStack getPoseStack() { return poseStack; } + public PoseStack getPoseStack() + { + return poseStack; + } + /** * {@return the source of rendering buffers} */ - public MultiBufferSource getMultiBufferSource() { return multiBufferSource; } + public MultiBufferSource getMultiBufferSource() + { + return multiBufferSource; + } /** * Fired before a block's selection highlight is rendered. * *

This event is {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}. - * If the event is cancelled, then the selection highlight will not be rendered.

+ * If the event is cancelled, then the selection highlight will not be rendered.

* *

This event is fired on the {@linkplain MinecraftForge#EVENT_BUS main Forge event bus}, - * only on the {@linkplain LogicalSide#CLIENT logical client}.

+ * only on the {@linkplain LogicalSide#CLIENT logical client}.

*/ @Cancelable - public static class HighlightBlock extends DrawSelectionEvent + public static class Block extends RenderHighlightEvent { - /** - * @hidden - */ - public HighlightBlock(LevelRenderer levelRenderer, Camera camera, BlockHitResult target, float partialTick, PoseStack poseStack, MultiBufferSource bufferSource) + @ApiStatus.Internal + public Block(LevelRenderer levelRenderer, Camera camera, BlockHitResult target, float partialTick, PoseStack poseStack, MultiBufferSource bufferSource) { super(levelRenderer, camera, target, partialTick, poseStack, bufferSource); } @@ -104,19 +123,17 @@ public BlockHitResult getTarget() } /** - * Fired before a block's selection highlight is rendered. + * Fired before an entity's selection highlight is rendered. * - *

This event is not {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}.

+ *

This event is not {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}.

* *

This event is fired on the {@linkplain MinecraftForge#EVENT_BUS main Forge event bus}, - * only on the {@linkplain LogicalSide#CLIENT logical client}.

+ * only on the {@linkplain LogicalSide#CLIENT logical client}.

*/ - public static class HighlightEntity extends DrawSelectionEvent + public static class Entity extends RenderHighlightEvent { - /** - * @hidden - */ - public HighlightEntity(LevelRenderer levelRenderer, Camera camera, EntityHitResult target, float partialTick, PoseStack poseStack, MultiBufferSource bufferSource) + @ApiStatus.Internal + public Entity(LevelRenderer levelRenderer, Camera camera, EntityHitResult target, float partialTick, PoseStack poseStack, MultiBufferSource bufferSource) { super(levelRenderer, camera, target, partialTick, poseStack, bufferSource); } diff --git a/src/main/java/net/minecraftforge/client/event/RenderItemInFrameEvent.java b/src/main/java/net/minecraftforge/client/event/RenderItemInFrameEvent.java index e09bf39709c..a0e39146b5d 100644 --- a/src/main/java/net/minecraftforge/client/event/RenderItemInFrameEvent.java +++ b/src/main/java/net/minecraftforge/client/event/RenderItemInFrameEvent.java @@ -15,7 +15,7 @@ import net.minecraftforge.eventbus.api.Cancelable; import net.minecraftforge.eventbus.api.Event; import net.minecraftforge.fml.LogicalSide; -import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.ApiStatus; /** * Fired before an item stack is rendered in an item frame. @@ -25,7 +25,7 @@ * If the event is cancelled, then the item stack will not be rendered

* *

This event is fired on the {@linkplain MinecraftForge#EVENT_BUS main Forge event bus}, - * only on the {@linkplain LogicalSide#CLIENT logical client}.

+ * only on the {@linkplain LogicalSide#CLIENT logical client}.

* * @see ItemFrameRenderer */ @@ -39,9 +39,7 @@ public class RenderItemInFrameEvent extends Event private final MultiBufferSource multiBufferSource; private final int packedLight; - /** - * @hidden - */ + @ApiStatus.Internal public RenderItemInFrameEvent(ItemFrame itemFrame, ItemFrameRenderer renderItemFrame, PoseStack poseStack, MultiBufferSource multiBufferSource, int packedLight) { @@ -80,14 +78,16 @@ public ItemFrameRenderer getRenderer() /** * {@return the pose stack used for rendering} */ - public PoseStack getPoseStack() { + public PoseStack getPoseStack() + { return poseStack; } /** * {@return the source of rendering buffers} */ - public MultiBufferSource getMultiBufferSource() { + public MultiBufferSource getMultiBufferSource() + { return multiBufferSource; } @@ -96,7 +96,8 @@ public MultiBufferSource getMultiBufferSource() { * * @see LightTexture */ - public int getPackedLight() { + public int getPackedLight() + { return packedLight; } } diff --git a/src/main/java/net/minecraftforge/client/event/RenderLevelLastEvent.java b/src/main/java/net/minecraftforge/client/event/RenderLevelLastEvent.java index f9a7ac680d8..2076d99c654 100644 --- a/src/main/java/net/minecraftforge/client/event/RenderLevelLastEvent.java +++ b/src/main/java/net/minecraftforge/client/event/RenderLevelLastEvent.java @@ -6,23 +6,22 @@ package net.minecraftforge.client.event; import com.mojang.blaze3d.vertex.PoseStack; - +import com.mojang.math.Matrix4f; import net.minecraft.client.renderer.GameRenderer; import net.minecraft.client.renderer.LevelRenderer; -import com.mojang.math.Matrix4f; -import net.minecraftforge.client.ForgeHooksClient; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.eventbus.api.Cancelable; import net.minecraftforge.fml.LogicalSide; +import org.jetbrains.annotations.ApiStatus; /** * Fired after all level rendering. * This can be used for custom rendering outside of e.g. a block entity or entity renderer. * - *

This event is not {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}.

+ *

This event is not {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}.

* *

This event is fired on the {@linkplain MinecraftForge#EVENT_BUS main Forge event bus}, - * only on the {@linkplain LogicalSide#CLIENT logical client}.

+ * only on the {@linkplain LogicalSide#CLIENT logical client}.

* * @see GameRenderer * @see LevelRenderer @@ -35,10 +34,7 @@ public class RenderLevelLastEvent extends net.minecraftforge.eventbus.api.Event private final Matrix4f projectionMatrix; private final long startNanos; - /** - * @hidden - * @see ForgeHooksClient#dispatchRenderLast(LevelRenderer, PoseStack, float, Matrix4f, long) - */ + @ApiStatus.Internal public RenderLevelLastEvent(LevelRenderer levelRenderer, PoseStack poseStack, float partialTick, Matrix4f projectionMatrix, long startNanos) { this.levelRenderer = levelRenderer; diff --git a/src/main/java/net/minecraftforge/client/event/RenderLivingEvent.java b/src/main/java/net/minecraftforge/client/event/RenderLivingEvent.java index a4feb85f0ba..9eb7859ae59 100644 --- a/src/main/java/net/minecraftforge/client/event/RenderLivingEvent.java +++ b/src/main/java/net/minecraftforge/client/event/RenderLivingEvent.java @@ -6,15 +6,16 @@ package net.minecraftforge.client.event; import com.mojang.blaze3d.vertex.PoseStack; +import net.minecraft.client.model.EntityModel; import net.minecraft.client.renderer.LightTexture; import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.entity.LivingEntityRenderer; +import net.minecraft.world.entity.LivingEntity; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.eventbus.api.Cancelable; import net.minecraftforge.eventbus.api.Event; -import net.minecraft.client.renderer.entity.LivingEntityRenderer; -import net.minecraft.client.model.EntityModel; -import net.minecraft.world.entity.LivingEntity; import net.minecraftforge.fml.LogicalSide; +import org.jetbrains.annotations.ApiStatus; /** * Fired when a {@link LivingEntity} is rendered. @@ -25,7 +26,6 @@ * * @param the living entity that is being rendered * @param the model for the living entity - * * @see RenderLivingEvent.Pre * @see RenderLivingEvent.Post * @see RenderPlayerEvent @@ -33,7 +33,6 @@ */ public abstract class RenderLivingEvent> extends Event { - private final LivingEntity entity; private final LivingEntityRenderer renderer; private final float partialTick; @@ -41,11 +40,9 @@ public abstract class RenderLivingEvent renderer, float partialTick, PoseStack poseStack, - MultiBufferSource multiBufferSource, int packedLight) + @ApiStatus.Internal + protected RenderLivingEvent(LivingEntity entity, LivingEntityRenderer renderer, float partialTick, PoseStack poseStack, + MultiBufferSource multiBufferSource, int packedLight) { this.entity = entity; this.renderer = renderer; @@ -58,29 +55,52 @@ public RenderLivingEvent(LivingEntity entity, LivingEntityRenderer rendere /** * @return the living entity being rendered */ - public LivingEntity getEntity() { return entity; } + public LivingEntity getEntity() + { + return entity; + } + /** * @return the renderer for the living entity */ - public LivingEntityRenderer getRenderer() { return renderer; } + public LivingEntityRenderer getRenderer() + { + return renderer; + } + /** * {@return the partial tick} */ - public float getPartialTick() { return partialTick; } + public float getPartialTick() + { + return partialTick; + } + /** * {@return the pose stack used for rendering} */ - public PoseStack getPoseStack() { return poseStack; } + public PoseStack getPoseStack() + { + return poseStack; + } + /** * {@return the source of rendering buffers} */ - public MultiBufferSource getMultiBufferSource() { return multiBufferSource; } + public MultiBufferSource getMultiBufferSource() + { + return multiBufferSource; + } + /** * {@return the amount of packed (sky and block) light for rendering} * * @see LightTexture */ - public int getPackedLight() { return packedLight; } + public int getPackedLight() + { + return packedLight; + } /** * Fired before an entity is rendered. @@ -88,10 +108,10 @@ public RenderLivingEvent(LivingEntity entity, LivingEntityRenderer rendere * *

This event is {@linkplain Cancelable cancelable}, and does not {@linkplain HasResult have a result}. * If this event is cancelled, then the entity will not be rendered and the corresponding - * {@link RenderLivingEvent.Post} will not be fired.

+ * {@link RenderLivingEvent.Post} will not be fired.

* *

This event is fired on the {@linkplain MinecraftForge#EVENT_BUS main Forge event bus}, - * only on the {@linkplain LogicalSide#CLIENT logical client}.

+ * only on the {@linkplain LogicalSide#CLIENT logical client}.

* * @param the living entity that is being rendered * @param the model for the living entity @@ -99,10 +119,9 @@ public RenderLivingEvent(LivingEntity entity, LivingEntityRenderer rendere @Cancelable public static class Pre> extends RenderLivingEvent { - /** - * @hidden - */ - public Pre(LivingEntity entity, LivingEntityRenderer renderer, float partialTick, PoseStack poseStack, MultiBufferSource multiBufferSource, int packedLight) { + @ApiStatus.Internal + public Pre(LivingEntity entity, LivingEntityRenderer renderer, float partialTick, PoseStack poseStack, MultiBufferSource multiBufferSource, int packedLight) + { super(entity, renderer, partialTick, poseStack, multiBufferSource, packedLight); } } @@ -110,20 +129,19 @@ public Pre(LivingEntity entity, LivingEntityRenderer renderer, float parti /** * Fired after an entity is rendered, if the corresponding {@link RenderLivingEvent.Post} is not cancelled. * - *

This event is not {@linkplain Cancelable cancelable}, and does not {@linkplain HasResult have a result}.

+ *

This event is not {@linkplain Cancelable cancelable}, and does not {@linkplain HasResult have a result}.

* *

This event is fired on the {@linkplain MinecraftForge#EVENT_BUS main Forge event bus}, - * only on the {@linkplain LogicalSide#CLIENT logical client}.

+ * only on the {@linkplain LogicalSide#CLIENT logical client}.

* * @param the living entity that was rendered * @param the model for the living entity */ public static class Post> extends RenderLivingEvent { - /** - * @hidden - */ - public Post(LivingEntity entity, LivingEntityRenderer renderer, float partialTick, PoseStack poseStack, MultiBufferSource multiBufferSource, int packedLight) { + @ApiStatus.Internal + public Post(LivingEntity entity, LivingEntityRenderer renderer, float partialTick, PoseStack poseStack, MultiBufferSource multiBufferSource, int packedLight) + { super(entity, renderer, partialTick, poseStack, multiBufferSource, packedLight); } } diff --git a/src/main/java/net/minecraftforge/client/event/RenderNameplateEvent.java b/src/main/java/net/minecraftforge/client/event/RenderNameTagEvent.java similarity index 88% rename from src/main/java/net/minecraftforge/client/event/RenderNameplateEvent.java rename to src/main/java/net/minecraftforge/client/event/RenderNameTagEvent.java index 6ef07b3216d..aafaa8f1c1f 100644 --- a/src/main/java/net/minecraftforge/client/event/RenderNameplateEvent.java +++ b/src/main/java/net/minecraftforge/client/event/RenderNameTagEvent.java @@ -8,18 +8,19 @@ import com.mojang.blaze3d.vertex.PoseStack; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.entity.EntityRenderer; -import net.minecraft.world.entity.Entity; import net.minecraft.network.chat.Component; +import net.minecraft.world.entity.Entity; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.event.entity.EntityEvent; import net.minecraftforge.eventbus.api.Cancelable; import net.minecraftforge.eventbus.api.Event; import net.minecraftforge.fml.LogicalSide; +import org.jetbrains.annotations.ApiStatus; /** * Fired before an entity renderer renders the nameplate of an entity. * - *

This event is not {@linkplain Cancelable cancellable}, and {@linkplain HasResult has a result}.

+ *

This event is not {@linkplain Cancelable cancellable}, and {@linkplain HasResult has a result}.

*
    *
  • {@link Result#ALLOW} - the nameplate will be forcibly rendered.
  • *
  • {@link Result#DEFAULT} - the vanilla logic will be used.
  • @@ -27,14 +28,13 @@ *
* *

This event is fired on the {@linkplain MinecraftForge#EVENT_BUS main Forge event bus}, - * only on the {@linkplain LogicalSide#CLIENT logical client}.

+ * only on the {@linkplain LogicalSide#CLIENT logical client}.

* * @see EntityRenderer */ @Event.HasResult -public class RenderNameplateEvent extends EntityEvent +public class RenderNameTagEvent extends EntityEvent { - private Component nameplateContent; private final Component originalContent; private final EntityRenderer entityRenderer; @@ -43,10 +43,8 @@ public class RenderNameplateEvent extends EntityEvent private final int packedLight; private final float partialTick; - /** - * @hidden - */ - public RenderNameplateEvent(Entity entity, Component content, EntityRenderer entityRenderer, PoseStack poseStack, MultiBufferSource multiBufferSource, int packedLight, float partialTick) + @ApiStatus.Internal + public RenderNameTagEvent(Entity entity, Component content, EntityRenderer entityRenderer, PoseStack poseStack, MultiBufferSource multiBufferSource, int packedLight, float partialTick) { super(entity); this.originalContent = content; diff --git a/src/main/java/net/minecraftforge/client/event/RenderPlayerEvent.java b/src/main/java/net/minecraftforge/client/event/RenderPlayerEvent.java index 25268034241..4990d62e538 100644 --- a/src/main/java/net/minecraftforge/client/event/RenderPlayerEvent.java +++ b/src/main/java/net/minecraftforge/client/event/RenderPlayerEvent.java @@ -8,12 +8,13 @@ import com.mojang.blaze3d.vertex.PoseStack; import net.minecraft.client.renderer.LightTexture; import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraftforge.common.MinecraftForge; -import net.minecraftforge.eventbus.api.Cancelable; import net.minecraft.client.renderer.entity.player.PlayerRenderer; import net.minecraft.world.entity.player.Player; +import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.event.entity.player.PlayerEvent; +import net.minecraftforge.eventbus.api.Cancelable; import net.minecraftforge.fml.LogicalSide; +import org.jetbrains.annotations.ApiStatus; /** * Fired when a player is being rendered. @@ -31,10 +32,8 @@ public abstract class RenderPlayerEvent extends PlayerEvent private final MultiBufferSource multiBufferSource; private final int packedLight; - /** - * @hidden - */ - public RenderPlayerEvent(Player player, PlayerRenderer renderer, float partialTick, PoseStack poseStack, MultiBufferSource multiBufferSource, int packedLight) + @ApiStatus.Internal + protected RenderPlayerEvent(Player player, PlayerRenderer renderer, float partialTick, PoseStack poseStack, MultiBufferSource multiBufferSource, int packedLight) { super(player); this.renderer = renderer; @@ -47,25 +46,44 @@ public RenderPlayerEvent(Player player, PlayerRenderer renderer, float partialTi /** * {@return the player entity renderer} */ - public PlayerRenderer getRenderer() { return renderer; } + public PlayerRenderer getRenderer() + { + return renderer; + } + /** * {@return the partial tick} */ - public float getPartialTick() { return partialTick; } + public float getPartialTick() + { + return partialTick; + } + /** * {@return the pose stack used for rendering} */ - public PoseStack getPoseStack() { return poseStack; } + public PoseStack getPoseStack() + { + return poseStack; + } + /** * {@return the source of rendering buffers} */ - public MultiBufferSource getMultiBufferSource() { return multiBufferSource; } + public MultiBufferSource getMultiBufferSource() + { + return multiBufferSource; + } + /** * {@return the amount of packed (sky and block) light for rendering} * * @see LightTexture */ - public int getPackedLight() { return packedLight; } + public int getPackedLight() + { + return packedLight; + } /** * Fired before the player is rendered. @@ -73,18 +91,17 @@ public RenderPlayerEvent(Player player, PlayerRenderer renderer, float partialTi * *

This event is {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}. * If this event is cancelled, then the player will not be rendered and the corresponding - * {@link RenderPlayerEvent.Post} will not be fired.

+ * {@link RenderPlayerEvent.Post} will not be fired.

* *

This event is fired on the {@linkplain MinecraftForge#EVENT_BUS main Forge event bus}, - * only on the {@linkplain LogicalSide#CLIENT logical client}.

+ * only on the {@linkplain LogicalSide#CLIENT logical client}.

*/ @Cancelable public static class Pre extends RenderPlayerEvent { - /** - * @hidden - */ - public Pre(Player player, PlayerRenderer renderer, float partialTick, PoseStack poseStack, MultiBufferSource multiBufferSource, int packedLight) { + @ApiStatus.Internal + public Pre(Player player, PlayerRenderer renderer, float partialTick, PoseStack poseStack, MultiBufferSource multiBufferSource, int packedLight) + { super(player, renderer, partialTick, poseStack, multiBufferSource, packedLight); } } @@ -92,19 +109,17 @@ public Pre(Player player, PlayerRenderer renderer, float partialTick, PoseStack /** * Fired after the player is rendered, if the corresponding {@link RenderPlayerEvent.Pre} is not cancelled. * - *

This event is not {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}.

+ *

This event is not {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}.

* *

This event is fired on the {@linkplain MinecraftForge#EVENT_BUS main Forge event bus}, - * only on the {@linkplain LogicalSide#CLIENT logical client}.

+ * only on the {@linkplain LogicalSide#CLIENT logical client}.

*/ public static class Post extends RenderPlayerEvent { - /** - * @hidden - */ - public Post(Player player, PlayerRenderer renderer, float partialTick, PoseStack poseStack, MultiBufferSource multiBufferSource, int packedLight) { + @ApiStatus.Internal + public Post(Player player, PlayerRenderer renderer, float partialTick, PoseStack poseStack, MultiBufferSource multiBufferSource, int packedLight) + { super(player, renderer, partialTick, poseStack, multiBufferSource, packedLight); } } - } diff --git a/src/main/java/net/minecraftforge/client/event/RenderTooltipEvent.java b/src/main/java/net/minecraftforge/client/event/RenderTooltipEvent.java index e4a8e357d36..786e2f8740a 100644 --- a/src/main/java/net/minecraftforge/client/event/RenderTooltipEvent.java +++ b/src/main/java/net/minecraftforge/client/event/RenderTooltipEvent.java @@ -5,23 +5,24 @@ package net.minecraftforge.client.event; -import java.util.Collections; -import java.util.List; - import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.datafixers.util.Either; import net.minecraft.client.gui.Font; import net.minecraft.client.gui.screens.inventory.tooltip.ClientTooltipComponent; +import net.minecraft.network.chat.FormattedText; import net.minecraft.world.inventory.tooltip.TooltipComponent; import net.minecraft.world.item.ItemStack; -import net.minecraft.network.chat.FormattedText; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.event.entity.player.ItemTooltipEvent; import net.minecraftforge.eventbus.api.Cancelable; import net.minecraftforge.eventbus.api.Event; import net.minecraftforge.fml.LogicalSide; +import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; +import java.util.Collections; +import java.util.List; + /** * Fired during tooltip rendering. * See the various subclasses for listening to specific events. @@ -40,11 +41,8 @@ public abstract class RenderTooltipEvent extends net.minecraftforge.eventbus.api protected Font font; protected final List components; - - /** - * @hidden - */ - public RenderTooltipEvent(@NotNull ItemStack itemStack, PoseStack poseStack, int x, int y, @NotNull Font font, @NotNull List components) + @ApiStatus.Internal + protected RenderTooltipEvent(@NotNull ItemStack itemStack, PoseStack poseStack, int x, int y, @NotNull Font font, @NotNull List components) { this.itemStack = itemStack; this.poseStack = poseStack; @@ -64,16 +62,18 @@ public ItemStack getItemStack() return itemStack; } - /** * {@return the pose stack used for rendering} */ - public PoseStack getPoseStack() { return poseStack; } + public PoseStack getPoseStack() + { + return poseStack; + } /** * {@return the unmodifiable list of tooltip components} * - *

Use {@link ItemTooltipEvent} or {@link GatherComponents} to modify tooltip contents or components.

+ *

Use {@link ItemTooltipEvent} or {@link GatherComponents} to modify tooltip contents or components.

*/ @NotNull public List getComponents() @@ -82,7 +82,7 @@ public List getComponents() } /** - *{@return the X position of the tooltip box} By default, this is the mouse X position. + * {@return the X position of the tooltip box} By default, this is the mouse X position. */ public int getX() { @@ -112,10 +112,10 @@ public Font getFont() * *

This event is {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}. * If this event is cancelled, then the list of components will be empty, causing the tooltip to not be rendered and - * the corresponding {@link RenderTooltipEvent.Pre} and {@link RenderTooltipEvent.Color} to not be fired.

+ * the corresponding {@link RenderTooltipEvent.Pre} and {@link RenderTooltipEvent.Color} to not be fired.

* *

This event is fired on the {@linkplain MinecraftForge#EVENT_BUS main Forge event bus}, - * only on the {@linkplain LogicalSide#CLIENT logical client}.

+ * only on the {@linkplain LogicalSide#CLIENT logical client}.

*/ @Cancelable public static class GatherComponents extends Event @@ -126,9 +126,7 @@ public static class GatherComponents extends Event private final List> tooltipElements; private int maxWidth; - /** - * @hidden - */ + @ApiStatus.Internal public GatherComponents(ItemStack itemStack, int screenWidth, int screenHeight, List> tooltipElements, int maxWidth) { this.itemStack = itemStack; @@ -203,10 +201,10 @@ public void setMaxWidth(int maxWidth) * *

This event is {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}. * If this event is cancelled, then the tooltip will not be rendered and the corresponding - * {@link RenderTooltipEvent.Color} will not be fired.

+ * {@link RenderTooltipEvent.Color} will not be fired.

* *

This event is fired on the {@linkplain MinecraftForge#EVENT_BUS main Forge event bus}, - * only on the {@linkplain LogicalSide#CLIENT logical client}.

+ * only on the {@linkplain LogicalSide#CLIENT logical client}.

*/ @Cancelable public static class Pre extends RenderTooltipEvent @@ -214,9 +212,7 @@ public static class Pre extends RenderTooltipEvent private final int screenWidth; private final int screenHeight; - /** - * @hidden - */ + @ApiStatus.Internal public Pre(@NotNull ItemStack stack, PoseStack poseStack, int x, int y, int screenWidth, int screenHeight, @NotNull Font font, @NotNull List components) { super(stack, poseStack, x, y, font, components); @@ -278,10 +274,10 @@ public void setY(int y) * Fired when the colours for the tooltip background are determined. * This can be used to modify the background color and the border's gradient colors. * - *

This event is not {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}.

+ *

This event is not {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}.

* *

This event is fired on the {@linkplain MinecraftForge#EVENT_BUS main Forge event bus}, - * only on the {@linkplain LogicalSide#CLIENT logical client}.

+ * only on the {@linkplain LogicalSide#CLIENT logical client}.

*/ public static class Color extends RenderTooltipEvent { @@ -293,9 +289,7 @@ public static class Color extends RenderTooltipEvent private int borderStart; private int borderEnd; - /** - * @hidden - */ + @ApiStatus.Internal public Color(@NotNull ItemStack stack, PoseStack poseStack, int x, int y, @NotNull Font fr, int background, int borderStart, int borderEnd, @NotNull List components) { super(stack, poseStack, x, y, fr, components); @@ -324,7 +318,6 @@ public int getBackgroundEnd() return backgroundEnd; } - /** * Sets the new color for the tooltip background. This sets both the gradient start and end color for the * background to this color. diff --git a/src/main/java/net/minecraftforge/client/event/ScreenEvent.java b/src/main/java/net/minecraftforge/client/event/ScreenEvent.java index d6b7c55910b..84795aa1522 100644 --- a/src/main/java/net/minecraftforge/client/event/ScreenEvent.java +++ b/src/main/java/net/minecraftforge/client/event/ScreenEvent.java @@ -5,49 +5,46 @@ package net.minecraftforge.client.event; -import java.util.Collections; -import java.util.List; -import java.util.Objects; -import java.util.function.Consumer; - import com.mojang.blaze3d.platform.InputConstants; import com.mojang.blaze3d.vertex.PoseStack; -import net.minecraft.client.MouseHandler; import net.minecraft.client.gui.components.events.GuiEventListener; +import net.minecraft.client.gui.screens.Screen; import net.minecraft.client.gui.screens.inventory.EffectRenderingInventoryScreen; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; -import net.minecraft.client.gui.screens.Screen; - -import net.minecraftforge.client.ForgeHooksClient; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.eventbus.api.Cancelable; import net.minecraftforge.eventbus.api.Event; import net.minecraftforge.fml.LogicalSide; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.Nullable; import org.lwjgl.glfw.GLFW; +import java.util.Collections; +import java.util.List; +import java.util.Objects; +import java.util.function.Consumer; + /** * Fired on different events/actions when a {@link Screen} is active and visible. * See the various subclasses for listening to different events. * *

These events are fired on the {@linkplain MinecraftForge#EVENT_BUS main Forge event bus}, - * only on the {@linkplain LogicalSide#CLIENT logical client}.

+ * only on the {@linkplain LogicalSide#CLIENT logical client}.

* - * @see ScreenEvent.InitScreenEvent - * @see ScreenEvent.DrawScreenEvent - * @see ScreenEvent.BackgroundDrawnEvent - * @see ScreenEvent.MouseInputEvent - * @see ScreenEvent.KeyboardKeyEvent + * @see Init + * @see Render + * @see BackgroundRendered + * @see MouseInput + * @see KeyInput */ @OnlyIn(Dist.CLIENT) -public class ScreenEvent extends Event +public abstract class ScreenEvent extends Event { private final Screen screen; - /** - * @hidden - */ - public ScreenEvent(Screen screen) + @ApiStatus.Internal + protected ScreenEvent(Screen screen) { this.screen = Objects.requireNonNull(screen); } @@ -68,26 +65,25 @@ public Screen getScreen() * {@link net.minecraft.client.gui.components.Widget} and {@link net.minecraft.client.gui.narration.NarratableEntry} * respectively.

* - * @see InitScreenEvent.Pre - * @see InitScreenEvent.Post + * @see Init.Pre + * @see Init.Post */ - public static class InitScreenEvent extends ScreenEvent + public static abstract class Init extends ScreenEvent { private final Consumer add; private final Consumer remove; private final List listenerList; - /** - * @hidden - */ - public InitScreenEvent(Screen screen, List listenerList, Consumer add, Consumer remove) + @ApiStatus.Internal + protected Init(Screen screen, List listenerList, Consumer add, Consumer remove) { super(screen); this.listenerList = Collections.unmodifiableList(listenerList); this.add = add; this.remove = remove; } + /** * {@return unmodifiable view of list of event listeners on the screen} */ @@ -121,17 +117,15 @@ public void removeListener(GuiEventListener listener) * *

This event is {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}. * If the event is cancelled, the initialization method will not be called, and the widgets and children lists - * will not be cleared.

+ * will not be cleared.

* *

This event is fired on the {@linkplain MinecraftForge#EVENT_BUS main Forge event bus}, - * only on the {@linkplain LogicalSide#CLIENT logical client}.

+ * only on the {@linkplain LogicalSide#CLIENT logical client}.

*/ @Cancelable - public static class Pre extends InitScreenEvent + public static class Pre extends Init { - /** - * @hidden - */ + @ApiStatus.Internal public Pre(Screen screen, List list, Consumer add, Consumer remove) { super(screen, list, add, remove); @@ -141,16 +135,14 @@ public Pre(Screen screen, List list, Consumerafter the screen's overridable initialization method is called. * - *

This event is not {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}.

+ *

This event is not {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}.

* *

This event is fired on the {@linkplain MinecraftForge#EVENT_BUS main Forge event bus}, - * only on the {@linkplain LogicalSide#CLIENT logical client}.

+ * only on the {@linkplain LogicalSide#CLIENT logical client}.

*/ - public static class Post extends InitScreenEvent + public static class Post extends Init { - /** - * @hidden - */ + @ApiStatus.Internal public Post(Screen screen, List list, Consumer add, Consumer remove) { super(screen, list, add, remove); @@ -162,21 +154,18 @@ public Post(Screen screen, List list, Consumerbefore the screen is drawn. * *

This event is {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}. - * If the event is cancelled, the screen will not be drawn.

+ * If the event is cancelled, the screen will not be drawn.

* *

This event is fired on the {@linkplain MinecraftForge#EVENT_BUS main Forge event bus}, - * only on the {@linkplain LogicalSide#CLIENT logical client}.

+ * only on the {@linkplain LogicalSide#CLIENT logical client}.

*/ @Cancelable - public static class Pre extends DrawScreenEvent + public static class Pre extends Render { - /** - * @hidden - */ + @ApiStatus.Internal public Pre(Screen screen, PoseStack poseStack, int mouseX, int mouseY, float partialTick) { super(screen, poseStack, mouseX, mouseY, partialTick); @@ -241,16 +228,14 @@ public Pre(Screen screen, PoseStack poseStack, int mouseX, int mouseY, float par /** * Fired after the screen is drawn. * - *

This event is not {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}.

+ *

This event is not {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}.

* *

This event is fired on the {@linkplain MinecraftForge#EVENT_BUS main Forge event bus}, - * only on the {@linkplain LogicalSide#CLIENT logical client}.

+ * only on the {@linkplain LogicalSide#CLIENT logical client}.

*/ - public static class Post extends DrawScreenEvent + public static class Post extends Render { - /** - * @hidden - */ + @ApiStatus.Internal public Post(Screen screen, PoseStack poseStack, int mouseX, int mouseY, float partialTick) { super(screen, poseStack, mouseX, mouseY, partialTick); @@ -262,19 +247,17 @@ public Post(Screen screen, PoseStack poseStack, int mouseX, int mouseY, float pa * Fired directly after the background of the screen is drawn. * Can be used for drawing above the background but below the tooltips. * - *

This event is not {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}.

+ *

This event is not {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}.

* *

This event is fired on the {@linkplain MinecraftForge#EVENT_BUS main Forge event bus}, - * only on the {@linkplain LogicalSide#CLIENT logical client}.

+ * only on the {@linkplain LogicalSide#CLIENT logical client}.

*/ - public static class BackgroundDrawnEvent extends ScreenEvent + public static class BackgroundRendered extends ScreenEvent { private final PoseStack poseStack; - /** - * @hidden - */ - public BackgroundDrawnEvent(Screen screen, PoseStack poseStack) + @ApiStatus.Internal + public BackgroundRendered(Screen screen, PoseStack poseStack) { super(screen); this.poseStack = poseStack; @@ -290,29 +273,51 @@ public PoseStack getPoseStack() } /** - * Fired to determine whether to render the potion indicators in the {@link EffectRenderingInventoryScreen inventory - * screen} in compact or classic mode. + * Fired ahead of rendering any active mob effects in the {@link EffectRenderingInventoryScreen inventory screen}. + * Can be used to select the size of the effects display (full or compact) or even hide or replace vanilla's rendering entirely. * - *

This event is not {@linkplain Cancelable cancellable} and {@linkplain HasResult has a result}.

- *
    - *
  • {@link Result#ALLOW} - forcibly renders the potion indicators in compact mode.
  • - *
  • {@link Result#DEFAULT} - defaults to vanilla behavior to using compact mode if the the screen width is too - * small for classic rendering of potion indicators.
  • - *
  • {@link Result#DENY} - forcibly renders the potion indicators in classic mode.
  • - *
+ *

This event is {@linkplain Cancelable cancellable} and does not {@linkplain HasResult have a result}. + * Cancelling this event will prevent vanilla rendering.

* *

This event is fired on the {@linkplain MinecraftForge#EVENT_BUS main Forge event bus}, - * only on the {@linkplain LogicalSide#CLIENT logical client}.

+ * only on the {@linkplain LogicalSide#CLIENT logical client}.

*/ - @HasResult - public static class PotionSizeEvent extends ScreenEvent + @Cancelable + public static class RenderInventoryMobEffects extends ScreenEvent { + private final int availableSpace; + private boolean compact; + + @ApiStatus.Internal + public RenderInventoryMobEffects(Screen screen, int availableSpace, boolean compact) + { + super(screen); + this.availableSpace = availableSpace; + this.compact = compact; + } + /** - * @hidden For internal use only. + * The available space to the right of the inventory. */ - public PotionSizeEvent(Screen screen) + public int getAvailableSpace() { - super(screen); + return availableSpace; + } + + /** + * Whether the effects should be rendered in compact mode (only icons, no text), or the default full size. + */ + public boolean isCompact() + { + return compact; + } + + /** + * Sets whether the effects should be rendered in compact mode (only icons, no text), or the default full size. + */ + public void setCompact(boolean compact) + { + this.compact = compact; } } @@ -320,20 +325,18 @@ public PotionSizeEvent(Screen screen) * Fired whenever an action is performed by the mouse. * See the various subclasses to listen for different actions. * - * @see ScreenEvent.MouseClickedEvent - * @see ScreenEvent.MouseReleasedEvent - * @see ScreenEvent.MouseDragEvent - * @see ScreenEvent.MouseScrollEvent + * @see MouseButtonPressed + * @see MouseButtonReleased + * @see MouseDragged + * @see MouseScrolled */ - public static abstract class MouseInputEvent extends ScreenEvent + private static abstract class MouseInput extends ScreenEvent { private final double mouseX; private final double mouseY; - /** - * @hidden - */ - public MouseInputEvent(Screen screen, double mouseX, double mouseY) + @ApiStatus.Internal + protected MouseInput(Screen screen, double mouseX, double mouseY) { super(screen); this.mouseX = mouseX; @@ -358,20 +361,18 @@ public double getMouseY() } /** - * Fired when a mouse button is clicked. + * Fired when a mouse button is pressed. * See the two subclasses for listening before and after the normal handling. * - * @see MouseClickedEvent.Pre - * @see MouseClickedEvent.Post + * @see MouseButtonPressed.Pre + * @see MouseButtonPressed.Post */ - public static abstract class MouseClickedEvent extends MouseInputEvent + public static abstract class MouseButtonPressed extends MouseInput { private final int button; - /** - * @hidden - */ - public MouseClickedEvent(Screen screen, double mouseX, double mouseY, int button) + @ApiStatus.Internal + public MouseButtonPressed(Screen screen, double mouseX, double mouseY, int button) { super(screen, mouseX, mouseY); this.button = button; @@ -393,18 +394,15 @@ public int getButton() * *

This event is {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}. * If the event is cancelled, the screen's mouse click handler will be bypassed - * and the corresponding {@link MouseClickedEvent.Post} will not be fired.

+ * and the corresponding {@link MouseButtonPressed.Post} will not be fired.

* *

This event is fired on the {@linkplain MinecraftForge#EVENT_BUS main Forge event bus}, - * only on the {@linkplain LogicalSide#CLIENT logical client}.

+ * only on the {@linkplain LogicalSide#CLIENT logical client}.

*/ @Cancelable - public static class Pre extends MouseClickedEvent + public static class Pre extends MouseButtonPressed { - /** - * @hidden - * @see ForgeHooksClient#onScreenMouseClickedPre(Screen, double, double, int) - */ + @ApiStatus.Internal public Pre(Screen screen, double mouseX, double mouseY, int button) { super(screen, mouseX, mouseY, button); @@ -412,10 +410,10 @@ public Pre(Screen screen, double mouseX, double mouseY, int button) } /** - * Fired after the mouse click is handled, if the corresponding {@link MouseClickedEvent.Pre} was not + * Fired after the mouse click is handled, if the corresponding {@link MouseButtonPressed.Pre} was not * cancelled. * - *

This event is not {@linkplain Cancelable cancellable}, {@linkplain HasResult has a result}.

+ *

This event is not {@linkplain Cancelable cancellable}, {@linkplain HasResult has a result}.

*
    *
  • {@link Result#ALLOW} - forcibly sets the mouse click as handled
  • *
  • {@link Result#DEFAULT} - defaults to the return value of @@ -424,17 +422,14 @@ public Pre(Screen screen, double mouseX, double mouseY, int button) *
* *

This event is fired on the {@linkplain MinecraftForge#EVENT_BUS main Forge event bus}, - * only on the {@linkplain LogicalSide#CLIENT logical client}.

+ * only on the {@linkplain LogicalSide#CLIENT logical client}.

*/ @HasResult - public static class Post extends MouseClickedEvent + public static class Post extends MouseButtonPressed { private final boolean handled; - /** - * @hidden - * @see ForgeHooksClient#onScreenMouseClickedPost(Screen, double, double, int, boolean) - */ + @ApiStatus.Internal public Post(Screen screen, double mouseX, double mouseY, int button, boolean handled) { super(screen, mouseX, mouseY, button); @@ -455,17 +450,15 @@ public boolean wasHandled() * Fired when a mouse button is released. * See the two subclasses for listening before and after the normal handling. * - * @see MouseReleasedEvent.Pre - * @see MouseReleasedEvent.Post + * @see MouseButtonReleased.Pre + * @see MouseButtonReleased.Post */ - public static abstract class MouseReleasedEvent extends MouseInputEvent + public static abstract class MouseButtonReleased extends MouseInput { private final int button; - /** - * @hidden - */ - public MouseReleasedEvent(Screen screen, double mouseX, double mouseY, int button) + @ApiStatus.Internal + public MouseButtonReleased(Screen screen, double mouseX, double mouseY, int button) { super(screen, mouseX, mouseY); this.button = button; @@ -487,18 +480,15 @@ public int getButton() * *

This event is {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}. * If the event is cancelled, the screen's mouse release handler will be bypassed - * and the corresponding {@link MouseReleasedEvent.Post} will not be fired.

+ * and the corresponding {@link MouseButtonReleased.Post} will not be fired.

* *

This event is fired on the {@linkplain MinecraftForge#EVENT_BUS main Forge event bus}, - * only on the {@linkplain LogicalSide#CLIENT logical client}.

+ * only on the {@linkplain LogicalSide#CLIENT logical client}.

*/ @Cancelable - public static class Pre extends MouseReleasedEvent + public static class Pre extends MouseButtonReleased { - /** - * @hidden - * @see ForgeHooksClient#onScreenMouseReleasedPre(Screen, double, double, int) - */ + @ApiStatus.Internal public Pre(Screen screen, double mouseX, double mouseY, int button) { super(screen, mouseX, mouseY, button); @@ -506,10 +496,10 @@ public Pre(Screen screen, double mouseX, double mouseY, int button) } /** - * Fired after the mouse release is handled, if the corresponding {@link MouseReleasedEvent.Pre} was + * Fired after the mouse release is handled, if the corresponding {@link MouseButtonReleased.Pre} was * not cancelled. * - *

This event is not {@linkplain Cancelable cancellable}, {@linkplain HasResult has a result}.

+ *

This event is not {@linkplain Cancelable cancellable}, {@linkplain HasResult has a result}.

*
    *
  • {@link Result#ALLOW} - forcibly sets the mouse release as handled
  • *
  • {@link Result#DEFAULT} - defaults to the return value of @@ -518,17 +508,14 @@ public Pre(Screen screen, double mouseX, double mouseY, int button) *
* *

This event is fired on the {@linkplain MinecraftForge#EVENT_BUS main Forge event bus}, - * only on the {@linkplain LogicalSide#CLIENT logical client}.

+ * only on the {@linkplain LogicalSide#CLIENT logical client}.

*/ @HasResult - public static class Post extends MouseReleasedEvent + public static class Post extends MouseButtonReleased { private final boolean handled; - /** - * @hidden - * @see ForgeHooksClient#onScreenMouseReleasedPost(Screen, double, double, int, boolean) - */ + @ApiStatus.Internal public Post(Screen screen, double mouseX, double mouseY, int button, boolean handled) { super(screen, mouseX, mouseY, button); @@ -549,19 +536,17 @@ public boolean wasHandled() * Fired when the mouse was dragged while a button is being held down. * See the two subclasses for listening before and after the normal handling. * - * @see MouseDragEvent.Pre - * @see MouseDragEvent.Post + * @see MouseDragged.Pre + * @see MouseDragged.Post */ - public static abstract class MouseDragEvent extends MouseInputEvent + public static abstract class MouseDragged extends MouseInput { private final int mouseButton; private final double dragX; private final double dragY; - /** - * @hidden - */ - public MouseDragEvent(Screen screen, double mouseX, double mouseY, int mouseButton, double dragX, double dragY) + @ApiStatus.Internal + public MouseDragged(Screen screen, double mouseX, double mouseY, int mouseButton, double dragX, double dragY) { super(screen, mouseX, mouseY); this.mouseButton = mouseButton; @@ -601,18 +586,15 @@ public double getDragY() * *

This event is {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}. * If the event is cancelled, the screen's mouse drag handler will be bypassed - * and the corresponding {@link MouseDragEvent.Post} will not be fired.

+ * and the corresponding {@link MouseDragged.Post} will not be fired.

* *

This event is fired on the {@linkplain MinecraftForge#EVENT_BUS main Forge event bus}, - * only on the {@linkplain LogicalSide#CLIENT logical client}.

+ * only on the {@linkplain LogicalSide#CLIENT logical client}.

*/ @Cancelable - public static class Pre extends MouseDragEvent + public static class Pre extends MouseDragged { - /** - * @hidden - * @see ForgeHooksClient#onScreenMouseDragPre(Screen, double, double, int, double, double) - */ + @ApiStatus.Internal public Pre(Screen screen, double mouseX, double mouseY, int mouseButton, double dragX, double dragY) { super(screen, mouseX, mouseY, mouseButton, dragX, dragY); @@ -621,21 +603,17 @@ public Pre(Screen screen, double mouseX, double mouseY, int mouseButton, double /** * Fired after the mouse drag is handled, if not handled by the screen - * and the corresponding {@link MouseDragEvent.Pre} is not cancelled. + * and the corresponding {@link MouseDragged.Pre} is not cancelled. * - *

This event is {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}. - * If the event is cancelled, the mouse drag will be set as handled.

+ *

This event is not {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}. + * If the event is cancelled, the mouse drag will be set as handled.

* *

This event is fired on the {@linkplain MinecraftForge#EVENT_BUS main Forge event bus}, - * only on the {@linkplain LogicalSide#CLIENT logical client}.

+ * only on the {@linkplain LogicalSide#CLIENT logical client}.

*/ - @Cancelable - public static class Post extends MouseDragEvent + public static class Post extends MouseDragged { - /** - * @hidden - * @see ForgeHooksClient#onScreenMouseDragPost(Screen, double, double, int, double, double) - */ + @ApiStatus.Internal public Post(Screen screen, double mouseX, double mouseY, int mouseButton, double dragX, double dragY) { super(screen, mouseX, mouseY, mouseButton, dragX, dragY); @@ -647,17 +625,15 @@ public Post(Screen screen, double mouseX, double mouseY, int mouseButton, double * Fired when the mouse was dragged while a button is being held down. * See the two subclasses for listening before and after the normal handling. * - * @see MouseScrollEvent.Pre - * @see MouseScrollEvent.Post + * @see MouseScrolled.Pre + * @see MouseScrolled.Post */ - public static abstract class MouseScrollEvent extends MouseInputEvent + public static abstract class MouseScrolled extends MouseInput { private final double scrollDelta; - /** - * @hidden - */ - public MouseScrollEvent(Screen screen, double mouseX, double mouseY, double scrollDelta) + @ApiStatus.Internal + public MouseScrolled(Screen screen, double mouseX, double mouseY, double scrollDelta) { super(screen, mouseX, mouseY); this.scrollDelta = scrollDelta; @@ -676,18 +652,15 @@ public double getScrollDelta() * *

This event is {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}. * If the event is cancelled, the screen's mouse scroll handler will be bypassed - * and the corresponding {@link MouseScrollEvent.Post} will not be fired.

+ * and the corresponding {@link MouseScrolled.Post} will not be fired.

* *

This event is fired on the {@linkplain MinecraftForge#EVENT_BUS main Forge event bus}, - * only on the {@linkplain LogicalSide#CLIENT logical client}.

+ * only on the {@linkplain LogicalSide#CLIENT logical client}.

*/ @Cancelable - public static class Pre extends MouseScrollEvent + public static class Pre extends MouseScrolled { - /** - * @hidden - * @see ForgeHooksClient#onScreenMouseScrollPre(MouseHandler, Screen, double) - */ + @ApiStatus.Internal public Pre(Screen screen, double mouseX, double mouseY, double scrollDelta) { super(screen, mouseX, mouseY, scrollDelta); @@ -696,21 +669,17 @@ public Pre(Screen screen, double mouseX, double mouseY, double scrollDelta) /** * Fired after the mouse scroll is handled, if not handled by the screen - * and the corresponding {@link MouseScrollEvent.Pre} is not cancelled. + * and the corresponding {@link MouseScrolled.Pre} is not cancelled. * - *

This event is {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}. - * If the event is cancelled, the mouse scroll will be set as handled.

+ *

This event is not {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}. + * If the event is cancelled, the mouse scroll will be set as handled.

* *

This event is fired on the {@linkplain MinecraftForge#EVENT_BUS main Forge event bus}, - * only on the {@linkplain LogicalSide#CLIENT logical client}.

+ * only on the {@linkplain LogicalSide#CLIENT logical client}.

*/ - @Cancelable - public static class Post extends MouseScrollEvent + public static class Post extends MouseScrolled { - /** - * @hidden - * @see ForgeHooksClient#onScreenMouseScrollPost(MouseHandler, Screen, double) - */ + @ApiStatus.Internal public Post(Screen screen, double mouseX, double mouseY, double scrollDelta) { super(screen, mouseX, mouseY, scrollDelta); @@ -720,23 +689,21 @@ public Post(Screen screen, double mouseX, double mouseY, double scrollDelta) /** *

Fired whenever a keyboard key is pressed or released. - * See the various subclasses to listen for key pressing or releasing.

+ * See the various subclasses to listen for key pressing or releasing.

* - * @see ScreenEvent.KeyboardKeyPressedEvent - * @see ScreenEvent.KeyboardKeyReleasedEvent + * @see KeyPressed + * @see KeyReleased * @see InputConstants * @see the online GLFW documentation */ - public static abstract class KeyboardKeyEvent extends ScreenEvent + private static abstract class KeyInput extends ScreenEvent { private final int keyCode; private final int scanCode; private final int modifiers; - /** - * @hidden - */ - public KeyboardKeyEvent(Screen screen, int keyCode, int scanCode, int modifiers) + @ApiStatus.Internal + protected KeyInput(Screen screen, int keyCode, int scanCode, int modifiers) { super(screen); this.keyCode = keyCode; @@ -758,7 +725,7 @@ public int getKeyCode() /** * {@return the platform-specific scan code} - * + *

* The scan code is unique for every key, regardless of whether it has a key code. * Scan codes are platform-specific but consistent over time, so keys will have different scan codes depending * on the platform but they are safe to save to disk as custom key bindings. @@ -791,17 +758,15 @@ public int getModifiers() * Fired when a keyboard key is pressed. * See the two subclasses for listening before and after the normal handling. * - * @see KeyboardKeyPressedEvent.Pre - * @see KeyboardKeyPressedEvent.Post + * @see KeyPressed.Pre + * @see KeyPressed.Post */ - public static abstract class KeyboardKeyPressedEvent extends KeyboardKeyEvent + public static abstract class KeyPressed extends KeyInput { - /** - * @hidden - */ - public KeyboardKeyPressedEvent(Screen screen, int keyCode, int scanCode, int modifiers) + @ApiStatus.Internal + public KeyPressed(Screen screen, int keyCode, int scanCode, int modifiers) { - super(screen, keyCode, scanCode, modifiers); + super(screen, keyCode, scanCode, modifiers); } /** @@ -809,18 +774,15 @@ public KeyboardKeyPressedEvent(Screen screen, int keyCode, int scanCode, int mod * *

This event is {@linkplain Cancelable cancellable} and does not {@linkplain HasResult have a result}. * If the event is cancelled, the screen's key press handler will be bypassed - * and the corresponding {@link KeyboardKeyPressedEvent.Post} will not be fired.

+ * and the corresponding {@link KeyPressed.Post} will not be fired.

* *

This event is fired on the {@linkplain MinecraftForge#EVENT_BUS main Forge event bus}, - * only on the {@linkplain LogicalSide#CLIENT logical client}.

+ * only on the {@linkplain LogicalSide#CLIENT logical client}.

*/ @Cancelable - public static class Pre extends KeyboardKeyPressedEvent + public static class Pre extends KeyPressed { - /** - * @hidden - * @see ForgeHooksClient#onScreenKeyPressedPre(Screen, int, int, int) - */ + @ApiStatus.Internal public Pre(Screen screen, int keyCode, int scanCode, int modifiers) { super(screen, keyCode, scanCode, modifiers); @@ -829,21 +791,18 @@ public Pre(Screen screen, int keyCode, int scanCode, int modifiers) /** * Fired after the key press is handled, if not handled by the screen - * and the corresponding {@link KeyboardKeyPressedEvent.Pre} is not cancelled. + * and the corresponding {@link KeyPressed.Pre} is not cancelled. * *

This event is {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}. - * If the event is cancelled, the key press will be set as handled.

+ * If the event is cancelled, the key press will be set as handled.

* *

This event is fired on the {@linkplain MinecraftForge#EVENT_BUS main Forge event bus}, - * only on the {@linkplain LogicalSide#CLIENT logical client}.

+ * only on the {@linkplain LogicalSide#CLIENT logical client}.

*/ @Cancelable - public static class Post extends KeyboardKeyPressedEvent + public static class Post extends KeyPressed { - /** - * @hidden - * @see ForgeHooksClient#onScreenKeyPressedPost(Screen, int, int, int) - */ + @ApiStatus.Internal public Post(Screen screen, int keyCode, int scanCode, int modifiers) { super(screen, keyCode, scanCode, modifiers); @@ -855,15 +814,13 @@ public Post(Screen screen, int keyCode, int scanCode, int modifiers) * Fired when a keyboard key is released. * See the two subclasses for listening before and after the normal handling. * - * @see KeyboardKeyReleasedEvent.Pre - * @see KeyboardKeyReleasedEvent.Post + * @see KeyReleased.Pre + * @see KeyReleased.Post */ - public static abstract class KeyboardKeyReleasedEvent extends KeyboardKeyEvent + public static abstract class KeyReleased extends KeyInput { - /** - * @hidden - */ - public KeyboardKeyReleasedEvent(Screen screen, int keyCode, int scanCode, int modifiers) + @ApiStatus.Internal + public KeyReleased(Screen screen, int keyCode, int scanCode, int modifiers) { super(screen, keyCode, scanCode, modifiers); } @@ -873,18 +830,15 @@ public KeyboardKeyReleasedEvent(Screen screen, int keyCode, int scanCode, int mo * *

This event is {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}. * If the event is cancelled, the screen's key release handler will be bypassed - * and the corresponding {@link KeyboardKeyReleasedEvent.Post} will not be fired.

+ * and the corresponding {@link KeyReleased.Post} will not be fired.

* *

This event is fired on the {@linkplain MinecraftForge#EVENT_BUS main Forge event bus}, - * only on the {@linkplain LogicalSide#CLIENT logical client}.

+ * only on the {@linkplain LogicalSide#CLIENT logical client}.

*/ @Cancelable - public static class Pre extends KeyboardKeyReleasedEvent + public static class Pre extends KeyReleased { - /** - * @hidden - * @see ForgeHooksClient#onScreenKeyReleasedPre(Screen, int, int, int) - */ + @ApiStatus.Internal public Pre(Screen screen, int keyCode, int scanCode, int modifiers) { super(screen, keyCode, scanCode, modifiers); @@ -893,21 +847,18 @@ public Pre(Screen screen, int keyCode, int scanCode, int modifiers) /** * Fired after the key release is handled, if not handled by the screen - * and the corresponding {@link KeyboardKeyReleasedEvent.Pre} is not cancelled. + * and the corresponding {@link KeyReleased.Pre} is not cancelled. * *

This event is {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}. - * If the event is cancelled, the key release will be set as handled.

+ * If the event is cancelled, the key release will be set as handled.

* *

This event is fired on the {@linkplain MinecraftForge#EVENT_BUS main Forge event bus}, - * only on the {@linkplain LogicalSide#CLIENT logical client}.

+ * only on the {@linkplain LogicalSide#CLIENT logical client}.

*/ @Cancelable - public static class Post extends KeyboardKeyReleasedEvent + public static class Post extends KeyReleased { - /** - * @hidden - * @see ForgeHooksClient#onScreenKeyReleasedPost(Screen, int, int, int) - */ + @ApiStatus.Internal public Post(Screen screen, int keyCode, int scanCode, int modifiers) { super(screen, keyCode, scanCode, modifiers); @@ -919,19 +870,17 @@ public Post(Screen screen, int keyCode, int scanCode, int modifiers) * Fired when a keyboard key corresponding to a character is typed. * See the two subclasses for listening before and after the normal handling. * - * @see KeyboardCharTypedEvent.Pre - * @see KeyboardCharTypedEvent.Post + * @see CharacterTyped.Pre + * @see CharacterTyped.Post * @see the online GLFW documentation */ - public static class KeyboardCharTypedEvent extends ScreenEvent + public static class CharacterTyped extends ScreenEvent { private final char codePoint; private final int modifiers; - /** - * @hidden - */ - public KeyboardCharTypedEvent(Screen screen, char codePoint, int modifiers) + @ApiStatus.Internal + public CharacterTyped(Screen screen, char codePoint, int modifiers) { super(screen); this.codePoint = codePoint; @@ -967,18 +916,15 @@ public int getModifiers() * *

This event is {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}. * If the event is cancelled, the screen's character input handler will be bypassed - * and the corresponding {@link KeyboardCharTypedEvent.Post} will not be fired.

+ * and the corresponding {@link CharacterTyped.Post} will not be fired.

* *

This event is fired on the {@linkplain MinecraftForge#EVENT_BUS main Forge event bus}, - * only on the {@linkplain LogicalSide#CLIENT logical client}.

+ * only on the {@linkplain LogicalSide#CLIENT logical client}.

*/ @Cancelable - public static class Pre extends KeyboardCharTypedEvent + public static class Pre extends CharacterTyped { - /** - * @hidden - * @see ForgeHooksClient#onScreenCharTypedPre(Screen, char, int) - */ + @ApiStatus.Internal public Pre(Screen screen, char codePoint, int modifiers) { super(screen, codePoint, modifiers); @@ -987,25 +933,95 @@ public Pre(Screen screen, char codePoint, int modifiers) /** * Fired after the character input is handled, if not handled by the screen - * and the corresponding {@link KeyboardCharTypedEvent.Pre} is not cancelled. + * and the corresponding {@link CharacterTyped.Pre} is not cancelled. * *

This event is {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}. - * If the event is cancelled, the character input will be set as handled.

+ * If the event is cancelled, the character input will be set as handled.

* *

This event is fired on the {@linkplain MinecraftForge#EVENT_BUS main Forge event bus}, - * only on the {@linkplain LogicalSide#CLIENT logical client}.

+ * only on the {@linkplain LogicalSide#CLIENT logical client}.

*/ - @Cancelable - public static class Post extends KeyboardCharTypedEvent + public static class Post extends CharacterTyped { - /** - * @hidden - * @see ForgeHooksClient#onScreenCharTypedPost(Screen, char, int) - */ + @ApiStatus.Internal public Post(Screen screen, char codePoint, int modifiers) { super(screen, codePoint, modifiers); } } } + + /** + * Fired before any {@link Screen} is opened, to allow changing it or preventing it from being opened. + * All screen layers on the screen are closed before this event is fired. + * + *

This event is {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}. + * If this event is cancelled, then the {@code Screen} shall be prevented from opening and any previous screen + * will remain open. However, cancelling this event will not prevent the closing of screen layers which happened before + * this event fired.

+ * + *

This event is fired on the {@linkplain MinecraftForge#EVENT_BUS main Forge event bus}, + * only on the {@linkplain LogicalSide#CLIENT logical client}.

+ */ + @Cancelable + public static class Opening extends ScreenEvent + { + @Nullable + private final Screen currentScreen; + private Screen newScreen; + + @ApiStatus.Internal + public Opening(@Nullable Screen currentScreen, Screen screen) + { + super(screen); + this.currentScreen = currentScreen; + this.newScreen = screen; + } + + /** + * Gets the currently open screen at the time of the event being fired. + *

+ * May be null if no screen was open. + */ + @Nullable + public Screen getCurrentScreen() + { + return currentScreen; + } + + /** + * @return The screen that will be opened if the event is not cancelled. May be null. + */ + @Nullable + public Screen getNewScreen() + { + return newScreen; + } + + /** + * Sets the new screen to be opened if the event is not cancelled. May be null. + */ + public void setNewScreen(Screen newScreen) + { + this.newScreen = newScreen; + } + } + + /** + * Fired before a {@link Screen} is closed. + * All screen layers on the screen are closed before this event is fired. + * + *

This event is not {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}.

+ * + *

This event is fired on the {@linkplain MinecraftForge#EVENT_BUS main Forge event bus}, + * only on the {@linkplain LogicalSide#CLIENT logical client}.

+ */ + public static class Closing extends ScreenEvent + { + @ApiStatus.Internal + public Closing(Screen screen) + { + super(screen); + } + } } diff --git a/src/main/java/net/minecraftforge/client/event/ScreenOpenEvent.java b/src/main/java/net/minecraftforge/client/event/ScreenOpenEvent.java deleted file mode 100644 index b24f7ef52b9..00000000000 --- a/src/main/java/net/minecraftforge/client/event/ScreenOpenEvent.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) Forge Development LLC and contributors - * SPDX-License-Identifier: LGPL-2.1-only - */ - -package net.minecraftforge.client.event; - -import net.minecraftforge.common.MinecraftForge; -import net.minecraftforge.eventbus.api.Cancelable; -import net.minecraftforge.eventbus.api.Event; -import net.minecraft.client.gui.screens.Screen; -import net.minecraftforge.fml.LogicalSide; - -/** - * Fired before any {@link Screen} will be opened, to allow changing or preventing it from being opened. All screen - * layers on the screen are closed before this event is fired. - * - *

This event is {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}. - * If this event is cancelled, then the {@code Screen} shall be prevented from opening and any previous screen - * will remain open. However, cancelling this event will not prevent the closing of screen layers which happened before - * this event fired.

- * - *

This event is fired on the {@linkplain MinecraftForge#EVENT_BUS main Forge event bus}, - * only on the {@linkplain LogicalSide#CLIENT logical client}.

- */ -@Cancelable -public class ScreenOpenEvent extends Event -{ - private Screen screen; - - /** - * @hidden - */ - public ScreenOpenEvent(Screen screen) - { - this.setScreen(screen); - } - - /** - * {@return the screen that will be opened, if the event is not cancelled} - */ - public Screen getScreen() - { - return screen; - } - - /** - * Sets the new screen to be opened, if the event is not cancelled. - * - * @param screen the new screen - */ - public void setScreen(Screen screen) - { - this.screen = screen; - } -} diff --git a/src/main/java/net/minecraftforge/client/event/ScreenshotEvent.java b/src/main/java/net/minecraftforge/client/event/ScreenshotEvent.java index 49c83a06447..801edc482c4 100644 --- a/src/main/java/net/minecraftforge/client/event/ScreenshotEvent.java +++ b/src/main/java/net/minecraftforge/client/event/ScreenshotEvent.java @@ -12,6 +12,7 @@ import net.minecraftforge.eventbus.api.Cancelable; import net.minecraftforge.eventbus.api.Event; import net.minecraftforge.fml.LogicalSide; +import org.jetbrains.annotations.ApiStatus; import java.io.File; import java.io.IOException; @@ -24,14 +25,13 @@ * to the player's chat.

* *

This event is fired on the {@linkplain MinecraftForge#EVENT_BUS main Forge event bus}, - * only on the {@linkplain LogicalSide#CLIENT logical client}.

+ * only on the {@linkplain LogicalSide#CLIENT logical client}.

* * @see Screenshot */ @Cancelable public class ScreenshotEvent extends Event { - public static final Component DEFAULT_CANCEL_REASON = Component.literal("Screenshot canceled"); private final NativeImage image; @@ -39,17 +39,17 @@ public class ScreenshotEvent extends Event private Component resultMessage = null; - /** - * @hidden - * @see net.minecraftforge.client.ForgeHooksClient#onScreenshot(NativeImage, File) - */ + @ApiStatus.Internal public ScreenshotEvent(NativeImage image, File screenshotFile) { this.image = image; this.screenshotFile = screenshotFile; - try { + try + { this.screenshotFile = screenshotFile.getCanonicalFile(); // FORGE: Fix errors on Windows with paths that include \.\ - } catch (IOException ignored) {} + } catch (IOException ignored) + { + } } /** @@ -109,5 +109,4 @@ public Component getCancelMessage() { return getResultMessage() != null ? getResultMessage() : DEFAULT_CANCEL_REASON; } - } diff --git a/src/main/java/net/minecraftforge/client/event/TextureStitchEvent.java b/src/main/java/net/minecraftforge/client/event/TextureStitchEvent.java index 09832d42b5e..cbb0aed6799 100644 --- a/src/main/java/net/minecraftforge/client/event/TextureStitchEvent.java +++ b/src/main/java/net/minecraftforge/client/event/TextureStitchEvent.java @@ -5,18 +5,17 @@ package net.minecraftforge.client.event; +import net.minecraft.client.renderer.texture.TextureAtlas; import net.minecraft.resources.ResourceLocation; -import net.minecraftforge.client.ForgeHooksClient; import net.minecraftforge.eventbus.api.Cancelable; import net.minecraftforge.eventbus.api.Event; -import net.minecraft.client.renderer.texture.TextureAtlas; import net.minecraftforge.fml.LogicalSide; import net.minecraftforge.fml.event.IModBusEvent; import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; +import org.jetbrains.annotations.ApiStatus; import java.util.Set; - /** * Fired before and after a texture atlas stitched together. * See the two subclasses to listen for before and after stitching. @@ -29,9 +28,7 @@ public class TextureStitchEvent extends Event implements IModBusEvent { private final TextureAtlas atlas; - /** - * @hidden - */ + @ApiStatus.Internal public TextureStitchEvent(TextureAtlas atlas) { this.atlas = atlas; @@ -47,21 +44,18 @@ public TextureAtlas getAtlas() /** *

Fired before a texture atlas is stitched together. - * This can be used to add custom sprites to be stitched into the atlas.

+ * This can be used to add custom sprites to be stitched into the atlas.

* - *

This event is not {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}.

+ *

This event is not {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}.

* *

This event is fired on the {@linkplain FMLJavaModLoadingContext#getModEventBus()} mod-specific event bus}, - * only on the {@linkplain LogicalSide#CLIENT logical client}.

+ * only on the {@linkplain LogicalSide#CLIENT logical client}.

*/ public static class Pre extends TextureStitchEvent { private final Set sprites; - /** - * @hidden - * @see ForgeHooksClient#onTextureStitchedPre(TextureAtlas, Set) - */ + @ApiStatus.Internal public Pre(TextureAtlas map, Set sprites) { super(map); @@ -76,7 +70,8 @@ public Pre(TextureAtlas map, Set sprites) * * @param sprite the location of the sprite */ - public boolean addSprite(ResourceLocation sprite) { + public boolean addSprite(ResourceLocation sprite) + { return this.sprites.add(sprite); } } @@ -84,17 +79,17 @@ public boolean addSprite(ResourceLocation sprite) { /** * Fired after a texture atlas is stitched together and all textures therein has been loaded. * - *

This event is not {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}.

+ *

This event is not {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}.

* *

This event is fired on the {@linkplain FMLJavaModLoadingContext#getModEventBus()} mod-specific event bus}, - * only on the {@linkplain LogicalSide#CLIENT logical client}.

+ * only on the {@linkplain LogicalSide#CLIENT logical client}.

*/ public static class Post extends TextureStitchEvent { - /** - * @hidden - * @see ForgeHooksClient#onTextureStitchedPost(TextureAtlas) - */ - public Post(TextureAtlas map){ super(map); } + @ApiStatus.Internal + public Post(TextureAtlas map) + { + super(map); + } } } diff --git a/src/main/java/net/minecraftforge/client/event/EntityViewRenderEvent.java b/src/main/java/net/minecraftforge/client/event/ViewportEvent.java similarity index 72% rename from src/main/java/net/minecraftforge/client/event/EntityViewRenderEvent.java rename to src/main/java/net/minecraftforge/client/event/ViewportEvent.java index e42a9f1db26..237e7987d8a 100644 --- a/src/main/java/net/minecraftforge/client/event/EntityViewRenderEvent.java +++ b/src/main/java/net/minecraftforge/client/event/ViewportEvent.java @@ -5,18 +5,16 @@ package net.minecraftforge.client.event; -import net.minecraft.client.Minecraft; +import com.mojang.blaze3d.shaders.FogShape; import net.minecraft.client.Camera; +import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.GameRenderer; import net.minecraft.world.level.material.FogType; -import net.minecraft.client.multiplayer.ClientLevel; -import net.minecraft.client.renderer.FogRenderer; -import net.minecraftforge.client.ForgeHooksClient; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.eventbus.api.Cancelable; +import net.minecraftforge.eventbus.api.Event; import net.minecraftforge.fml.LogicalSide; - -import com.mojang.blaze3d.shaders.FogShape; +import org.jetbrains.annotations.ApiStatus; /** * Fired for hooking into the entity view rendering in {@link GameRenderer}. @@ -24,23 +22,21 @@ * See the various subclasses for listening to different features. * *

These events are fired on the {@linkplain MinecraftForge#EVENT_BUS main Forge event bus}, - * only on the {@linkplain LogicalSide#CLIENT logical client}.

+ * only on the {@linkplain LogicalSide#CLIENT logical client}.

* - * @see EntityViewRenderEvent.RenderFogEvent - * @see EntityViewRenderEvent.FogColors - * @see EntityViewRenderEvent.CameraSetup - * @see EntityViewRenderEvent.FieldOfView + * @see RenderFog + * @see ComputeFogColor + * @see ComputeCameraAngles + * @see ComputeFov */ -public abstract class EntityViewRenderEvent extends net.minecraftforge.eventbus.api.Event +public abstract class ViewportEvent extends Event { private final GameRenderer renderer; private final Camera camera; private final double partialTick; - /** - * @hidden - */ - public EntityViewRenderEvent(GameRenderer renderer, Camera camera, double partialTick) + @ApiStatus.Internal + public ViewportEvent(GameRenderer renderer, Camera camera, double partialTick) { this.renderer = renderer; this.camera = camera; @@ -72,28 +68,24 @@ public double getPartialTick() } /** - * Fired for customizing the rendering of the fog visible to the player. The plane distances are based on - * the player's render distance. + * Fired for rendering custom fog. The plane distances are based on the player's render distance. * *

This event is {@linkplain Cancelable cancellable}, and {@linkplain HasResult has a result}.
* The event must be cancelled for any changes to the plane distances to take effect.

* *

This event is fired on the {@linkplain MinecraftForge#EVENT_BUS main Forge event bus}, - * only on the {@linkplain LogicalSide#CLIENT logical client}.

+ * only on the {@linkplain LogicalSide#CLIENT logical client}.

*/ @Cancelable - public static class RenderFogEvent extends EntityViewRenderEvent + public static class RenderFog extends ViewportEvent { private final FogType type; private float farPlaneDistance; private float nearPlaneDistance; private FogShape fogShape; - /** - * @hidden - * @see ForgeHooksClient#onFogRender(FogType, Camera, float, float, float, FogShape) - */ - public RenderFogEvent(FogType type, Camera camera, float partialTicks, float nearPlaneDistance, float farPlaneDistance, FogShape fogShape) + @ApiStatus.Internal + public RenderFog(FogType type, Camera camera, float partialTicks, float nearPlaneDistance, float farPlaneDistance, FogShape fogShape) { super(Minecraft.getInstance().gameRenderer, camera, partialTicks); this.type = type; @@ -190,22 +182,19 @@ public void scaleNearPlaneDistance(float factor) /** * Fired for customizing the color of the fog visible to the player. * - *

This event is not {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}.

+ *

This event is not {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}.

* *

This event is fired on the {@linkplain MinecraftForge#EVENT_BUS main Forge event bus}, - * only on the {@linkplain LogicalSide#CLIENT logical client}.

+ * only on the {@linkplain LogicalSide#CLIENT logical client}.

*/ - public static class FogColors extends EntityViewRenderEvent + public static class ComputeFogColor extends ViewportEvent { private float red; private float green; private float blue; - /** - * @hidden - * @see FogRenderer#setupColor(Camera, float, ClientLevel, int, float) - */ - public FogColors(Camera camera, float partialTicks, float red, float green, float blue) + @ApiStatus.Internal + public ComputeFogColor(Camera camera, float partialTicks, float red, float green, float blue) { super(Minecraft.getInstance().gameRenderer, camera, partialTicks); this.setRed(red); @@ -216,55 +205,75 @@ public FogColors(Camera camera, float partialTicks, float red, float green, floa /** * {@return the red color value of the fog} */ - public float getRed() { return red; } + public float getRed() + { + return red; + } + /** * Sets the new red color value of the fog. * * @param red the new red color value */ - public void setRed(float red) { this.red = red; } + public void setRed(float red) + { + this.red = red; + } + /** * {@return the green color value of the fog} */ - public float getGreen() { return green; } + public float getGreen() + { + return green; + } + /** * Sets the new green color value of the fog. * * @param green the new blue color value */ - public void setGreen(float green) { this.green = green; } + public void setGreen(float green) + { + this.green = green; + } + /** * {@return the blue color value of the fog} */ - public float getBlue() { return blue; } + public float getBlue() + { + return blue; + } + /** * Sets the new blue color value of the fog. * * @param blue the new blue color value */ - public void setBlue(float blue) { this.blue = blue; } + public void setBlue(float blue) + { + this.blue = blue; + } } /** * Fired to allow altering the angles of the player's camera. * This can be used to alter the player's view for different effects, such as applying roll. * - *

This event is not {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}.

+ *

This event is not {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}.

* *

This event is fired on the {@linkplain MinecraftForge#EVENT_BUS main Forge event bus}, - * only on the {@linkplain LogicalSide#CLIENT logical client}.

+ * only on the {@linkplain LogicalSide#CLIENT logical client}.

*/ - public static class CameraSetup extends EntityViewRenderEvent + public static class ComputeCameraAngles extends ViewportEvent { private float yaw; private float pitch; private float roll; - /** - * @hidden - * @see ForgeHooksClient#onCameraSetup(GameRenderer, Camera, float) - */ - public CameraSetup(GameRenderer renderer, Camera camera, double renderPartialTicks, float yaw, float pitch, float roll) + @ApiStatus.Internal + public ComputeCameraAngles(GameRenderer renderer, Camera camera, double renderPartialTicks, float yaw, float pitch, float roll) { super(renderer, camera, renderPartialTicks); this.setYaw(yaw); @@ -275,55 +284,76 @@ public CameraSetup(GameRenderer renderer, Camera camera, double renderPartialTic /** * {@return the yaw of the player's camera} */ - public float getYaw() { return yaw; } + public float getYaw() + { + return yaw; + } + /** * Sets the yaw of the player's camera. * * @param yaw the new yaw */ - public void setYaw(float yaw) { this.yaw = yaw; } + public void setYaw(float yaw) + { + this.yaw = yaw; + } + /** * {@return the pitch of the player's camera} */ - public float getPitch() { return pitch; } + public float getPitch() + { + return pitch; + } + /** * Sets the pitch of the player's camera. * * @param pitch the new pitch */ - public void setPitch(float pitch) { this.pitch = pitch; } + public void setPitch(float pitch) + { + this.pitch = pitch; + } + /** * {@return the roll of the player's camera} */ - public float getRoll() { return roll; } + public float getRoll() + { + return roll; + } + /** * Sets the roll of the player's camera. * * @param roll the new roll */ - public void setRoll(float roll) { this.roll = roll; } + public void setRoll(float roll) + { + this.roll = roll; + } } /** * Fired for altering the raw field of view (FOV). * This is after the FOV settings are applied, and before modifiers such as the Nausea effect. * - *

This event is not {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}.

+ *

This event is not {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}.

* *

This event is fired on the {@linkplain MinecraftForge#EVENT_BUS main Forge event bus}, - * only on the {@linkplain LogicalSide#CLIENT logical client}.

+ * only on the {@linkplain LogicalSide#CLIENT logical client}.

* - * @see FOVModifierEvent + * @see ComputeFovModifierEvent */ - public static class FieldOfView extends EntityViewRenderEvent + public static class ComputeFov extends ViewportEvent { private double fov; - /** - * @hidden - * @see ForgeHooksClient#getFieldOfView(GameRenderer, Camera, double, double) - */ - public FieldOfView(GameRenderer renderer, Camera camera, double renderPartialTicks, double fov) { + @ApiStatus.Internal + public ComputeFov(GameRenderer renderer, Camera camera, double renderPartialTicks, double fov) + { super(renderer, camera, renderPartialTicks); this.setFOV(fov); } @@ -331,7 +361,8 @@ public FieldOfView(GameRenderer renderer, Camera camera, double renderPartialTic /** * {@return the raw field of view value} */ - public double getFOV() { + public double getFOV() + { return fov; } @@ -340,7 +371,8 @@ public double getFOV() { * * @param fov the new FOV value */ - public void setFOV(double fov) { + public void setFOV(double fov) + { this.fov = fov; } } diff --git a/src/main/java/net/minecraftforge/client/event/sound/PlaySoundEvent.java b/src/main/java/net/minecraftforge/client/event/sound/PlaySoundEvent.java index f70c9024b6e..6cd191a76e5 100644 --- a/src/main/java/net/minecraftforge/client/event/sound/PlaySoundEvent.java +++ b/src/main/java/net/minecraftforge/client/event/sound/PlaySoundEvent.java @@ -10,6 +10,7 @@ import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.eventbus.api.Cancelable; import net.minecraftforge.fml.LogicalSide; +import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; /** @@ -18,10 +19,10 @@ * others). This can be used to change or prevent (by passing {@code null)} a sound from being played through * {@link #setSound(SoundInstance)}). * - *

This event is not {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}.

+ *

This event is not {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}.

* *

This event is fired on the {@linkplain MinecraftForge#EVENT_BUS main Forge event bus}, - * only on the {@linkplain LogicalSide#CLIENT logical client}.

+ * only on the {@linkplain LogicalSide#CLIENT logical client}.

* * @see PlaySoundSourceEvent * @see PlayStreamingSourceEvent @@ -33,9 +34,7 @@ public class PlaySoundEvent extends SoundEvent @Nullable private SoundInstance sound; - /** - * @hidden - */ + @ApiStatus.Internal public PlaySoundEvent(SoundEngine manager, SoundInstance sound) { super(manager); diff --git a/src/main/java/net/minecraftforge/client/event/sound/PlaySoundSourceEvent.java b/src/main/java/net/minecraftforge/client/event/sound/PlaySoundSourceEvent.java index 8feedcc49ea..404c5a9688e 100644 --- a/src/main/java/net/minecraftforge/client/event/sound/PlaySoundSourceEvent.java +++ b/src/main/java/net/minecraftforge/client/event/sound/PlaySoundSourceEvent.java @@ -5,31 +5,30 @@ package net.minecraftforge.client.event.sound; +import com.mojang.blaze3d.audio.Channel; import net.minecraft.client.resources.sounds.SoundInstance; import net.minecraft.client.sounds.SoundEngine; -import com.mojang.blaze3d.audio.Channel; import net.minecraftforge.client.event.sound.SoundEvent.SoundSourceEvent; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.eventbus.api.Cancelable; import net.minecraftforge.fml.LogicalSide; +import org.jetbrains.annotations.ApiStatus; /** * Fired when a non-streaming sound is being played. A non-streaming sound is loaded fully into memory * in a buffer before being played, and used for most sounds of short length such as sound effects for clicking * buttons. * - *

This event is not {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}.

+ *

This event is not {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}.

* *

This event is fired on the {@linkplain MinecraftForge#EVENT_BUS main Forge event bus}, - * only on the {@linkplain LogicalSide#CLIENT logical client}.

+ * only on the {@linkplain LogicalSide#CLIENT logical client}.

* * @see PlayStreamingSourceEvent */ public class PlaySoundSourceEvent extends SoundSourceEvent { - /** - * @hidden - */ + @ApiStatus.Internal public PlaySoundSourceEvent(SoundEngine engine, SoundInstance sound, Channel channel) { super(engine, sound, channel); diff --git a/src/main/java/net/minecraftforge/client/event/sound/PlayStreamingSourceEvent.java b/src/main/java/net/minecraftforge/client/event/sound/PlayStreamingSourceEvent.java index 7de226f8a22..abdab79e695 100644 --- a/src/main/java/net/minecraftforge/client/event/sound/PlayStreamingSourceEvent.java +++ b/src/main/java/net/minecraftforge/client/event/sound/PlayStreamingSourceEvent.java @@ -5,31 +5,30 @@ package net.minecraftforge.client.event.sound; +import com.mojang.blaze3d.audio.Channel; import net.minecraft.client.resources.sounds.SoundInstance; import net.minecraft.client.sounds.SoundEngine; -import com.mojang.blaze3d.audio.Channel; import net.minecraftforge.client.event.sound.SoundEvent.SoundSourceEvent; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.eventbus.api.Cancelable; import net.minecraftforge.fml.LogicalSide; +import org.jetbrains.annotations.ApiStatus; /** * Fired when a streaming sound is being played. A streaming sound is streamed directly from its source * (such as a file), and used for sounds of long length which are unsuitable to keep fully loaded in-memory in a buffer * (as is done for regular non-streaming sounds), such as background music or music discs. * - *

This event is not {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}.

+ *

This event is not {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}.

* *

This event is fired on the {@linkplain MinecraftForge#EVENT_BUS main Forge event bus}, - * only on the {@linkplain LogicalSide#CLIENT logical client}.

+ * only on the {@linkplain LogicalSide#CLIENT logical client}.

* * @see PlayStreamingSourceEvent */ public class PlayStreamingSourceEvent extends SoundSourceEvent { - /** - * @hidden - */ + @ApiStatus.Internal public PlayStreamingSourceEvent(SoundEngine engine, SoundInstance sound, Channel channel) { super(engine, sound, channel); diff --git a/src/main/java/net/minecraftforge/client/event/sound/SoundEngineLoadEvent.java b/src/main/java/net/minecraftforge/client/event/sound/SoundEngineLoadEvent.java index 94259c28729..bc7907fd034 100644 --- a/src/main/java/net/minecraftforge/client/event/sound/SoundEngineLoadEvent.java +++ b/src/main/java/net/minecraftforge/client/event/sound/SoundEngineLoadEvent.java @@ -10,21 +10,20 @@ import net.minecraftforge.fml.LogicalSide; import net.minecraftforge.fml.event.IModBusEvent; import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; +import org.jetbrains.annotations.ApiStatus; /** * Fired when the {@link SoundEngine} is constructed or (re)loaded, such as during game initialization or when the sound * output device is changed. * - *

This event is not {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}.

+ *

This event is not {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}.

* *

This event is fired on the {@linkplain FMLJavaModLoadingContext#getModEventBus() mod-specific event bus}, - * only on the {@linkplain LogicalSide#CLIENT logical client}.

+ * only on the {@linkplain LogicalSide#CLIENT logical client}.

*/ public class SoundEngineLoadEvent extends SoundEvent implements IModBusEvent { - /** - * @hidden - */ + @ApiStatus.Internal public SoundEngineLoadEvent(SoundEngine manager) { super(manager); diff --git a/src/main/java/net/minecraftforge/client/event/sound/SoundEvent.java b/src/main/java/net/minecraftforge/client/event/sound/SoundEvent.java index e5a522d0a67..e05ca365eff 100644 --- a/src/main/java/net/minecraftforge/client/event/sound/SoundEvent.java +++ b/src/main/java/net/minecraftforge/client/event/sound/SoundEvent.java @@ -11,25 +11,24 @@ import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.eventbus.api.Event; import net.minecraftforge.fml.LogicalSide; +import org.jetbrains.annotations.ApiStatus; /** * Superclass for sound related events. * *

These events are fired on the {@linkplain MinecraftForge#EVENT_BUS main Forge event bus}, - * only on the {@linkplain LogicalSide#CLIENT logical client}.

+ * only on the {@linkplain LogicalSide#CLIENT logical client}.

* * @see SoundSourceEvent * @see PlaySoundEvent * @see SoundEngineLoadEvent */ -public class SoundEvent extends Event +public abstract class SoundEvent extends Event { private final SoundEngine engine; - /** - * @hidden - */ - public SoundEvent(SoundEngine engine) + @ApiStatus.Internal + protected SoundEvent(SoundEngine engine) { this.engine = engine; } @@ -46,21 +45,19 @@ public SoundEngine getEngine() * Superclass for when a sound has started to play on an audio channel. * *

These events are fired on the {@linkplain MinecraftForge#EVENT_BUS main Forge event bus}, - * only on the {@linkplain LogicalSide#CLIENT logical client}.

+ * only on the {@linkplain LogicalSide#CLIENT logical client}.

* * @see PlaySoundSourceEvent * @see PlayStreamingSourceEvent */ - public static class SoundSourceEvent extends SoundEvent + public static abstract class SoundSourceEvent extends SoundEvent { private final SoundInstance sound; private final Channel channel; private final String name; - /** - * @hidden - */ - public SoundSourceEvent(SoundEngine engine, SoundInstance sound, Channel channel) + @ApiStatus.Internal + protected SoundSourceEvent(SoundEngine engine, SoundInstance sound, Channel channel) { super(engine); this.name = sound.getLocation().getPath(); diff --git a/src/main/java/net/minecraftforge/client/extensions/ForgeItemBlockRenderTypes.java b/src/main/java/net/minecraftforge/client/extensions/ForgeItemBlockRenderTypes.java deleted file mode 100644 index ab2189da4f7..00000000000 --- a/src/main/java/net/minecraftforge/client/extensions/ForgeItemBlockRenderTypes.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright (c) Forge Development LLC and contributors - * SPDX-License-Identifier: LGPL-2.1-only - */ - -package net.minecraftforge.client.extensions; - -import it.unimi.dsi.fastutil.objects.Object2ObjectMap; -import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; -import net.minecraft.client.renderer.RenderType; -import net.minecraft.core.Holder; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.material.Fluid; -import net.minecraftforge.registries.ForgeRegistries; -import org.jetbrains.annotations.Nullable; - -import java.util.Map; -import java.util.Objects; -import java.util.function.Predicate; - -public class ForgeItemBlockRenderTypes -{ - private static final Predicate SOLID_PREDICATE = type -> type == RenderType.solid(); - private static final Object LOCK = new Object(); - - private static final Map, Predicate> blockRenderChecks = createMap(); - private static final Map, Predicate> fluidRenderChecks = createMap(); - - @Nullable - private static volatile Map, Predicate> blockRenderChecksReadOnly = null; - @Nullable - private static volatile Map, Predicate> fluidRenderChecksReadOnly = null; - - public static void setRenderLayer(Block block, Predicate predicate) - { - Objects.requireNonNull(predicate); - synchronized (LOCK) - { - blockRenderChecks.put(ForgeRegistries.BLOCKS.getDelegateOrThrow(block), predicate); - blockRenderChecksReadOnly = null; - } - } - - public static void setRenderLayer(Fluid fluid, Predicate predicate) - { - Objects.requireNonNull(predicate); - synchronized (LOCK) - { - fluidRenderChecks.put(ForgeRegistries.FLUIDS.getDelegateOrThrow(fluid), predicate); - fluidRenderChecksReadOnly = null; - } - } - - protected static Map, Predicate> getBlockLayerPredicates() - { - Map, Predicate> map = blockRenderChecksReadOnly; - if (map == null) - { - synchronized (LOCK) - { - blockRenderChecksReadOnly = map = copy(blockRenderChecks); - } - } - return map; - } - - protected static Map, Predicate> getFluidLayerPredicates() - { - Map, Predicate> map = fluidRenderChecksReadOnly; - if (map == null) - { - synchronized (LOCK) - { - fluidRenderChecksReadOnly = map = copy(fluidRenderChecks); - } - } - return map; - } - - private static Map, Predicate> copy(Map, Predicate> map) - { - var newMap = new Object2ObjectOpenHashMap<>(map); - newMap.defaultReturnValue(SOLID_PREDICATE); - return newMap; - } - - private static Map, Predicate> createMap() - { - Object2ObjectMap, Predicate> map = new Object2ObjectOpenHashMap<>( - Object2ObjectOpenHashMap.DEFAULT_INITIAL_SIZE, .75F - ); - map.defaultReturnValue(SOLID_PREDICATE); - return map; - } - - protected static void initFromVanillaMaps(Map typeByBlock, Map typeByFluid) - { - for (Map.Entry entry : typeByBlock.entrySet()) - { - RenderType type = entry.getValue(); - blockRenderChecks.put(ForgeRegistries.BLOCKS.getDelegateOrThrow(entry.getKey()), t -> t == type); - } - - for (Map.Entry entry : typeByFluid.entrySet()) - { - RenderType type = entry.getValue(); - fluidRenderChecks.put(ForgeRegistries.FLUIDS.getDelegateOrThrow(entry.getKey()), t -> t == type); - } - } -} diff --git a/src/main/java/net/minecraftforge/client/extensions/IForgeBakedModel.java b/src/main/java/net/minecraftforge/client/extensions/IForgeBakedModel.java index d08b6b533cc..fb4f5f85761 100644 --- a/src/main/java/net/minecraftforge/client/extensions/IForgeBakedModel.java +++ b/src/main/java/net/minecraftforge/client/extensions/IForgeBakedModel.java @@ -5,28 +5,26 @@ package net.minecraftforge.client.extensions; -import java.util.Collections; -import java.util.List; - import com.mojang.blaze3d.vertex.PoseStack; - -import com.mojang.datafixers.util.Pair; -import net.minecraft.util.RandomSource; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.ItemBlockRenderTypes; +import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.block.model.BakedQuad; -import net.minecraft.client.resources.model.BakedModel; import net.minecraft.client.renderer.block.model.ItemTransforms; import net.minecraft.client.renderer.texture.TextureAtlasSprite; -import net.minecraft.world.item.ItemStack; -import net.minecraft.core.Direction; +import net.minecraft.client.resources.model.BakedModel; import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.util.RandomSource; +import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.BlockAndTintGetter; -import net.minecraftforge.client.model.data.IModelData; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraftforge.client.ChunkRenderTypeSet; +import net.minecraftforge.client.model.data.ModelData; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.List; + /** * Extension interface for {@link IForgeBakedModel}. */ @@ -37,51 +35,76 @@ private BakedModel self() return (BakedModel) this; } + /** + * A null {@link RenderType} is used for the breaking overlay as well as non-standard rendering, so models should return all their quads. + */ @NotNull - default List getQuads(@Nullable BlockState state, @Nullable Direction side, @NotNull RandomSource rand, @NotNull IModelData extraData) + default List getQuads(@Nullable BlockState state, @Nullable Direction side, @NotNull RandomSource rand, @NotNull ModelData data, @Nullable RenderType renderType) { return self().getQuads(state, side, rand); } - default boolean useAmbientOcclusion(BlockState state) { return self().useAmbientOcclusion(); } + default boolean useAmbientOcclusion(BlockState state) + { + return self().useAmbientOcclusion(); + } /** - * Override to tell the new model loader that it shouldn't wrap this model + * Applies a transform for the given {@link ItemTransforms.TransformType} and {@code applyLeftHandTransform}, and + * returns the model to be rendered. */ - default boolean doesHandlePerspectives() { return false; } - - /* - * Returns the pair of the model for the given perspective, and the matrix that - * should be applied to the GL state before rendering it (matrix may be null). - */ - default BakedModel handlePerspective(ItemTransforms.TransformType cameraTransformType, PoseStack poseStack) + default BakedModel applyTransform(ItemTransforms.TransformType transformType, PoseStack poseStack, boolean applyLeftHandTransform) { - return net.minecraftforge.client.ForgeHooksClient.handlePerspective(self(), cameraTransformType, poseStack); + self().getTransforms().getTransform(transformType).apply(applyLeftHandTransform, poseStack); + return self(); } - default @NotNull IModelData getModelData(@NotNull BlockAndTintGetter level, @NotNull BlockPos pos, @NotNull BlockState state, @NotNull IModelData modelData) + default @NotNull ModelData getModelData(@NotNull BlockAndTintGetter level, @NotNull BlockPos pos, @NotNull BlockState state, @NotNull ModelData modelData) { return modelData; } - default TextureAtlasSprite getParticleIcon(@NotNull IModelData data) + default TextureAtlasSprite getParticleIcon(@NotNull ModelData data) { return self().getParticleIcon(); } /** - * Override to true, to tell forge to call the getLayerModels method below. + * Gets the set of {@link RenderType render types} to use when drawing this block in the level. + * Supported types are those returned by {@link RenderType#chunkBufferLayers()}. + *

+ * By default, defers query to {@link ItemBlockRenderTypes}. + */ + default ChunkRenderTypeSet getRenderTypes(@NotNull BlockState state, @NotNull RandomSource rand, @NotNull ModelData data) + { + return ItemBlockRenderTypes.getRenderLayers(state); + } + + /** + * Gets an ordered list of {@link RenderType render types} to use when drawing this item. + * All render types using the {@link com.mojang.blaze3d.vertex.DefaultVertexFormat#NEW_ENTITY} format are supported. + *

+ * This method will only be called on the models returned by {@link #getRenderPasses(ItemStack, boolean)}. + *

+ * By default, defers query to {@link ItemBlockRenderTypes}. + * + * @see #getRenderPasses(ItemStack, boolean) */ - default boolean isLayered() + default List getRenderTypes(ItemStack itemStack, boolean fabulous) { - return false; + return List.of(ItemBlockRenderTypes.getRenderType(itemStack, fabulous)); } /** - * If {@see isLayered()} returns true, this is called to get the list of layers to draw. + * Gets an ordered list of baked models used to render this model as an item. + * Each of those models' render types will be queried via {@link #getRenderTypes(ItemStack, boolean)}. + *

+ * By default, returns the model itself. + * + * @see #getRenderTypes(ItemStack, boolean) */ - default List> getLayerModels(ItemStack itemStack, boolean fabulous) + default List getRenderPasses(ItemStack itemStack, boolean fabulous) { - return Collections.singletonList(Pair.of(self(), ItemBlockRenderTypes.getRenderType(itemStack, fabulous))); + return List.of(self()); } } diff --git a/src/main/java/net/minecraftforge/client/extensions/IForgeBlockAndTintGetter.java b/src/main/java/net/minecraftforge/client/extensions/IForgeBlockAndTintGetter.java new file mode 100644 index 00000000000..23d9d27345a --- /dev/null +++ b/src/main/java/net/minecraftforge/client/extensions/IForgeBlockAndTintGetter.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) Forge Development LLC and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.minecraftforge.client.extensions; + +import net.minecraft.core.Direction; +import net.minecraft.world.level.BlockAndTintGetter; + +/** + * Extension interface for {@link BlockAndTintGetter}. + */ +public interface IForgeBlockAndTintGetter +{ + private BlockAndTintGetter self() + { + return (BlockAndTintGetter) this; + } + + /** + * Computes the shade for a given normal. + * Alternate version of the vanilla method taking in a {@link Direction}. + */ + default float getShade(float normalX, float normalY, float normalZ, boolean shade) + { + return self().getShade(Direction.getNearest(normalX, normalY, normalZ), shade); + } +} diff --git a/src/main/java/net/minecraftforge/client/extensions/IForgeDimensionSpecialEffects.java b/src/main/java/net/minecraftforge/client/extensions/IForgeDimensionSpecialEffects.java new file mode 100644 index 00000000000..03e6defa90c --- /dev/null +++ b/src/main/java/net/minecraftforge/client/extensions/IForgeDimensionSpecialEffects.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) Forge Development LLC and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.minecraftforge.client.extensions; + +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.math.Matrix4f; +import net.minecraft.client.Camera; +import net.minecraft.client.multiplayer.ClientLevel; +import net.minecraft.client.renderer.DimensionSpecialEffects; +import net.minecraft.client.renderer.LightTexture; + +/** + * Extension interface for {@link DimensionSpecialEffects}. + */ +public interface IForgeDimensionSpecialEffects +{ + private DimensionSpecialEffects self() + { + return (DimensionSpecialEffects) this; + } + + /** + * Renders the clouds of this dimension. + * + * @return true to prevent vanilla cloud rendering + */ + default boolean renderClouds(ClientLevel level, int ticks, float partialTick, PoseStack poseStack, double camX, double camY, double camZ, Matrix4f projectionMatrix) + { + return false; + } + + /** + * Renders the sky of this dimension. + * + * @return true to prevent vanilla sky rendering + */ + default boolean renderSky(ClientLevel level, int ticks, float partialTick, PoseStack poseStack, Camera camera, Matrix4f projectionMatrix, boolean isFoggy, Runnable setupFog) + { + return false; + } + + /** + * Renders the snow and rain effects of this dimension. + * + * @return true to prevent vanilla snow and rain rendering + */ + default boolean renderSnowAndRain(ClientLevel level, int ticks, float partialTick, LightTexture lightTexture, double camX, double camY, double camZ) + { + return false; + } + + /** + * Ticks the rain of this dimension. + * + * @return true to prevent vanilla rain ticking + */ + default boolean tickRain(ClientLevel level, int ticks, Camera camera) + { + return false; + } +} diff --git a/src/main/java/net/minecraftforge/client/extensions/IForgeKeyMapping.java b/src/main/java/net/minecraftforge/client/extensions/IForgeKeyMapping.java index 898a681adf9..22b720a350a 100644 --- a/src/main/java/net/minecraftforge/client/extensions/IForgeKeyMapping.java +++ b/src/main/java/net/minecraftforge/client/extensions/IForgeKeyMapping.java @@ -24,7 +24,7 @@ private KeyMapping self() @NotNull InputConstants.Key getKey(); /** - * Checks that the key conflict context and modifier are active, and that the keyCode matches this binding. + * {@return true if the key conflict context and modifier are active and the keyCode matches this binding, false otherwise} */ default boolean isActiveAndMatches(InputConstants.Key keyCode) { diff --git a/src/main/java/net/minecraftforge/client/extensions/IForgeMinecraft.java b/src/main/java/net/minecraftforge/client/extensions/IForgeMinecraft.java index 9436086de9f..fc282a80338 100644 --- a/src/main/java/net/minecraftforge/client/extensions/IForgeMinecraft.java +++ b/src/main/java/net/minecraftforge/client/extensions/IForgeMinecraft.java @@ -9,6 +9,8 @@ import net.minecraft.client.gui.screens.Screen; import net.minecraftforge.client.ForgeHooksClient; +import java.util.Locale; + /** * Extension interface for {@link IForgeMinecraft}. */ @@ -36,4 +38,13 @@ default void popGuiLayer() { ForgeHooksClient.popGuiLayer(self()); } + + /** + * Retrieves the {@link Locale} set by the player. + * Useful for creating string and number formatters. + */ + default Locale getLocale() + { + return self().getLanguageManager().getSelected().getJavaLocale(); + } } diff --git a/src/main/java/net/minecraftforge/client/extensions/IForgeModelState.java b/src/main/java/net/minecraftforge/client/extensions/IForgeModelState.java deleted file mode 100644 index d0fe103b3e3..00000000000 --- a/src/main/java/net/minecraftforge/client/extensions/IForgeModelState.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) Forge Development LLC and contributors - * SPDX-License-Identifier: LGPL-2.1-only - */ - -package net.minecraftforge.client.extensions; - -import com.mojang.math.Transformation; -import net.minecraft.client.resources.model.ModelState; - -/** - * Extension interface for {@link ModelState}. An {@code ModelState} is a function from model part to a - * transformation that should be applied when that part is baked, thus representing the current "state" of the model - * and its parts. - */ -public interface IForgeModelState -{ - private ModelState self() - { - return (ModelState) this; - } - - /** - * {@return A transformation to apply to the part} This may be an {@linkplain Transformation#isIdentity() identity - * transformation} if there is no transformation to be applied. The coordinate system of the transform is determined - * by the part type. - * - * @param part part of the model we are wanting to transform. An empty optional means - * we want a transform for the entire model. - */ - default Transformation getPartTransformation(Object part) - { - return Transformation.identity(); - } -} diff --git a/src/main/java/net/minecraftforge/client/extensions/IForgeVertexConsumer.java b/src/main/java/net/minecraftforge/client/extensions/IForgeVertexConsumer.java index 844101e6439..9739aee3672 100644 --- a/src/main/java/net/minecraftforge/client/extensions/IForgeVertexConsumer.java +++ b/src/main/java/net/minecraftforge/client/extensions/IForgeVertexConsumer.java @@ -5,25 +5,15 @@ package net.minecraftforge.client.extensions; -import com.mojang.blaze3d.vertex.DefaultVertexFormat; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.VertexConsumer; -import com.mojang.blaze3d.vertex.VertexFormat; +import com.mojang.blaze3d.vertex.VertexFormatElement; +import com.mojang.math.Matrix3f; +import com.mojang.math.Vector3f; import net.minecraft.client.renderer.block.model.BakedQuad; -import net.minecraftforge.client.model.pipeline.LightUtil; - -import org.jetbrains.annotations.Nullable; -import org.lwjgl.system.MemoryStack; +import net.minecraftforge.client.model.IQuadTransformer; -import java.nio.Buffer; import java.nio.ByteBuffer; -import java.nio.IntBuffer; - -import com.mojang.math.Matrix3f; -import com.mojang.math.Matrix4f; -import com.mojang.math.Vector3f; -import com.mojang.math.Vector4f; -import net.minecraft.core.Vec3i; /** * Extension interface for {@link VertexConsumer}. @@ -35,90 +25,43 @@ private VertexConsumer self() return (VertexConsumer) this; } - VertexFormat getVertexFormat(); - - // Copy of putBulkData, but enables tinting and per-vertex alpha - default void putBulkData(PoseStack.Pose poseStack, BakedQuad bakedQuad, float red, float green, float blue, int packedLight, int packedOverlay, boolean readExistingColor) { - putBulkData(poseStack, bakedQuad, red, green, blue, 1.0f, packedLight, packedOverlay, readExistingColor); - } - - // Copy of putBulkData with alpha support - default void putBulkData(PoseStack.Pose pose, BakedQuad bakedQuad, float red, float green, float blue, float alpha, int packedLight, int packedOverlay) { - putBulkData(pose, bakedQuad, new float[]{1.0F, 1.0F, 1.0F, 1.0F}, red, green, blue, alpha, new int[]{packedLight, packedLight, packedLight, packedLight}, packedOverlay, false); - } - - // Copy of putBulkData with alpha support - default void putBulkData(PoseStack.Pose pose, BakedQuad bakedQuad, float red, float green, float blue, float alpha, int packedLight, int packedOverlay, boolean readExistingColor) { - putBulkData(pose, bakedQuad, new float[]{1.0F, 1.0F, 1.0F, 1.0F}, red, green, blue, alpha, new int[]{packedLight, packedLight, packedLight, packedLight}, packedOverlay, readExistingColor); + /** + * Consumes an unknown {@link VertexFormatElement} as a raw int data array. + *

+ * If the consumer needs to store the data for later use, it must copy it. There are no guarantees on immutability. + */ + default VertexConsumer misc(VertexFormatElement element, int... rawData) + { + return self(); } - // Copy of putBulkData with alpha support - default void putBulkData(PoseStack.Pose pose, BakedQuad bakedQuad, float[] baseBrightness, float red, float green, float blue, float alpha, int[] lightmap, int packedOverlay, boolean readExistingColor) { - int[] aint = bakedQuad.getVertices(); - Vec3i faceNormal = bakedQuad.getDirection().getNormal(); - Vector3f normal = new Vector3f((float)faceNormal.getX(), (float)faceNormal.getY(), (float)faceNormal.getZ()); - Matrix4f matrix4f = pose.pose(); - normal.transform(pose.normal()); - int intSize = DefaultVertexFormat.BLOCK.getIntegerSize(); - int vertexCount = aint.length / intSize; - - try (MemoryStack memorystack = MemoryStack.stackPush()) { - ByteBuffer bytebuffer = memorystack.malloc(DefaultVertexFormat.BLOCK.getVertexSize()); - IntBuffer intbuffer = bytebuffer.asIntBuffer(); - - for(int v = 0; v < vertexCount; ++v) { - ((Buffer)intbuffer).clear(); - intbuffer.put(aint, v * 8, 8); - float f = bytebuffer.getFloat(0); - float f1 = bytebuffer.getFloat(4); - float f2 = bytebuffer.getFloat(8); - float cr; - float cg; - float cb; - float ca; - if (readExistingColor) { - float r = (float)(bytebuffer.get(12) & 255) / 255.0F; - float g = (float)(bytebuffer.get(13) & 255) / 255.0F; - float b = (float)(bytebuffer.get(14) & 255) / 255.0F; - float a = (float)(bytebuffer.get(15) & 255) / 255.0F; - cr = r * baseBrightness[v] * red; - cg = g * baseBrightness[v] * green; - cb = b * baseBrightness[v] * blue; - ca = a * alpha; - } else { - cr = baseBrightness[v] * red; - cg = baseBrightness[v] * green; - cb = baseBrightness[v] * blue; - ca = alpha; - } - - int lightmapCoord = applyBakedLighting(lightmap[v], bytebuffer); - float f9 = bytebuffer.getFloat(16); - float f10 = bytebuffer.getFloat(20); - Vector4f pos = new Vector4f(f, f1, f2, 1.0F); - pos.transform(matrix4f); - applyBakedNormals(normal, bytebuffer, pose.normal()); - self().vertex(pos.x(), pos.y(), pos.z(), cr, cg, cb, ca, f9, f10, packedOverlay, lightmapCoord, normal.x(), normal.y(), normal.z()); - } - } + /** + * Variant with no per-vertex shading. + */ + default void putBulkData(PoseStack.Pose pose, BakedQuad bakedQuad, float red, float green, float blue, float alpha, int packedLight, int packedOverlay, boolean readExistingColor) + { + self().putBulkData(pose, bakedQuad, new float[] { 1.0F, 1.0F, 1.0F, 1.0F }, red, green, blue, alpha, new int[] { packedLight, packedLight, packedLight, packedLight }, packedOverlay, readExistingColor); } - default int applyBakedLighting(int packedLight, ByteBuffer data) { - int bl = packedLight&0xFFFF; - int sl = (packedLight>>16)&0xFFFF; - int offset = LightUtil.getLightOffset(0) * 4; // int offset for vertex 0 * 4 bytes per int + default int applyBakedLighting(int packedLight, ByteBuffer data) + { + int bl = packedLight & 0xFFFF; + int sl = (packedLight >> 16) & 0xFFFF; + int offset = IQuadTransformer.UV2 * 4; // int offset for vertex 0 * 4 bytes per int int blBaked = Short.toUnsignedInt(data.getShort(offset)); int slBaked = Short.toUnsignedInt(data.getShort(offset + 2)); bl = Math.max(bl, blBaked); sl = Math.max(sl, slBaked); - return bl | (sl<<16); + return bl | (sl << 16); } - default void applyBakedNormals(Vector3f generated, ByteBuffer data, Matrix3f normalTransform) { + default void applyBakedNormals(Vector3f generated, ByteBuffer data, Matrix3f normalTransform) + { byte nx = data.get(28); byte ny = data.get(29); byte nz = data.get(30); - if (nx != 0 || ny != 0 || nz != 0) { + if (nx != 0 || ny != 0 || nz != 0) + { generated.set(nx / 127f, ny / 127f, nz / 127f); generated.transform(normalTransform); } diff --git a/src/main/java/net/minecraftforge/client/IBlockRenderProperties.java b/src/main/java/net/minecraftforge/client/extensions/common/IClientBlockExtensions.java similarity index 83% rename from src/main/java/net/minecraftforge/client/IBlockRenderProperties.java rename to src/main/java/net/minecraftforge/client/extensions/common/IClientBlockExtensions.java index e73723146ce..24ed17844b9 100644 --- a/src/main/java/net/minecraftforge/client/IBlockRenderProperties.java +++ b/src/main/java/net/minecraftforge/client/extensions/common/IClientBlockExtensions.java @@ -3,7 +3,7 @@ * SPDX-License-Identifier: LGPL-2.1-only */ -package net.minecraftforge.client; +package net.minecraftforge.client.extensions.common; import com.mojang.math.Vector3d; import net.minecraft.client.particle.ParticleEngine; @@ -14,15 +14,32 @@ import net.minecraft.world.item.enchantment.EnchantmentHelper; import net.minecraft.world.level.Level; import net.minecraft.world.level.LevelReader; +import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.material.Material; import net.minecraft.world.phys.HitResult; +import net.minecraftforge.fml.LogicalSide; -public interface IBlockRenderProperties +import java.util.function.Consumer; + +/** + * {@linkplain LogicalSide#CLIENT Client-only} extensions to {@link Block}. + * + * @see Block#initializeClient(Consumer) + */ +public interface IClientBlockExtensions { - IBlockRenderProperties DUMMY = new IBlockRenderProperties() + IClientBlockExtensions DEFAULT = new IClientBlockExtensions() { }; + + static IClientBlockExtensions of(BlockState state) { - }; + return of(state.getBlock()); + } + + static IClientBlockExtensions of(Block block) + { + return block.getRenderPropertiesInternal() instanceof IClientBlockExtensions e ? e : DEFAULT; + } /** * Spawn a digging particle effect in the level, this is a wrapper diff --git a/src/main/java/net/minecraftforge/client/IFluidTypeRenderProperties.java b/src/main/java/net/minecraftforge/client/extensions/common/IClientFluidTypeExtensions.java similarity index 75% rename from src/main/java/net/minecraftforge/client/IFluidTypeRenderProperties.java rename to src/main/java/net/minecraftforge/client/extensions/common/IClientFluidTypeExtensions.java index 061561232c6..c2d6fb9a5bd 100644 --- a/src/main/java/net/minecraftforge/client/IFluidTypeRenderProperties.java +++ b/src/main/java/net/minecraftforge/client/extensions/common/IClientFluidTypeExtensions.java @@ -3,7 +3,7 @@ * SPDX-License-Identifier: LGPL-2.1-only */ -package net.minecraftforge.client; +package net.minecraftforge.client.extensions.common; import com.mojang.blaze3d.shaders.FogShape; import com.mojang.blaze3d.systems.RenderSystem; @@ -20,41 +20,47 @@ import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.client.renderer.FogRenderer; import net.minecraft.client.renderer.GameRenderer; -import net.minecraft.client.renderer.ItemBlockRenderTypes; import net.minecraft.client.renderer.LightTexture; -import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.ScreenEffectRenderer; import net.minecraft.core.BlockPos; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.level.BlockAndTintGetter; import net.minecraft.world.level.material.Fluid; import net.minecraft.world.level.material.FluidState; import net.minecraft.world.level.material.Fluids; -import net.minecraftforge.client.model.FluidModel; import net.minecraftforge.fluids.FluidStack; import net.minecraftforge.fluids.FluidType; -import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; +import net.minecraftforge.fml.LogicalSide; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.Objects; +import java.util.function.Consumer; import java.util.stream.Stream; /** - * An interface which defines properties relating to how a {@link FluidType} - * should render. + * {@linkplain LogicalSide#CLIENT Client-only} extensions to {@link FluidType}. * - *

Note: This does not define any data regarding {@link RenderType}s as those - * are specified by the Fluid via {@link ItemBlockRenderTypes#setRenderLayer(Fluid, RenderType)} - * in the {@link FMLClientSetupEvent}. + * @see FluidType#initializeClient(Consumer) */ -public interface IFluidTypeRenderProperties +public interface IClientFluidTypeExtensions { - /** - * A dummy instance returned when no render properties are specified. - */ - IFluidTypeRenderProperties DUMMY = new IFluidTypeRenderProperties() + IClientFluidTypeExtensions DEFAULT = new IClientFluidTypeExtensions() { }; + + static IClientFluidTypeExtensions of(FluidState state) + { + return of(state.getFluidType()); + } + + static IClientFluidTypeExtensions of(Fluid fluid) + { + return of(fluid.getFluidType()); + } + + static IClientFluidTypeExtensions of(FluidType type) { - }; + return type.getRenderPropertiesInternal() instanceof IClientFluidTypeExtensions props ? props : DEFAULT; + } /* Default Accessors */ @@ -66,7 +72,7 @@ public interface IFluidTypeRenderProperties * * @return the tint applied to the fluid's textures in ARGB format */ - default int getColorTint() + default int getTintColor() { return 0xFFFFFFFF; } @@ -127,7 +133,7 @@ default ResourceLocation getOverlayTexture() /** * Returns a stream of textures applied to a fluid. * - *

This is used by the {@link FluidModel} to load in all textures that + *

This is used by the {@link net.minecraft.client.resources.model.ModelBakery} to load in all textures that * can be applied on reload. * * @return a stream of textures applied to a fluid @@ -135,7 +141,7 @@ default ResourceLocation getOverlayTexture() default Stream getTextures() { return Stream.of(this.getStillTexture(), this.getFlowingTexture(), this.getOverlayTexture()) - .filter(Objects::nonNull); + .filter(Objects::nonNull); } /** @@ -160,32 +166,14 @@ default ResourceLocation getRenderOverlayTexture(Minecraft mc) * Renders {@code #getRenderOverlayTexture} onto the camera when within * the fluid. * - * @param mc the client instance - * @param stack the transformations representing the current rendering position + * @param mc the client instance + * @param poseStack the transformations representing the current rendering position */ - default void renderOverlay(Minecraft mc, PoseStack stack) + default void renderOverlay(Minecraft mc, PoseStack poseStack) { ResourceLocation texture = this.getRenderOverlayTexture(mc); - if (texture == null) return; - RenderSystem.setShader(GameRenderer::getPositionTexShader); - RenderSystem.enableTexture(); - RenderSystem.setShaderTexture(0, texture); - BufferBuilder buffer = Tesselator.getInstance().getBuilder(); - BlockPos playerEyePos = new BlockPos(mc.player.getX(), mc.player.getEyeY(), mc.player.getZ()); - float brightness = LightTexture.getBrightness(mc.player.level.dimensionType(), mc.player.level.getMaxLocalRawBrightness(playerEyePos)); - RenderSystem.enableBlend(); - RenderSystem.defaultBlendFunc(); - RenderSystem.setShaderColor(brightness, brightness, brightness, 0.1F); - float uOffset = -mc.player.getYRot() / 64.0F; - float vOffset = mc.player.getXRot() / 64.0F; - Matrix4f pose = stack.last().pose(); - buffer.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_TEX); - buffer.vertex(pose, -1.0F, -1.0F, -0.5F).uv(4.0F + uOffset, 4.0F + vOffset).endVertex(); - buffer.vertex(pose, 1.0F, -1.0F, -0.5F).uv(uOffset, 4.0F + vOffset).endVertex(); - buffer.vertex(pose, 1.0F, 1.0F, -0.5F).uv(uOffset, vOffset).endVertex(); - buffer.vertex(pose, -1.0F, 1.0F, -0.5F).uv(4.0F + uOffset, vOffset).endVertex(); - BufferUploader.drawWithShader(buffer.end()); - RenderSystem.disableBlend(); + if (texture != null) + ScreenEffectRenderer.renderFluid(mc, poseStack, texture); } /** @@ -194,12 +182,12 @@ default void renderOverlay(Minecraft mc, PoseStack stack) *

The result expects a three float vector representing the red, green, * and blue channels respectively. Each channel should be between [0,1]. * - * @param camera the camera instance - * @param partialTick the delta time of where the current frame is within a tick - * @param level the level the camera is located in - * @param renderDistance the render distance of the client + * @param camera the camera instance + * @param partialTick the delta time of where the current frame is within a tick + * @param level the level the camera is located in + * @param renderDistance the render distance of the client * @param darkenWorldAmount the amount to darken the world by - * @param fluidFogColor the current color of the fog + * @param fluidFogColor the current color of the fog * @return the color of the fog */ @NotNull @@ -212,13 +200,13 @@ default Vector3f modifyFogColor(Camera camera, float partialTick, ClientLevel le * Modifies how the fog is currently being rendered when the camera is * within a fluid. * - * @param camera the camera instance - * @param mode the type of fog being rendered + * @param camera the camera instance + * @param mode the type of fog being rendered * @param renderDistance the render distance of the client - * @param partialTick the delta time of where the current frame is within a tick - * @param nearDistance the near plane of where the fog starts to render - * @param farDistance the far plane of where the fog ends rendering - * @param shape the shape of the fog being rendered + * @param partialTick the delta time of where the current frame is within a tick + * @param nearDistance the near plane of where the fog starts to render + * @param farDistance the far plane of where the fog ends rendering + * @param shape the shape of the fog being rendered */ default void modifyFogRender(Camera camera, FogRenderer.FogMode mode, float renderDistance, float partialTick, float nearDistance, float farDistance, FogShape shape) { @@ -236,9 +224,9 @@ default void modifyFogRender(Camera camera, FogRenderer.FogMode mode, float rend *

Important: This method should only return {@code null} for {@link Fluids#EMPTY}. * All other implementations must define this property. * - * @param state the state of the fluid + * @param state the state of the fluid * @param getter the getter the fluid can be obtained from - * @param pos the position of the fluid + * @param pos the position of the fluid * @return the reference of the texture to apply to a source fluid */ default ResourceLocation getStillTexture(FluidState state, BlockAndTintGetter getter, BlockPos pos) @@ -256,9 +244,9 @@ default ResourceLocation getStillTexture(FluidState state, BlockAndTintGetter ge *

Important: This method should only return {@code null} for {@link Fluids#EMPTY}. * All other implementations must define this property. * - * @param state the state of the fluid + * @param state the state of the fluid * @param getter the getter the fluid can be obtained from - * @param pos the position of the fluid + * @param pos the position of the fluid * @return the reference of the texture to apply to a flowing fluid */ default ResourceLocation getFlowingTexture(FluidState state, BlockAndTintGetter getter, BlockPos pos) @@ -276,9 +264,9 @@ default ResourceLocation getFlowingTexture(FluidState state, BlockAndTintGetter * texture itself (e.g. {@code minecraft:block/water_overlay} will point to * {@code assets/minecraft/textures/block/water_overlay.png}). * - * @param state the state of the fluid + * @param state the state of the fluid * @param getter the getter the fluid can be obtained from - * @param pos the position of the fluid + * @param pos the position of the fluid * @return the reference of the texture to apply to a fluid directly touching * a non-opaque block */ @@ -287,26 +275,24 @@ default ResourceLocation getOverlayTexture(FluidState state, BlockAndTintGetter return this.getOverlayTexture(); } - /** * Returns the tint applied to the fluid's textures. * *

The result represents a 32-bit integer where each 8-bits represent * the alpha, red, green, and blue channel respectively. * - * @param state the state of the fluid + * @param state the state of the fluid * @param getter the getter the fluid can be obtained from - * @param pos the position of the fluid + * @param pos the position of the fluid * @return the tint applied to the fluid's textures in ARGB format */ - default int getColorTint(FluidState state, BlockAndTintGetter getter, BlockPos pos) + default int getTintColor(FluidState state, BlockAndTintGetter getter, BlockPos pos) { - return this.getColorTint(); + return this.getTintColor(); } /* Stack-Based Accessors */ - /** * Returns the tint applied to the fluid's textures. * @@ -316,9 +302,9 @@ default int getColorTint(FluidState state, BlockAndTintGetter getter, BlockPos p * @param stack the stack the fluid is in * @return the tint applied to the fluid's textures in ARGB format */ - default int getColorTint(FluidStack stack) + default int getTintColor(FluidStack stack) { - return this.getColorTint(); + return this.getTintColor(); } /** diff --git a/src/main/java/net/minecraftforge/client/extensions/common/IClientItemExtensions.java b/src/main/java/net/minecraftforge/client/extensions/common/IClientItemExtensions.java new file mode 100644 index 00000000000..0c84c8f0cdb --- /dev/null +++ b/src/main/java/net/minecraftforge/client/extensions/common/IClientItemExtensions.java @@ -0,0 +1,145 @@ +/* + * Copyright (c) Forge Development LLC and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.minecraftforge.client.extensions.common; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.Font; +import net.minecraft.client.model.HumanoidModel; +import net.minecraft.client.model.Model; +import net.minecraft.client.renderer.BlockEntityWithoutLevelRenderer; +import net.minecraft.client.resources.model.BakedModel; +import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraftforge.client.ForgeHooksClient; +import net.minecraftforge.fml.LogicalSide; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.function.Consumer; + +/** + * {@linkplain LogicalSide#CLIENT Client-only} extensions to {@link Item}. + * + * @see Item#initializeClient(Consumer) + */ +public interface IClientItemExtensions +{ + IClientItemExtensions DEFAULT = new IClientItemExtensions() { }; + + static IClientItemExtensions of(ItemStack stack) + { + return of(stack.getItem()); + } + + static IClientItemExtensions of(Item item) + { + return item.getRenderPropertiesInternal() instanceof IClientItemExtensions e ? e : DEFAULT; + } + + /** + * Returns the font used to render data related to this item as specified in the {@code context}. + * Return {@code null} to use the default font. + * + * @param stack The item stack + * @param context The context in which the font will be used + * @return A {@link Font} or null to use the default + */ + @Nullable + default Font getFont(ItemStack stack, FontContext context) + { + return null; + } + + /** + * Queries the humanoid armor model for this item when it's equipped. + * + * @param livingEntity The entity wearing the armor + * @param itemStack The item stack + * @param equipmentSlot The slot the item is in + * @param original The original armor model. Will have attributes set. + * @return A HumanoidModel to be rendered. Relevant properties are to be copied over by the caller. + * @see #getGenericArmorModel(LivingEntity, ItemStack, EquipmentSlot, HumanoidModel) + */ + @NotNull + default HumanoidModel getHumanoidArmorModel(LivingEntity livingEntity, ItemStack itemStack, EquipmentSlot equipmentSlot, HumanoidModel original) + { + return original; + } + + /** + * Queries the armor model for this item when it's equipped. Useful in place of + * {@link #getHumanoidArmorModel(LivingEntity, ItemStack, EquipmentSlot, HumanoidModel)} for wrapping the original + * model or returning anything non-standard. + *

+ * If you override this method you are responsible for copying any properties you care about from the original model. + * + * @param livingEntity The entity wearing the armor + * @param itemStack The item stack + * @param equipmentSlot The slot the item is in + * @param original The original armor model. Will have attributes set. + * @return A Model to be rendered. Relevant properties must be copied over manually. + * @see #getHumanoidArmorModel(LivingEntity, ItemStack, EquipmentSlot, HumanoidModel) + */ + @NotNull + default Model getGenericArmorModel(LivingEntity livingEntity, ItemStack itemStack, EquipmentSlot equipmentSlot, HumanoidModel original) + { + HumanoidModel replacement = getHumanoidArmorModel(livingEntity, itemStack, equipmentSlot, original); + if (replacement != original) + { + ForgeHooksClient.copyModelProperties(original, replacement); + return replacement; + } + return original; + } + + /** + * Called when the client starts rendering the HUD, and is wearing this item in the helmet slot. + *

+ * This is where pumpkins would render their overlay. + * + * @param stack The item stack + * @param player The player entity + * @param width The viewport width + * @param height Viewport height + * @param partialTick Partial tick time, useful for interpolation + */ + default void renderHelmetOverlay(ItemStack stack, Player player, int width, int height, float partialTick) + { + } + + /** + * Queries this item's renderer. + *

+ * Only used if {@link BakedModel#isCustomRenderer()} returns {@code true} or {@link BlockState#getRenderShape()} + * returns {@link net.minecraft.world.level.block.RenderShape#ENTITYBLOCK_ANIMATED}. + *

+ * By default, returns vanilla's block entity renderer. + */ + default BlockEntityWithoutLevelRenderer getCustomRenderer() + { + return Minecraft.getInstance().getItemRenderer().getBlockEntityRenderer(); + } + + enum FontContext + { + /** + * Used to display the amount of items in the {@link ItemStack}. + */ + ITEM_COUNT, + /** + * Used to display text in the {@link net.minecraft.world.inventory.tooltip.TooltipComponent}. + */ + TOOLTIP, + /** + * Used to display the item name above the hotbar when the player selects it. + */ + SELECTED_ITEM_NAME + } +} diff --git a/src/main/java/net/minecraftforge/client/extensions/common/IClientMobEffectExtensions.java b/src/main/java/net/minecraftforge/client/extensions/common/IClientMobEffectExtensions.java new file mode 100644 index 00000000000..899f58630f5 --- /dev/null +++ b/src/main/java/net/minecraftforge/client/extensions/common/IClientMobEffectExtensions.java @@ -0,0 +1,106 @@ +/* + * Copyright (c) Forge Development LLC and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.minecraftforge.client.extensions.common; + +import com.mojang.blaze3d.vertex.PoseStack; +import net.minecraft.client.gui.Gui; +import net.minecraft.client.gui.screens.inventory.EffectRenderingInventoryScreen; +import net.minecraft.world.effect.MobEffect; +import net.minecraft.world.effect.MobEffectInstance; +import net.minecraftforge.fml.LogicalSide; + +import java.util.function.Consumer; + +/** + * {@linkplain LogicalSide#CLIENT Client-only} extensions to {@link MobEffect}. + * + * @see MobEffect#initializeClient(Consumer) + */ +public interface IClientMobEffectExtensions +{ + IClientMobEffectExtensions DEFAULT = new IClientMobEffectExtensions() { }; + + static IClientMobEffectExtensions of(MobEffectInstance instance) + { + return of(instance.getEffect()); + } + + static IClientMobEffectExtensions of(MobEffect effect) + { + return effect.getEffectRendererInternal() instanceof IClientMobEffectExtensions r ? r : DEFAULT; + } + + /** + * Queries whether the given effect should be shown in the player's inventory. + *

+ * By default, this returns {@code true}. + */ + default boolean isVisibleInInventory(MobEffectInstance instance) + { + return true; + } + + /** + * Queries whether the given effect should be shown in the HUD. + *

+ * By default, this returns {@code true}. + */ + default boolean isVisibleInGui(MobEffectInstance instance) + { + return true; + } + + /** + * Renders the icon of the specified effect in the player's inventory. + * This can be used to render icons from your own texture sheet. + * + * @param instance The effect instance + * @param screen The effect-rendering screen + * @param poseStack The pose stack + * @param x The x coordinate + * @param y The y coordinate + * @param blitOffset The blit offset + * @return true to prevent default rendering, false otherwise + */ + default boolean renderInventoryIcon(MobEffectInstance instance, EffectRenderingInventoryScreen screen, PoseStack poseStack, int x, int y, int blitOffset) + { + return false; + } + + /** + * Renders the text of the specified effect in the player's inventory. + * + * @param instance The effect instance + * @param screen The effect-rendering screen + * @param poseStack The pose stack + * @param x The x coordinate + * @param y The y coordinate + * @param blitOffset The blit offset + * @return true to prevent default rendering, false otherwise + */ + default boolean renderInventoryText(MobEffectInstance instance, EffectRenderingInventoryScreen screen, PoseStack poseStack, int x, int y, int blitOffset) + { + return false; + } + + /** + * Renders the icon of the specified effect on the player's HUD. + * This can be used to render icons from your own texture sheet. + * + * @param instance The effect instance + * @param gui The gui + * @param poseStack The pose stack + * @param x The x coordinate + * @param y The y coordinate + * @param z The z depth + * @param alpha The alpha value. Blinks when the effect is about to run out + * @return true to prevent default rendering, false otherwise + */ + default boolean renderGuiIcon(MobEffectInstance instance, Gui gui, PoseStack poseStack, int x, int y, float z, float alpha) + { + return false; + } +} diff --git a/src/main/java/net/minecraftforge/client/gui/ClientTooltipComponentManager.java b/src/main/java/net/minecraftforge/client/gui/ClientTooltipComponentManager.java new file mode 100644 index 00000000000..2ee297d8ed9 --- /dev/null +++ b/src/main/java/net/minecraftforge/client/gui/ClientTooltipComponentManager.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) Forge Development LLC and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.minecraftforge.client.gui; + +import com.google.common.collect.ImmutableMap; +import net.minecraft.client.gui.screens.inventory.tooltip.ClientTooltipComponent; +import net.minecraft.world.inventory.tooltip.TooltipComponent; +import net.minecraftforge.client.event.RegisterClientTooltipComponentFactoriesEvent; +import net.minecraftforge.fml.ModLoader; +import net.minecraftforge.fml.ModLoadingContext; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.Nullable; + +import java.util.HashMap; +import java.util.function.Function; + +/** + * Manager for {@link ClientTooltipComponent} factories. + *

+ * Provides a lookup. + */ +public final class ClientTooltipComponentManager +{ + private static ImmutableMap, Function> FACTORIES; + + /** + * Creates a client component for the given argument, or null if unsupported. + */ + @Nullable + public static ClientTooltipComponent createClientTooltipComponent(TooltipComponent component) + { + var factory = FACTORIES.get(component.getClass()); + return factory != null ? factory.apply(component) : null; + } + + @ApiStatus.Internal + public static void init() + { + var factories = new HashMap, Function>(); + var event = new RegisterClientTooltipComponentFactoriesEvent(factories); + ModLoader.get().postEventWithWrapInModOrder(event, (mc, e) -> ModLoadingContext.get().setActiveContainer(mc), (mc, e) -> ModLoadingContext.get().setActiveContainer(null)); + FACTORIES = ImmutableMap.copyOf(factories); + } + + private ClientTooltipComponentManager() + { + } +} diff --git a/src/main/java/net/minecraftforge/client/gui/IIngameOverlay.java b/src/main/java/net/minecraftforge/client/gui/IIngameOverlay.java deleted file mode 100644 index 4600df891c2..00000000000 --- a/src/main/java/net/minecraftforge/client/gui/IIngameOverlay.java +++ /dev/null @@ -1,13 +0,0 @@ -/* - * Copyright (c) Forge Development LLC and contributors - * SPDX-License-Identifier: LGPL-2.1-only - */ - -package net.minecraftforge.client.gui; - -import com.mojang.blaze3d.vertex.PoseStack; - -public interface IIngameOverlay -{ - void render(ForgeIngameGui gui, PoseStack poseStack, float partialTick, int width, int height); -} diff --git a/src/main/java/net/minecraftforge/client/gui/ModListScreen.java b/src/main/java/net/minecraftforge/client/gui/ModListScreen.java index 61696480562..b1d12a0517f 100644 --- a/src/main/java/net/minecraftforge/client/gui/ModListScreen.java +++ b/src/main/java/net/minecraftforge/client/gui/ModListScreen.java @@ -20,7 +20,7 @@ import net.minecraft.client.gui.narration.NarrationElementOutput; import net.minecraft.client.renderer.GameRenderer; import net.minecraftforge.client.gui.widget.ModListWidget; -import net.minecraftforge.fml.loading.moddiscovery.ModFile; +import net.minecraftforge.client.gui.widget.ScrollPanel; import net.minecraftforge.fml.loading.moddiscovery.ModFileInfo; import net.minecraftforge.resource.PathResourcePack; import org.apache.commons.lang3.tuple.Pair; @@ -184,7 +184,7 @@ protected void drawPanel(PoseStack poseStack, int entryRight, int relativeY, Tes RenderSystem.setShaderTexture(0, logoPath); // Draw the logo image inscribed in a rectangle with width entryWidth (minus some padding) and height 50 int headerHeight = 50; - GuiUtils.drawInscribedRect(poseStack, left + PADDING, relativeY, width - (PADDING * 2), headerHeight, logoDims.width, logoDims.height, false, true); + ScreenUtils.blitInscribed(poseStack, left + PADDING, relativeY, width - (PADDING * 2), headerHeight, logoDims.width, logoDims.height, false, true); relativeY += headerHeight + PADDING; } diff --git a/src/main/java/net/minecraftforge/client/gui/ModMismatchDisconnectedScreen.java b/src/main/java/net/minecraftforge/client/gui/ModMismatchDisconnectedScreen.java index 333411bb4ea..c3086b6861c 100644 --- a/src/main/java/net/minecraftforge/client/gui/ModMismatchDisconnectedScreen.java +++ b/src/main/java/net/minecraftforge/client/gui/ModMismatchDisconnectedScreen.java @@ -14,6 +14,7 @@ import java.util.Optional; import java.util.stream.Collectors; +import net.minecraftforge.client.gui.widget.ScrollPanel; import org.apache.commons.lang3.tuple.Pair; import com.mojang.blaze3d.vertex.PoseStack; diff --git a/src/main/java/net/minecraftforge/client/gui/OverlayRegistry.java b/src/main/java/net/minecraftforge/client/gui/OverlayRegistry.java deleted file mode 100644 index 1c7790a8a59..00000000000 --- a/src/main/java/net/minecraftforge/client/gui/OverlayRegistry.java +++ /dev/null @@ -1,186 +0,0 @@ -/* - * Copyright (c) Forge Development LLC and contributors - * SPDX-License-Identifier: LGPL-2.1-only - */ - -package net.minecraftforge.client.gui; - -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.Collections; -import java.util.List; -import java.util.Map; - -public class OverlayRegistry -{ - /** - * Adds a new overlay entry to the registry, placed at the beginning of the list. - * Call from {@link net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent}. No need for enqueueWork. - * @param displayName A string for debug purposes, used primarily in exception traces coming from the overlays. - * @param overlay An instance, lambda or method reference for the logic used in rendering the overlay. - * @return The same object passed into the {@code overlay} parameter. - */ - public static synchronized IIngameOverlay registerOverlayBottom(@NotNull String displayName, @NotNull IIngameOverlay overlay) - { - return registerOverlay(-1, null, displayName, overlay); - } - - /** - * Adds a new overlay entry to the registry, placed before the {@code other} parameter in the list. - * Call from {@link net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent}. No need for enqueueWork. - * @param other The overlay to insert before. The overlay must be registered. - * @param displayName A string for debug purposes, used primarily in exception traces coming from the overlays. - * @param overlay An instance, lambda or method reference for the logic used in rendering the overlay. - * @return The same object passed into the {@code overlay} parameter. - */ - public static synchronized IIngameOverlay registerOverlayBelow(@NotNull IIngameOverlay other, @NotNull String displayName, @NotNull IIngameOverlay overlay) - { - return registerOverlay(-1, other, displayName, overlay); - } - - /** - * Adds a new overlay entry to the registry, placed after the {@code other} parameter in the list. - * Call from {@link net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent}. No need for enqueueWork. - * @param other The overlay to insert after. The overlay must be registered. - * @param displayName A string for debug purposes, used primarily in exception traces coming from the overlays. - * @param overlay An instance, lambda or method reference for the logic used in rendering the overlay. - * @return The same object passed into the {@code overlay} parameter. - */ - public static synchronized IIngameOverlay registerOverlayAbove(@NotNull IIngameOverlay other, @NotNull String displayName, @NotNull IIngameOverlay overlay) - { - return registerOverlay(1, other, displayName, overlay); - } - - /** - * Adds a new overlay entry to the registry, placed at the end of the list. - * Call from {@link net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent}. No need for enqueueWork. - * @param displayName A string for debug purposes, used primarily in exception traces coming from the overlays. - * @param overlay An instance, lambda or method reference for the logic used in rendering the overlay. - * @return The same object passed into the {@code overlay} parameter. - */ - public static synchronized IIngameOverlay registerOverlayTop(@NotNull String displayName, @NotNull IIngameOverlay overlay) - { - return registerOverlay(1, null, displayName, overlay); - } - - private static IIngameOverlay registerOverlay(int sort, @Nullable IIngameOverlay other, @NotNull String displayName, @NotNull IIngameOverlay overlay) - { - OverlayEntry entry = overlays.get(overlay); - - if (entry != null) - { - overlaysOrdered.remove(entry); - } - - int insertAt = overlays.size(); - if (other == null) - { - if (sort < 0) - insertAt = 0; - } - else - { - for (int i = 0; i < overlaysOrdered.size(); i++) - { - OverlayEntry ov = overlaysOrdered.get(i); - if (ov.getOverlay() == other) - { - if (sort < 0) insertAt = i; - else insertAt = i+1; - break; - } - } - } - - entry = new OverlayEntry(overlay, displayName); - - overlaysOrdered.add(insertAt, entry); - overlays.put(overlay, entry); - - return overlay; - } - - /** - * Enables or disables an overlay. This is preferred over removing overlays. - * @param overlay The overlay object to enable or disable - * @param enable The new state - */ - public static synchronized void enableOverlay(@NotNull IIngameOverlay overlay, boolean enable) - { - OverlayEntry entry = overlays.get(overlay); - if (entry != null) - { - entry.setEnabled(enable); - } - } - - /** - * Returns the information on a registered overlay. - * @param overlay The overlay to obtain the information for. - * @return The registration entry for this overlay. - */ - @Nullable - public static synchronized OverlayEntry getEntry(@NotNull IIngameOverlay overlay) - { - return overlays.get(overlay); - } - - /** - * @return Returns an unmodifiable view of the ordered list of entries. - */ - public static List orderedEntries() - { - return Collections.unmodifiableList(overlaysOrdered); - } - - private static final Map overlays = Maps.newHashMap(); - private static final List overlaysOrdered = Lists.newArrayList(); - - public static class OverlayEntry { - private final IIngameOverlay overlay; - private final String displayName; - private boolean enabled = true; - - public OverlayEntry(IIngameOverlay overlay, String displayName) - { - this.overlay = overlay; - this.displayName = displayName; - } - - /** - * @return Returns the overlay renderer. - */ - public IIngameOverlay getOverlay() - { - return overlay; - } - - /** - * @return Returns the debug name for this entry. - */ - public String getDisplayName() - { - return displayName; - } - - /** - * @return Returns true if the entry will be rendered. - */ - public boolean isEnabled() - { - return enabled; - } - - /** - * For internal use. Call via {@link #enableOverlay(IIngameOverlay, boolean)}. - */ - private void setEnabled(boolean enabled) - { - this.enabled = enabled; - } - } - -} diff --git a/src/main/java/net/minecraftforge/client/gui/GuiUtils.java b/src/main/java/net/minecraftforge/client/gui/ScreenUtils.java similarity index 80% rename from src/main/java/net/minecraftforge/client/gui/GuiUtils.java rename to src/main/java/net/minecraftforge/client/gui/ScreenUtils.java index aac29daa210..1cc04add9cd 100644 --- a/src/main/java/net/minecraftforge/client/gui/GuiUtils.java +++ b/src/main/java/net/minecraftforge/client/gui/ScreenUtils.java @@ -7,33 +7,22 @@ import com.mojang.blaze3d.vertex.VertexFormat; import net.minecraft.client.gui.GuiComponent; -import net.minecraft.client.gui.Font; import net.minecraft.client.renderer.GameRenderer; -import net.minecraft.client.renderer.MultiBufferSource; import com.mojang.blaze3d.vertex.Tesselator; import com.mojang.blaze3d.vertex.BufferBuilder; import com.mojang.blaze3d.vertex.DefaultVertexFormat; -import net.minecraft.world.item.ItemStack; import net.minecraft.resources.ResourceLocation; import com.mojang.math.Matrix4f; -import net.minecraft.network.chat.FormattedText; -import net.minecraft.locale.Language; -import net.minecraft.network.chat.Style; -import net.minecraftforge.client.event.RenderTooltipEvent; -import net.minecraftforge.common.MinecraftForge; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.systems.RenderSystem; -import java.util.ArrayList; -import java.util.List; - /** * This class provides several methods and constants used by the Config GUI classes. * * @author bspkrs */ -public class GuiUtils +public class ScreenUtils { public static final int DEFAULT_BACKGROUND_COLOR = 0xF0100010; public static final int DEFAULT_BORDER_COLOR_START = 0x505000FF; @@ -43,12 +32,12 @@ public class GuiUtils public static final String VALID = "\u2714"; public static final String INVALID = "\u2715"; - public static int[] colorCodes = new int[] { 0, 170, 43520, 43690, 11141120, 11141290, 16755200, 11184810, 5592405, 5592575, 5635925, 5636095, 16733525, 16733695, 16777045, 16777215, + public static int[] TEXT_COLOR_CODES = new int[] { 0, 170, 43520, 43690, 11141120, 11141290, 16755200, 11184810, 5592405, 5592575, 5635925, 5636095, 16733525, 16733695, 16777045, 16777215, 0, 42, 10752, 10794, 2752512, 2752554, 2763264, 2763306, 1381653, 1381695, 1392405, 1392447, 4134165, 4134207, 4144917, 4144959 }; - public static int getColorCode(char c, boolean isLighter) + public static int getColorFromFormattingCharacter(char c, boolean isLighter) { - return colorCodes[isLighter ? "0123456789abcdef".indexOf(c) : "0123456789abcdef".indexOf(c) + 16]; + return TEXT_COLOR_CODES[isLighter ? "0123456789abcdef".indexOf(c) : "0123456789abcdef".indexOf(c) + 16]; } /** @@ -68,10 +57,10 @@ public static int getColorCode(char c, boolean isLighter) * @param borderSize the size of the box's borders * @param zLevel the zLevel to draw at */ - public static void drawContinuousTexturedBox(PoseStack poseStack, int x, int y, int u, int v, int width, int height, int textureWidth, int textureHeight, - int borderSize, float zLevel) + public static void blitWithBorder(PoseStack poseStack, int x, int y, int u, int v, int width, int height, int textureWidth, int textureHeight, + int borderSize, float zLevel) { - drawContinuousTexturedBox(poseStack, x, y, u, v, width, height, textureWidth, textureHeight, borderSize, borderSize, borderSize, borderSize, zLevel); + blitWithBorder(poseStack, x, y, u, v, width, height, textureWidth, textureHeight, borderSize, borderSize, borderSize, borderSize, zLevel); } /** @@ -92,10 +81,10 @@ public static void drawContinuousTexturedBox(PoseStack poseStack, int x, int y, * @param borderSize the size of the box's borders * @param zLevel the zLevel to draw at */ - public static void drawContinuousTexturedBox(PoseStack poseStack, ResourceLocation res, int x, int y, int u, int v, int width, int height, int textureWidth, int textureHeight, - int borderSize, float zLevel) + public static void blitWithBorder(PoseStack poseStack, ResourceLocation res, int x, int y, int u, int v, int width, int height, int textureWidth, int textureHeight, + int borderSize, float zLevel) { - drawContinuousTexturedBox(poseStack, res, x, y, u, v, width, height, textureWidth, textureHeight, borderSize, borderSize, borderSize, borderSize, zLevel); + blitWithBorder(poseStack, res, x, y, u, v, width, height, textureWidth, textureHeight, borderSize, borderSize, borderSize, borderSize, zLevel); } /** @@ -119,12 +108,12 @@ public static void drawContinuousTexturedBox(PoseStack poseStack, ResourceLocati * @param rightBorder the size of the box's right border * @param zLevel the zLevel to draw at */ - public static void drawContinuousTexturedBox(PoseStack poseStack, ResourceLocation res, int x, int y, int u, int v, int width, int height, int textureWidth, int textureHeight, - int topBorder, int bottomBorder, int leftBorder, int rightBorder, float zLevel) + public static void blitWithBorder(PoseStack poseStack, ResourceLocation res, int x, int y, int u, int v, int width, int height, int textureWidth, int textureHeight, + int topBorder, int bottomBorder, int leftBorder, int rightBorder, float zLevel) { RenderSystem.setShader(GameRenderer::getPositionTexShader); RenderSystem.setShaderTexture(0, res); - drawContinuousTexturedBox(poseStack, x, y, u, v, width, height, textureWidth, textureHeight, topBorder, bottomBorder, leftBorder, rightBorder, zLevel); + blitWithBorder(poseStack, x, y, u, v, width, height, textureWidth, textureHeight, topBorder, bottomBorder, leftBorder, rightBorder, zLevel); } /** @@ -147,8 +136,8 @@ public static void drawContinuousTexturedBox(PoseStack poseStack, ResourceLocati * @param rightBorder the size of the box's right border * @param zLevel the zLevel to draw at */ - public static void drawContinuousTexturedBox(PoseStack poseStack, int x, int y, int u, int v, int width, int height, int textureWidth, int textureHeight, - int topBorder, int bottomBorder, int leftBorder, int rightBorder, float zLevel) + public static void blitWithBorder(PoseStack poseStack, int x, int y, int u, int v, int width, int height, int textureWidth, int textureHeight, + int topBorder, int bottomBorder, int leftBorder, int rightBorder, float zLevel) { RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F); RenderSystem.enableBlend(); @@ -241,12 +230,12 @@ public static void drawGradientRect(Matrix4f mat, int zLevel, int left, int top, RenderSystem.enableTexture(); } - public static void drawInscribedRect(PoseStack poseStack, int x, int y, int boundsWidth, int boundsHeight, int rectWidth, int rectHeight) + public static void blitInscribed(PoseStack poseStack, int x, int y, int boundsWidth, int boundsHeight, int rectWidth, int rectHeight) { - drawInscribedRect(poseStack, x, y, boundsWidth, boundsHeight, rectWidth, rectHeight, true, true); + blitInscribed(poseStack, x, y, boundsWidth, boundsHeight, rectWidth, rectHeight, true, true); } - public static void drawInscribedRect(PoseStack poseStack, int x, int y, int boundsWidth, int boundsHeight, int rectWidth, int rectHeight, boolean centerX, boolean centerY) + public static void blitInscribed(PoseStack poseStack, int x, int y, int boundsWidth, int boundsHeight, int rectWidth, int rectHeight, boolean centerX, boolean centerY) { if (rectWidth * boundsHeight > rectHeight * boundsWidth) { int h = boundsHeight; diff --git a/src/main/java/net/minecraftforge/client/gui/NotificationModUpdateScreen.java b/src/main/java/net/minecraftforge/client/gui/TitleScreenModUpdateIndicator.java similarity index 80% rename from src/main/java/net/minecraftforge/client/gui/NotificationModUpdateScreen.java rename to src/main/java/net/minecraftforge/client/gui/TitleScreenModUpdateIndicator.java index 86f8dcac49c..92a99031a83 100644 --- a/src/main/java/net/minecraftforge/client/gui/NotificationModUpdateScreen.java +++ b/src/main/java/net/minecraftforge/client/gui/TitleScreenModUpdateIndicator.java @@ -21,7 +21,7 @@ import net.minecraftforge.api.distmarker.Dist; @OnlyIn(Dist.CLIENT) -public class NotificationModUpdateScreen extends Screen +public class TitleScreenModUpdateIndicator extends Screen { private static final ResourceLocation VERSION_CHECK_ICONS = new ResourceLocation(ForgeVersion.MOD_ID, "textures/gui/version_check_icons.png"); @@ -30,7 +30,7 @@ public class NotificationModUpdateScreen extends Screen private VersionChecker.Status showNotification = null; private boolean hasCheckedForUpdates = false; - public NotificationModUpdateScreen(Button modButton) + public TitleScreenModUpdateIndicator(Button modButton) { super(Component.translatable("forge.menu.updatescreen.title")); this.modButton = modButton; @@ -67,12 +67,12 @@ public void render(PoseStack poseStack, int mouseX, int mouseY, float partialTic blit(poseStack, x + w - (h / 2 + 4), y + (h / 2 - 4), showNotification.getSheetOffset() * 8, (showNotification.isAnimated() && ((System.currentTimeMillis() / 800 & 1) == 1)) ? 8 : 0, 8, 8, 64, 16); } - public static NotificationModUpdateScreen init(TitleScreen guiMainMenu, Button modButton) + public static TitleScreenModUpdateIndicator init(TitleScreen guiMainMenu, Button modButton) { - NotificationModUpdateScreen notificationModUpdateScreen = new NotificationModUpdateScreen(modButton); - notificationModUpdateScreen.resize(guiMainMenu.getMinecraft(), guiMainMenu.width, guiMainMenu.height); - notificationModUpdateScreen.init(); - return notificationModUpdateScreen; + TitleScreenModUpdateIndicator titleScreenModUpdateIndicator = new TitleScreenModUpdateIndicator(modButton); + titleScreenModUpdateIndicator.resize(guiMainMenu.getMinecraft(), guiMainMenu.width, guiMainMenu.height); + titleScreenModUpdateIndicator.init(); + return titleScreenModUpdateIndicator; } } diff --git a/src/main/java/net/minecraftforge/client/gui/ForgeIngameGui.java b/src/main/java/net/minecraftforge/client/gui/overlay/ForgeGui.java similarity index 52% rename from src/main/java/net/minecraftforge/client/gui/ForgeIngameGui.java rename to src/main/java/net/minecraftforge/client/gui/overlay/ForgeGui.java index 72143a6e1a2..4d52a833b40 100644 --- a/src/main/java/net/minecraftforge/client/gui/ForgeIngameGui.java +++ b/src/main/java/net/minecraftforge/client/gui/overlay/ForgeGui.java @@ -3,72 +3,77 @@ * SPDX-License-Identifier: LGPL-2.1-only */ -package net.minecraftforge.client.gui; - -import static net.minecraftforge.client.event.RenderGameOverlayEvent.ElementType.*; - -import java.util.ArrayList; -import java.util.List; +package net.minecraftforge.client.gui.overlay; +import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.vertex.PoseStack; +import net.minecraft.Util; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.Font; -import net.minecraft.client.gui.GuiComponent; import net.minecraft.client.gui.Gui; +import net.minecraft.client.gui.GuiComponent; import net.minecraft.client.gui.components.DebugScreenOverlay; import net.minecraft.client.multiplayer.ClientPacketListener; import net.minecraft.client.renderer.GameRenderer; import net.minecraft.client.resources.language.I18n; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.Mth; +import net.minecraft.util.StringUtil; +import net.minecraft.world.effect.MobEffects; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.ai.attributes.Attributes; import net.minecraft.world.entity.ai.attributes.AttributeInstance; +import net.minecraft.world.entity.ai.attributes.Attributes; import net.minecraft.world.entity.player.Player; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.effect.MobEffects; +import net.minecraft.world.food.FoodData; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.Blocks; import net.minecraft.world.scores.Objective; -import net.minecraft.world.scores.PlayerTeam; -import net.minecraft.world.scores.Scoreboard; -import net.minecraft.tags.FluidTags; -import net.minecraft.world.food.FoodData; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.util.StringUtil; -import net.minecraft.Util; -import net.minecraft.util.Mth; -import net.minecraft.world.level.GameType; -import net.minecraftforge.client.RenderProperties; -import net.minecraftforge.client.event.RenderGameOverlayEvent; -import net.minecraftforge.client.event.RenderGameOverlayEvent.ElementType; +import net.minecraftforge.client.event.CustomizeGuiOverlayEvent; +import net.minecraftforge.client.event.RenderGuiEvent; +import net.minecraftforge.client.event.RenderGuiOverlayEvent; +import net.minecraftforge.client.extensions.common.IClientItemExtensions; import net.minecraftforge.common.ForgeMod; import net.minecraftforge.common.MinecraftForge; - import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.jetbrains.annotations.Nullable; -import org.lwjgl.opengl.GL11; -import com.mojang.blaze3d.systems.RenderSystem; +import java.util.ArrayList; +import java.util.List; -public class ForgeIngameGui extends Gui +/** + * Forge wrapper around {@link Gui} to be able to render {@link IGuiOverlay HUD overlays}. + */ +public class ForgeGui extends Gui { private static final Logger LOGGER = LogManager.getLogger(); private static final int WHITE = 0xFFFFFF; /* - * If the Euclidian distance to the moused-over block in meters is less than this value, the "Looking at" text will appear on the debug overlay. + * If the Euclidean distance to the moused-over block in meters is less than this value, the "Looking at" text will appear on the debug overlay. */ public static double rayTraceDistance = 20.0D; - public int left_height = 39; - public int right_height = 39; + public int leftHeight = 39; + public int rightHeight = 39; private Font font = null; - private RenderGameOverlayEvent eventParent; - private ForgeDebugScreenOverlay debugOverlay; + private final ForgeDebugScreenOverlay debugOverlay; + + public ForgeGui(Minecraft mc) + { + super(mc, mc.getItemRenderer()); + debugOverlay = new ForgeDebugScreenOverlay(mc); + } + + public Minecraft getMinecraft() + { + return minecraft; + } public void setupOverlayRenderState(boolean blend, boolean depthText) { @@ -110,253 +115,40 @@ public void setupOverlayRenderState(boolean blend, boolean depthTest, @Nullable RenderSystem.setShader(GameRenderer::getPositionTexShader); } - public static final IIngameOverlay VIGNETTE_ELEMENT = OverlayRegistry.registerOverlayTop("Vignette", (gui, poseStack, partialTick, screenWidth, screenHeight) -> { - if (Minecraft.useFancyGraphics()) - { - gui.setupOverlayRenderState(true, false); - gui.renderVignette(gui.minecraft.getCameraEntity()); - } - }); - - public static final IIngameOverlay SPYGLASS_ELEMENT = OverlayRegistry.registerOverlayTop("Spyglass", (gui, poseStack, partialTick, screenWidth, screenHeight) -> { - gui.setupOverlayRenderState(true, false); - gui.renderSpyglassOverlay(); - }); - - public static final IIngameOverlay HELMET_ELEMENT = OverlayRegistry.registerOverlayTop("Helmet", (gui, poseStack, partialTick, screenWidth, screenHeight) -> { - gui.setupOverlayRenderState(true, false); - gui.renderHelmet(partialTick, poseStack); - }); - - public static final IIngameOverlay FROSTBITE_ELEMENT = OverlayRegistry.registerOverlayTop("Frostbite", (gui, poseStack, partialTick, screenWidth, screenHeight) -> { - gui.setupOverlayRenderState(true, false); - gui.renderFrostbite(poseStack); - }); - - public static final IIngameOverlay PORTAL_ELEMENT = OverlayRegistry.registerOverlayTop("Portal", (gui, poseStack, partialTick, screenWidth, screenHeight) -> { - - if (!gui.minecraft.player.hasEffect(MobEffects.CONFUSION)) - { - gui.setupOverlayRenderState(true, false); - gui.renderPortalOverlay(partialTick); - } - - }); - - public static final IIngameOverlay HOTBAR_ELEMENT = OverlayRegistry.registerOverlayTop("Hotbar", (gui, poseStack, partialTick, screenWidth, screenHeight) -> { - if (!gui.minecraft.options.hideGui) - { - gui.setupOverlayRenderState(true, false); - if (gui.minecraft.gameMode.getPlayerMode() == GameType.SPECTATOR) - { - gui.spectatorGui.renderHotbar(poseStack); - } - else - { - gui.renderHotbar(partialTick, poseStack); - } - } - }); - - public static final IIngameOverlay CROSSHAIR_ELEMENT = OverlayRegistry.registerOverlayTop("Crosshair", (gui, poseStack, partialTick, screenWidth, screenHeight) -> { - if (!gui.minecraft.options.hideGui) - { - gui.setupOverlayRenderState(true, false); - gui.setBlitOffset(-90); - - gui.renderCrosshair(poseStack); - } - }); - - public static final IIngameOverlay BOSS_HEALTH_ELEMENT = OverlayRegistry.registerOverlayTop("Boss Health", (gui, poseStack, partialTick, screenWidth, screenHeight) -> { - if (!gui.minecraft.options.hideGui) - { - gui.setupOverlayRenderState(true, false); - gui.setBlitOffset(-90); - - gui.renderBossHealth(poseStack); - } - }); - - public static final IIngameOverlay PLAYER_HEALTH_ELEMENT = OverlayRegistry.registerOverlayTop("Player Health", (gui, poseStack, partialTick, screenWidth, screenHeight) -> { - if (!gui.minecraft.options.hideGui && gui.shouldDrawSurvivalElements()) - { - gui.setupOverlayRenderState(true, false); - gui.renderHealth(screenWidth, screenHeight, poseStack); - } - }); - - public static final IIngameOverlay ARMOR_LEVEL_ELEMENT = OverlayRegistry.registerOverlayTop("Armor Level",(gui, poseStack, partialTick, screenWidth, screenHeight) -> { - if (!gui.minecraft.options.hideGui && gui.shouldDrawSurvivalElements()) - { - gui.setupOverlayRenderState(true, false); - gui.renderArmor(poseStack, screenWidth, screenHeight); - } - }); - - public static final IIngameOverlay FOOD_LEVEL_ELEMENT = OverlayRegistry.registerOverlayTop("Food Level", (gui, poseStack, partialTick, screenWidth, screenHeight) -> { - boolean isMounted = gui.minecraft.player.getVehicle() instanceof LivingEntity; - if (!isMounted && !gui.minecraft.options.hideGui && gui.shouldDrawSurvivalElements()) - { - gui.setupOverlayRenderState(true, false); - gui.renderFood(screenWidth, screenHeight, poseStack); - } - }); - - public static final IIngameOverlay MOUNT_HEALTH_ELEMENT = OverlayRegistry.registerOverlayTop("Mount Health", (gui, poseStack, partialTick, screenWidth, screenHeight) -> { - if (!gui.minecraft.options.hideGui && gui.shouldDrawSurvivalElements()) - { - gui.setupOverlayRenderState(true, false); - gui.renderHealthMount(screenWidth, screenHeight, poseStack); - } - }); - - public static final IIngameOverlay AIR_LEVEL_ELEMENT = OverlayRegistry.registerOverlayTop("Air Level", (gui, poseStack, partialTick, screenWidth, screenHeight) -> { - if (!gui.minecraft.options.hideGui && gui.shouldDrawSurvivalElements()) - { - gui.setupOverlayRenderState(true, false); - gui.renderAir(screenWidth, screenHeight, poseStack); - } - }); - - public static final IIngameOverlay JUMP_BAR_ELEMENT = OverlayRegistry.registerOverlayTop("Jump Bar", (gui, poseStack, partialTick, screenWidth, screenHeight) -> { - if (gui.minecraft.player.isRidingJumpable() && !gui.minecraft.options.hideGui) - { - gui.setupOverlayRenderState(true, false); - gui.renderJumpMeter(poseStack, screenWidth / 2 - 91); - } - }); - - public static final IIngameOverlay EXPERIENCE_BAR_ELEMENT = OverlayRegistry.registerOverlayTop("Experience Bar", (gui, poseStack, partialTick, screenWidth, screenHeight) -> { - if (!gui.minecraft.player.isRidingJumpable() && !gui.minecraft.options.hideGui) - { - gui.setupOverlayRenderState(true, false); - gui.renderExperience(screenWidth / 2 - 91, poseStack); - } - }); - - public static final IIngameOverlay ITEM_NAME_ELEMENT = OverlayRegistry.registerOverlayTop("Item Name", (gui, poseStack, partialTick, screenWidth, screenHeight) -> { - if (!gui.minecraft.options.hideGui) - { - gui.setupOverlayRenderState(true, false); - if (gui.minecraft.options.heldItemTooltips && gui.minecraft.gameMode.getPlayerMode() != GameType.SPECTATOR) { - gui.renderSelectedItemName(poseStack); - } else if (gui.minecraft.player.isSpectator()) { - gui.spectatorGui.renderTooltip(poseStack); - } - } - }); - - public static final IIngameOverlay SLEEP_FADE_ELEMENT = OverlayRegistry.registerOverlayTop("Sleep Fade", (gui, poseStack, partialTick, screenWidth, screenHeight) -> { - gui.renderSleepFade(screenWidth, screenHeight, poseStack); - }); - - public static final IIngameOverlay HUD_TEXT_ELEMENT = OverlayRegistry.registerOverlayTop("Text Columns", (gui, poseStack, partialTick, screenWidth, screenHeight) -> { - gui.renderHUDText(screenWidth, screenHeight, poseStack); - }); - - public static final IIngameOverlay FPS_GRAPH_ELEMENT = OverlayRegistry.registerOverlayTop("FPS Graph", (gui, poseStack, partialTick, screenWidth, screenHeight) -> { - gui.renderFPSGraph(poseStack); - }); - - public static final IIngameOverlay POTION_ICONS_ELEMENT = OverlayRegistry.registerOverlayTop("Potion Icons", (gui, poseStack, partialTick, screenWidth, screenHeight) -> { - gui.renderEffects(poseStack); - }); - - public static final IIngameOverlay RECORD_OVERLAY_ELEMENT = OverlayRegistry.registerOverlayTop("Record", (gui, poseStack, partialTick, screenWidth, screenHeight) -> { - if (!gui.minecraft.options.hideGui) - { - gui.renderRecordOverlay(screenWidth, screenHeight, partialTick, poseStack); - } - }); - - public static final IIngameOverlay SUBTITLES_ELEMENT = OverlayRegistry.registerOverlayTop("Subtitles", (gui, poseStack, partialTick, screenWidth, screenHeight) -> { - if (!gui.minecraft.options.hideGui) - { - gui.renderSubtitles(poseStack); - } - }); - - public static final IIngameOverlay TITLE_TEXT_ELEMENT = OverlayRegistry.registerOverlayTop("Title Text", (gui, poseStack, partialTick, screenWidth, screenHeight) -> { - if (!gui.minecraft.options.hideGui) - { - gui.renderTitle(screenWidth, screenHeight, partialTick, poseStack); - } - }); - - public static final IIngameOverlay SCOREBOARD_ELEMENT = OverlayRegistry.registerOverlayTop("Scoreboard", (gui, poseStack, partialTick, screenWidth, screenHeight) -> { - - Scoreboard scoreboard = gui.minecraft.level.getScoreboard(); - Objective objective = null; - PlayerTeam scoreplayerteam = scoreboard.getPlayersTeam(gui.minecraft.player.getScoreboardName()); - if (scoreplayerteam != null) - { - int slot = scoreplayerteam.getColor().getId(); - if (slot >= 0) objective = scoreboard.getDisplayObjective(3 + slot); - } - Objective scoreobjective1 = objective != null ? objective : scoreboard.getDisplayObjective(1); - if (scoreobjective1 != null) - { - gui.displayScoreboardSidebar(poseStack, scoreobjective1); - } - }); - - public static final IIngameOverlay CHAT_PANEL_ELEMENT = OverlayRegistry.registerOverlayTop("Chat History", (gui, poseStack, partialTick, screenWidth, screenHeight) -> { - - RenderSystem.enableBlend(); - RenderSystem.blendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, 1, 0); - - gui.renderChat(screenWidth, screenHeight, poseStack); - }); - - public static final IIngameOverlay PLAYER_LIST_ELEMENT = OverlayRegistry.registerOverlayTop("Player List", (gui, poseStack, partialTick, screenWidth, screenHeight) -> { - - RenderSystem.enableBlend(); - RenderSystem.blendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, 1, 0); - - gui.renderPlayerList(screenWidth, screenHeight, poseStack); - }); - - public ForgeIngameGui(Minecraft mc) - { - super(mc, mc.getItemRenderer()); - debugOverlay = new ForgeDebugScreenOverlay(mc); - } - @Override public void render(PoseStack poseStack, float partialTick) { this.screenWidth = this.minecraft.getWindow().getGuiScaledWidth(); this.screenHeight = this.minecraft.getWindow().getGuiScaledHeight(); - eventParent = new RenderGameOverlayEvent(poseStack, partialTick, this.minecraft.getWindow()); - right_height = 39; - left_height = 39; + rightHeight = 39; + leftHeight = 39; - if (pre(ALL, poseStack)) return; + if (MinecraftForge.EVENT_BUS.post(new RenderGuiEvent.Pre(minecraft.getWindow(), poseStack, partialTick))) + { + return; + } font = minecraft.font; this.random.setSeed(tickCount * 312871L); - OverlayRegistry.orderedEntries().forEach(entry -> { + GuiOverlayManager.getOverlays().forEach(entry -> { try { - if (!entry.isEnabled()) return; - IIngameOverlay overlay = entry.getOverlay(); - if (pre(overlay, poseStack)) return; + IGuiOverlay overlay = entry.overlay(); + if (pre(entry, poseStack)) return; overlay.render(this, poseStack, partialTick, screenWidth, screenHeight); - post(overlay, poseStack); - } - catch(Exception e) + post(entry, poseStack); + } catch (Exception e) { - LOGGER.error("Error rendering overlay '{}'", entry.getDisplayName(), e); + LOGGER.error("Error rendering overlay '{}'", entry.id(), e); } }); RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F); - post(ALL, poseStack); + MinecraftForge.EVENT_BUS.post(new RenderGuiEvent.Post(minecraft.getWindow(), poseStack, partialTick)); } public boolean shouldDrawSurvivalElements() @@ -378,7 +170,7 @@ protected void renderBossHealth(PoseStack poseStack) minecraft.getProfiler().pop(); } - private void renderSpyglassOverlay() + void renderSpyglassOverlay() { float deltaFrame = this.minecraft.getDeltaFrameTime(); this.scopeScale = Mth.lerp(0.5F * deltaFrame, this.scopeScale, 1.125F); @@ -387,14 +179,15 @@ private void renderSpyglassOverlay() if (this.minecraft.player.isScoping()) { this.renderSpyglassOverlay(this.scopeScale); - } else + } + else { this.scopeScale = 0.5F; } } } - private void renderHelmet(float partialTick, PoseStack poseStack) + void renderHelmet(float partialTick, PoseStack poseStack) { ItemStack itemstack = this.minecraft.player.getInventory().getArmor(3); @@ -407,14 +200,15 @@ private void renderHelmet(float partialTick, PoseStack poseStack) } else { - RenderProperties.get(item).renderHelmetOverlay(itemstack, minecraft.player, this.screenWidth, this.screenHeight, partialTick); + IClientItemExtensions.of(item).renderHelmetOverlay(itemstack, minecraft.player, this.screenWidth, this.screenHeight, partialTick); } } } - private void renderFrostbite(PoseStack pStack) + void renderFrostbite(PoseStack pStack) { - if (this.minecraft.player.getTicksFrozen() > 0) { + if (this.minecraft.player.getTicksFrozen() > 0) + { this.renderTextureOverlay(POWDER_SNOW_OUTLINE_LOCATION, this.minecraft.player.getPercentFrozen()); } } @@ -425,7 +219,7 @@ protected void renderArmor(PoseStack poseStack, int width, int height) RenderSystem.enableBlend(); int left = width / 2 - 91; - int top = height - left_height; + int top = height - leftHeight; int level = minecraft.player.getArmorValue(); for (int i = 1; level > 0 && i < 20; i += 2) @@ -444,7 +238,7 @@ else if (i > level) } left += 8; } - left_height += 10; + leftHeight += 10; RenderSystem.disableBlend(); minecraft.getProfiler().pop(); @@ -464,22 +258,22 @@ protected void renderPortalOverlay(float partialTick) protected void renderAir(int width, int height, PoseStack poseStack) { minecraft.getProfiler().push("air"); - Player player = (Player)this.minecraft.getCameraEntity(); + Player player = (Player) this.minecraft.getCameraEntity(); RenderSystem.enableBlend(); int left = width / 2 + 91; - int top = height - right_height; + int top = height - rightHeight; int air = player.getAirSupply(); if (player.isEyeInFluidType(ForgeMod.WATER_TYPE.get()) || air < 300) { - int full = Mth.ceil((double)(air - 2) * 10.0D / 300.0D); - int partial = Mth.ceil((double)air * 10.0D / 300.0D) - full; + int full = Mth.ceil((double) (air - 2) * 10.0D / 300.0D); + int partial = Mth.ceil((double) air * 10.0D / 300.0D) - full; for (int i = 0; i < full + partial; ++i) { blit(poseStack, left - i * 8 - 9, top, (i < full ? 16 : 25), 18, 9, 9); } - right_height += 10; + rightHeight += 10; } RenderSystem.disableBlend(); @@ -492,19 +286,19 @@ public void renderHealth(int width, int height, PoseStack pStack) minecraft.getProfiler().push("health"); RenderSystem.enableBlend(); - Player player = (Player)this.minecraft.getCameraEntity(); + Player player = (Player) this.minecraft.getCameraEntity(); int health = Mth.ceil(player.getHealth()); - boolean highlight = healthBlinkTime > (long)tickCount && (healthBlinkTime - (long)tickCount) / 3L %2L == 1L; + boolean highlight = healthBlinkTime > (long) tickCount && (healthBlinkTime - (long) tickCount) / 3L % 2L == 1L; if (health < this.lastHealth && player.invulnerableTime > 0) { this.lastHealthTime = Util.getMillis(); - this.healthBlinkTime = (long)(this.tickCount + 20); + this.healthBlinkTime = (long) (this.tickCount + 20); } else if (health > this.lastHealth && player.invulnerableTime > 0) { this.lastHealthTime = Util.getMillis(); - this.healthBlinkTime = (long)(this.tickCount + 10); + this.healthBlinkTime = (long) (this.tickCount + 10); } if (Util.getMillis() - this.lastHealthTime > 1000L) @@ -518,18 +312,18 @@ else if (health > this.lastHealth && player.invulnerableTime > 0) int healthLast = this.displayHealth; AttributeInstance attrMaxHealth = player.getAttribute(Attributes.MAX_HEALTH); - float healthMax = Math.max((float)attrMaxHealth.getValue(), Math.max(healthLast, health)); + float healthMax = Math.max((float) attrMaxHealth.getValue(), Math.max(healthLast, health)); int absorb = Mth.ceil(player.getAbsorptionAmount()); int healthRows = Mth.ceil((healthMax + absorb) / 2.0F / 10.0F); int rowHeight = Math.max(10 - (healthRows - 2), 3); - this.random.setSeed((long)(tickCount * 312871)); + this.random.setSeed((long) (tickCount * 312871)); int left = width / 2 - 91; - int top = height - left_height; - left_height += (healthRows * rowHeight); - if (rowHeight != 10) left_height += 10 - rowHeight; + int top = height - leftHeight; + leftHeight += (healthRows * rowHeight); + if (rowHeight != 10) leftHeight += 10 - rowHeight; int regen = -1; if (player.hasEffect(MobEffects.REGENERATION)) @@ -547,11 +341,11 @@ public void renderFood(int width, int height, PoseStack poseStack) { minecraft.getProfiler().push("food"); - Player player = (Player)this.minecraft.getCameraEntity(); + Player player = (Player) this.minecraft.getCameraEntity(); RenderSystem.enableBlend(); int left = width / 2 + 91; - int top = height - right_height; - right_height += 10; + int top = height - rightHeight; + rightHeight += 10; boolean unused = false;// Unused flag in vanilla, seems to be part of a 'fade out' mechanic FoodData stats = minecraft.player.getFoodData(); @@ -596,14 +390,14 @@ protected void renderSleepFade(int width, int height, PoseStack poseStack) RenderSystem.disableDepthTest(); // RenderSystem.disableAlphaTest(); int sleepTime = minecraft.player.getSleepTimer(); - float opacity = (float)sleepTime / 100.0F; + float opacity = (float) sleepTime / 100.0F; if (opacity > 1.0F) { - opacity = 1.0F - (float)(sleepTime - 100) / 10.0F; + opacity = 1.0F - (float) (sleepTime - 100) / 10.0F; } - int color = (int)(220.0F * opacity) << 24 | 1052704; + int color = (int) (220.0F * opacity) << 24 | 1052704; fill(poseStack, 0, 0, width, height, color); // RenderSystem.enableAlphaTest(); RenderSystem.enableDepthTest(); @@ -643,8 +437,9 @@ protected void renderHUDText(int width, int height, PoseStack poseStack) { minecraft.getProfiler().push("forgeHudText"); RenderSystem.defaultBlendFunc(); - ArrayList listL = new ArrayList(); - ArrayList listR = new ArrayList(); + + var listL = new ArrayList(); + var listR = new ArrayList(); if (minecraft.isDemo()) { @@ -655,48 +450,45 @@ protected void renderHUDText(int width, int height, PoseStack poseStack) } else { - listR.add(I18n.get("demo.remainingTime", StringUtil.formatTickDuration((int)(120500L - time)))); + listR.add(I18n.get("demo.remainingTime", StringUtil.formatTickDuration((int) (120500L - time)))); } } - if (this.minecraft.options.renderDebug && !pre(DEBUG, poseStack)) + if (this.minecraft.options.renderDebug) { debugOverlay.update(); listL.addAll(debugOverlay.getLeft()); listR.addAll(debugOverlay.getRight()); - post(DEBUG, poseStack); } - RenderGameOverlayEvent.Text event = new RenderGameOverlayEvent.Text(poseStack, eventParent, listL, listR); - if (!MinecraftForge.EVENT_BUS.post(event)) + var event = new CustomizeGuiOverlayEvent.DebugText(minecraft.getWindow(), poseStack, minecraft.getFrameTime(), listL, listR); + MinecraftForge.EVENT_BUS.post(event); + + int top = 2; + for (String msg : listL) { - int top = 2; - for (String msg : listL) + if (msg != null && !msg.isEmpty()) { - if (msg != null && !msg.isEmpty()) - { - fill(poseStack, 1, top - 1, 2 + font.width(msg) + 1, top + font.lineHeight - 1, -1873784752); - font.draw(poseStack, msg, 2, top, 14737632); - } - top += font.lineHeight; + fill(poseStack, 1, top - 1, 2 + font.width(msg) + 1, top + font.lineHeight - 1, -1873784752); + font.draw(poseStack, msg, 2, top, 14737632); } + top += font.lineHeight; + } - top = 2; - for (String msg : listR) + top = 2; + for (String msg : listR) + { + if (msg != null && !msg.isEmpty()) { - if (msg != null && !msg.isEmpty()) - { - int w = font.width(msg); - int left = width - 2 - w; - fill(poseStack, left - 1, top - 1, left + w + 1, top + font.lineHeight - 1, -1873784752); - font.draw(poseStack, msg, left, top, 14737632); - } - top += font.lineHeight; + int w = font.width(msg); + int left = width - 2 - w; + fill(poseStack, left - 1, top - 1, left + w + 1, top + font.lineHeight - 1, -1873784752); + font.draw(poseStack, msg, left, top, 14737632); } + top += font.lineHeight; } minecraft.getProfiler().pop(); - post(TEXT, poseStack); } protected void renderFPSGraph(PoseStack poseStack) @@ -712,8 +504,8 @@ protected void renderRecordOverlay(int width, int height, float partialTick, Pos if (overlayMessageTime > 0) { minecraft.getProfiler().push("overlayMessage"); - float hue = (float)overlayMessageTime - partialTick; - int opacity = (int)(hue * 255.0F / 20.0F); + float hue = (float) overlayMessageTime - partialTick; + int opacity = (int) (hue * 255.0F / 20.0F); if (opacity > 255) opacity = 255; if (opacity > 8) @@ -738,15 +530,15 @@ protected void renderTitle(int width, int height, float partialTick, PoseStack p if (title != null && titleTime > 0) { minecraft.getProfiler().push("titleAndSubtitle"); - float age = (float)this.titleTime - partialTick; + float age = (float) this.titleTime - partialTick; int opacity = 255; if (titleTime > titleFadeOutTime + titleStayTime) { - float f3 = (float)(titleFadeInTime + titleStayTime + titleFadeOutTime) - age; - opacity = (int)(f3 * 255.0F / (float)titleFadeInTime); + float f3 = (float) (titleFadeInTime + titleStayTime + titleFadeOutTime) - age; + opacity = (int) (f3 * 255.0F / (float) titleFadeInTime); } - if (titleTime <= titleFadeOutTime) opacity = (int)(age * 255.0F / (float)this.titleFadeOutTime); + if (titleTime <= titleFadeOutTime) opacity = (int) (age * 255.0F / (float) this.titleFadeOutTime); opacity = Mth.clamp(opacity, 0, 255); @@ -759,13 +551,13 @@ protected void renderTitle(int width, int height, float partialTick, PoseStack p pStack.pushPose(); pStack.scale(4.0F, 4.0F, 4.0F); int l = opacity << 24 & -16777216; - this.getFont().drawShadow(pStack, this.title.getVisualOrderText(), (float)(-this.getFont().width(this.title) / 2), -10.0F, 16777215 | l); + this.getFont().drawShadow(pStack, this.title.getVisualOrderText(), (float) (-this.getFont().width(this.title) / 2), -10.0F, 16777215 | l); pStack.popPose(); if (this.subtitle != null) { pStack.pushPose(); pStack.scale(2.0F, 2.0F, 2.0F); - this.getFont().drawShadow(pStack, this.subtitle.getVisualOrderText(), (float)(-this.getFont().width(this.subtitle) / 2), 5.0F, 16777215 | l); + this.getFont().drawShadow(pStack, this.subtitle.getVisualOrderText(), (float) (-this.getFont().width(this.subtitle) / 2), 5.0F, 16777215 | l); pStack.popPose(); } RenderSystem.disableBlend(); @@ -780,16 +572,14 @@ protected void renderChat(int width, int height, PoseStack pStack) { minecraft.getProfiler().push("chat"); - RenderGameOverlayEvent.Chat event = new RenderGameOverlayEvent.Chat(pStack, eventParent, 0, height - 48); - if (MinecraftForge.EVENT_BUS.post(event)) return; + var event = new CustomizeGuiOverlayEvent.Chat(minecraft.getWindow(), pStack, minecraft.getFrameTime(), 0, height - 48); + MinecraftForge.EVENT_BUS.post(event); pStack.pushPose(); pStack.translate(event.getPosX(), event.getPosY(), 0.0D); chat.render(pStack, tickCount); pStack.popPose(); - post(CHAT, pStack); - minecraft.getProfiler().pop(); } @@ -801,9 +591,8 @@ protected void renderPlayerList(int width, int height, PoseStack poseStack) if (minecraft.options.keyPlayerList.isDown() && (!minecraft.isLocalServer() || handler.getOnlinePlayers().size() > 1 || scoreobjective != null)) { this.tabList.setVisible(true); - if (pre(PLAYER_LIST, poseStack)) return; this.tabList.render(poseStack, width, this.minecraft.level.getScoreboard(), scoreobjective); - post(PLAYER_LIST, poseStack); + } else { @@ -813,7 +602,7 @@ protected void renderPlayerList(int width, int height, PoseStack poseStack) protected void renderHealthMount(int width, int height, PoseStack poseStack) { - Player player = (Player)minecraft.getCameraEntity(); + Player player = (Player) minecraft.getCameraEntity(); Entity tmp = player.getVehicle(); if (!(tmp instanceof LivingEntity)) return; @@ -824,10 +613,10 @@ protected void renderHealthMount(int width, int height, PoseStack poseStack) minecraft.getProfiler().popPush("mountHealth"); RenderSystem.enableBlend(); - LivingEntity mount = (LivingEntity)tmp; - int health = (int)Math.ceil((double)mount.getHealth()); + LivingEntity mount = (LivingEntity) tmp; + int health = (int) Math.ceil((double) mount.getHealth()); float healthMax = mount.getMaxHealth(); - int hearts = (int)(healthMax + 0.5F) / 2; + int hearts = (int) (healthMax + 0.5F) / 2; if (hearts > 30) hearts = 30; @@ -838,7 +627,7 @@ protected void renderHealthMount(int width, int height, PoseStack poseStack) for (int heart = 0; hearts > 0; heart += 20) { - int top = height - right_height; + int top = height - rightHeight; int rowCount = Math.min(hearts, 10); hearts -= rowCount; @@ -854,49 +643,50 @@ else if (i * 2 + 1 + heart == health) blit(poseStack, x, top, HALF, 9, 9, 9); } - right_height += 10; + rightHeight += 10; } RenderSystem.disableBlend(); } //Helper macros - private boolean pre(ElementType type, PoseStack poseStack) + private boolean pre(NamedGuiOverlay overlay, PoseStack poseStack) { - return MinecraftForge.EVENT_BUS.post(new RenderGameOverlayEvent.Pre(poseStack, eventParent, type)); + return MinecraftForge.EVENT_BUS.post(new RenderGuiOverlayEvent.Pre(minecraft.getWindow(), poseStack, minecraft.getFrameTime(), overlay)); } - private void post(ElementType type, PoseStack poseStack) - { - MinecraftForge.EVENT_BUS.post(new RenderGameOverlayEvent.Post(poseStack, eventParent, type)); - } - private boolean pre(IIngameOverlay overlay, PoseStack poseStack) - { - return MinecraftForge.EVENT_BUS.post(new RenderGameOverlayEvent.PreLayer(poseStack, eventParent, overlay)); - } - private void post(IIngameOverlay overlay, PoseStack poseStack) + + private void post(NamedGuiOverlay overlay, PoseStack poseStack) { - MinecraftForge.EVENT_BUS.post(new RenderGameOverlayEvent.PostLayer(poseStack, eventParent, overlay)); + MinecraftForge.EVENT_BUS.post(new RenderGuiOverlayEvent.Post(minecraft.getWindow(), poseStack, minecraft.getFrameTime(), overlay)); } + private void bind(ResourceLocation res) { RenderSystem.setShaderTexture(0, res); } - private class ForgeDebugScreenOverlay extends DebugScreenOverlay + private static class ForgeDebugScreenOverlay extends DebugScreenOverlay { - private Minecraft mc; + private final Minecraft mc; + private ForgeDebugScreenOverlay(Minecraft mc) { super(mc); this.mc = mc; } + public void update() { Entity entity = this.mc.getCameraEntity(); this.block = entity.pick(rayTraceDistance, 0.0F, false); this.liquid = entity.pick(rayTraceDistance, 0.0F, true); } - @Override protected void drawGameInformation(PoseStack poseStack){} - @Override protected void drawSystemInformation(PoseStack poseStack){} + + @Override + protected void drawGameInformation(PoseStack poseStack) {} + + @Override + protected void drawSystemInformation(PoseStack poseStack) {} + private List getLeft() { List ret = this.getGameInformation(); @@ -906,6 +696,10 @@ private List getLeft() ret.add("For help: press F3 + Q"); return ret; } - private List getRight(){ return this.getSystemInformation(); } + + private List getRight() + { + return this.getSystemInformation(); + } } } diff --git a/src/main/java/net/minecraftforge/client/gui/overlay/GuiOverlayManager.java b/src/main/java/net/minecraftforge/client/gui/overlay/GuiOverlayManager.java new file mode 100644 index 00000000000..9c03fcc7f2c --- /dev/null +++ b/src/main/java/net/minecraftforge/client/gui/overlay/GuiOverlayManager.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) Forge Development LLC and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.minecraftforge.client.gui.overlay; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import net.minecraft.resources.ResourceLocation; +import net.minecraftforge.client.event.RegisterGuiOverlaysEvent; +import net.minecraftforge.fml.ModLoader; +import net.minecraftforge.fml.ModLoadingContext; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.function.Function; + +/** + * Manager for {@linkplain IGuiOverlay HUD overlays}. + *

+ * Provides a lookup by ID, as well as all registered {@link IGuiOverlay overlays}. + */ +public final class GuiOverlayManager +{ + private static ImmutableList OVERLAYS; + private static ImmutableMap OVERLAYS_BY_NAME; + + /** + * Retrieves an ordered list of all registered overlays. + */ + public static ImmutableList getOverlays() + { + return OVERLAYS; + } + + /** + * Finds the overlay corresponding to a given ID. + * Do not call this before {@link RegisterGuiOverlaysEvent} has finished firing. + */ + @Nullable + public static NamedGuiOverlay findOverlay(ResourceLocation id) + { + return OVERLAYS_BY_NAME.get(id); + } + + @ApiStatus.Internal + public static void init() + { + var overlays = new HashMap(); + var orderedOverlays = new ArrayList(); + preRegisterVanillaOverlays(overlays, orderedOverlays); + var event = new RegisterGuiOverlaysEvent(overlays, orderedOverlays); + ModLoader.get().postEventWithWrapInModOrder(event, (mc, e) -> ModLoadingContext.get().setActiveContainer(mc), (mc, e) -> ModLoadingContext.get().setActiveContainer(null)); + OVERLAYS = orderedOverlays.stream() + .map(id -> new NamedGuiOverlay(id, overlays.get(id))) + .collect(ImmutableList.toImmutableList()); + OVERLAYS_BY_NAME = OVERLAYS.stream() + .collect(ImmutableMap.toImmutableMap(NamedGuiOverlay::id, Function.identity())); + } + + /** + * Pre-registers vanilla overlays so they are available for ordering. + */ + private static void preRegisterVanillaOverlays(HashMap overlays, ArrayList orderedOverlays) + { + for (var entry : VanillaGuiOverlay.values()) + { + overlays.put(entry.id(), entry.overlay); + orderedOverlays.add(entry.id()); + } + } + + private GuiOverlayManager() + { + } +} diff --git a/src/main/java/net/minecraftforge/client/gui/overlay/IGuiOverlay.java b/src/main/java/net/minecraftforge/client/gui/overlay/IGuiOverlay.java new file mode 100644 index 00000000000..03f02440a19 --- /dev/null +++ b/src/main/java/net/minecraftforge/client/gui/overlay/IGuiOverlay.java @@ -0,0 +1,20 @@ +/* + * Copyright (c) Forge Development LLC and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.minecraftforge.client.gui.overlay; + +import com.mojang.blaze3d.vertex.PoseStack; +import net.minecraftforge.client.event.RegisterGuiOverlaysEvent; + +/** + * A HUD overlay. + * + * @see RegisterGuiOverlaysEvent + */ +@FunctionalInterface +public interface IGuiOverlay +{ + void render(ForgeGui gui, PoseStack poseStack, float partialTick, int width, int height); +} diff --git a/src/main/java/net/minecraftforge/client/gui/overlay/NamedGuiOverlay.java b/src/main/java/net/minecraftforge/client/gui/overlay/NamedGuiOverlay.java new file mode 100644 index 00000000000..03bf94ea19d --- /dev/null +++ b/src/main/java/net/minecraftforge/client/gui/overlay/NamedGuiOverlay.java @@ -0,0 +1,24 @@ +/* + * Copyright (c) Forge Development LLC and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.minecraftforge.client.gui.overlay; + +import net.minecraft.resources.ResourceLocation; +import org.jetbrains.annotations.ApiStatus; + +/** + * An object representation of an {@link IGuiOverlay overlay} with a name. + *

+ * Useful to identify overlays in {@link net.minecraftforge.client.event.RenderGuiOverlayEvent}. + *

+ * Users should not be instantiating this themselves. Retrieve from {@link GuiOverlayManager}. + */ +public record NamedGuiOverlay(ResourceLocation id, IGuiOverlay overlay) +{ + @ApiStatus.Internal + public NamedGuiOverlay + { + } +} diff --git a/src/main/java/net/minecraftforge/client/gui/overlay/VanillaGuiOverlay.java b/src/main/java/net/minecraftforge/client/gui/overlay/VanillaGuiOverlay.java new file mode 100644 index 00000000000..7fa6ed3672b --- /dev/null +++ b/src/main/java/net/minecraftforge/client/gui/overlay/VanillaGuiOverlay.java @@ -0,0 +1,224 @@ +/* + * Copyright (c) Forge Development LLC and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.minecraftforge.client.gui.overlay; + +import com.mojang.blaze3d.systems.RenderSystem; +import net.minecraft.client.Minecraft; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.effect.MobEffects; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.level.GameType; +import net.minecraft.world.scores.Objective; +import net.minecraft.world.scores.PlayerTeam; +import net.minecraft.world.scores.Scoreboard; +import org.jetbrains.annotations.NotNull; +import org.lwjgl.opengl.GL11; + +/** + * All the vanilla {@linkplain IGuiOverlay HUD overlays} in the order that they render. + */ +public enum VanillaGuiOverlay +{ + VIGNETTE("vignette", (gui, poseStack, partialTick, screenWidth, screenHeight) -> { + if (Minecraft.useFancyGraphics()) + { + gui.setupOverlayRenderState(true, false); + gui.renderVignette(gui.getMinecraft().getCameraEntity()); + } + }), + SPYGLASS("spyglass", (gui, poseStack, partialTick, screenWidth, screenHeight) -> { + gui.setupOverlayRenderState(true, false); + gui.renderSpyglassOverlay(); + }), + HELMET("helmet", (gui, poseStack, partialTick, screenWidth, screenHeight) -> { + gui.setupOverlayRenderState(true, false); + gui.renderHelmet(partialTick, poseStack); + }), + FROSTBITE("frostbite", (gui, poseStack, partialTick, screenWidth, screenHeight) -> { + gui.setupOverlayRenderState(true, false); + gui.renderFrostbite(poseStack); + }), + PORTAL("portal", (gui, poseStack, partialTick, screenWidth, screenHeight) -> { + + if (!gui.getMinecraft().player.hasEffect(MobEffects.CONFUSION)) + { + gui.setupOverlayRenderState(true, false); + gui.renderPortalOverlay(partialTick); + } + + }), + HOTBAR("hotbar", (gui, poseStack, partialTick, screenWidth, screenHeight) -> { + if (!gui.getMinecraft().options.hideGui) + { + gui.setupOverlayRenderState(true, false); + if (gui.getMinecraft().gameMode.getPlayerMode() == GameType.SPECTATOR) + { + gui.getSpectatorGui().renderHotbar(poseStack); + } + else + { + gui.renderHotbar(partialTick, poseStack); + } + } + }), + CROSSHAIR("crosshair", (gui, poseStack, partialTick, screenWidth, screenHeight) -> { + if (!gui.getMinecraft().options.hideGui) + { + gui.setupOverlayRenderState(true, false); + gui.setBlitOffset(-90); + + gui.renderCrosshair(poseStack); + } + }), + BOSS_EVENT_PROGRESS("boss_event_progress", (gui, poseStack, partialTick, screenWidth, screenHeight) -> { + if (!gui.getMinecraft().options.hideGui) + { + gui.setupOverlayRenderState(true, false); + gui.setBlitOffset(-90); + + gui.renderBossHealth(poseStack); + } + }), + PLAYER_HEALTH("player_health", (gui, poseStack, partialTick, screenWidth, screenHeight) -> { + if (!gui.getMinecraft().options.hideGui && gui.shouldDrawSurvivalElements()) + { + gui.setupOverlayRenderState(true, false); + gui.renderHealth(screenWidth, screenHeight, poseStack); + } + }), + ARMOR_LEVEL("armor_level", (gui, poseStack, partialTick, screenWidth, screenHeight) -> { + if (!gui.getMinecraft().options.hideGui && gui.shouldDrawSurvivalElements()) + { + gui.setupOverlayRenderState(true, false); + gui.renderArmor(poseStack, screenWidth, screenHeight); + } + }), + FOOD_LEVEL("food_level", (gui, poseStack, partialTick, screenWidth, screenHeight) -> { + boolean isMounted = gui.getMinecraft().player.getVehicle() instanceof LivingEntity; + if (!isMounted && !gui.getMinecraft().options.hideGui && gui.shouldDrawSurvivalElements()) + { + gui.setupOverlayRenderState(true, false); + gui.renderFood(screenWidth, screenHeight, poseStack); + } + }), + MOUNT_HEALTH("mount_health", (gui, poseStack, partialTick, screenWidth, screenHeight) -> { + if (!gui.getMinecraft().options.hideGui && gui.shouldDrawSurvivalElements()) + { + gui.setupOverlayRenderState(true, false); + gui.renderHealthMount(screenWidth, screenHeight, poseStack); + } + }), + AIR_LEVEL("air_level", (gui, poseStack, partialTick, screenWidth, screenHeight) -> { + if (!gui.getMinecraft().options.hideGui && gui.shouldDrawSurvivalElements()) + { + gui.setupOverlayRenderState(true, false); + gui.renderAir(screenWidth, screenHeight, poseStack); + } + }), + JUMP_BAR("jump_bar", (gui, poseStack, partialTick, screenWidth, screenHeight) -> { + if (gui.getMinecraft().player.isRidingJumpable() && !gui.getMinecraft().options.hideGui) + { + gui.setupOverlayRenderState(true, false); + gui.renderJumpMeter(poseStack, screenWidth / 2 - 91); + } + }), + EXPERIENCE_BAR("experience_bar", (gui, poseStack, partialTick, screenWidth, screenHeight) -> { + if (!gui.getMinecraft().player.isRidingJumpable() && !gui.getMinecraft().options.hideGui) + { + gui.setupOverlayRenderState(true, false); + gui.renderExperience(screenWidth / 2 - 91, poseStack); + } + }), + ITEM_NAME("item_name", (gui, poseStack, partialTick, screenWidth, screenHeight) -> { + if (!gui.getMinecraft().options.hideGui) + { + gui.setupOverlayRenderState(true, false); + if (gui.getMinecraft().options.heldItemTooltips && gui.getMinecraft().gameMode.getPlayerMode() != GameType.SPECTATOR) + { + gui.renderSelectedItemName(poseStack); + } + else if (gui.getMinecraft().player.isSpectator()) + { + gui.getSpectatorGui().renderTooltip(poseStack); + } + } + }), + SLEEP_FADE("sleep_fade", (gui, poseStack, partialTick, screenWidth, screenHeight) -> { + gui.renderSleepFade(screenWidth, screenHeight, poseStack); + }), + DEBUG_TEXT("debug_text", (gui, poseStack, partialTick, screenWidth, screenHeight) -> { + gui.renderHUDText(screenWidth, screenHeight, poseStack); + }), + FPS_GRAPH("fps_graph", (gui, poseStack, partialTick, screenWidth, screenHeight) -> { + gui.renderFPSGraph(poseStack); + }), + POTION_ICONS("potion_icons", (gui, poseStack, partialTick, screenWidth, screenHeight) -> { + gui.renderEffects(poseStack); + }), + RECORD_OVERLAY("record_overlay", (gui, poseStack, partialTick, screenWidth, screenHeight) -> { + if (!gui.getMinecraft().options.hideGui) + { + gui.renderRecordOverlay(screenWidth, screenHeight, partialTick, poseStack); + } + }), + SUBTITLES("subtitles", (gui, poseStack, partialTick, screenWidth, screenHeight) -> { + if (!gui.getMinecraft().options.hideGui) + { + gui.renderSubtitles(poseStack); + } + }), + TITLE_TEXT("title_text", (gui, poseStack, partialTick, screenWidth, screenHeight) -> { + if (!gui.getMinecraft().options.hideGui) + { + gui.renderTitle(screenWidth, screenHeight, partialTick, poseStack); + } + }), + SCOREBOARD("scoreboard", (gui, poseStack, partialTick, screenWidth, screenHeight) -> { + + Scoreboard scoreboard = gui.getMinecraft().level.getScoreboard(); + Objective objective = null; + PlayerTeam scoreplayerteam = scoreboard.getPlayersTeam(gui.getMinecraft().player.getScoreboardName()); + if (scoreplayerteam != null) + { + int slot = scoreplayerteam.getColor().getId(); + if (slot >= 0) objective = scoreboard.getDisplayObjective(3 + slot); + } + Objective scoreobjective1 = objective != null ? objective : scoreboard.getDisplayObjective(1); + if (scoreobjective1 != null) + { + gui.displayScoreboardSidebar(poseStack, scoreobjective1); + } + }), + CHAT_PANEL("chat_panel", (gui, poseStack, partialTick, screenWidth, screenHeight) -> { + + RenderSystem.enableBlend(); + RenderSystem.blendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, 1, 0); + + gui.renderChat(screenWidth, screenHeight, poseStack); + }), + PLAYER_LIST("player_list", (gui, poseStack, partialTick, screenWidth, screenHeight) -> { + + RenderSystem.enableBlend(); + RenderSystem.blendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, 1, 0); + + gui.renderPlayerList(screenWidth, screenHeight, poseStack); + }); + + private final ResourceLocation id; + final IGuiOverlay overlay; + + VanillaGuiOverlay(String id, IGuiOverlay overlay) + { + this.id = new ResourceLocation("minecraft", id); + this.overlay = overlay; + } + + @NotNull + public ResourceLocation id() + { + return id; + } +} diff --git a/src/main/java/net/minecraftforge/client/gui/widget/ExtendedButton.java b/src/main/java/net/minecraftforge/client/gui/widget/ExtendedButton.java index 7ece01d69dd..5beb2763cfe 100644 --- a/src/main/java/net/minecraftforge/client/gui/widget/ExtendedButton.java +++ b/src/main/java/net/minecraftforge/client/gui/widget/ExtendedButton.java @@ -9,7 +9,7 @@ import net.minecraft.client.Minecraft; import net.minecraft.client.gui.components.Button; import net.minecraft.network.chat.Component; -import net.minecraftforge.client.gui.GuiUtils; +import net.minecraftforge.client.gui.ScreenUtils; /** * This class provides a button that fixes several bugs present in the vanilla GuiButton drawing code. @@ -36,7 +36,7 @@ public void renderButton(PoseStack poseStack, int mouseX, int mouseY, float part { Minecraft mc = Minecraft.getInstance(); int k = this.getYImage(this.isHovered); - GuiUtils.drawContinuousTexturedBox(poseStack, WIDGETS_LOCATION, this.x, this.y, 0, 46 + k * 20, this.width, this.height, 200, 20, 2, 3, 2, 2, this.getBlitOffset()); + ScreenUtils.blitWithBorder(poseStack, WIDGETS_LOCATION, this.x, this.y, 0, 46 + k * 20, this.width, this.height, 200, 20, 2, 3, 2, 2, this.getBlitOffset()); this.renderBg(poseStack, mc, mouseX, mouseY); Component buttonText = this.getMessage(); diff --git a/src/main/java/net/minecraftforge/client/gui/ScrollPanel.java b/src/main/java/net/minecraftforge/client/gui/widget/ScrollPanel.java similarity index 98% rename from src/main/java/net/minecraftforge/client/gui/ScrollPanel.java rename to src/main/java/net/minecraftforge/client/gui/widget/ScrollPanel.java index 4d3bdf47a92..fd37f214008 100644 --- a/src/main/java/net/minecraftforge/client/gui/ScrollPanel.java +++ b/src/main/java/net/minecraftforge/client/gui/widget/ScrollPanel.java @@ -3,7 +3,7 @@ * SPDX-License-Identifier: LGPL-2.1-only */ -package net.minecraftforge.client.gui; +package net.minecraftforge.client.gui.widget; import java.util.Collections; import java.util.List; @@ -23,6 +23,7 @@ import net.minecraft.client.gui.components.events.AbstractContainerEventHandler; import net.minecraft.client.gui.components.events.GuiEventListener; import net.minecraft.client.gui.components.Widget; +import net.minecraftforge.client.gui.ScreenUtils; /** * Abstract scroll panel class. @@ -367,7 +368,7 @@ public void render(PoseStack matrix, int mouseX, int mouseY, float partialTick) protected void drawGradientRect(PoseStack poseStack, int left, int top, int right, int bottom, int color1, int color2) { - GuiUtils.drawGradientRect(poseStack.last().pose(), 0, left, top, right, bottom, color1, color2); + ScreenUtils.drawGradientRect(poseStack.last().pose(), 0, left, top, right, bottom, color1, color2); } @Override diff --git a/src/main/java/net/minecraftforge/client/gui/widget/UnicodeGlyphButton.java b/src/main/java/net/minecraftforge/client/gui/widget/UnicodeGlyphButton.java index e58e7fd4808..1c5a84ba8eb 100644 --- a/src/main/java/net/minecraftforge/client/gui/widget/UnicodeGlyphButton.java +++ b/src/main/java/net/minecraftforge/client/gui/widget/UnicodeGlyphButton.java @@ -9,7 +9,7 @@ import net.minecraft.client.Minecraft; import net.minecraft.network.chat.Component; -import net.minecraftforge.client.gui.GuiUtils; +import net.minecraftforge.client.gui.ScreenUtils; /** * This class provides a button that shows a string glyph at the beginning. The glyph can be scaled using the glyphScale parameter. @@ -36,7 +36,7 @@ public void render(PoseStack poseStack, int mouseX, int mouseY, float partialTic Minecraft mc = Minecraft.getInstance(); this.isHovered = mouseX >= this.x && mouseY >= this.y && mouseX < this.x + this.width && mouseY < this.y + this.height; int k = this.getYImage(this.isHovered); - GuiUtils.drawContinuousTexturedBox(poseStack, WIDGETS_LOCATION, this.x, this.y, 0, 46 + k * 20, this.width, this.height, 200, 20, 2, 3, 2, 2, this.getBlitOffset()); + ScreenUtils.blitWithBorder(poseStack, WIDGETS_LOCATION, this.x, this.y, 0, 46 + k * 20, this.width, this.height, 200, 20, 2, 3, 2, 2, this.getBlitOffset()); this.renderBg(poseStack, mc, mouseX, mouseY); Component buttonText = this.createNarrationMessage(); diff --git a/src/main/java/net/minecraftforge/client/loading/ClientModLoader.java b/src/main/java/net/minecraftforge/client/loading/ClientModLoader.java index 7ed8d9ecdb5..91d1c4cbd76 100644 --- a/src/main/java/net/minecraftforge/client/loading/ClientModLoader.java +++ b/src/main/java/net/minecraftforge/client/loading/ClientModLoader.java @@ -43,7 +43,6 @@ import net.minecraft.server.packs.metadata.pack.PackMetadataSection; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; -import net.minecraftforge.client.model.ModelLoaderRegistry; import net.minecraftforge.common.ForgeConfig; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.client.gui.LoadingErrorScreen; @@ -162,8 +161,6 @@ public static boolean completeModLoading() if (error == null) { // We can finally start the forge eventbus up MinecraftForge.EVENT_BUS.start(); - // allow the ModelLoaderRegistry to register loaders as reload listeners - ModelLoaderRegistry.afterFirstReload(); } else { // Double check we have the langs loaded for forge LanguageHook.loadForgeAndMCLangs(); diff --git a/src/main/java/net/minecraftforge/client/model/BakedItemModel.java b/src/main/java/net/minecraftforge/client/model/BakedItemModel.java deleted file mode 100644 index 5d808dde17f..00000000000 --- a/src/main/java/net/minecraftforge/client/model/BakedItemModel.java +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright (c) Forge Development LLC and contributors - * SPDX-License-Identifier: LGPL-2.1-only - */ - -package net.minecraftforge.client.model; - -import java.util.List; - -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMap; -import com.mojang.blaze3d.vertex.PoseStack; -import net.minecraft.util.RandomSource; -import net.minecraft.world.level.block.state.BlockState; -import com.mojang.math.Transformation; -import net.minecraft.client.renderer.block.model.BakedQuad; -import net.minecraft.client.resources.model.BakedModel; -import net.minecraft.client.renderer.block.model.ItemTransforms.TransformType; -import net.minecraft.client.renderer.block.model.ItemOverrides; -import net.minecraft.client.renderer.texture.TextureAtlasSprite; -import net.minecraft.core.Direction; -import org.jetbrains.annotations.Nullable; - -public class BakedItemModel implements BakedModel -{ - protected final ImmutableList quads; - protected final TextureAtlasSprite particle; - protected final ImmutableMap transforms; - protected final ItemOverrides overrides; - protected final BakedModel guiModel; - protected final boolean isSideLit; - - public BakedItemModel(ImmutableList quads, TextureAtlasSprite particle, ImmutableMap transforms, ItemOverrides overrides, boolean untransformed, boolean isSideLit) - { - this.quads = quads; - this.particle = particle; - this.transforms = transforms; - this.overrides = overrides; - this.isSideLit = isSideLit; - this.guiModel = untransformed && hasGuiIdentity(transforms) ? new BakedGuiItemModel<>(this) : null; - } - - private static boolean hasGuiIdentity(ImmutableMap transforms) - { - Transformation guiTransform = transforms.get(TransformType.GUI); - return guiTransform == null || guiTransform.isIdentity(); - } - - @Override public boolean useAmbientOcclusion() { return true; } - @Override public boolean isGui3d() { return false; } - @Override public boolean usesBlockLight() { return isSideLit; } - @Override public boolean isCustomRenderer() { return false; } - @Override public TextureAtlasSprite getParticleIcon() { return particle; } - @Override public ItemOverrides getOverrides() { return overrides; } - - @Override - public List getQuads(@Nullable BlockState state, @Nullable Direction side, RandomSource rand) - { - if (side == null) - { - return quads; - } - return ImmutableList.of(); - } - - @Override - public BakedModel handlePerspective(TransformType type, PoseStack poseStack) - { - if (type == TransformType.GUI && this.guiModel != null) - { - return this.guiModel.handlePerspective(type, poseStack); - } - return PerspectiveMapWrapper.handlePerspective(this, transforms, type, poseStack); - } - - public static class BakedGuiItemModel extends BakedModelWrapper - { - private final ImmutableList quads; - - public BakedGuiItemModel(T originalModel) - { - super(originalModel); - ImmutableList.Builder builder = ImmutableList.builder(); - for (BakedQuad quad : originalModel.quads) - { - if (quad.getDirection() == Direction.SOUTH) - { - builder.add(quad); - } - } - this.quads = builder.build(); - } - - @Override - public List getQuads (@Nullable BlockState state, @Nullable Direction side, RandomSource rand) - { - if(side == null) - { - return quads; - } - return ImmutableList.of(); - } - - @Override - public boolean doesHandlePerspectives() - { - return true; - } - - @Override - public BakedModel handlePerspective(TransformType type, PoseStack poseStack) - { - if (type == TransformType.GUI) - { - return PerspectiveMapWrapper.handlePerspective(this, originalModel.transforms, type, poseStack); - } - return this.originalModel.handlePerspective(type, poseStack); - } - } -} diff --git a/src/main/java/net/minecraftforge/client/model/BakedModelWrapper.java b/src/main/java/net/minecraftforge/client/model/BakedModelWrapper.java index 27ae84a0e6a..014bf6490af 100644 --- a/src/main/java/net/minecraftforge/client/model/BakedModelWrapper.java +++ b/src/main/java/net/minecraftforge/client/model/BakedModelWrapper.java @@ -5,23 +5,31 @@ package net.minecraftforge.client.model; -import java.util.List; - import com.mojang.blaze3d.vertex.PoseStack; -import net.minecraft.util.RandomSource; -import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.block.model.BakedQuad; -import net.minecraft.client.resources.model.BakedModel; -import net.minecraft.client.renderer.block.model.ItemTransforms; import net.minecraft.client.renderer.block.model.ItemOverrides; +import net.minecraft.client.renderer.block.model.ItemTransforms; import net.minecraft.client.renderer.texture.TextureAtlasSprite; -import net.minecraft.core.Direction; +import net.minecraft.client.resources.model.BakedModel; import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.util.RandomSource; +import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.BlockAndTintGetter; -import net.minecraftforge.client.model.data.IModelData; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraftforge.client.ChunkRenderTypeSet; +import net.minecraftforge.client.model.data.ModelData; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.List; + +/** + * Wrapper for {@link BakedModel} which delegates all operations to its parent. + *

+ * Useful for creating wrapper baked models which only override certain properties. + */ public abstract class BakedModelWrapper implements BakedModel { protected final T originalModel; @@ -86,34 +94,46 @@ public ItemOverrides getOverrides() } @Override - public boolean doesHandlePerspectives() + public BakedModel applyTransform(ItemTransforms.TransformType cameraTransformType, PoseStack poseStack, boolean applyLeftHandTransform) { - return originalModel.doesHandlePerspectives(); + return originalModel.applyTransform(cameraTransformType, poseStack, applyLeftHandTransform); } @Override - public BakedModel handlePerspective(ItemTransforms.TransformType cameraTransformType, PoseStack poseStack) + public TextureAtlasSprite getParticleIcon(@NotNull ModelData data) { - return originalModel.handlePerspective(cameraTransformType, poseStack); + return originalModel.getParticleIcon(data); } + @NotNull @Override - public TextureAtlasSprite getParticleIcon(@NotNull IModelData data) + public List getQuads(@Nullable BlockState state, @Nullable Direction side, @NotNull RandomSource rand, @NotNull ModelData extraData, @Nullable RenderType renderType) { - return originalModel.getParticleIcon(data); + return originalModel.getQuads(state, side, rand, extraData, renderType); } @NotNull @Override - public List getQuads(@Nullable BlockState state, @Nullable Direction side, @NotNull RandomSource rand, @NotNull IModelData extraData) + public ModelData getModelData(@NotNull BlockAndTintGetter level, @NotNull BlockPos pos, @NotNull BlockState state, @NotNull ModelData modelData) { - return originalModel.getQuads(state, side, rand, extraData); + return originalModel.getModelData(level, pos, state, modelData); } - @NotNull @Override - public IModelData getModelData(@NotNull BlockAndTintGetter level, @NotNull BlockPos pos, @NotNull BlockState state, @NotNull IModelData modelData) + public ChunkRenderTypeSet getRenderTypes(@NotNull BlockState state, @NotNull RandomSource rand, @NotNull ModelData data) { - return originalModel.getModelData(level, pos, state, modelData); + return originalModel.getRenderTypes(state, rand, data); + } + + @Override + public List getRenderTypes(ItemStack itemStack, boolean fabulous) + { + return originalModel.getRenderTypes(itemStack, fabulous); + } + + @Override + public List getRenderPasses(ItemStack itemStack, boolean fabulous) + { + return originalModel.getRenderPasses(itemStack, fabulous); } } diff --git a/src/main/java/net/minecraftforge/client/model/CompositeModel.java b/src/main/java/net/minecraftforge/client/model/CompositeModel.java index 483c05a442e..61a77039b2c 100644 --- a/src/main/java/net/minecraftforge/client/model/CompositeModel.java +++ b/src/main/java/net/minecraftforge/client/model/CompositeModel.java @@ -5,366 +5,429 @@ package net.minecraftforge.client.model; +import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.gson.JsonDeserializationContext; import com.google.gson.JsonElement; import com.google.gson.JsonObject; -import com.mojang.blaze3d.vertex.PoseStack; +import com.google.gson.JsonParseException; import com.mojang.datafixers.util.Pair; -import net.minecraft.util.RandomSource; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.client.renderer.texture.TextureAtlasSprite; -import net.minecraft.server.packs.resources.ResourceManager; -import net.minecraft.core.Direction; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.core.BlockPos; -import net.minecraft.world.level.BlockAndTintGetter; -import net.minecraftforge.client.model.data.*; -import net.minecraftforge.client.model.geometry.IModelGeometryPart; -import net.minecraftforge.client.model.geometry.IMultipartModelGeometry; - -import java.util.*; -import java.util.function.Function; - +import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.block.model.BakedQuad; import net.minecraft.client.renderer.block.model.BlockModel; import net.minecraft.client.renderer.block.model.ItemOverrides; import net.minecraft.client.renderer.block.model.ItemTransforms; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.client.resources.model.BakedModel; import net.minecraft.client.resources.model.Material; import net.minecraft.client.resources.model.ModelBakery; import net.minecraft.client.resources.model.ModelState; import net.minecraft.client.resources.model.UnbakedModel; +import net.minecraft.core.Direction; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.RandomSource; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraftforge.client.ChunkRenderTypeSet; +import net.minecraftforge.client.RenderTypeGroup; +import net.minecraftforge.client.model.data.ModelData; +import net.minecraftforge.client.model.data.ModelProperty; +import net.minecraftforge.client.model.geometry.IGeometryBakingContext; +import net.minecraftforge.client.model.geometry.IGeometryLoader; +import net.minecraftforge.client.model.geometry.IUnbakedGeometry; +import net.minecraftforge.common.util.ConcatenatedListView; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -public class CompositeModel implements IDynamicBakedModel +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.IdentityHashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.function.Function; + +/** + * A model composed of several named children. + *

+ * These respect component visibility as specified in {@link IGeometryBakingContext} and can additionally be provided + * with an item-specific render ordering, for multi-pass arrangements. + */ +public class CompositeModel implements IUnbakedGeometry { - private final ImmutableMap bakedParts; - private final boolean isAmbientOcclusion; - private final boolean isGui3d; - private final boolean isSideLit; - private final TextureAtlasSprite particle; - private final ItemOverrides overrides; - private final ModelState transforms; - - public CompositeModel(boolean isGui3d, boolean isSideLit, boolean isAmbientOcclusion, TextureAtlasSprite particle, ImmutableMap bakedParts, ModelState combinedTransform, ItemOverrides overrides) - { - this.bakedParts = bakedParts; - this.isAmbientOcclusion = isAmbientOcclusion; - this.isGui3d = isGui3d; - this.isSideLit = isSideLit; - this.particle = particle; - this.overrides = overrides; - this.transforms = combinedTransform; - } + private static final Logger LOGGER = LogManager.getLogger(); - @NotNull - @Override - public List getQuads(@Nullable BlockState state, @Nullable Direction side, @NotNull RandomSource rand, @NotNull IModelData extraData) - { - List quads = new ArrayList<>(); - for(Map.Entry entry : bakedParts.entrySet()) - { - quads.addAll(entry.getValue().getQuads(state, side, rand, CompositeModelData.get(extraData, entry.getKey()))); - } - return quads; - } + private final ImmutableMap children; + private final ImmutableList itemPasses; + private final boolean logWarning; - @NotNull - @Override - public IModelData getModelData(@NotNull BlockAndTintGetter level, @NotNull BlockPos pos, @NotNull BlockState state, @NotNull IModelData modelData) + public CompositeModel(ImmutableMap children, ImmutableList itemPasses) { - CompositeModelData composite = new CompositeModelData(); - for(Map.Entry entry : bakedParts.entrySet()) - { - composite.putSubmodelData(entry.getKey(), entry.getValue().getModelData(level, pos, state, ModelDataWrapper.wrap(modelData))); - } - return composite; + this(children, itemPasses, false); } - @Override - public boolean useAmbientOcclusion() + private CompositeModel(ImmutableMap children, ImmutableList itemPasses, boolean logWarning) { - return isAmbientOcclusion; + this.children = children; + this.itemPasses = itemPasses; + this.logWarning = logWarning; } @Override - public boolean isGui3d() + public BakedModel bake(IGeometryBakingContext context, ModelBakery bakery, Function spriteGetter, ModelState modelState, ItemOverrides overrides, ResourceLocation modelLocation) { - return isGui3d; - } + if (logWarning) + LOGGER.warn("Model \"" + modelLocation + "\" is using the deprecated \"parts\" field in its composite model instead of \"children\". This field will be removed in 1.20."); - @Override - public boolean usesBlockLight() - { - return isSideLit; - } + Material particleLocation = context.getMaterial("particle"); + TextureAtlasSprite particle = spriteGetter.apply(particleLocation); - @Override - public boolean isCustomRenderer() - { - return false; - } + var rootTransform = context.getRootTransform(); + if (!rootTransform.isIdentity()) + modelState = new SimpleModelState(modelState.getRotation().compose(rootTransform), modelState.isUvLocked()); - @Override - public TextureAtlasSprite getParticleIcon() - { - return particle; - } + var bakedPartsBuilder = ImmutableMap.builder(); + for (var entry : children.entrySet()) + { + var name = entry.getKey(); + if (!context.isComponentVisible(name, true)) + continue; + var model = entry.getValue(); + bakedPartsBuilder.put(name, model.bake(bakery, model, spriteGetter, modelState, modelLocation, true)); + } + var bakedParts = bakedPartsBuilder.build(); - @Override - public ItemOverrides getOverrides() - { - return overrides; - } + var itemPassesBuilder = ImmutableList.builder(); + for (String name : this.itemPasses) + { + var model = bakedParts.get(name); + if (model == null) + throw new IllegalStateException("Specified \"" + name + "\" in \"item_render_order\", but that is not a child of this model."); + itemPassesBuilder.add(model); + } - @Override - public boolean doesHandlePerspectives() - { - return true; + return new Baked(context.isGui3d(), context.useBlockLight(), context.useAmbientOcclusion(), particle, context.getTransforms(), overrides, bakedParts, itemPassesBuilder.build()); } @Override - public BakedModel handlePerspective(ItemTransforms.TransformType cameraTransformType, PoseStack poseStack) - { - return PerspectiveMapWrapper.handlePerspective(this, transforms, cameraTransformType, poseStack); - } - - @Nullable - public BakedModel getPart(String name) + public Collection getMaterials(IGeometryBakingContext context, Function modelGetter, Set> missingTextureErrors) { - return bakedParts.get(name); + Set textures = new HashSet<>(); + if (context.hasMaterial("particle")) + textures.add(context.getMaterial("particle")); + for (BlockModel part : children.values()) + textures.addAll(part.getMaterials(modelGetter, missingTextureErrors)); + return textures; } - private static class Submodel implements IModelGeometryPart + public static class Baked implements IDynamicBakedModel { - private final String name; - private final BlockModel model; - private final ModelState modelTransform; - - private Submodel(String name, BlockModel model, ModelState modelTransform) + private final boolean isAmbientOcclusion; + private final boolean isGui3d; + private final boolean isSideLit; + private final TextureAtlasSprite particle; + private final ItemOverrides overrides; + private final ItemTransforms transforms; + private final ImmutableMap children; + private final ImmutableList itemPasses; + + public Baked(boolean isGui3d, boolean isSideLit, boolean isAmbientOcclusion, TextureAtlasSprite particle, ItemTransforms transforms, ItemOverrides overrides, ImmutableMap children, ImmutableList itemPasses) { - this.name = name; - this.model = model; - this.modelTransform = modelTransform; + this.children = children; + this.isAmbientOcclusion = isAmbientOcclusion; + this.isGui3d = isGui3d; + this.isSideLit = isSideLit; + this.particle = particle; + this.overrides = overrides; + this.transforms = transforms; + this.itemPasses = itemPasses; } + @NotNull @Override - public String name() + public List getQuads(@Nullable BlockState state, @Nullable Direction side, @NotNull RandomSource rand, @NotNull ModelData data, @Nullable RenderType renderType) { - return name; + List> quadLists = new ArrayList<>(); + for (Map.Entry entry : children.entrySet()) + { + if (renderType == null || (state != null && entry.getValue().getRenderTypes(state, rand, data).contains(renderType))) + { + quadLists.add(entry.getValue().getQuads(state, side, rand, CompositeModel.Data.resolve(data, entry.getKey()), renderType)); + } + } + return ConcatenatedListView.of(quadLists); } @Override - public void addQuads(IModelConfiguration owner, IModelBuilder modelBuilder, ModelBakery bakery, Function spriteGetter, ModelState modelTransform, ResourceLocation modelLocation) + public boolean useAmbientOcclusion() { - throw new UnsupportedOperationException("Attempted to call adQuads on a Submodel instance. Please don't."); + return isAmbientOcclusion; } - public BakedModel bakeModel(ModelBakery bakery, Function spriteGetter, ModelState modelTransform, ResourceLocation modelLocation) + @Override + public boolean isGui3d() { - return model.bake(bakery, spriteGetter, new CompositeModelState(this.modelTransform, modelTransform, - this.modelTransform.isUvLocked() || modelTransform.isUvLocked()), modelLocation); + return isGui3d; } @Override - public Collection getTextures(IModelConfiguration owner, Function modelGetter, Set> missingTextureErrors) + public boolean usesBlockLight() { - return model.getMaterials(modelGetter, missingTextureErrors); + return isSideLit; } - } - public static class Geometry implements IMultipartModelGeometry - { - private final ImmutableMap parts; - - Geometry(ImmutableMap parts) + @Override + public boolean isCustomRenderer() { - this.parts = parts; + return false; } @Override - public Collection getParts() + public TextureAtlasSprite getParticleIcon() { - return parts.values(); + return particle; } @Override - public Optional getPart(String name) + public ItemOverrides getOverrides() { - return Optional.ofNullable(parts.get(name)); + return overrides; } @Override - public BakedModel bake(IModelConfiguration owner, ModelBakery bakery, Function spriteGetter, ModelState modelTransform, ItemOverrides overrides, ResourceLocation modelLocation) + public ItemTransforms getTransforms() { - Material particleLocation = owner.resolveTexture("particle"); - TextureAtlasSprite particle = spriteGetter.apply(particleLocation); - - ImmutableMap.Builder bakedParts = ImmutableMap.builder(); - for(Map.Entry part : parts.entrySet()) - { - Submodel submodel = part.getValue(); - if (!owner.getPartVisibility(submodel)) - continue; - bakedParts.put(part.getKey(), submodel.bakeModel(bakery, spriteGetter, modelTransform, modelLocation)); - } - return new CompositeModel(owner.isShadedInGui(), owner.isSideLit(), owner.useSmoothLighting(), particle, bakedParts.build(), owner.getCombinedTransform(), overrides); + return transforms; } @Override - public Collection getTextures(IModelConfiguration owner, Function modelGetter, Set> missingTextureErrors) + public ChunkRenderTypeSet getRenderTypes(@NotNull BlockState state, @NotNull RandomSource rand, @NotNull ModelData data) { - Set textures = new HashSet<>(); - for(Submodel part : parts.values()) - { - textures.addAll(part.getTextures(owner, modelGetter, missingTextureErrors)); - } - return textures; + var sets = new ArrayList(); + for (Map.Entry entry : children.entrySet()) + sets.add(entry.getValue().getRenderTypes(state, rand, CompositeModel.Data.resolve(data, entry.getKey()))); + return ChunkRenderTypeSet.union(sets); } - } - public static class Loader implements IModelLoader - { - public static final Loader INSTANCE = new Loader(); + @Override + public List getRenderPasses(ItemStack itemStack, boolean fabulous) + { + return itemPasses; + } - private Loader() {} + @Nullable + public BakedModel getPart(String name) + { + return children.get(name); + } - @Override - public void onResourceManagerReload(ResourceManager resourceManager) + public static Builder builder(IGeometryBakingContext owner, TextureAtlasSprite particle, ItemOverrides overrides, ItemTransforms cameraTransforms) { + return builder(owner.useAmbientOcclusion(), owner.isGui3d(), owner.useBlockLight(), particle, overrides, cameraTransforms); + } + public static Builder builder(boolean isAmbientOcclusion, boolean isGui3d, boolean isSideLit, TextureAtlasSprite particle, ItemOverrides overrides, ItemTransforms cameraTransforms) + { + return new Builder(isAmbientOcclusion, isGui3d, isSideLit, particle, overrides, cameraTransforms); } - @Override - public Geometry read(JsonDeserializationContext deserializationContext, JsonObject modelContents) + public static class Builder { - if (!modelContents.has("parts")) - throw new RuntimeException("Composite model requires a \"parts\" element."); - ImmutableMap.Builder parts = ImmutableMap.builder(); - for(Map.Entry part : modelContents.get("parts").getAsJsonObject().entrySet()) + private final boolean isAmbientOcclusion; + private final boolean isGui3d; + private final boolean isSideLit; + private final List children = new ArrayList<>(); + private final List quads = new ArrayList<>(); + private final ItemOverrides overrides; + private final ItemTransforms transforms; + private TextureAtlasSprite particle; + private RenderTypeGroup lastRenderTypes = RenderTypeGroup.EMPTY; + + private Builder(boolean isAmbientOcclusion, boolean isGui3d, boolean isSideLit, TextureAtlasSprite particle, ItemOverrides overrides, ItemTransforms transforms) + { + this.isAmbientOcclusion = isAmbientOcclusion; + this.isGui3d = isGui3d; + this.isSideLit = isSideLit; + this.particle = particle; + this.overrides = overrides; + this.transforms = transforms; + } + + public void addLayer(BakedModel model) + { + flushQuads(null); + children.add(model); + } + + private void addLayer(RenderTypeGroup renderTypes, List quads) + { + var modelBuilder = IModelBuilder.of(true, isSideLit, false, transforms, overrides, particle, renderTypes); + quads.forEach(modelBuilder::addUnculledFace); + children.add(modelBuilder.build()); + } + + private void flushQuads(RenderTypeGroup renderTypes) + { + if (Objects.equals(renderTypes, lastRenderTypes)) + { + if (quads.size() > 0) + { + addLayer(lastRenderTypes, quads); + quads.clear(); + } + lastRenderTypes = renderTypes; + } + } + + public Builder setParticle(TextureAtlasSprite particleSprite) { - // TODO: Allow customizing state? If so, how? - ModelState modelTransform = SimpleModelState.IDENTITY; - parts.put(part.getKey(), new Submodel( - part.getKey(), - deserializationContext.deserialize(part.getValue(), BlockModel.class), - modelTransform)); + this.particle = particleSprite; + return this; + } + + public Builder addQuads(RenderTypeGroup renderTypes, BakedQuad... quadsToAdd) + { + flushQuads(renderTypes); + Collections.addAll(quads, quadsToAdd); + return this; + } + + public Builder addQuads(RenderTypeGroup renderTypes, Collection quadsToAdd) + { + flushQuads(renderTypes); + quads.addAll(quadsToAdd); + return this; + } + + public BakedModel build() + { + if (quads.size() > 0) + { + addLayer(lastRenderTypes, quads); + } + var childrenBuilder = ImmutableMap.builder(); + var itemPassesBuilder = ImmutableList.builder(); + int i = 0; + for (var model : this.children) + { + childrenBuilder.put("model_" + (i++), model); + itemPassesBuilder.add(model); + } + return new Baked(isAmbientOcclusion, isGui3d, isSideLit, particle, transforms, overrides, childrenBuilder.build(), itemPassesBuilder.build()); } - return new Geometry(parts.build()); } + } /** * A model data container which stores data for child components. */ - public static class CompositeModelData extends ModelDataMap + public static class Data { - public static final ModelProperty SUBMODEL_DATA = new ModelProperty<>(); + public static final ModelProperty PROPERTY = new ModelProperty<>(); - /** - * Helper to get the CompositeModelData from an unknown IModelData instance. - * @param modelData The undetermined instance to get data from - * @return An optional representing the composite data, if present. - */ - public static Optional get(IModelData modelData) - { - return Optional.ofNullable(modelData.getData(SUBMODEL_DATA)); - } + private final Map partData; - /** - * Helper to get child data from an unknown IModelData instance. - * @param modelData The undetermined instance to get data from - * @param name The name of the child part to get data for. - * @return The data for the child, or empty if not available. - */ - public static IModelData get(IModelData modelData, String name) + private Data(Map partData) { - return get(modelData).map(data -> data.getSubmodelData(name)) - .orElse(EmptyModelData.INSTANCE); + this.partData = partData; } - // Implementation - - private final Map parts = new HashMap<>(); - - public IModelData getSubmodelData(String name) + @Nullable + public ModelData get(String name) { - if (parts.containsKey(name)) - return parts.get(name); - return EmptyModelData.INSTANCE; + return partData.get(name); } - public void putSubmodelData(String name, IModelData data) + /** + * Helper to get the data from a {@link ModelData} instance. + * + * @param modelData The object to get data from + * @param name The name of the part to get data for + * @return The data for the part, or the one passed in if not found + */ + public static ModelData resolve(ModelData modelData, String name) { - parts.put(name, data); + var compositeData = modelData.get(PROPERTY); + if (compositeData == null) + return modelData; + var partData = compositeData.get(name); + return partData != null ? partData : modelData; } - @Override - public boolean hasProperty(ModelProperty prop) + public static Builder builder() { - return prop == SUBMODEL_DATA ||super.hasProperty(prop); + return new Builder(); } - @SuppressWarnings("unchecked") - @Nullable - @Override - public T getData(ModelProperty prop) + public static final class Builder { - if (prop == SUBMODEL_DATA) - return (T)this; - return super.getData(prop); - } + private final Map partData = new IdentityHashMap<>(); - @SuppressWarnings("unchecked") - @Nullable - @Override - public T setData(ModelProperty prop, T data) - { - if (prop == SUBMODEL_DATA) - return (T)this; - return super.setData(prop, data); + public Builder with(String name, ModelData data) + { + partData.put(name, data); + return this; + } + + public Data build() + { + return new Data(partData); + } } } - /** - * Wrapper for an IModelData instance which allows forwarding queries to the parent, - * but stores any new/modified values itself, avoiding modifications to the parent. - */ - private static class ModelDataWrapper extends ModelDataMap + public static final class Loader implements IGeometryLoader { - private final IModelData parent; - - public static IModelData wrap(IModelData parent) - { - return new ModelDataWrapper(parent); - } + public static final Loader INSTANCE = new Loader(); - private ModelDataWrapper(IModelData parent) + private Loader() { - this.parent = parent; } @Override - public boolean hasProperty(ModelProperty prop) + public CompositeModel read(JsonObject jsonObject, JsonDeserializationContext deserializationContext) { - return super.hasProperty(prop) || parent.hasProperty(prop); - } + List itemPasses = new ArrayList<>(); + ImmutableMap.Builder childrenBuilder = ImmutableMap.builder(); + readChildren(jsonObject, "children", deserializationContext, childrenBuilder, itemPasses, false); + boolean logWarning = readChildren(jsonObject, "parts", deserializationContext, childrenBuilder, itemPasses, true); - @Nullable - @Override - public T getData(ModelProperty prop) - { - return super.hasProperty(prop) ? super.getData(prop) : parent.getData(prop); + var children = childrenBuilder.build(); + if (children.isEmpty()) + throw new JsonParseException("Composite model requires a \"children\" element with at least one element."); + + if (jsonObject.has("item_render_order")) + { + itemPasses.clear(); + for (var element : jsonObject.getAsJsonArray("item_render_order")) + { + var name = element.getAsString(); + if (!children.containsKey(name)) + throw new JsonParseException("Specified \"" + name + "\" in \"item_render_order\", but that is not a child of this model."); + itemPasses.add(name); + } + } + + return new CompositeModel(children, ImmutableList.copyOf(itemPasses), logWarning); } - @Nullable - @Override - public T setData(ModelProperty prop, T data) + private boolean readChildren(JsonObject jsonObject, String name, JsonDeserializationContext deserializationContext, ImmutableMap.Builder children, List itemPasses, boolean logWarning) { - // We do not want to delegate setting to the parent - return super.setData(prop, data); + if (!jsonObject.has(name)) + return false; + var childrenJsonObject = jsonObject.getAsJsonObject(name); + for (Map.Entry entry : childrenJsonObject.entrySet()) + { + children.put(entry.getKey(), deserializationContext.deserialize(entry.getValue(), BlockModel.class)); + itemPasses.add(entry.getKey()); // We can do this because GSON preserves ordering during deserialization + } + return logWarning; } } } diff --git a/src/main/java/net/minecraftforge/client/model/CompositeModelState.java b/src/main/java/net/minecraftforge/client/model/CompositeModelState.java deleted file mode 100644 index 1940871204e..00000000000 --- a/src/main/java/net/minecraftforge/client/model/CompositeModelState.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (c) Forge Development LLC and contributors - * SPDX-License-Identifier: LGPL-2.1-only - */ - -package net.minecraftforge.client.model; - -import com.google.common.base.Objects; -import com.mojang.math.Transformation; -import net.minecraft.client.resources.model.ModelState; - -/** - * An {@link ModelState} that combines the transforms from two child {@link ModelState}. - */ -public class CompositeModelState implements ModelState -{ - private final ModelState first; - private final ModelState second; - private final boolean uvLock; - - public CompositeModelState(ModelState first, ModelState second) - { - this(first, second, false); - } - - public CompositeModelState(ModelState first, ModelState second, boolean uvLock) - { - this.first = first; - this.second = second; - this.uvLock = uvLock; - } - - @Override - public boolean isUvLocked() - { - return uvLock; - } - - @Override - public Transformation getRotation() - { - return first.getRotation().compose(second.getRotation()); - } - - @Override - public Transformation getPartTransformation(Object part) - { - return first.getPartTransformation(part).compose(second.getPartTransformation(part)); - } - - @Override - public boolean equals(Object o) - { - if (this == o) - { - return true; - } - if (o == null || getClass() != o.getClass()) - { - return false; - } - CompositeModelState that = (CompositeModelState) o; - return Objects.equal(first, that.first) && Objects.equal(second, that.second); - } - - @Override - public int hashCode() - { - return Objects.hashCode(first, second); - } -} diff --git a/src/main/java/net/minecraftforge/client/model/DynamicBucketModel.java b/src/main/java/net/minecraftforge/client/model/DynamicBucketModel.java deleted file mode 100644 index b3faa8ede74..00000000000 --- a/src/main/java/net/minecraftforge/client/model/DynamicBucketModel.java +++ /dev/null @@ -1,264 +0,0 @@ -/* - * Copyright (c) Forge Development LLC and contributors - * SPDX-License-Identifier: LGPL-2.1-only - */ - -package net.minecraftforge.client.model; - -import com.google.common.collect.*; -import com.google.gson.JsonDeserializationContext; -import com.google.gson.JsonObject; -import com.mojang.datafixers.util.Pair; -import net.minecraft.client.multiplayer.ClientLevel; -import com.mojang.math.Quaternion; -import com.mojang.math.Transformation; -import net.minecraft.client.renderer.block.model.ItemTransforms.TransformType; -import net.minecraft.client.renderer.texture.TextureAtlasSprite; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.level.material.Fluid; -import net.minecraft.world.level.material.Fluids; -import net.minecraft.world.item.ItemStack; -import net.minecraft.server.packs.resources.ResourceManager; -import net.minecraft.core.Direction; -import net.minecraft.resources.ResourceLocation; -import net.minecraftforge.client.ForgeHooksClient; -import net.minecraftforge.client.RenderProperties; -import net.minecraftforge.client.model.geometry.IModelGeometry; -import net.minecraftforge.fluids.FluidUtil; -import net.minecraftforge.registries.ForgeRegistries; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - -import java.util.*; -import java.util.function.Function; - -import net.minecraft.client.renderer.block.model.ItemOverrides; -import net.minecraft.client.resources.model.BakedModel; -import net.minecraft.client.resources.model.BlockModelRotation; -import net.minecraft.client.resources.model.Material; -import net.minecraft.client.resources.model.ModelBakery; -import net.minecraft.client.resources.model.ModelState; -import net.minecraft.client.resources.model.UnbakedModel; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -public final class DynamicBucketModel implements IModelGeometry -{ - private static final Logger LOGGER = LogManager.getLogger(); - - // minimal Z offset to prevent depth-fighting - private static final float NORTH_Z_COVER = 7.496f / 16f; - private static final float SOUTH_Z_COVER = 8.504f / 16f; - private static final float NORTH_Z_FLUID = 7.498f / 16f; - private static final float SOUTH_Z_FLUID = 8.502f / 16f; - - @NotNull - private final Fluid fluid; - - private final boolean flipGas; - private final boolean tint; - private final boolean coverIsMask; - private final boolean applyFluidLuminosity; - - @Deprecated - public DynamicBucketModel(Fluid fluid, boolean flipGas, boolean tint, boolean coverIsMask) - { - this(fluid, flipGas, tint, coverIsMask, true); - } - - public DynamicBucketModel(Fluid fluid, boolean flipGas, boolean tint, boolean coverIsMask, boolean applyFluidLuminosity) - { - this.fluid = fluid; - this.flipGas = flipGas; - this.tint = tint; - this.coverIsMask = coverIsMask; - this.applyFluidLuminosity = applyFluidLuminosity; - } - - /** - * Returns a new ModelDynBucket representing the given fluid, but with the same - * other properties (flipGas, tint, coverIsMask). - */ - public DynamicBucketModel withFluid(Fluid newFluid) - { - return new DynamicBucketModel(newFluid, flipGas, tint, coverIsMask, applyFluidLuminosity); - } - - @Override - public BakedModel bake(IModelConfiguration owner, ModelBakery bakery, Function spriteGetter, ModelState modelTransform, ItemOverrides overrides, ResourceLocation modelLocation) - { - Material particleLocation = owner.isTexturePresent("particle") ? owner.resolveTexture("particle") : null; - Material baseLocation = owner.isTexturePresent("base") ? owner.resolveTexture("base") : null; - Material fluidMaskLocation = owner.isTexturePresent("fluid") ? owner.resolveTexture("fluid") : null; - Material coverLocation = owner.isTexturePresent("cover") ? owner.resolveTexture("cover") : null; - - ModelState transformsFromModel = owner.getCombinedTransform(); - - TextureAtlasSprite fluidSprite = fluid != Fluids.EMPTY ? spriteGetter.apply(ForgeHooksClient.getBlockMaterial(RenderProperties.get(fluid).getStillTexture())) : null; - TextureAtlasSprite coverSprite = (coverLocation != null && (!coverIsMask || baseLocation != null)) ? spriteGetter.apply(coverLocation) : null; - - ImmutableMap transformMap = - PerspectiveMapWrapper.getTransforms(new CompositeModelState(transformsFromModel, modelTransform)); - - TextureAtlasSprite particleSprite = particleLocation != null ? spriteGetter.apply(particleLocation) : null; - - if (particleSprite == null) particleSprite = fluidSprite; - if (particleSprite == null && !coverIsMask) particleSprite = coverSprite; - - // if the fluid is lighter than air, will manipulate the initial state to be rotated 180deg to turn it upside down - if (flipGas && fluid != Fluids.EMPTY && fluid.getFluidType().isLighterThanAir()) - { - modelTransform = new SimpleModelState( - modelTransform.getRotation().blockCornerToCenter().compose( - new Transformation(null, new Quaternion(0, 0, 1, 0), null, null)).blockCenterToCorner()); - } - - Transformation transform = modelTransform.getRotation(); - - ItemMultiLayerBakedModel.Builder builder = ItemMultiLayerBakedModel.builder(owner, particleSprite, new ContainedFluidOverrideHandler(overrides, bakery, owner, this), transformMap); - - if (baseLocation != null) - { - // build base (insidest) - builder.addQuads(ItemLayerModel.getLayerRenderType(false), ItemLayerModel.getQuadsForSprites(ImmutableList.of(baseLocation), transform, spriteGetter)); - } - - if (fluidMaskLocation != null && fluidSprite != null) - { - TextureAtlasSprite templateSprite = spriteGetter.apply(fluidMaskLocation); - if (templateSprite != null) - { - // build liquid layer (inside) - int luminosity = applyFluidLuminosity ? fluid.getFluidType().getLightLevel() : 0; - int color = tint ? RenderProperties.get(fluid).getColorTint() : 0xFFFFFFFF; - builder.addQuads(ItemLayerModel.getLayerRenderType(luminosity > 0), ItemTextureQuadConverter.convertTexture(transform, templateSprite, fluidSprite, NORTH_Z_FLUID, Direction.NORTH, color, 1, luminosity)); - builder.addQuads(ItemLayerModel.getLayerRenderType(luminosity > 0), ItemTextureQuadConverter.convertTexture(transform, templateSprite, fluidSprite, SOUTH_Z_FLUID, Direction.SOUTH, color, 1, luminosity)); - } - } - - if (coverIsMask) - { - if (coverSprite != null && baseLocation != null) - { - TextureAtlasSprite baseSprite = spriteGetter.apply(baseLocation); - builder.addQuads(ItemLayerModel.getLayerRenderType(false), ItemTextureQuadConverter.convertTexture(transform, coverSprite, baseSprite, NORTH_Z_COVER, Direction.NORTH, 0xFFFFFFFF, 2)); - builder.addQuads(ItemLayerModel.getLayerRenderType(false), ItemTextureQuadConverter.convertTexture(transform, coverSprite, baseSprite, SOUTH_Z_COVER, Direction.SOUTH, 0xFFFFFFFF, 2)); - } - } - else - { - if (coverSprite != null) - { - builder.addQuads(ItemLayerModel.getLayerRenderType(false), ItemTextureQuadConverter.genQuad(transform, 0, 0, 16, 16, NORTH_Z_COVER, coverSprite, Direction.NORTH, 0xFFFFFFFF, 2)); - builder.addQuads(ItemLayerModel.getLayerRenderType(false), ItemTextureQuadConverter.genQuad(transform, 0, 0, 16, 16, SOUTH_Z_COVER, coverSprite, Direction.SOUTH, 0xFFFFFFFF, 2)); - } - } - - builder.setParticle(particleSprite); - - return builder.build(); - } - - @Override - public Collection getTextures(IModelConfiguration owner, Function modelGetter, Set> missingTextureErrors) - { - Set texs = Sets.newHashSet(); - - if (owner.isTexturePresent("particle")) texs.add(owner.resolveTexture("particle")); - if (owner.isTexturePresent("base")) texs.add(owner.resolveTexture("base")); - if (owner.isTexturePresent("fluid")) texs.add(owner.resolveTexture("fluid")); - if (owner.isTexturePresent("cover")) texs.add(owner.resolveTexture("cover")); - - return texs; - } - - public enum Loader implements IModelLoader - { - INSTANCE; - - @Override - public void onResourceManagerReload(ResourceManager resourceManager) - { - // no need to clear cache since we create a new model instance - } - - @Override - public DynamicBucketModel read(JsonDeserializationContext deserializationContext, JsonObject modelContents) - { - if (!modelContents.has("fluid")) - throw new RuntimeException("Bucket model requires 'fluid' value."); - - ResourceLocation fluidName = new ResourceLocation(modelContents.get("fluid").getAsString()); - - Fluid fluid = ForgeRegistries.FLUIDS.getValue(fluidName); - - boolean flip = false; - if (modelContents.has("flipGas")) - { - flip = modelContents.get("flipGas").getAsBoolean(); - } - - boolean tint = true; - if (modelContents.has("applyTint")) - { - tint = modelContents.get("applyTint").getAsBoolean(); - } - - boolean coverIsMask = true; - if (modelContents.has("coverIsMask")) - { - coverIsMask = modelContents.get("coverIsMask").getAsBoolean(); - } - - boolean applyFluidLuminosity = true; - if (modelContents.has("applyFluidLuminosity")) - { - applyFluidLuminosity = modelContents.get("applyFluidLuminosity").getAsBoolean(); - } - - // create new model with correct liquid - return new DynamicBucketModel(fluid, flip, tint, coverIsMask, applyFluidLuminosity); - } - } - - private static final class ContainedFluidOverrideHandler extends ItemOverrides - { - private final Map cache = Maps.newHashMap(); // contains all the baked models since they'll never change - private final ItemOverrides nested; - private final ModelBakery bakery; - private final IModelConfiguration owner; - private final DynamicBucketModel parent; - - private ContainedFluidOverrideHandler(ItemOverrides nested, ModelBakery bakery, IModelConfiguration owner, DynamicBucketModel parent) - { - this.nested = nested; - this.bakery = bakery; - this.owner = owner; - this.parent = parent; - } - - @Override - public BakedModel resolve(BakedModel originalModel, ItemStack stack, @Nullable ClientLevel level, @Nullable LivingEntity entity, int seed) - { - BakedModel overriden = nested.resolve(originalModel, stack, level, entity, seed); - if (overriden != originalModel) return overriden; - return FluidUtil.getFluidContained(stack) - .map(fluidStack -> { - Fluid fluid = fluidStack.getFluid(); - String name = ForgeRegistries.FLUIDS.getKey(fluid).toString(); - - if (!cache.containsKey(name)) - { - DynamicBucketModel unbaked = this.parent.withFluid(fluid); - BakedModel bakedModel = unbaked.bake(owner, bakery, ForgeModelBakery.defaultTextureGetter(), BlockModelRotation.X0_Y0, this, new ResourceLocation("forge:bucket_override")); - cache.put(name, bakedModel); - return bakedModel; - } - - return cache.get(name); - }) - // not a fluid item apparently - .orElse(originalModel); // empty bucket - } - } -} diff --git a/src/main/java/net/minecraftforge/client/model/DynamicFluidContainerModel.java b/src/main/java/net/minecraftforge/client/model/DynamicFluidContainerModel.java new file mode 100644 index 00000000000..6f734bf425a --- /dev/null +++ b/src/main/java/net/minecraftforge/client/model/DynamicFluidContainerModel.java @@ -0,0 +1,304 @@ +/* + * Copyright (c) Forge Development LLC and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.minecraftforge.client.model; + +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonObject; +import com.mojang.datafixers.util.Pair; +import com.mojang.math.Quaternion; +import com.mojang.math.Transformation; +import com.mojang.math.Vector3f; +import net.minecraft.client.color.item.ItemColor; +import net.minecraft.client.multiplayer.ClientLevel; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.block.model.ItemOverrides; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.resources.model.BakedModel; +import net.minecraft.client.resources.model.BlockModelRotation; +import net.minecraft.client.resources.model.Material; +import net.minecraft.client.resources.model.ModelBakery; +import net.minecraft.client.resources.model.ModelState; +import net.minecraft.client.resources.model.UnbakedModel; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.GsonHelper; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.material.Fluid; +import net.minecraft.world.level.material.Fluids; +import net.minecraftforge.client.ForgeHooksClient; +import net.minecraftforge.client.ForgeRenderTypes; +import net.minecraftforge.client.RenderTypeGroup; +import net.minecraftforge.client.extensions.common.IClientFluidTypeExtensions; +import net.minecraftforge.client.model.geometry.IGeometryBakingContext; +import net.minecraftforge.client.model.geometry.IGeometryLoader; +import net.minecraftforge.client.model.geometry.IUnbakedGeometry; +import net.minecraftforge.client.model.geometry.StandaloneGeometryBakingContext; +import net.minecraftforge.client.model.geometry.UnbakedGeometryHelper; +import net.minecraftforge.fluids.FluidUtil; +import net.minecraftforge.registries.ForgeRegistries; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Collection; +import java.util.Map; +import java.util.Set; +import java.util.function.Function; + +/** + * A dynamic fluid container model, capable of re-texturing itself at runtime to match the contained fluid. + *

+ * Composed of a base layer, a fluid layer (applied with a mask) and a cover layer (optionally applied with a mask). + * The entire model may optionally be flipped if the fluid is gaseous, and the fluid layer may glow if light-emitting. + *

+ * Fluid tinting requires registering a separate {@link ItemColor}. An implementation is provided in {@link Colors}. + * + * @see Colors + */ +public class DynamicFluidContainerModel implements IUnbakedGeometry +{ + private static final Logger LOGGER = LogManager.getLogger(); + + // Depth offsets to prevent Z-fighting + private static final Transformation FLUID_TRANSFORM = new Transformation(Vector3f.ZERO, Quaternion.ONE, new Vector3f(1, 1, 1.002f), Quaternion.ONE); + private static final Transformation COVER_TRANSFORM = new Transformation(Vector3f.ZERO, Quaternion.ONE, new Vector3f(1, 1, 1.004f), Quaternion.ONE); + // Transformer to set quads to max brightness + private static final IQuadTransformer MAX_LIGHTMAP_TRANSFORMER = IQuadTransformer.applyingLightmap(0x00F000F0); + + private final Fluid fluid; + private final boolean flipGas; + private final boolean coverIsMask; + private final boolean applyFluidLuminosity; + private final boolean deprecatedLoader; + private final Map deprecationWarnings; + + public DynamicFluidContainerModel(Fluid fluid, boolean flipGas, boolean coverIsMask, boolean applyFluidLuminosity) + { + this(fluid, flipGas, coverIsMask, applyFluidLuminosity, false, Map.of()); + } + + private DynamicFluidContainerModel(Fluid fluid, boolean flipGas, boolean coverIsMask, boolean applyFluidLuminosity, boolean deprecatedLoader, Map deprecationWarnings) + { + this.fluid = fluid; + this.flipGas = flipGas; + this.coverIsMask = coverIsMask; + this.applyFluidLuminosity = applyFluidLuminosity; + this.deprecatedLoader = deprecatedLoader; + this.deprecationWarnings = deprecationWarnings; + } + + public static RenderTypeGroup getLayerRenderTypes(boolean unlit) + { + return new RenderTypeGroup(RenderType.translucent(), unlit ? ForgeRenderTypes.ITEM_UNSORTED_UNLIT_TRANSLUCENT.get() : ForgeRenderTypes.ITEM_UNSORTED_TRANSLUCENT.get()); + } + + /** + * Returns a new ModelDynBucket representing the given fluid, but with the same + * other properties (flipGas, tint, coverIsMask). + */ + public DynamicFluidContainerModel withFluid(Fluid newFluid) + { + return new DynamicFluidContainerModel(newFluid, flipGas, coverIsMask, applyFluidLuminosity, false, Map.of()); + } + + @Override + public BakedModel bake(IGeometryBakingContext context, ModelBakery bakery, Function spriteGetter, ModelState modelState, ItemOverrides overrides, ResourceLocation modelLocation) + { + if (deprecatedLoader) + LOGGER.warn("Model \"" + modelLocation + "\" is using the deprecated loader \"forge:bucket\" instead of \"forge:fluid_container\". This loader will be removed in 1.20."); + for (var entry : deprecationWarnings.entrySet()) + LOGGER.warn("Model \"" + modelLocation + "\" is using the deprecated \"" + entry.getKey() + "\" field in its fluid container model instead of \"" + entry.getValue() + "\". This field will be removed in 1.20."); + + Material particleLocation = context.hasMaterial("particle") ? context.getMaterial("particle") : null; + Material baseLocation = context.hasMaterial("base") ? context.getMaterial("base") : null; + Material fluidMaskLocation = context.hasMaterial("fluid") ? context.getMaterial("fluid") : null; + Material coverLocation = context.hasMaterial("cover") ? context.getMaterial("cover") : null; + + TextureAtlasSprite baseSprite = baseLocation != null ? spriteGetter.apply(baseLocation) : null; + TextureAtlasSprite fluidSprite = fluid != Fluids.EMPTY ? spriteGetter.apply(ForgeHooksClient.getBlockMaterial(IClientFluidTypeExtensions.of(fluid).getStillTexture())) : null; + TextureAtlasSprite coverSprite = (coverLocation != null && (!coverIsMask || baseLocation != null)) ? spriteGetter.apply(coverLocation) : null; + + TextureAtlasSprite particleSprite = particleLocation != null ? spriteGetter.apply(particleLocation) : null; + + if (particleSprite == null) particleSprite = fluidSprite; + if (particleSprite == null && !coverIsMask) particleSprite = coverSprite; + + // If the fluid is lighter than air, rotate 180deg to turn it upside down + if (flipGas && fluid != Fluids.EMPTY && fluid.getFluidType().isLighterThanAir()) + { + modelState = new SimpleModelState( + modelState.getRotation().compose( + new Transformation(null, new Quaternion(0, 0, 1, 0), null, null))); + } + + // We need to disable GUI 3D and block lighting for this to render properly + var itemContext = StandaloneGeometryBakingContext.builder(context).withGui3d(false).withUseBlockLight(false).build(modelLocation); + var modelBuilder = CompositeModel.Baked.builder(itemContext, particleSprite, new ContainedFluidOverrideHandler(overrides, bakery, itemContext, this), context.getTransforms()); + + var normalRenderTypes = getLayerRenderTypes(false); + + if (baseLocation != null && baseSprite != null) + { + // Base texture + var unbaked = UnbakedGeometryHelper.createUnbakedItemElements(0, baseSprite); + var quads = UnbakedGeometryHelper.bakeElements(unbaked, $ -> baseSprite, modelState, modelLocation); + modelBuilder.addQuads(normalRenderTypes, quads); + } + + if (fluidMaskLocation != null && fluidSprite != null) + { + TextureAtlasSprite templateSprite = spriteGetter.apply(fluidMaskLocation); + if (templateSprite != null) + { + // Fluid layer + var transformedState = new SimpleModelState(modelState.getRotation().compose(FLUID_TRANSFORM), modelState.isUvLocked()); + var unbaked = UnbakedGeometryHelper.createUnbakedItemMaskElements(1, templateSprite); // Use template as mask + var quads = UnbakedGeometryHelper.bakeElements(unbaked, $ -> fluidSprite, transformedState, modelLocation); // Bake with fluid texture + + var unlit = applyFluidLuminosity && fluid.getFluidType().getLightLevel() > 0; + var renderTypes = getLayerRenderTypes(unlit); + if (unlit) MAX_LIGHTMAP_TRANSFORMER.processInPlace(quads); + + modelBuilder.addQuads(renderTypes, quads); + } + } + + if (coverSprite != null) + { + var sprite = coverIsMask ? baseSprite : coverSprite; + if (sprite != null) + { + // Cover/overlay + var transformedState = new SimpleModelState(modelState.getRotation().compose(COVER_TRANSFORM), modelState.isUvLocked()); + var unbaked = UnbakedGeometryHelper.createUnbakedItemMaskElements(2, coverSprite); // Use cover as mask + var quads = UnbakedGeometryHelper.bakeElements(unbaked, $ -> sprite, transformedState, modelLocation); // Bake with selected texture + modelBuilder.addQuads(normalRenderTypes, quads); + } + } + + modelBuilder.setParticle(particleSprite); + + return modelBuilder.build(); + } + + @Override + public Collection getMaterials(IGeometryBakingContext context, Function modelGetter, Set> missingTextureErrors) + { + Set textures = Sets.newHashSet(); + if (context.hasMaterial("particle")) textures.add(context.getMaterial("particle")); + if (context.hasMaterial("base")) textures.add(context.getMaterial("base")); + if (context.hasMaterial("fluid")) textures.add(context.getMaterial("fluid")); + if (context.hasMaterial("cover")) textures.add(context.getMaterial("cover")); + return textures; + } + + public static final class Loader implements IGeometryLoader + { + public static final Loader INSTANCE = new Loader(false); + @Deprecated(forRemoval = true, since = "1.19") + public static final Loader INSTANCE_DEPRECATED = new Loader(true); + + private final boolean deprecated; + + private Loader(boolean deprecated) + { + this.deprecated = deprecated; + } + + @Override + public DynamicFluidContainerModel read(JsonObject jsonObject, JsonDeserializationContext deserializationContext) + { + if (!jsonObject.has("fluid")) + throw new RuntimeException("Bucket model requires 'fluid' value."); + + ResourceLocation fluidName = new ResourceLocation(jsonObject.get("fluid").getAsString()); + + Fluid fluid = ForgeRegistries.FLUIDS.getValue(fluidName); + + boolean flip = GsonHelper.getAsBoolean(jsonObject, "flip_gas", false); + boolean coverIsMask = GsonHelper.getAsBoolean(jsonObject, "cover_is_mask", true); + boolean applyFluidLuminosity = GsonHelper.getAsBoolean(jsonObject, "apply_fluid_luminosity", true); + + // TODO: Deprecated names. To be removed in 1.20 + var deprecationWarningsBuilder = ImmutableMap.builder(); + if (jsonObject.has("flipGas")) + { + flip = GsonHelper.getAsBoolean(jsonObject, "flipGas"); + deprecationWarningsBuilder.put("flipGas", "flip_gas"); + } + if (jsonObject.has("coverIsMask")) + { + coverIsMask = GsonHelper.getAsBoolean(jsonObject, "coverIsMask"); + deprecationWarningsBuilder.put("coverIsMask", "cover_is_mask"); + } + if (jsonObject.has("applyFluidLuminosity")) + { + applyFluidLuminosity = GsonHelper.getAsBoolean(jsonObject, "applyFluidLuminosity"); + deprecationWarningsBuilder.put("applyFluidLuminosity", "apply_fluid_luminosity"); + } + + // create new model with correct liquid + return new DynamicFluidContainerModel(fluid, flip, coverIsMask, applyFluidLuminosity, deprecated, deprecationWarningsBuilder.build()); + } + } + + private static final class ContainedFluidOverrideHandler extends ItemOverrides + { + private final Map cache = Maps.newHashMap(); // contains all the baked models since they'll never change + private final ItemOverrides nested; + private final ModelBakery bakery; + private final IGeometryBakingContext owner; + private final DynamicFluidContainerModel parent; + + private ContainedFluidOverrideHandler(ItemOverrides nested, ModelBakery bakery, IGeometryBakingContext owner, DynamicFluidContainerModel parent) + { + this.nested = nested; + this.bakery = bakery; + this.owner = owner; + this.parent = parent; + } + + @Override + public BakedModel resolve(BakedModel originalModel, ItemStack stack, @Nullable ClientLevel level, @Nullable LivingEntity entity, int seed) + { + BakedModel overridden = nested.resolve(originalModel, stack, level, entity, seed); + if (overridden != originalModel) return overridden; + return FluidUtil.getFluidContained(stack) + .map(fluidStack -> { + Fluid fluid = fluidStack.getFluid(); + String name = ForgeRegistries.FLUIDS.getKey(fluid).toString(); + + if (!cache.containsKey(name)) + { + DynamicFluidContainerModel unbaked = this.parent.withFluid(fluid); + BakedModel bakedModel = unbaked.bake(owner, bakery, Material::sprite, BlockModelRotation.X0_Y0, this, new ResourceLocation("forge:bucket_override")); + cache.put(name, bakedModel); + return bakedModel; + } + + return cache.get(name); + }) + // not a fluid item apparently + .orElse(originalModel); // empty bucket + } + } + + public static class Colors implements ItemColor + { + @Override + public int getColor(@NotNull ItemStack stack, int tintIndex) + { + if (tintIndex != 1) return 0xFFFFFFFF; + return FluidUtil.getFluidContained(stack) + .map(fluidStack -> IClientFluidTypeExtensions.of(fluidStack.getFluid()).getTintColor(fluidStack)) + .orElse(0xFFFFFFFF); + } + } +} diff --git a/src/main/java/net/minecraftforge/client/model/ElementsModel.java b/src/main/java/net/minecraftforge/client/model/ElementsModel.java new file mode 100644 index 00000000000..daa33f2634c --- /dev/null +++ b/src/main/java/net/minecraftforge/client/model/ElementsModel.java @@ -0,0 +1,133 @@ +/* + * Copyright (c) Forge Development LLC and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.minecraftforge.client.model; + +import com.google.common.collect.Sets; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; +import com.mojang.datafixers.util.Pair; +import net.minecraft.client.renderer.block.model.BlockElement; +import net.minecraft.client.renderer.block.model.BlockElementFace; +import net.minecraft.client.renderer.block.model.BlockModel; +import net.minecraft.client.renderer.texture.MissingTextureAtlasSprite; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.resources.model.Material; +import net.minecraft.client.resources.model.ModelBakery; +import net.minecraft.client.resources.model.ModelState; +import net.minecraft.client.resources.model.UnbakedModel; +import net.minecraft.core.Direction; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.GsonHelper; +import net.minecraftforge.client.model.geometry.IGeometryBakingContext; +import net.minecraftforge.client.model.geometry.IGeometryLoader; +import net.minecraftforge.client.model.geometry.SimpleUnbakedGeometry; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Set; +import java.util.function.Function; + +/** + * A model composed of vanilla {@linkplain BlockElement block elements}. + */ +public class ElementsModel extends SimpleUnbakedGeometry +{ + private static final Logger LOGGER = LogManager.getLogger(); + + private final List elements; + private final boolean deprecatedLoader; + + public ElementsModel(List elements) + { + this(elements, false); + } + + private ElementsModel(List elements, boolean deprecatedLoader) + { + this.elements = elements; + this.deprecatedLoader = deprecatedLoader; + } + + @Override + protected void addQuads(IGeometryBakingContext context, IModelBuilder modelBuilder, ModelBakery bakery, Function spriteGetter, ModelState modelState, ResourceLocation modelLocation) + { + if (deprecatedLoader) + LOGGER.warn("Model \"" + modelLocation + "\" is using the deprecated loader \"minecraft:elements\" instead of \"forge:elements\". This loader will be removed in 1.20."); + + var rootTransform = context.getRootTransform(); + if (!rootTransform.isIdentity()) + modelState = new SimpleModelState(modelState.getRotation().compose(rootTransform), modelState.isUvLocked()); + + for (BlockElement element : elements) + { + for (Direction direction : element.faces.keySet()) + { + var face = element.faces.get(direction); + var sprite = spriteGetter.apply(context.getMaterial(face.texture)); + var quad = BlockModel.bakeFace(element, face, sprite, direction, modelState, modelLocation); + + if (face.cullForDirection == null) + modelBuilder.addUnculledFace(quad); + else + modelBuilder.addCulledFace(modelState.getRotation().rotateTransform(face.cullForDirection), quad); + } + } + } + + @Override + public Collection getMaterials(IGeometryBakingContext context, Function modelGetter, Set> missingTextureErrors) + { + Set textures = Sets.newHashSet(); + if (context.hasMaterial("particle")) + textures.add(context.getMaterial("particle")); + for (BlockElement part : elements) + { + for (BlockElementFace face : part.faces.values()) + { + Material texture = context.getMaterial(face.texture); + if (texture.texture().equals(MissingTextureAtlasSprite.getLocation())) + missingTextureErrors.add(Pair.of(face.texture, context.getModelName())); + textures.add(texture); + } + } + + return textures; + } + + public static final class Loader implements IGeometryLoader + { + public static final Loader INSTANCE = new Loader(false); + @Deprecated(forRemoval = true, since = "1.19") + public static final Loader INSTANCE_DEPRECATED = new Loader(true); + + private final boolean deprecated; + + private Loader(boolean deprecated) + { + this.deprecated = deprecated; + } + + @Override + public ElementsModel read(JsonObject jsonObject, JsonDeserializationContext deserializationContext) throws JsonParseException + { + if (!jsonObject.has("elements")) + throw new JsonParseException("An element model must have an \"elements\" member."); + + List elements = new ArrayList<>(); + for (JsonElement element : GsonHelper.getAsJsonArray(jsonObject, "elements")) + { + elements.add(deserializationContext.deserialize(element, BlockElement.class)); + } + + return new ElementsModel(elements, deprecated); + } + } +} diff --git a/src/main/java/net/minecraftforge/client/model/EmptyModel.java b/src/main/java/net/minecraftforge/client/model/EmptyModel.java new file mode 100644 index 00000000000..f77d9c31813 --- /dev/null +++ b/src/main/java/net/minecraftforge/client/model/EmptyModel.java @@ -0,0 +1,82 @@ +/* + * Copyright (c) Forge Development LLC and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.minecraftforge.client.model; + +import com.mojang.datafixers.util.Pair; +import net.minecraft.client.renderer.block.model.ItemOverrides; +import net.minecraft.client.renderer.block.model.ItemTransforms; +import net.minecraft.client.renderer.texture.MissingTextureAtlasSprite; +import net.minecraft.client.renderer.texture.TextureAtlas; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.resources.model.BakedModel; +import net.minecraft.client.resources.model.Material; +import net.minecraft.client.resources.model.ModelBakery; +import net.minecraft.client.resources.model.ModelState; +import net.minecraft.client.resources.model.SimpleBakedModel; +import net.minecraft.client.resources.model.UnbakedModel; +import net.minecraft.resources.ResourceLocation; +import net.minecraftforge.client.RenderTypeGroup; +import net.minecraftforge.client.model.geometry.IGeometryBakingContext; +import net.minecraftforge.client.model.geometry.IGeometryLoader; +import net.minecraftforge.client.model.geometry.IUnbakedGeometry; +import net.minecraftforge.client.model.geometry.SimpleUnbakedGeometry; +import net.minecraftforge.client.textures.UnitTextureAtlasSprite; + +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.Function; + +/** + * A completely empty model with no quads or texture dependencies. + *

+ * You can access it as a {@link BakedModel}, an {@link IUnbakedGeometry} or an {@link IGeometryLoader}. + */ +public class EmptyModel extends SimpleUnbakedGeometry +{ + public static final BakedModel BAKED = new Baked(); + public static final EmptyModel INSTANCE = new EmptyModel(); + public static final IGeometryLoader LOADER = (json, ctx) -> INSTANCE; + + private EmptyModel() + { + } + + @Override + protected void addQuads(IGeometryBakingContext owner, IModelBuilder modelBuilder, ModelBakery bakery, Function spriteGetter, ModelState modelTransform, ResourceLocation modelLocation) + { + // NO-OP + } + + @Override + public BakedModel bake(IGeometryBakingContext context, ModelBakery bakery, Function spriteGetter, ModelState modelState, ItemOverrides overrides, ResourceLocation modelLocation) + { + return BAKED; + } + + @Override + public Collection getMaterials(IGeometryBakingContext context, Function modelGetter, Set> missingTextureErrors) + { + return List.of(); // NO-OP + } + + private static class Baked extends SimpleBakedModel + { + private static final Material MISSING_TEXTURE = new Material(TextureAtlas.LOCATION_BLOCKS, MissingTextureAtlasSprite.getLocation()); + + public Baked() + { + super(List.of(), Map.of(), false, false, false, UnitTextureAtlasSprite.INSTANCE, ItemTransforms.NO_TRANSFORMS, ItemOverrides.EMPTY, RenderTypeGroup.EMPTY); + } + + @Override + public TextureAtlasSprite getParticleIcon() + { + return MISSING_TEXTURE.sprite(); + } + } +} diff --git a/src/main/java/net/minecraftforge/client/model/ExtendedBlockModelDeserializer.java b/src/main/java/net/minecraftforge/client/model/ExtendedBlockModelDeserializer.java new file mode 100644 index 00000000000..34209bf156e --- /dev/null +++ b/src/main/java/net/minecraftforge/client/model/ExtendedBlockModelDeserializer.java @@ -0,0 +1,101 @@ +/* + * Copyright (c) Forge Development LLC and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.minecraftforge.client.model; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; +import com.mojang.math.Transformation; +import net.minecraft.client.renderer.block.model.BlockElement; +import net.minecraft.client.renderer.block.model.BlockElementFace; +import net.minecraft.client.renderer.block.model.BlockFaceUV; +import net.minecraft.client.renderer.block.model.BlockModel; +import net.minecraft.client.renderer.block.model.ItemOverride; +import net.minecraft.client.renderer.block.model.ItemTransform; +import net.minecraft.client.renderer.block.model.ItemTransforms; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.GsonHelper; +import net.minecraftforge.client.model.geometry.GeometryLoaderManager; +import net.minecraftforge.client.model.geometry.IUnbakedGeometry; +import net.minecraftforge.common.util.TransformationHelper; +import org.jetbrains.annotations.Nullable; + +import java.lang.reflect.Type; +import java.util.List; +import java.util.Locale; +import java.util.Map; + +/** + * A version of {@link BlockModel.Deserializer} capable of deserializing models with custom loaders, as well as other + * changes introduced to the spec by Forge. + */ +public class ExtendedBlockModelDeserializer extends BlockModel.Deserializer +{ + public static final Gson INSTANCE = (new GsonBuilder()) + .registerTypeAdapter(BlockModel.class, new ExtendedBlockModelDeserializer()) + .registerTypeAdapter(BlockElement.class, new BlockElement.Deserializer()) + .registerTypeAdapter(BlockElementFace.class, new BlockElementFace.Deserializer()) + .registerTypeAdapter(BlockFaceUV.class, new BlockFaceUV.Deserializer()) + .registerTypeAdapter(ItemTransform.class, new ItemTransform.Deserializer()) + .registerTypeAdapter(ItemTransforms.class, new ItemTransforms.Deserializer()) + .registerTypeAdapter(ItemOverride.class, new ItemOverride.Deserializer()) + .registerTypeAdapter(Transformation.class, new TransformationHelper.Deserializer()) + .create(); + + public BlockModel deserialize(JsonElement element, Type targetType, JsonDeserializationContext deserializationContext) throws JsonParseException + { + BlockModel model = super.deserialize(element, targetType, deserializationContext); + JsonObject jsonobject = element.getAsJsonObject(); + IUnbakedGeometry geometry = deserializeGeometry(deserializationContext, jsonobject); + + List elements = model.getElements(); + if (geometry != null) + { + elements.clear(); + model.customData.setCustomGeometry(geometry); + } + + if (jsonobject.has("transform")) + { + JsonObject transform = GsonHelper.getAsJsonObject(jsonobject, "transform"); + model.customData.setRootTransform(deserializationContext.deserialize(transform, Transformation.class)); + } + + if (jsonobject.has("render_type")) + { + var renderTypeHintName = GsonHelper.getAsString(jsonobject, "render_type"); + model.customData.setRenderTypeHint(new ResourceLocation(renderTypeHintName)); + } + + if (jsonobject.has("visibility")) + { + JsonObject visibility = GsonHelper.getAsJsonObject(jsonobject, "visibility"); + for (Map.Entry part : visibility.entrySet()) + { + model.customData.visibilityData.setVisibilityState(part.getKey(), part.getValue().getAsBoolean()); + } + } + + return model; + } + + @Nullable + public static IUnbakedGeometry deserializeGeometry(JsonDeserializationContext deserializationContext, JsonObject object) throws JsonParseException + { + if (!object.has("loader")) + return null; + + var name = new ResourceLocation(GsonHelper.getAsString(object, "loader")); + var loader = GeometryLoaderManager.get(name); + if (loader == null) + throw new JsonParseException(String.format(Locale.ENGLISH, "Model loader '%s' not found. Registered loaders: %s", name, GeometryLoaderManager.getLoaderList())); + + return loader.read(object, deserializationContext); + } +} diff --git a/src/main/java/net/minecraftforge/client/model/FluidModel.java b/src/main/java/net/minecraftforge/client/model/FluidModel.java deleted file mode 100644 index d9435fce77a..00000000000 --- a/src/main/java/net/minecraftforge/client/model/FluidModel.java +++ /dev/null @@ -1,476 +0,0 @@ -/* - * Copyright (c) Forge Development LLC and contributors - * SPDX-License-Identifier: LGPL-2.1-only - */ - -package net.minecraftforge.client.model; - -import java.util.function.Function; -import java.util.stream.Collectors; -import java.util.Collection; -import java.util.EnumMap; -import java.util.List; -import java.util.Optional; -import java.util.Set; - -import com.mojang.blaze3d.vertex.PoseStack; -import net.minecraft.util.RandomSource; -import net.minecraft.world.level.block.state.BlockState; -import com.mojang.math.Transformation; -import net.minecraft.client.renderer.block.model.ItemTransforms.TransformType; -import net.minecraft.client.renderer.texture.TextureAtlasSprite; -import com.mojang.blaze3d.vertex.DefaultVertexFormat; -import com.mojang.blaze3d.vertex.VertexFormat; -import com.mojang.blaze3d.vertex.VertexFormatElement; -import net.minecraft.world.level.material.Fluid; -import net.minecraft.world.level.material.Fluids; -import net.minecraft.core.Direction; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.util.Mth; -import net.minecraftforge.client.ForgeHooksClient; -import net.minecraftforge.client.IFluidTypeRenderProperties; -import net.minecraftforge.client.RenderProperties; -import net.minecraftforge.client.model.data.IModelData; -import net.minecraftforge.client.model.geometry.IModelGeometry; -import net.minecraftforge.client.model.pipeline.BakedQuadBuilder; -import net.minecraftforge.client.model.pipeline.IVertexConsumer; -import net.minecraftforge.client.model.pipeline.TRSRTransformer; - -import com.google.common.cache.CacheBuilder; -import com.google.common.cache.CacheLoader; -import com.google.common.cache.LoadingCache; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMap; - -// TODO: Write a model loader and test/fix as needed -import net.minecraft.client.renderer.block.model.BakedQuad; -import net.minecraft.client.renderer.block.model.ItemOverrides; -import net.minecraft.client.resources.model.BakedModel; -import net.minecraft.client.resources.model.Material; -import net.minecraft.client.resources.model.ModelBakery; -import net.minecraft.client.resources.model.ModelState; -import net.minecraft.client.resources.model.UnbakedModel; -import org.jetbrains.annotations.Nullable; - -public final class FluidModel implements IModelGeometry -{ - public static final FluidModel WATER = new FluidModel(Fluids.WATER); - public static final FluidModel LAVA = new FluidModel(Fluids.LAVA); - - private final Fluid fluid; - - public FluidModel(Fluid fluid) - { - this.fluid = fluid; - } - - @Override - public Collection getTextures(IModelConfiguration owner, Function modelGetter, Set> missingTextureErrors) - { - return ForgeHooksClient.getFluidMaterials(fluid).collect(Collectors.toList()); - } - - @Override - public BakedModel bake(IModelConfiguration owner, ModelBakery bakery, Function spriteGetter, ModelState modelTransform, ItemOverrides overrides, ResourceLocation modelLocation) - { - IFluidTypeRenderProperties props = RenderProperties.get(fluid); - return new CachingBakedFluid( - modelTransform.getRotation(), - PerspectiveMapWrapper.getTransforms(modelTransform), - modelLocation, - props.getColorTint(), - spriteGetter.apply(ForgeHooksClient.getBlockMaterial(props.getStillTexture())), - spriteGetter.apply(ForgeHooksClient.getBlockMaterial(props.getFlowingTexture())), - Optional.ofNullable(props.getOverlayTexture()).map(ForgeHooksClient::getBlockMaterial).map(spriteGetter), - fluid.getFluidType().isLighterThanAir(), - null - ); - } - - private static final class CachingBakedFluid extends BakedFluid - { - private final LoadingCache modelCache = CacheBuilder.newBuilder().maximumSize(200).build(new CacheLoader() - { - @Override - public BakedFluid load(Long key) - { - boolean statePresent = (key & 1) != 0; - key >>>= 1; - int[] cornerRound = new int[4]; - for (int i = 0; i < 4; i++) - { - cornerRound[i] = (int) (key & 0x3FF); - key >>>= 10; - } - int flowRound = (int) (key & 0x7FF) - 1024; - key >>>= 11; - boolean[] overlaySides = new boolean[4]; - for (int i = 0; i < 4; i++) - { - overlaySides[i] = (key & 1) != 0; - key >>>= 1; - } - return new BakedFluid(transformation, transforms, modelLocation, color, still, flowing, overlay, gas, statePresent, cornerRound, flowRound, overlaySides); - } - }); - - public CachingBakedFluid(Transformation transformation, ImmutableMap transforms, ResourceLocation modelLocation, int color, TextureAtlasSprite still, TextureAtlasSprite flowing, Optional overlay, boolean gas, Optional stateOption) - { - super(transformation, transforms, modelLocation, color, still, flowing, overlay, gas, stateOption.isPresent(), getCorners(stateOption), getFlow(stateOption), getOverlay(stateOption)); - } - - /** - * Gets the quantized fluid levels for each corner. - * - * Each value is packed into 10 bits of the model key, so max range is [0,1024). - * The value is currently stored/interpreted as the closest multiple of 1/864. - * The divisor is chosen here to allows likely flow values to be exactly representable - * while also providing good use of the available value range. - * (For fluids with default quanta, this evenly divides the per-block intervals of 1/9 by 96) - */ - private static int[] getCorners(Optional stateOption) - { - int[] cornerRound = {0, 0, 0, 0}; - if (stateOption.isPresent()) - { - IModelData state = stateOption.get(); - for (int i = 0; i < 4; i++) - { - Float level = null; // TODO fluids state.getValue(BlockFluidBase.LEVEL_CORNERS[i]); - cornerRound[i] = Math.round((level == null ? 8f / 9f : level) * 864); - } - } - return cornerRound; - } - - /** - * Gets the quantized flow direction of the fluid. - * - * This value comprises 11 bits of the model key, and is signed, so the max range is [-1024,1024). - * The value is currently stored as the angle rounded to the nearest degree. - * A value of -1000 is used to signify no flow. - */ - private static int getFlow(Optional stateOption) - { - Float flow = -1000f; - if (stateOption.isPresent()) - { - flow = null; // TODO fluids stateOption.get().getValue(BlockFluidBase.FLOW_DIRECTION); - if (flow == null) flow = -1000f; - } - int flowRound = (int) Math.round(Math.toDegrees(flow)); - flowRound = Mth.clamp(flowRound, -1000, 1000); - return flowRound; - } - - /** - * Gets the overlay texture flag for each side. - * - * This value determines if the fluid "overlay" texture should be used for that side, - * instead of the normal "flowing" texture (if applicable for that fluid). - * The sides are stored here by their regular horizontal index. - */ - private static boolean[] getOverlay(Optional stateOption) - { - boolean[] overlaySides = new boolean[4]; - if (stateOption.isPresent()) - { - IModelData state = stateOption.get(); - for (int i = 0; i < 4; i++) - { - Boolean overlay = null; // TODO fluids state.getValue(BlockFluidBase.SIDE_OVERLAYS[i]); - if (overlay != null) overlaySides[i] = overlay; - } - } - return overlaySides; - } - - @Override - public List getQuads(@Nullable BlockState state, @Nullable Direction side, RandomSource rand, IModelData modelData) - { - if (side != null) - { - Optional exState = Optional.of(modelData); - - int[] cornerRound = getCorners(exState); - int flowRound = getFlow(exState); - boolean[] overlaySides = getOverlay(exState); - - long key = 0L; - for (int i = 3; i >= 0; i--) - { - key <<= 1; - key |= overlaySides[i] ? 1 : 0; - } - key <<= 11; - key |= flowRound + 1024; - for (int i = 3; i >= 0; i--) - { - key <<= 10; - key |= cornerRound[i]; - } - key <<= 1; - key |= 1; - - return modelCache.getUnchecked(key).getQuads(state, side, rand); - } - - return super.getQuads(state, side, rand); - } - } - - private static class BakedFluid implements BakedModel - { - private static final int x[] = { 0, 0, 1, 1 }; - private static final int z[] = { 0, 1, 1, 0 }; - private static final float eps = 1e-3f; - - protected final Transformation transformation; - protected final ImmutableMap transforms; - protected final ResourceLocation modelLocation; - protected final int color; - protected final TextureAtlasSprite still, flowing; - protected final Optional overlay; - protected final boolean gas; - protected final ImmutableMap> faceQuads; - - public BakedFluid(Transformation transformation, ImmutableMap transforms, ResourceLocation modelLocation, int color, TextureAtlasSprite still, TextureAtlasSprite flowing, Optional overlay, boolean gas, boolean statePresent, int[] cornerRound, int flowRound, boolean[] sideOverlays) - { - this.transformation = transformation; - this.transforms = transforms; - this.modelLocation = modelLocation; - this.color = color; - this.still = still; - this.flowing = flowing; - this.overlay = overlay; - this.gas = gas; - this.faceQuads = buildQuads(statePresent, cornerRound, flowRound, sideOverlays); - } - - private ImmutableMap> buildQuads(boolean statePresent, int[] cornerRound, int flowRound, boolean[] sideOverlays) - { - EnumMap> faceQuads = new EnumMap<>(Direction.class); - for (Direction side : Direction.values()) - { - faceQuads.put(side, ImmutableList.of()); - } - - if (statePresent) - { - // y levels - float[] y = new float[4]; - boolean fullVolume = true; - for (int i = 0; i < 4; i++) - { - float value = cornerRound[i] / 864f; - if (value < 1f) fullVolume = false; - y[i] = gas ? 1f - value : value; - } - - // flow - boolean isFlowing = flowRound > -1000; - - float flow = isFlowing ? (float) Math.toRadians(flowRound) : 0f; - TextureAtlasSprite topSprite = isFlowing ? flowing : still; - float scale = isFlowing ? 4f : 8f; - - float c = Mth.cos(flow) * scale; - float s = Mth.sin(flow) * scale; - - // top - Direction top = gas ? Direction.DOWN : Direction.UP; - - // base uv offset for flow direction - VertexParameter uv = i -> c * (x[i] * 2 - 1) + s * (z[i] * 2 - 1); - - VertexParameter topX = i -> x[i]; - VertexParameter topY = i -> y[i]; - VertexParameter topZ = i -> z[i]; - VertexParameter topU = i -> 8 + uv.get(i); - VertexParameter topV = i -> 8 + uv.get((i + 1) % 4); - - { - ImmutableList.Builder builder = ImmutableList.builder(); - - builder.add(buildQuad(top, topSprite, gas, false, topX, topY, topZ, topU, topV)); - if (!fullVolume) builder.add(buildQuad(top, topSprite, !gas, true, topX, topY, topZ, topU, topV)); - - faceQuads.put(top, builder.build()); - } - - // bottom - Direction bottom = top.getOpposite(); - faceQuads.put(bottom, ImmutableList.of( - buildQuad(bottom, still, gas, false, - i -> z[i], - i -> gas ? 1 : 0, - i -> x[i], - i -> z[i] * 16, - i -> x[i] * 16 - ) - )); - - // sides - for (int i = 0; i < 4; i++) - { - Direction side = Direction.from2DDataValue((5 - i) % 4); // [W, S, E, N] - boolean useOverlay = overlay.isPresent() && sideOverlays[side.get2DDataValue()]; - int si = i; // local var for lambda capture - - VertexParameter sideX = j -> x[(si + x[j]) % 4]; - VertexParameter sideY = j -> z[j] == 0 ? (gas ? 1 : 0) : y[(si + x[j]) % 4]; - VertexParameter sideZ = j -> z[(si + x[j]) % 4]; - VertexParameter sideU = j -> x[j] * 8; - VertexParameter sideV = j -> (gas ? sideY.get(j) : 1 - sideY.get(j)) * 8; - - ImmutableList.Builder builder = ImmutableList.builder(); - - if (!useOverlay) builder.add(buildQuad(side, flowing, gas, true, sideX, sideY, sideZ, sideU, sideV)); - builder.add(buildQuad(side, useOverlay ? overlay.get() : flowing, !gas, false, sideX, sideY, sideZ, sideU, sideV)); - - faceQuads.put(side, builder.build()); - } - } - else - { - // inventory - faceQuads.put(Direction.SOUTH, ImmutableList.of( - buildQuad(Direction.UP, still, false, false, - i -> z[i], - i -> x[i], - i -> 0, - i -> z[i] * 16, - i -> x[i] * 16 - ) - )); - } - - return ImmutableMap.copyOf(faceQuads); - } - - // maps vertex index to parameter value - private interface VertexParameter - { - float get(int index); - } - - private BakedQuad buildQuad(Direction side, TextureAtlasSprite texture, boolean flip, boolean offset, VertexParameter x, VertexParameter y, VertexParameter z, VertexParameter u, VertexParameter v) - { - BakedQuadBuilder builder = new BakedQuadBuilder(texture); - - builder.setQuadOrientation(side); - builder.setQuadTint(0); - - boolean hasTransform = !transformation.isIdentity(); - IVertexConsumer consumer = hasTransform ? new TRSRTransformer(builder, transformation) : builder; - - for (int i = 0; i < 4; i++) - { - int vertex = flip ? 3 - i : i; - putVertex( - consumer, side, offset, - x.get(vertex), y.get(vertex), z.get(vertex), - texture.getU(u.get(vertex)), - texture.getV(v.get(vertex)) - ); - } - - return builder.build(); - } - - private void putVertex(IVertexConsumer consumer, Direction side, boolean offset, float x, float y, float z, float u, float v) - { - VertexFormat format = DefaultVertexFormat.BLOCK; - ImmutableList elements = format.getElements(); - for(int e = 0; e < elements.size(); e++) - { - switch(elements.get(e).getUsage()) - { - case POSITION: - float dx = offset ? side.getNormal().getX() * eps : 0f; - float dy = offset ? side.getNormal().getY() * eps : 0f; - float dz = offset ? side.getNormal().getZ() * eps : 0f; - consumer.put(e, x - dx, y - dy, z - dz, 1f); - break; - case COLOR: - float r = ((color >> 16) & 0xFF) / 255f; - float g = ((color >> 8) & 0xFF) / 255f; - float b = ( color & 0xFF) / 255f; - float a = ((color >> 24) & 0xFF) / 255f; - consumer.put(e, r, g, b, a); - break; - case NORMAL: - float offX = (float) side.getStepX(); - float offY = (float) side.getStepY(); - float offZ = (float) side.getStepZ(); - consumer.put(e, offX, offY, offZ, 0f); - break; - case UV: - if(elements.get(e).getIndex() == 0) - { - consumer.put(e, u, v, 0f, 1f); - break; - } - // else fallthrough to default - default: - consumer.put(e); - break; - } - } - } - - @Override - public boolean useAmbientOcclusion() - { - return true; - } - - @Override - public boolean isGui3d() - { - return false; - } - - @Override - public boolean usesBlockLight() - { - return false; - } - - @Override - public boolean isCustomRenderer() - { - return false; - } - - @Override - public TextureAtlasSprite getParticleIcon() - { - return still; - } - - @Override - public List getQuads(@Nullable BlockState state, @Nullable Direction side, RandomSource rand) - { - return side == null ? ImmutableList.of() : faceQuads.get(side); - } - - @Override - public ItemOverrides getOverrides() - { - return ItemOverrides.EMPTY; - } - - @Override - public boolean doesHandlePerspectives() - { - return true; - } - - @Override - public BakedModel handlePerspective(TransformType type, PoseStack poseStack) - { - return PerspectiveMapWrapper.handlePerspective(this, transforms, type, poseStack); - } - } -} diff --git a/src/main/java/net/minecraftforge/client/ItemModelMesherForge.java b/src/main/java/net/minecraftforge/client/model/ForgeItemModelShaper.java similarity index 72% rename from src/main/java/net/minecraftforge/client/ItemModelMesherForge.java rename to src/main/java/net/minecraftforge/client/model/ForgeItemModelShaper.java index 6c501576b8c..eda74760c9f 100644 --- a/src/main/java/net/minecraftforge/client/ItemModelMesherForge.java +++ b/src/main/java/net/minecraftforge/client/model/ForgeItemModelShaper.java @@ -3,12 +3,9 @@ * SPDX-License-Identifier: LGPL-2.1-only */ -package net.minecraftforge.client; - -import java.util.Map; +package net.minecraftforge.client.model; import com.google.common.collect.Maps; - import net.minecraft.client.renderer.ItemModelShaper; import net.minecraft.client.resources.model.BakedModel; import net.minecraft.client.resources.model.ModelBakery; @@ -21,15 +18,17 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.Map; + /** - * Wrapper around ItemModeMesher that cleans up the internal maps to respect ID remapping. + * Wrapper around {@link ItemModelShaper} that cleans up the internal maps to respect ID remapping. */ -public class ItemModelMesherForge extends ItemModelShaper +public class ForgeItemModelShaper extends ItemModelShaper { - final Map, ModelResourceLocation> locations = Maps.newHashMap(); - final Map, BakedModel> models = Maps.newHashMap(); + private final Map, ModelResourceLocation> locations = Maps.newHashMap(); + private final Map, BakedModel> models = Maps.newHashMap(); - public ItemModelMesherForge(ModelManager manager) + public ForgeItemModelShaper(ModelManager manager) { super(manager); } @@ -55,19 +54,13 @@ public void rebuildCache() final ModelManager manager = this.getModelManager(); for (Map.Entry, ModelResourceLocation> e : locations.entrySet()) { - models.put(e.getKey(), manager.getModel(e.getValue())); + models.put(e.getKey(), manager.getModel(e.getValue())); } } public ModelResourceLocation getLocation(@NotNull ItemStack stack) { ModelResourceLocation location = locations.get(ForgeRegistries.ITEMS.getDelegateOrThrow(stack.getItem())); - - if (location == null) - { - location = ModelBakery.MISSING_MODEL_LOCATION; - } - - return location; + return location == null ? ModelBakery.MISSING_MODEL_LOCATION : location; } } diff --git a/src/main/java/net/minecraftforge/client/model/ForgeModelBakery.java b/src/main/java/net/minecraftforge/client/model/ForgeModelBakery.java deleted file mode 100644 index e3d30af692c..00000000000 --- a/src/main/java/net/minecraftforge/client/model/ForgeModelBakery.java +++ /dev/null @@ -1,263 +0,0 @@ -/* - * Copyright (c) Forge Development LLC and contributors - * SPDX-License-Identifier: LGPL-2.1-only - */ - -package net.minecraftforge.client.model; - -import java.util.HashSet; -import java.util.Map; -import java.util.Set; - -import net.minecraft.client.color.block.BlockColors; -import net.minecraft.client.renderer.texture.TextureAtlasSprite; -import net.minecraft.client.renderer.texture.TextureAtlas; -import net.minecraft.util.profiling.ProfilerFiller; -import net.minecraft.server.packs.resources.ResourceManager; -import net.minecraft.resources.ResourceLocation; -import net.minecraftforge.logging.ModelLoaderErrorMessage; - -import java.util.function.Function; - -import com.google.common.collect.Maps; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - -import static net.minecraftforge.fml.Logging.MODELLOADING; - -import net.minecraft.client.resources.model.BakedModel; -import net.minecraft.client.resources.model.Material; -import net.minecraft.client.resources.model.ModelBakery; -import net.minecraft.client.resources.model.ModelResourceLocation; -import net.minecraft.client.resources.model.UnbakedModel; -import org.jetbrains.annotations.Nullable; - -public final class ForgeModelBakery extends ModelBakery -{ - private static final Logger LOGGER = LogManager.getLogger(); - private final Map loadingExceptions = Maps.newHashMap(); - private UnbakedModel missingModel = null; - - private boolean isLoading = false; - - private static ForgeModelBakery instance; - - @Nullable - public static ForgeModelBakery instance() - { - return instance; - } - - public boolean isLoading() - { - return isLoading; - } - - public ForgeModelBakery(ResourceManager manager, BlockColors colours, ProfilerFiller profiler, int maxMipmapLevel) - { - super(manager, colours, false); - instance = this; - processLoading(profiler, maxMipmapLevel); - } - - private static Set specialModels = new HashSet<>(); - - /** - * Indicate to vanilla that it should load and bake the given model, even if no blocks or - * items use it. This is useful if e.g. you have baked models only for entity renderers. - * Call during {@link net.minecraftforge.client.event.ModelRegistryEvent} - * @param rl The model, either {@link ModelResourceLocation} to point to a blockstate variant, - * or plain {@link ResourceLocation} to point directly to a json in the models folder. - */ - public static void addSpecialModel(ResourceLocation rl) { - specialModels.add(rl); - } - - @Override - public Set getSpecialModels() { - return specialModels; - } - - /** - * Hooked from ModelBakery, allows using MRLs that don't end with "inventory" for items. - */ - public static ModelResourceLocation getInventoryVariant(String s) - { - if(s.contains("#")) - { - return new ModelResourceLocation(s); - } - return new ModelResourceLocation(s, "inventory"); - } - - protected ResourceLocation getModelLocation(ResourceLocation model) - { - return new ResourceLocation(model.getNamespace(), model.getPath() + ".json"); - } - - protected UnbakedModel getMissingModel() - { - if (missingModel == null) - { - try - { - missingModel = getModel(MISSING_MODEL_LOCATION); - } - catch(Exception e) - { - throw new RuntimeException("Missing the missing model, this should never happen"); - } - } - return missingModel; - } - - /** - * Use this if you don't care about the exception and want some model anyway. - */ - public UnbakedModel getModelOrMissing(ResourceLocation location) - { - try - { - return getModel(location); - } - catch(Exception e) - { - return getMissingModel(); - } - } - - /** - * Use this if you want the model, but need to log the error. - */ - public UnbakedModel getModelOrLogError(ResourceLocation location, String error) - { - try - { - return getModel(location); - } - catch(Exception e) - { - LOGGER.error(error, e); - return getMissingModel(); - } - } - - // Temporary to compile things - public static final class White { - public static final ResourceLocation LOCATION = new ResourceLocation("white"); - private static TextureAtlasSprite instance = null; - @SuppressWarnings("deprecation") - public static final TextureAtlasSprite instance() - { - if (instance == null) - { - instance = new Material(TextureAtlas.LOCATION_BLOCKS, LOCATION).sprite(); - } - return instance; - } - } - - /** - * 16x16 pure white sprite. - */ - /*/ TODO Custom TAS - public static final class White extends TextureAtlasSprite - { - public static final ResourceLocation LOCATION = new ResourceLocation("white"); - public static final White INSTANCE = new White(); - - private White() - { - super(LOCATION.toString()); - this.width = this.height = 16; - } - - @Override - public boolean hasCustomLoader(IResourceManager manager, ResourceLocation location) - { - return true; - } - - @Override - public boolean load(IResourceManager manager, ResourceLocation location, Function textureGetter) - { - BufferedImage image = new BufferedImage(this.getIconWidth(), this.getIconHeight(), BufferedImage.TYPE_INT_ARGB); - Graphics2D graphics = image.createGraphics(); - graphics.setBackground(Color.WHITE); - graphics.clearRect(0, 0, this.getIconWidth(), this.getIconHeight()); - int[][] pixels = new int[Minecraft.getMinecraft().gameSettings.mipmapLevels + 1][]; - pixels[0] = new int[image.getWidth() * image.getHeight()]; - image.getRGB(0, 0, image.getWidth(), image.getHeight(), pixels[0], 0, image.getWidth()); - this.clearFramesTextureData(); - this.framesTextureData.add(pixels); - return false; - } - - public void register(TextureMap map) - { - map.setTextureEntry(White.INSTANCE); - } - } -*/ - @SuppressWarnings("serial") - public static class ItemLoadingException extends ModelLoadingException - { - private final Exception normalException; - private final Exception blockstateException; - - public ItemLoadingException(String message, Exception normalException, Exception blockstateException) - { - super(message); - this.normalException = normalException; - this.blockstateException = blockstateException; - } - } - - /** - * Internal, do not use. - */ - public void onPostBakeEvent(Map modelRegistry) - { - BakedModel missingModel = modelRegistry.get(MISSING_MODEL_LOCATION); - for(Map.Entry entry : loadingExceptions.entrySet()) - { - // ignoring pure ResourceLocation arguments, all things we care about pass ModelResourceLocation - if(entry.getKey() instanceof ModelResourceLocation) - { - LOGGER.debug(MODELLOADING, ()-> new ModelLoaderErrorMessage((ModelResourceLocation)entry.getKey(), entry.getValue())); - final ModelResourceLocation location = (ModelResourceLocation)entry.getKey(); - final BakedModel model = modelRegistry.get(location); - if(model == null) - { - modelRegistry.put(location, missingModel); - } - } - } - loadingExceptions.clear(); - isLoading = false; - } - - /** - * Helper method for registering all itemstacks for given item to map to universal bucket model. - *//* - public static void setBucketModelDefinition(Item item) { - ModelLoader.setCustomMeshDefinition(item, stack -> ModelDynBucket.LOCATION); - ModelBakery.registerItemVariants(item, ModelDynBucket.LOCATION); - } -*/ - - private static final Function DEFAULT_MODEL_GETTER = (rl) -> ForgeModelBakery.instance().getModelOrMissing(rl); - - /** - * Get the default texture getter the models will be baked with. - */ - public static Function defaultTextureGetter() - { - return Material::sprite; - } - - public static Function defaultModelGetter() - { - return DEFAULT_MODEL_GETTER; - } -} diff --git a/src/main/java/net/minecraftforge/client/model/data/IDynamicBakedModel.java b/src/main/java/net/minecraftforge/client/model/IDynamicBakedModel.java similarity index 62% rename from src/main/java/net/minecraftforge/client/model/data/IDynamicBakedModel.java rename to src/main/java/net/minecraftforge/client/model/IDynamicBakedModel.java index 2bc6a5ae3b3..4bb1f5cbf38 100644 --- a/src/main/java/net/minecraftforge/client/model/data/IDynamicBakedModel.java +++ b/src/main/java/net/minecraftforge/client/model/IDynamicBakedModel.java @@ -3,31 +3,34 @@ * SPDX-License-Identifier: LGPL-2.1-only */ -package net.minecraftforge.client.model.data; +package net.minecraftforge.client.model; -import java.util.List; - -import net.minecraft.util.RandomSource; -import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.block.model.BakedQuad; import net.minecraft.client.resources.model.BakedModel; import net.minecraft.core.Direction; +import net.minecraft.util.RandomSource; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraftforge.client.extensions.IForgeBakedModel; +import net.minecraftforge.client.model.data.ModelData; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.List; + /** - * Convenience interface with default implementation of {@link BakedModel#getQuads(BlockState, Direction, RandomSource, IModelData)}. + * Convenience interface with default implementation of {@link IForgeBakedModel#getQuads(BlockState, Direction, RandomSource, ModelData, RenderType)}. */ public interface IDynamicBakedModel extends BakedModel { @Override default @NotNull List getQuads(@Nullable BlockState state, @Nullable Direction side, @NotNull RandomSource rand) { - return getQuads(state, side, rand, EmptyModelData.INSTANCE); + return getQuads(state, side, rand, ModelData.EMPTY, null); } // Force this to be overriden otherwise this introduces a default cycle between the two overloads. @Override @NotNull - List getQuads(@Nullable BlockState state, @Nullable Direction side, @NotNull RandomSource rand, @NotNull IModelData extraData); + List getQuads(@Nullable BlockState state, @Nullable Direction side, @NotNull RandomSource rand, @NotNull ModelData extraData, @Nullable RenderType renderType); } diff --git a/src/main/java/net/minecraftforge/client/model/IModelBuilder.java b/src/main/java/net/minecraftforge/client/model/IModelBuilder.java index 66c0689fb30..457082fcfa6 100644 --- a/src/main/java/net/minecraftforge/client/model/IModelBuilder.java +++ b/src/main/java/net/minecraftforge/client/model/IModelBuilder.java @@ -6,50 +6,111 @@ package net.minecraftforge.client.model; import net.minecraft.client.renderer.block.model.BakedQuad; -import net.minecraft.client.resources.model.BakedModel; import net.minecraft.client.renderer.block.model.ItemOverrides; -import net.minecraft.client.resources.model.SimpleBakedModel; +import net.minecraft.client.renderer.block.model.ItemTransforms; import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.resources.model.BakedModel; +import net.minecraft.client.resources.model.SimpleBakedModel; import net.minecraft.core.Direction; +import net.minecraftforge.client.RenderTypeGroup; +import java.util.List; + +/** + * Base interface for any object that collects culled and unculled faces and bakes them into a model. + *

+ * Provides a generic base implementation via {@link #of(boolean, boolean, boolean, ItemTransforms, ItemOverrides, TextureAtlasSprite, RenderTypeGroup)} + * and a quad-collecting alternative via {@link #collecting(List)}. + */ public interface IModelBuilder> { - static IModelBuilder of(IModelConfiguration owner, ItemOverrides overrides, TextureAtlasSprite particle) + /** + * Creates a new model builder that uses the provided attributes in the final baked model. + */ + static IModelBuilder of(boolean hasAmbientOcclusion, boolean usesBlockLight, boolean isGui3d, + ItemTransforms transforms, ItemOverrides overrides, TextureAtlasSprite particle, + RenderTypeGroup renderTypes) + { + return new Simple(hasAmbientOcclusion, usesBlockLight, isGui3d, transforms, overrides, particle, renderTypes); + } + + /** + * Creates a new model builder that collects quads to the provided list, returning + * {@linkplain EmptyModel#BAKED an empty model} if you call {@link #build()}. + */ + static IModelBuilder collecting(List quads) { - return new Simple(new SimpleBakedModel.Builder(owner, overrides).particle(particle)); + return new Collecting(quads); } - T addFaceQuad(Direction facing, BakedQuad quad); - T addGeneralQuad(BakedQuad quad); + T addCulledFace(Direction facing, BakedQuad quad); + + T addUnculledFace(BakedQuad quad); BakedModel build(); - class Simple implements IModelBuilder { - final SimpleBakedModel.Builder builder; + class Simple implements IModelBuilder + { + private final SimpleBakedModel.Builder builder; + private final RenderTypeGroup renderTypes; - Simple(SimpleBakedModel.Builder builder) + private Simple(boolean hasAmbientOcclusion, boolean usesBlockLight, boolean isGui3d, + ItemTransforms transforms, ItemOverrides overrides, TextureAtlasSprite particle, + RenderTypeGroup renderTypes) { - this.builder = builder; + this.builder = new SimpleBakedModel.Builder(hasAmbientOcclusion, usesBlockLight, isGui3d, transforms, overrides).particle(particle); + this.renderTypes = renderTypes; } @Override - public Simple addFaceQuad(Direction facing, BakedQuad quad) + public Simple addCulledFace(Direction facing, BakedQuad quad) { builder.addCulledFace(facing, quad); return this; } @Override - public Simple addGeneralQuad(BakedQuad quad) + public Simple addUnculledFace(BakedQuad quad) { builder.addUnculledFace(quad); return this; } + @Deprecated + @Override + public BakedModel build() + { + return builder.build(renderTypes); + } + } + + class Collecting implements IModelBuilder + { + private final List quads; + + private Collecting(List quads) + { + this.quads = quads; + } + + @Override + public Collecting addCulledFace(Direction facing, BakedQuad quad) + { + quads.add(quad); + return this; + } + + @Override + public Collecting addUnculledFace(BakedQuad quad) + { + quads.add(quad); + return this; + } + @Override public BakedModel build() { - return builder.build(); + return EmptyModel.BAKED; } } } diff --git a/src/main/java/net/minecraftforge/client/model/IModelConfiguration.java b/src/main/java/net/minecraftforge/client/model/IModelConfiguration.java deleted file mode 100644 index 491a75c386b..00000000000 --- a/src/main/java/net/minecraftforge/client/model/IModelConfiguration.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright (c) Forge Development LLC and contributors - * SPDX-License-Identifier: LGPL-2.1-only - */ - -package net.minecraftforge.client.model; - -import net.minecraft.client.resources.model.ModelState; -import net.minecraft.client.resources.model.UnbakedModel; -import net.minecraft.client.renderer.block.model.ItemTransforms; -import net.minecraft.client.resources.model.Material; -import net.minecraftforge.client.model.geometry.IModelGeometryPart; -import org.jetbrains.annotations.Nullable; - -/* - * Interface that provides generic access to the data within BlockModel, - * while allowing non-blockmodel usage of models - */ -public interface IModelConfiguration { - - /** - * If available, gets the owning model (usually BlockModel) of this configuration - */ - @Nullable - UnbakedModel getOwnerModel(); - - /** - * @return The name of the model being baked, for logging and cache purposes. - */ - String getModelName(); - - /** - * Checks if a texture is present in the model. - * @param name The name of a texture channel. - */ - boolean isTexturePresent(String name); - - /** - * Resolves the final texture name, taking into account texture aliases and replacements. - * @param name The name of a texture channel. - * @return The location of the texture, or the missing texture if not found. - */ - Material resolveTexture(String name); - - /** - * @return True if the item is a 3D model, false if it's a generated item model. - * TODO: Rename. - * This value has nothing to do with shading anymore, and this name is misleading. - * It's actual purpose seems to be relegated to translating the model during rendering, so that it's centered. - */ - boolean isShadedInGui(); - - /** - * @return True if the item is lit from the side - */ - boolean isSideLit(); - - /** - * @return True if the item requires per-vertex lighting. - */ - boolean useSmoothLighting(); - - /** - * Gets the vanilla camera transforms data. - * Do not use for non-vanilla code. For general usage, prefer getCombinedState. - */ - ItemTransforms getCameraTransforms(); - - /** - * @return The combined transformation state including vanilla and forge transforms data. - */ - ModelState getCombinedTransform(); - - /** - * Queries the visibility information for the model parts. - * @param part A part for which to query visibility. - * @param fallback A boolean specifying the default visibility if an override isn't found in the model data. - * @return The final computed visibility. - */ - default boolean getPartVisibility(IModelGeometryPart part, boolean fallback) { - return fallback; - } - - /** - * Queries the visibility information for the model parts. Same as above, but defaulting to visible. - * @param part A part for which to query visibility. - * @return The final computed visibility. - */ - default boolean getPartVisibility(IModelGeometryPart part) { - return getPartVisibility(part, true); - } - -} diff --git a/src/main/java/net/minecraftforge/client/model/IModelLoader.java b/src/main/java/net/minecraftforge/client/model/IModelLoader.java deleted file mode 100644 index 57c77e35964..00000000000 --- a/src/main/java/net/minecraftforge/client/model/IModelLoader.java +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Copyright (c) Forge Development LLC and contributors - * SPDX-License-Identifier: LGPL-2.1-only - */ - -package net.minecraftforge.client.model; - -import com.google.gson.JsonDeserializationContext; -import com.google.gson.JsonObject; -import net.minecraft.server.packs.resources.ResourceManagerReloadListener; -import net.minecraftforge.client.model.geometry.IModelGeometry; - -public interface IModelLoader> extends ResourceManagerReloadListener -{ - T read(JsonDeserializationContext deserializationContext, JsonObject modelContents); -} diff --git a/src/main/java/net/minecraftforge/client/model/IQuadTransformer.java b/src/main/java/net/minecraftforge/client/model/IQuadTransformer.java new file mode 100644 index 00000000000..671e3c08728 --- /dev/null +++ b/src/main/java/net/minecraftforge/client/model/IQuadTransformer.java @@ -0,0 +1,142 @@ +/* + * Copyright (c) Forge Development LLC and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.minecraftforge.client.model; + +import com.mojang.blaze3d.vertex.DefaultVertexFormat; +import com.mojang.blaze3d.vertex.VertexFormatElement; +import com.mojang.math.Transformation; +import com.mojang.math.Vector3f; +import com.mojang.math.Vector4f; +import net.minecraft.client.renderer.block.model.BakedQuad; + +import java.util.Arrays; +import java.util.List; + +/** + * Transformer for {@link BakedQuad baked quads}. + * + * @see #applying(Transformation) + * @see #applyingLightmap(int) + */ +public interface IQuadTransformer +{ + int STRIDE = DefaultVertexFormat.BLOCK.getIntegerSize(); + int POSITION = findOffset(DefaultVertexFormat.ELEMENT_POSITION); + int COLOR = findOffset(DefaultVertexFormat.ELEMENT_COLOR); + int UV0 = findOffset(DefaultVertexFormat.ELEMENT_UV0); + int UV1 = findOffset(DefaultVertexFormat.ELEMENT_UV1); + int UV2 = findOffset(DefaultVertexFormat.ELEMENT_UV2); + int NORMAL = findOffset(DefaultVertexFormat.ELEMENT_NORMAL); + + void processInPlace(BakedQuad quad); + + default void processInPlace(List quads) + { + for (BakedQuad quad : quads) + processInPlace(quad); + } + + default BakedQuad process(BakedQuad quad) + { + var copy = copy(quad); + processInPlace(copy); + return copy; + } + + default List process(List inputs) + { + return inputs.stream().map(IQuadTransformer::copy).peek(this::processInPlace).toList(); + } + + default IQuadTransformer andThen(IQuadTransformer other) + { + return quad -> { + processInPlace(quad); + other.processInPlace(quad); + }; + } + + /** + * Creates a {@link BakedQuad} transformer that does nothing. + */ + static IQuadTransformer empty() + { + return quad -> {}; + } + + /** + * Creates a {@link BakedQuad} transformer that applies the specified {@link Transformation}. + */ + static IQuadTransformer applying(Transformation transform) + { + if (transform.isIdentity()) + return empty(); + return quad -> { + var vertices = quad.getVertices(); + for (int i = 0; i < 4; i++) + { + int offset = i * STRIDE + POSITION; + float x = Float.intBitsToFloat(vertices[offset]); + float y = Float.intBitsToFloat(vertices[offset + 1]); + float z = Float.intBitsToFloat(vertices[offset + 2]); + + Vector4f pos = new Vector4f(x, y, z, 1); + transform.transformPosition(pos); + pos.perspectiveDivide(); + + vertices[offset] = Float.floatToRawIntBits(pos.x()); + vertices[offset + 1] = Float.floatToRawIntBits(pos.y()); + vertices[offset + 2] = Float.floatToRawIntBits(pos.z()); + } + + for (int i = 0; i < 4; i++) + { + int offset = i * STRIDE + NORMAL; + int normalIn = vertices[offset]; + if ((normalIn >> 8) != 0) + { + float x = ((byte) (normalIn & 0xFF)) / 127.0f; + float y = ((byte) ((normalIn >> 8) & 0xFF)) / 127.0f; + float z = ((byte) ((normalIn >> 16) & 0xFF)) / 127.0f; + + Vector3f pos = new Vector3f(x, y, z); + transform.transformNormal(pos); + pos.normalize(); + + vertices[offset] = (((byte) (x * 127.0f)) & 0xFF) | + ((((byte) (y * 127.0f)) & 0xFF) << 8) | + ((((byte) (z * 127.0f)) & 0xFF) << 16) | + (normalIn & 0xFF000000); + } + } + }; + } + + /** + * Creates a {@link BakedQuad} transformer that applies the specified lightmap. + */ + static IQuadTransformer applyingLightmap(int lightmap) + { + return quad -> { + var vertices = quad.getVertices(); + for (int i = 0; i < 4; i++) + vertices[i * STRIDE + UV2] = lightmap; + }; + } + + private static BakedQuad copy(BakedQuad quad) + { + var vertices = quad.getVertices(); + return new BakedQuad(Arrays.copyOf(vertices, vertices.length), quad.getTintIndex(), quad.getDirection(), quad.getSprite(), quad.isShade()); + } + + private static int findOffset(VertexFormatElement element) + { + // Divide by 4 because we want the int offset + var index = DefaultVertexFormat.BLOCK.getElements().indexOf(element); + return index < 0 ? -1 : DefaultVertexFormat.BLOCK.getOffset(index) / 4; + } +} diff --git a/src/main/java/net/minecraftforge/client/model/ItemLayerModel.java b/src/main/java/net/minecraftforge/client/model/ItemLayerModel.java index 7958f2ae1ef..60ccdb54a77 100644 --- a/src/main/java/net/minecraftforge/client/model/ItemLayerModel.java +++ b/src/main/java/net/minecraftforge/client/model/ItemLayerModel.java @@ -5,488 +5,172 @@ package net.minecraftforge.client.model; -import com.google.common.collect.*; -import com.google.gson.JsonArray; +import com.google.common.collect.ImmutableList; import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonElement; import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; import com.mojang.datafixers.util.Pair; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; +import it.unimi.dsi.fastutil.ints.IntOpenHashSet; +import it.unimi.dsi.fastutil.ints.IntSet; import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.block.model.ItemModelGenerator; -import net.minecraft.client.renderer.texture.TextureAtlasSprite; -import com.mojang.blaze3d.vertex.VertexFormat; -import com.mojang.blaze3d.vertex.VertexFormatElement; -import net.minecraft.server.packs.resources.ResourceManager; -import net.minecraft.core.Direction; -import net.minecraft.util.GsonHelper; -import net.minecraft.resources.ResourceLocation; -import com.mojang.math.Transformation; -import net.minecraftforge.client.ForgeRenderTypes; -import net.minecraftforge.client.model.geometry.IModelGeometry; -import net.minecraftforge.client.model.pipeline.BakedQuadBuilder; -import net.minecraftforge.client.model.pipeline.IVertexConsumer; -import net.minecraftforge.client.model.pipeline.TRSRTransformer; - -import java.util.*; -import java.util.function.Function; - -import net.minecraft.client.renderer.block.model.BakedQuad; import net.minecraft.client.renderer.block.model.ItemOverrides; -import net.minecraft.client.renderer.block.model.ItemTransforms; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.client.resources.model.BakedModel; import net.minecraft.client.resources.model.Material; import net.minecraft.client.resources.model.ModelBakery; import net.minecraft.client.resources.model.ModelState; import net.minecraft.client.resources.model.UnbakedModel; +import net.minecraft.resources.ResourceLocation; +import net.minecraftforge.client.ForgeRenderTypes; +import net.minecraftforge.client.RenderTypeGroup; +import net.minecraftforge.client.model.geometry.IGeometryBakingContext; +import net.minecraftforge.client.model.geometry.IGeometryLoader; +import net.minecraftforge.client.model.geometry.IUnbakedGeometry; +import net.minecraftforge.client.model.geometry.UnbakedGeometryHelper; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import org.jetbrains.annotations.Nullable; +import java.util.Collection; +import java.util.Map; +import java.util.Set; +import java.util.function.Function; + /** - * Forge reimplementation of vanilla {@link ItemModelGenerator}, i.e. builtin/generated models, - * with the following changes: - * - Represented as a true {@link UnbakedModel} so it can be baked as usual instead of using - * special-case logic like vanilla does. - * - Various fixes in the baking logic. - * - Not limited to 4 layers maximum. + * Forge reimplementation of vanilla's {@link ItemModelGenerator}, i.e. builtin/generated models with some tweaks: + * - Represented as {@link IUnbakedGeometry} so it can be baked as usual instead of being special-cased + * - Not limited to an arbitrary number of layers (5) + * - Support for per-layer render types */ -public final class ItemLayerModel implements IModelGeometry +public class ItemLayerModel implements IUnbakedGeometry { - public static final ItemLayerModel INSTANCE = new ItemLayerModel(ImmutableList.of()); + private static final Logger LOGGER = LogManager.getLogger(); - private static final Direction[] HORIZONTALS = {Direction.UP, Direction.DOWN}; - private static final Direction[] VERTICALS = {Direction.WEST, Direction.EAST}; + // Transformer to set quads to max brightness + private static final IQuadTransformer MAX_LIGHTMAP_TRANSFORMER = IQuadTransformer.applyingLightmap(0x00F000F0); + @Nullable private ImmutableList textures; - private final ImmutableSet fullbrightLayers; - - public ItemLayerModel() - { - this(null, ImmutableSet.of()); - } + private final IntSet emissiveLayers; + private final Int2ObjectMap renderTypeNames; + private final boolean deprecatedLoader, logWarning; - public ItemLayerModel(ImmutableList textures) + public ItemLayerModel(@Nullable ImmutableList textures, IntSet emissiveLayers, Int2ObjectMap renderTypeNames) { - this(textures, ImmutableSet.of()); + this(textures, emissiveLayers, renderTypeNames, false, false); } - public ItemLayerModel(@Nullable ImmutableList textures, ImmutableSet fullbrightLayers) + private ItemLayerModel(@Nullable ImmutableList textures, IntSet emissiveLayers, Int2ObjectMap renderTypeNames, boolean deprecatedLoader, boolean logWarning) { this.textures = textures; - this.fullbrightLayers = fullbrightLayers; - } - - private static ImmutableList getTextures(IModelConfiguration model) - { - ImmutableList.Builder builder = ImmutableList.builder(); - for(int i = 0; model.isTexturePresent("layer" + i); i++) - { - builder.add(model.resolveTexture("layer" + i)); - } - return builder.build(); + this.emissiveLayers = emissiveLayers; + this.renderTypeNames = renderTypeNames; + this.deprecatedLoader = deprecatedLoader; + this.logWarning = logWarning; } @Override - public BakedModel bake(IModelConfiguration owner, ModelBakery bakery, - Function spriteGetter, ModelState modelTransform, - ItemOverrides overrides, ResourceLocation modelLocation) - { - ImmutableMap transformMap = - PerspectiveMapWrapper.getTransforms(new CompositeModelState(owner.getCombinedTransform(), modelTransform)); - Transformation transform = modelTransform.getRotation(); - TextureAtlasSprite particle = spriteGetter.apply( - owner.isTexturePresent("particle") ? owner.resolveTexture("particle") : textures.get(0) - ); - - ItemMultiLayerBakedModel.Builder builder = ItemMultiLayerBakedModel.builder(owner, particle, overrides, transformMap); - for(int i = 0; i < textures.size(); i++) - { - TextureAtlasSprite tas = spriteGetter.apply(textures.get(i)); - boolean fullbright = fullbrightLayers.contains(i); - RenderType rt = getLayerRenderType(fullbright); - builder.addQuads(rt, getQuadsForSprite(i, tas, transform, fullbright)); - } - - return builder.build(); - } - - public static RenderType getLayerRenderType(boolean isFullbright) + public BakedModel bake(IGeometryBakingContext context, ModelBakery bakery, Function spriteGetter, ModelState modelState, ItemOverrides overrides, ResourceLocation modelLocation) { - return isFullbright ? ForgeRenderTypes.ITEM_UNSORTED_UNLIT_TRANSLUCENT.get() : ForgeRenderTypes.ITEM_UNSORTED_TRANSLUCENT.get(); - } - - public static ImmutableList getQuadsForSprites(List textures, Transformation transform, Function spriteGetter) - { - return getQuadsForSprites(textures, transform, spriteGetter, Collections.emptySet()); - } - - public static ImmutableList getQuadsForSprites(List textures, Transformation transform, Function spriteGetter, Set fullbrights) - { - ImmutableList.Builder builder = ImmutableList.builder(); - for(int i = 0; i < textures.size(); i++) - { - TextureAtlasSprite tas = spriteGetter.apply(textures.get(i)); - builder.addAll(getQuadsForSprite(i, tas, transform, fullbrights.contains(i))); - } - return builder.build(); - } - - public static ImmutableList getQuadsForSprite(int tint, TextureAtlasSprite sprite, Transformation transform) - { - return getQuadsForSprite(tint, sprite, transform, false); - } - - public static ImmutableList getQuadsForSprite(int tint, TextureAtlasSprite sprite, Transformation transform, boolean fullbright) - { - ImmutableList.Builder builder = ImmutableList.builder(); - - int uMax = sprite.getWidth(); - int vMax = sprite.getHeight(); + if (textures == null) + throw new IllegalStateException("Textures have not been initialized. Either pass them in through the constructor or call getMaterials(...) first."); - FaceData faceData = new FaceData(uMax, vMax); - boolean translucent = false; + if (deprecatedLoader) + LOGGER.warn("Model \"" + modelLocation + "\" is using the deprecated loader \"forge:item-layers\" instead of \"forge:item_layers\". This loader will be removed in 1.20."); + if (logWarning) + LOGGER.warn("Model \"" + modelLocation + "\" is using the deprecated \"fullbright_layers\" field in its item layer model instead of \"emissive_layers\". This field will be removed in 1.20."); - for(int f = 0; f < sprite.getFrameCount(); f++) - { - boolean ptu; - boolean[] ptv = new boolean[uMax]; - Arrays.fill(ptv, true); - for(int v = 0; v < vMax; v++) - { - ptu = true; - for(int u = 0; u < uMax; u++) - { - int alpha = sprite.getPixelRGBA(f, u, vMax - v - 1) >> 24 & 0xFF; - boolean t = alpha / 255f <= 0.1f; - - if (!t && alpha < 255) - { - translucent = true; - } - - if(ptu && !t) // left - transparent, right - opaque - { - faceData.set(Direction.WEST, u, v); - } - if(!ptu && t) // left - opaque, right - transparent - { - faceData.set(Direction.EAST, u-1, v); - } - if(ptv[u] && !t) // up - transparent, down - opaque - { - faceData.set(Direction.UP, u, v); - } - if(!ptv[u] && t) // up - opaque, down - transparent - { - faceData.set(Direction.DOWN, u, v-1); - } - - ptu = t; - ptv[u] = t; - } - if(!ptu) // last - opaque - { - faceData.set(Direction.EAST, uMax-1, v); - } - } - // last line - for(int u = 0; u < uMax; u++) - { - if(!ptv[u]) - { - faceData.set(Direction.DOWN, u, vMax-1); - } - } - } + TextureAtlasSprite particle = spriteGetter.apply( + context.hasMaterial("particle") ? context.getMaterial("particle") : textures.get(0) + ); + var rootTransform = context.getRootTransform(); + if (!rootTransform.isIdentity()) + modelState = new SimpleModelState(modelState.getRotation().compose(rootTransform), modelState.isUvLocked()); - // horizontal quads - for (Direction facing : HORIZONTALS) + var normalRenderTypes = new RenderTypeGroup(RenderType.translucent(), ForgeRenderTypes.ITEM_UNSORTED_TRANSLUCENT.get()); + CompositeModel.Baked.Builder builder = CompositeModel.Baked.builder(context, particle, overrides, context.getTransforms()); + for (int i = 0; i < textures.size(); i++) { - for (int v = 0; v < vMax; v++) - { - int uStart = 0, uEnd = uMax; - boolean building = false; - for (int u = 0; u < uMax; u++) - { - boolean face = faceData.get(facing, u, v); - if (!translucent) - { - if (face) - { - if (!building) - { - building = true; - uStart = u; - } - uEnd = u + 1; - } - } - else - { - if (building && !face) // finish current quad - { - // make quad [uStart, u] - int off = facing == Direction.DOWN ? 1 : 0; - builder.add(buildSideQuad(transform, facing, tint, sprite, uStart, v+off, u-uStart, fullbright)); - building = false; - } - else if (!building && face) // start new quad - { - building = true; - uStart = u; - } - } - } - if (building) // build remaining quad - { - // make quad [uStart, uEnd] - int off = facing == Direction.DOWN ? 1 : 0; - builder.add(buildSideQuad(transform, facing, tint, sprite, uStart, v+off, uEnd-uStart, fullbright)); - } - } + TextureAtlasSprite sprite = spriteGetter.apply(textures.get(i)); + var unbaked = UnbakedGeometryHelper.createUnbakedItemElements(i, sprite); + var quads = UnbakedGeometryHelper.bakeElements(unbaked, $ -> sprite, modelState, modelLocation); + if (emissiveLayers.contains(i)) MAX_LIGHTMAP_TRANSFORMER.processInPlace(quads); + var renderTypeName = renderTypeNames.get(i); + var renderTypes = renderTypeName != null ? context.getRenderType(renderTypeName) : null; + builder.addQuads(renderTypes != null ? renderTypes : normalRenderTypes, quads); } - // vertical quads - for (Direction facing : VERTICALS) - { - for (int u = 0; u < uMax; u++) - { - int vStart = 0, vEnd = vMax; - boolean building = false; - for (int v = 0; v < vMax; v++) - { - boolean face = faceData.get(facing, u, v); - if (!translucent) - { - if (face) - { - if (!building) - { - building = true; - vStart = v; - } - vEnd = v + 1; - } - } - else - { - if (building && !face) // finish current quad - { - // make quad [vStart, v] - int off = facing == Direction.EAST ? 1 : 0; - builder.add(buildSideQuad(transform, facing, tint, sprite, u+off, vStart, v-vStart, fullbright)); - building = false; - } - else if (!building && face) // start new quad - { - building = true; - vStart = v; - } - } - } - if (building) // build remaining quad - { - // make quad [vStart, vEnd] - int off = facing == Direction.EAST ? 1 : 0; - builder.add(buildSideQuad(transform, facing, tint, sprite, u+off, vStart, vEnd-vStart, fullbright)); - } - } - } - - // front - builder.add(buildQuad(transform, Direction.NORTH, sprite, tint, fullbright, - 0, 0, 7.5f / 16f, sprite.getU0(), sprite.getV1(), - 0, 1, 7.5f / 16f, sprite.getU0(), sprite.getV0(), - 1, 1, 7.5f / 16f, sprite.getU1(), sprite.getV0(), - 1, 0, 7.5f / 16f, sprite.getU1(), sprite.getV1() - )); - // back - builder.add(buildQuad(transform, Direction.SOUTH, sprite, tint, fullbright, - 0, 0, 8.5f / 16f, sprite.getU0(), sprite.getV1(), - 1, 0, 8.5f / 16f, sprite.getU1(), sprite.getV1(), - 1, 1, 8.5f / 16f, sprite.getU1(), sprite.getV0(), - 0, 1, 8.5f / 16f, sprite.getU0(), sprite.getV0() - )); - return builder.build(); } @Override - public Collection getTextures(IModelConfiguration owner, Function modelGetter, Set> missingTextureErrors) - { - textures = getTextures(owner); - return textures; - } - - private static class FaceData + public Collection getMaterials(IGeometryBakingContext context, Function modelGetter, Set> missingTextureErrors) { - private final EnumMap data = new EnumMap<>(Direction.class); - - private final int vMax; - - FaceData(int uMax, int vMax) - { - this.vMax = vMax; + if (textures != null) + return textures; - data.put(Direction.WEST, new BitSet(uMax * vMax)); - data.put(Direction.EAST, new BitSet(uMax * vMax)); - data.put(Direction.UP, new BitSet(uMax * vMax)); - data.put(Direction.DOWN, new BitSet(uMax * vMax)); - } - - public void set(Direction facing, int u, int v) - { - data.get(facing).set(getIndex(u, v)); - } - - public boolean get(Direction facing, int u, int v) - { - return data.get(facing).get(getIndex(u, v)); - } - - private int getIndex(int u, int v) + ImmutableList.Builder builder = ImmutableList.builder(); + if (context.hasMaterial("particle")) + builder.add(context.getMaterial("particle")); + for (int i = 0; context.hasMaterial("layer" + i); i++) { - return v * vMax + u; + builder.add(context.getMaterial("layer" + i)); } + return textures = builder.build(); } - private static BakedQuad buildSideQuad(Transformation transform, Direction side, int tint, TextureAtlasSprite sprite, int u, int v, int size, boolean fullbright) + public static final class Loader implements IGeometryLoader { - final float eps = 1e-2f; + public static final Loader INSTANCE = new Loader(false); + @Deprecated(forRemoval = true, since = "1.19") + public static final Loader INSTANCE_DEPRECATED = new Loader(true); - int width = sprite.getWidth(); - int height = sprite.getHeight(); + private final boolean deprecated; - float x0 = (float) u / width; - float y0 = (float) v / height; - float x1 = x0, y1 = y0; - float z0 = 7.5f / 16f, z1 = 8.5f / 16f; - - switch(side) + private Loader(boolean deprecated) { - case WEST: - z0 = 8.5f / 16f; - z1 = 7.5f / 16f; - case EAST: - y1 = (float) (v + size) / height; - break; - case DOWN: - z0 = 8.5f / 16f; - z1 = 7.5f / 16f; - case UP: - x1 = (float) (u + size) / width; - break; - default: - throw new IllegalArgumentException("can't handle z-oriented side"); + this.deprecated = deprecated; } - float dx = side.getNormal().getX() * eps / width; - float dy = side.getNormal().getY() * eps / height; - - float u0 = 16f * (x0 - dx); - float u1 = 16f * (x1 - dx); - float v0 = 16f * (1f - y0 - dy); - float v1 = 16f * (1f - y1 - dy); - - return buildQuad( - transform, remap(side), sprite, tint, fullbright, - x0, y0, z0, sprite.getU(u0), sprite.getV(v0), - x1, y1, z0, sprite.getU(u1), sprite.getV(v1), - x1, y1, z1, sprite.getU(u1), sprite.getV(v1), - x0, y0, z1, sprite.getU(u0), sprite.getV(v0) - ); - } - - private static Direction remap(Direction side) - { - // getOpposite is related to the swapping of V direction - return side.getAxis() == Direction.Axis.Y ? side.getOpposite() : side; - } - - private static BakedQuad buildQuad(Transformation transform, Direction side, TextureAtlasSprite sprite, int tint, boolean fullbright, - float x0, float y0, float z0, float u0, float v0, - float x1, float y1, float z1, float u1, float v1, - float x2, float y2, float z2, float u2, float v2, - float x3, float y3, float z3, float u3, float v3) - { - BakedQuadBuilder builder = new BakedQuadBuilder(sprite); - - builder.setQuadTint(tint); - builder.setQuadOrientation(side); - builder.setApplyDiffuseLighting(false); - - boolean hasTransform = !transform.isIdentity(); - IVertexConsumer consumer = hasTransform ? new TRSRTransformer(builder, transform) : builder; - - int uLight, vLight; - uLight = vLight = fullbright ? 15 : 0; - - putVertex(consumer, side, x0, y0, z0, u0, v0, uLight, vLight); - putVertex(consumer, side, x1, y1, z1, u1, v1, uLight, vLight); - putVertex(consumer, side, x2, y2, z2, u2, v2, uLight, vLight); - putVertex(consumer, side, x3, y3, z3, u3, v3, uLight, vLight); - - return builder.build(); - } - - private static void putVertex(IVertexConsumer consumer, Direction side, float x, float y, float z, float u, float v, int uLight, int vLight) - { - VertexFormat format = consumer.getVertexFormat(); - for(int e = 0; e < format.getElements().size(); e++) + @Override + public ItemLayerModel read(JsonObject jsonObject, JsonDeserializationContext deserializationContext) { - VertexFormatElement element = format.getElements().get(e); - outer:switch(element.getUsage()) + var renderTypeNames = new Int2ObjectOpenHashMap(); + if (jsonObject.has("render_types")) { - case POSITION: - consumer.put(e, x, y, z, 1f); - break; - case COLOR: - consumer.put(e, 1f, 1f, 1f, 1f); - break; - case NORMAL: - float offX = (float) side.getStepX(); - float offY = (float) side.getStepY(); - float offZ = (float) side.getStepZ(); - consumer.put(e, offX, offY, offZ, 0f); - break; - case UV: - switch(element.getIndex()) + var renderTypes = jsonObject.getAsJsonObject("render_types"); + for (Map.Entry entry : renderTypes.entrySet()) { - case 0: - consumer.put(e, u, v, 0f, 1f); - break outer; - case 2: - consumer.put(e, (uLight<<4)/32768.0f, (vLight<<4)/32768.0f, 0, 1); - break outer; + var renderType = new ResourceLocation(entry.getKey()); + for (var layer : entry.getValue().getAsJsonArray()) + if (renderTypeNames.put(layer.getAsInt(), renderType) != null) + throw new JsonParseException("Registered duplicate render type for layer " + layer); } - // else fallthrough to default - default: - consumer.put(e); - break; } - } - } - public static class Loader implements IModelLoader - { - public static final Loader INSTANCE = new Loader(); + var emissiveLayers = new IntOpenHashSet(); + readUnlit(jsonObject, "emissive_layers", renderTypeNames, emissiveLayers, false); + boolean logWarning = readUnlit(jsonObject, "fullbright_layers", renderTypeNames, emissiveLayers, true); // TODO: Deprecated name. To be removed in 1.20 - @Override - public void onResourceManagerReload(ResourceManager resourceManager) - { - // nothing to do + return new ItemLayerModel(null, emissiveLayers, renderTypeNames, deprecated, logWarning); } - @Override - public ItemLayerModel read(JsonDeserializationContext deserializationContext, JsonObject modelContents) + private boolean readUnlit(JsonObject jsonObject, String name, Int2ObjectOpenHashMap renderTypeNames, IntOpenHashSet litLayers, boolean logWarning) { - ImmutableSet.Builder fullbrightLayers = ImmutableSet.builder(); - if (modelContents.has("fullbright_layers")) + if (!jsonObject.has(name)) + return false; + var fullbrightLayers = jsonObject.getAsJsonArray(name); + var renderType = new ResourceLocation("forge", "item_unlit"); + for (var layer : fullbrightLayers) { - JsonArray arr = GsonHelper.getAsJsonArray(modelContents, "fullbright_layers"); - for(int i=0;i> layerModels; - private final ImmutableMap cameraTransforms; - - public ItemMultiLayerBakedModel(boolean smoothLighting, boolean shadedInGui, boolean sideLit, - TextureAtlasSprite particle, ItemOverrides overrides, - ImmutableMap cameraTransforms, - ImmutableList> layerModels) - { - this.smoothLighting = smoothLighting; - this.shadedInGui = shadedInGui; - this.sideLit = sideLit; - this.particle = particle; - this.overrides = overrides; - this.layerModels = layerModels; - this.cameraTransforms = cameraTransforms; - } - - @Override - public List getQuads(@Nullable BlockState state, @Nullable Direction side, RandomSource rand, IModelData modelData) - { - List quads = Lists.newArrayList(); - layerModels.forEach(lm -> quads.addAll(lm.getFirst().getQuads(state, side, rand, modelData))); - return quads; - } - - @Override - public boolean useAmbientOcclusion() - { - return smoothLighting; - } - - @Override - public boolean isGui3d() - { - return shadedInGui; - } - - @Override - public boolean usesBlockLight() - { - return sideLit; - } - - @Override - public boolean isCustomRenderer() - { - return false; - } - - @Override - public TextureAtlasSprite getParticleIcon() - { - return particle; - } - - @Override - public ItemOverrides getOverrides() - { - return overrides; - } - - @Override - public boolean doesHandlePerspectives() - { - return true; - } - - @Override - public BakedModel handlePerspective(ItemTransforms.TransformType cameraTransformType, PoseStack poseStack) - { - return PerspectiveMapWrapper.handlePerspective(this, cameraTransforms, cameraTransformType, poseStack); - } - - //@Override - public boolean isLayered() - { - return true; - } - - //@Override - public List> getLayerModels(ItemStack itemStack, boolean fabulous) - { - return layerModels; - } - - public static Builder builder(IModelConfiguration owner, TextureAtlasSprite particle, ItemOverrides overrides, - ImmutableMap cameraTransforms) - { - return new Builder(owner, particle, overrides, cameraTransforms); - } - - public static class Builder - { - private final ImmutableList.Builder> builder = ImmutableList.builder(); - private final List quads = Lists.newArrayList(); - private final ItemOverrides overrides; - private final ImmutableMap cameraTransforms; - private final IModelConfiguration owner; - private TextureAtlasSprite particle; - private RenderType lastRt = null; - - private Builder(IModelConfiguration owner, TextureAtlasSprite particle, ItemOverrides overrides, - ImmutableMap cameraTransforms) - { - this.owner = owner; - this.particle = particle; - this.overrides = overrides; - this.cameraTransforms = cameraTransforms; - } - - private void addLayer(ImmutableList.Builder> builder, List quads, RenderType rt) - { - BakedModel model = new BakedItemModel(ImmutableList.copyOf(quads), particle, ImmutableMap.of(), ItemOverrides.EMPTY, true, owner.isSideLit()); - builder.add(Pair.of(model, rt)); - } - - private void flushQuads(RenderType rt) - { - if (rt != lastRt) - { - if (quads.size() > 0) - { - addLayer(builder, quads, lastRt); - quads.clear(); - } - lastRt = rt; - } - } - - public Builder setParticle(TextureAtlasSprite particleSprite) - { - this.particle = particleSprite; - return this; - } - - public Builder addQuads(RenderType rt, BakedQuad... quadsToAdd) - { - flushQuads(rt); - Collections.addAll(quads, quadsToAdd); - return this; - } - - public Builder addQuads(RenderType rt, Collection quadsToAdd) - { - flushQuads(rt); - quads.addAll(quadsToAdd); - return this; - } - - public BakedModel build() - { - if (quads.size() > 0) - { - addLayer(builder, quads, lastRt); - } - return new ItemMultiLayerBakedModel(owner.useSmoothLighting(), owner.isShadedInGui(), owner.isSideLit(), - particle, overrides, cameraTransforms, builder.build()); - } - } -} diff --git a/src/main/java/net/minecraftforge/client/model/ItemTextureQuadConverter.java b/src/main/java/net/minecraftforge/client/model/ItemTextureQuadConverter.java deleted file mode 100644 index cbebdc448e8..00000000000 --- a/src/main/java/net/minecraftforge/client/model/ItemTextureQuadConverter.java +++ /dev/null @@ -1,323 +0,0 @@ -/* - * Copyright (c) Forge Development LLC and contributors - * SPDX-License-Identifier: LGPL-2.1-only - */ - -package net.minecraftforge.client.model; - -import com.google.common.collect.Lists; - -import net.minecraft.client.renderer.block.model.BakedQuad; -import net.minecraft.client.renderer.texture.TextureAtlasSprite; -import com.mojang.blaze3d.vertex.VertexFormat; -import com.mojang.blaze3d.vertex.VertexFormatElement; -import net.minecraft.core.Direction; -import com.mojang.math.Transformation; -import net.minecraftforge.client.model.pipeline.BakedQuadBuilder; -import net.minecraftforge.client.model.pipeline.IVertexConsumer; -import net.minecraftforge.client.model.pipeline.TRSRTransformer; - -import java.util.List; - -public final class ItemTextureQuadConverter -{ - private ItemTextureQuadConverter() - { - // non-instantiable - } - - /** - * Takes a texture and converts it into BakedQuads. - * The conversion is done by scanning the texture horizontally and vertically and creating "strips" of the texture. - * Strips that are of the same size and follow each other are converted into one bigger quad. - *
- * The resulting list of quads is the texture represented as a list of horizontal OR vertical quads, - * depending on which creates less quads. If the amount of quads is equal, horizontal is preferred. - * - * @param template The input texture to convert - * @param sprite The texture whose UVs shall be used - * @return The generated quads. - */ - public static List convertTexture(Transformation transform, TextureAtlasSprite template, TextureAtlasSprite sprite, float z, Direction facing, int color, int tint) - { - return convertTexture(transform, template, sprite, z, facing, color, tint, 0); - } - public static List convertTexture(Transformation transform, TextureAtlasSprite template, TextureAtlasSprite sprite, float z, Direction facing, int color, int tint, int luminosity) - { - List horizontal = convertTextureHorizontal(transform, template, sprite, z, facing, color, tint, luminosity); - List vertical = convertTextureVertical(transform, template, sprite, z, facing, color, tint, luminosity); - - return horizontal.size() <= vertical.size() ? horizontal : vertical; - } - - /** - * Scans a texture and converts it into a list of horizontal strips stacked on top of each other. - * The height of the strips is as big as possible. - */ - public static List convertTextureHorizontal(Transformation transform, TextureAtlasSprite template, TextureAtlasSprite sprite, float z, Direction facing, int color, int tint) - { - return convertTextureHorizontal(transform, template, sprite, z, facing, color, tint, 0); - } - public static List convertTextureHorizontal(Transformation transform, TextureAtlasSprite template, TextureAtlasSprite sprite, float z, Direction facing, int color, int tint, int luminosity) - { - int w = template.getWidth(); - int h = template.getHeight(); - float wScale = 16f / (float)w; - float hScale = 16f / (float)h; - List quads = Lists.newArrayList(); - - // the y-position of the current batch of quads - int startY = 0; - for (int y = 1; y <= h; y++) - { - if (y < h) - { - // we check if the visibility of the next row matches the one for the current row - // if they are, we can extend the quad downwards - boolean sameRow = true; - for (int x = 0; x < w; x++) - { - if (template.isTransparent(0, x, y) != template.isTransparent(0, x, startY)) - { - sameRow = false; - break; - } - } - - if (sameRow) - continue; // continue to search for rows with same visibility - } - - // all rows from startX (inclusive) to x (exclusive) have same visibility - // create a batch of quads - // the upper left x-position of the current quad - int startX = -1; - for (int x = 0; x <= w; x++) - { - if (x < w) - { - // current pixel - boolean isVisible = !template.isTransparent(0, x, startY); - - // no current quad but found a new one - if (startX < 0 && isVisible) - { - startX = x; - } - - if (isVisible) - continue; // continue to search for visible pixels in the current quad - } - - // got a current quad, but it ends here - if (startX >= 0) - { - // create the quad - quads.add(genQuad(transform, - (float)startX * wScale, - (float)startY * hScale, - (float)x * wScale, - (float)y * hScale, - z, sprite, facing, color, tint, luminosity)); - - // clear current quad - startX = -1; - } - } - - // next batch of quads start at the current line - startY = y; - } - - return quads; - } - - /** - * Scans a texture and converts it into a list of vertical strips stacked next to each other from left to right. - * The width of the strips is as big as possible. - */ - public static List convertTextureVertical(Transformation transform, TextureAtlasSprite template, TextureAtlasSprite sprite, float z, Direction facing, int color, int tint) - { - return convertTextureVertical(transform, template, sprite, z, facing, color, tint, 0); - } - public static List convertTextureVertical(Transformation transform, TextureAtlasSprite template, TextureAtlasSprite sprite, float z, Direction facing, int color, int tint, int luminosity) - { - int w = template.getWidth(); - int h = template.getHeight(); - float wScale = 16f / (float)w; - float hScale = 16f / (float)h; - List quads = Lists.newArrayList(); - - // the x-position of the current batch of quads - int startX = 0; - for (int x = 1; x <= w; x++) - { - if (x < w) - { - // we check if the visibility of the next column matches the one for the current row - // if they are, we can extend the quad downwards - boolean sameColumn = true; - for (int y = 0; y < h; y++) - { - if (template.isTransparent(0, x, y) != template.isTransparent(0, startX, y)) - { - sameColumn = false; - break; - } - } - - if (sameColumn) - continue; // continue to search for columns with same visibility - } - - // all columns from startY (inclusive) to y (exclusive) have same visibility - // create a batch of quads - // the upper left y-position of the current quad - int startY = -1; - for (int y = 0; y <= h; y++) - { - if (y < h) - { - // current pixel - boolean isVisible = !template.isTransparent(0, startX, y); - - // no current quad but found a new one - if (startY < 0 && isVisible) - { - startY = y; - } - - if (isVisible) - continue; // continue to search for visible pixels in the current quad - } - - // got a current quad, but it ends here - if (startY >= 0) - { - // create the quad - quads.add(genQuad(transform, - (float)startX * wScale, - (float)startY * hScale, - (float)x * wScale, - (float)y * hScale, - z, sprite, facing, color, tint, luminosity)); - - // clear current quad - startY = -1; - } - } - - // next batch of quads start at the current column - startX = x; - } - - return quads; - } - - private static boolean isVisible(int color) - { - return (color >> 24 & 255) / 255f > 0.1f; - } - - /** - * Generates a Front/Back quad for an itemmodel. Therefore only supports facing NORTH and SOUTH. - * Coordinates are [0,16] to match the usual coordinates used in TextureAtlasSprites - */ - public static BakedQuad genQuad(Transformation transform, float x1, float y1, float x2, float y2, float z, TextureAtlasSprite sprite, Direction facing, int color, int tint) - { - return genQuad(transform, x1, y1, x2, y2, z, sprite, facing, color, tint, 0); - } - public static BakedQuad genQuad(Transformation transform, float x1, float y1, float x2, float y2, float z, TextureAtlasSprite sprite, Direction facing, int color, int tint, int luminosity) - { - float u1 = sprite.getU(x1); - float v1 = sprite.getV(y1); - float u2 = sprite.getU(x2); - float v2 = sprite.getV(y2); - - x1 /= 16f; - y1 /= 16f; - x2 /= 16f; - y2 /= 16f; - - float tmp = y1; - y1 = 1f - y2; - y2 = 1f - tmp; - - return putQuad(transform, facing, sprite, color, tint, x1, y1, x2, y2, z, u1, v1, u2, v2, luminosity); - } - - private static BakedQuad putQuad(Transformation transform, Direction side, TextureAtlasSprite sprite, int color, int tint, - float x1, float y1, float x2, float y2, float z, - float u1, float v1, float u2, float v2, int luminosity) - { - BakedQuadBuilder builder = new BakedQuadBuilder(sprite); - - builder.setQuadTint(tint); - builder.setQuadOrientation(side); - builder.setApplyDiffuseLighting(luminosity == 0); - - // only apply the transform if it's not identity - boolean hasTransform = !transform.isIdentity(); - IVertexConsumer consumer = hasTransform ? new TRSRTransformer(builder, transform) : builder; - - if (side == Direction.SOUTH) - { - putVertex(consumer, side, x1, y1, z, u1, v2, color, luminosity); - putVertex(consumer, side, x2, y1, z, u2, v2, color, luminosity); - putVertex(consumer, side, x2, y2, z, u2, v1, color, luminosity); - putVertex(consumer, side, x1, y2, z, u1, v1, color, luminosity); - } - else - { - putVertex(consumer, side, x1, y1, z, u1, v2, color, luminosity); - putVertex(consumer, side, x1, y2, z, u1, v1, color, luminosity); - putVertex(consumer, side, x2, y2, z, u2, v1, color, luminosity); - putVertex(consumer, side, x2, y1, z, u2, v2, color, luminosity); - } - return builder.build(); - } - - private static void putVertex(IVertexConsumer consumer, Direction side, - float x, float y, float z, float u, float v, int color, int luminosity) - { - VertexFormat format = consumer.getVertexFormat(); - for (int e = 0; e < format.getElements().size(); e++) - { - VertexFormatElement element = format.getElements().get(e); - switch (element.getUsage()) - { - case POSITION: - consumer.put(e, x, y, z, 1f); - break; - case COLOR: - float r = ((color >> 16) & 0xFF) / 255f; // red - float g = ((color >> 8) & 0xFF) / 255f; // green - float b = ((color >> 0) & 0xFF) / 255f; // blue - float a = ((color >> 24) & 0xFF) / 255f; // alpha - consumer.put(e, r, g, b, a); - break; - case NORMAL: - float offX = (float) side.getStepX(); - float offY = (float) side.getStepY(); - float offZ = (float) side.getStepZ(); - consumer.put(e, offX, offY, offZ, 0f); - break; - case UV: - if (element.getIndex() == 0) - { - consumer.put(e, u, v, 0f, 1f); - break; - } - else if (element.getIndex() == 2) - { - consumer.put(e, (luminosity<<4)/32768.0f, (luminosity<<4)/32768.0f, 0f, 1f); - break; - } - // else fallthrough to default - default: - consumer.put(e); - break; - } - } - } -} diff --git a/src/main/java/net/minecraftforge/client/model/ModelDataManager.java b/src/main/java/net/minecraftforge/client/model/ModelDataManager.java deleted file mode 100644 index bf06509adb0..00000000000 --- a/src/main/java/net/minecraftforge/client/model/ModelDataManager.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright (c) Forge Development LLC and contributors - * SPDX-License-Identifier: LGPL-2.1-only - */ - -package net.minecraftforge.client.model; - -import java.lang.ref.WeakReference; -import java.util.Collections; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; - -import com.google.common.base.Preconditions; - -import net.minecraft.client.Minecraft; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.core.BlockPos; -import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.Level; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.client.model.data.IModelData; -import net.minecraftforge.event.world.ChunkEvent; -import net.minecraftforge.eventbus.api.SubscribeEvent; -import net.minecraftforge.fml.common.Mod.EventBusSubscriber; -import net.minecraftforge.fml.common.Mod.EventBusSubscriber.Bus; -import org.jetbrains.annotations.Nullable; - -@EventBusSubscriber(modid = "forge", bus = Bus.FORGE, value = Dist.CLIENT) -public class ModelDataManager -{ - private static WeakReference currentLevel = new WeakReference<>(null); - - private static final Map> needModelDataRefresh = new ConcurrentHashMap<>(); - - private static final Map> modelDataCache = new ConcurrentHashMap<>(); - - private static void cleanCaches(Level level) - { - Preconditions.checkNotNull(level, "Level must not be null"); - Preconditions.checkArgument(level == Minecraft.getInstance().level, "Cannot use model data for a level other than the current client level"); - if (level != currentLevel.get()) - { - currentLevel = new WeakReference<>(level); - needModelDataRefresh.clear(); - modelDataCache.clear(); - } - } - - public static void requestModelDataRefresh(BlockEntity te) - { - Preconditions.checkNotNull(te, "Tile entity must not be null"); - Level level = te.getLevel(); - - cleanCaches(level); - needModelDataRefresh.computeIfAbsent(new ChunkPos(te.getBlockPos()), $ -> Collections.synchronizedSet(new HashSet<>())) - .add(te.getBlockPos()); - } - - private static void refreshModelData(Level level, ChunkPos chunk) - { - cleanCaches(level); - Set needUpdate = needModelDataRefresh.remove(chunk); - - if (needUpdate != null) - { - Map data = modelDataCache.computeIfAbsent(chunk, $ -> new ConcurrentHashMap<>()); - for (BlockPos pos : needUpdate) - { - BlockEntity toUpdate = level.getBlockEntity(pos); - if (toUpdate != null && !toUpdate.isRemoved()) - { - data.put(pos, toUpdate.getModelData()); - } - else - { - data.remove(pos); - } - } - } - } - - @SubscribeEvent - public static void onChunkUnload(ChunkEvent.Unload event) - { - if (!event.getChunk().getWorldForge().isClientSide()) return; - - ChunkPos chunk = event.getChunk().getPos(); - needModelDataRefresh.remove(chunk); - modelDataCache.remove(chunk); - } - - public static @Nullable IModelData getModelData(Level level, BlockPos pos) - { - return getModelData(level, new ChunkPos(pos)).get(pos); - } - - public static Map getModelData(Level level, ChunkPos pos) - { - Preconditions.checkArgument(level.isClientSide, "Cannot request model data for server level"); - refreshModelData(level, pos); - return modelDataCache.getOrDefault(pos, Collections.emptyMap()); - } -} diff --git a/src/main/java/net/minecraftforge/client/model/ModelLoaderRegistry.java b/src/main/java/net/minecraftforge/client/model/ModelLoaderRegistry.java deleted file mode 100644 index dd4edf45124..00000000000 --- a/src/main/java/net/minecraftforge/client/model/ModelLoaderRegistry.java +++ /dev/null @@ -1,428 +0,0 @@ -/* - * Copyright (c) Forge Development LLC and contributors - * SPDX-License-Identifier: LGPL-2.1-only - */ - -package net.minecraftforge.client.model; - -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; -import com.google.common.collect.Sets; -import com.google.gson.*; -import com.mojang.datafixers.util.Pair; -import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.texture.TextureAtlas; -import net.minecraft.client.renderer.texture.MissingTextureAtlasSprite; -import net.minecraft.client.renderer.texture.TextureAtlasSprite; -import net.minecraft.server.packs.resources.ReloadableResourceManager; -import net.minecraft.server.packs.resources.ResourceManager; -import net.minecraft.core.Direction; -import net.minecraft.util.GsonHelper; -import net.minecraft.resources.ResourceLocation; -import com.mojang.math.Transformation; -import net.minecraftforge.client.event.ModelRegistryEvent; -import net.minecraftforge.client.event.RegisterClientReloadListenersEvent; -import net.minecraftforge.client.model.geometry.IModelGeometry; -import net.minecraftforge.client.model.geometry.ISimpleModelGeometry; -import net.minecraftforge.client.model.obj.OBJLoader; -import net.minecraftforge.common.model.TransformationHelper; - -import java.lang.reflect.Type; -import java.util.*; -import java.util.function.Function; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import java.util.stream.Collectors; - -import net.minecraft.client.renderer.block.model.BlockElement; -import net.minecraft.client.renderer.block.model.BlockElementFace; -import net.minecraft.client.renderer.block.model.BlockFaceUV; -import net.minecraft.client.renderer.block.model.BlockModel; -import net.minecraft.client.renderer.block.model.ItemModelGenerator; -import net.minecraft.client.renderer.block.model.ItemOverride; -import net.minecraft.client.renderer.block.model.ItemTransform; -import net.minecraft.client.renderer.block.model.ItemTransforms; -import net.minecraft.client.resources.model.BakedModel; -import net.minecraft.client.resources.model.Material; -import net.minecraft.client.resources.model.ModelBakery; -import net.minecraft.client.resources.model.ModelState; -import net.minecraft.client.resources.model.UnbakedModel; -import org.jetbrains.annotations.Nullable; -import net.minecraftforge.common.util.Lazy; -import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; - -/** - * Central hub for custom model loaders. - */ -public class ModelLoaderRegistry -{ - public static final String WHITE_TEXTURE = "forge:white"; - - private static final ItemModelGenerator ITEM_MODEL_GENERATOR = new ItemModelGenerator(); - private static final Map> loaders = Maps.newHashMap(); - private static volatile boolean registryFrozen = false; - - // Forge built-in loaders - public static void init() - { - // avoid loading the loaders eagerly. This method gets called during datagen, which the loaders cannot deal with - var builtInLoaders = Lazy.of(() -> Map.of( - new ResourceLocation("minecraft", "elements"), VanillaProxy.Loader.INSTANCE, - new ResourceLocation("forge", "obj"), OBJLoader.INSTANCE, - new ResourceLocation("forge", "bucket"), DynamicBucketModel.Loader.INSTANCE, - new ResourceLocation("forge", "composite"), CompositeModel.Loader.INSTANCE, - new ResourceLocation("forge", "multi-layer"), MultiLayerModel.Loader.INSTANCE, - new ResourceLocation("forge", "item-layers"), ItemLayerModel.Loader.INSTANCE, - new ResourceLocation("forge", "separate-perspective"), SeparatePerspectiveModel.Loader.INSTANCE - )); - - // TODO: Implement as new model loaders - //registerLoader(new ResourceLocation("forge:b3d"), new ModelLoaderAdapter(B3DLoader.INSTANCE)); - //registerLoader(new ResourceLocation("forge:fluid"), new ModelLoaderAdapter(ModelFluid.FluidLoader.INSTANCE)); - - var modEventBus = FMLJavaModLoadingContext.get().getModEventBus(); - modEventBus.addListener(event -> builtInLoaders.get().values().forEach(event::registerReloadListener)); - modEventBus.addListener(event -> builtInLoaders.get().forEach(ModelLoaderRegistry::registerLoader)); - } - - /** - * INTERNAL METHOD, DO NOT CALL - */ - public static void onModelLoadingStart() - { - // Minecraft recreates the ModelBakery on resource reload, but this should only run once during init. - if (!registryFrozen) - { - net.minecraftforge.fml.ModLoader.get().postEvent(new ModelRegistryEvent()); - registryFrozen = true; - } - } - - /** - * Internal method, only present for enabling legacy behavior of automatic registration of model loaders - * as resource reload listeners. - */ - @Deprecated - public static void afterFirstReload() - { - for (IModelLoader loader : loaders.values()) - { - ((ReloadableResourceManager) Minecraft.getInstance().getResourceManager()).registerReloadListenerIfNotPresent(loader); - } - } - - /** - * Makes system aware of your loader.
- * Must be called from within {@link ModelRegistryEvent} - *

- * Note: This method currently registers the model loader as a resource reload listener automatically, - * if it is not already registered. This behavior is deprecated and will be removed in the future. - * If the model loader needs to be a resource reload listener as well, use {@link net.minecraftforge.client.event.RegisterClientReloadListenersEvent}. - */ - public static void registerLoader(ResourceLocation id, IModelLoader loader) - { - if (registryFrozen) - throw new IllegalStateException("Can not register model loaders after models have started loading. Please use ModelRegistryEvent to register your loaders."); - - synchronized(loaders) - { - loaders.put(id, loader); - } - } - - public static IModelGeometry getModel(ResourceLocation loaderId, JsonDeserializationContext deserializationContext, JsonObject data) - { - try - { - if (!loaders.containsKey(loaderId)) - { - throw new IllegalStateException(String.format(Locale.ENGLISH, "Model loader '%s' not found. Registered loaders: %s", loaderId, - loaders.keySet().stream().map(ResourceLocation::toString).collect(Collectors.joining(", ")))); - } - - IModelLoader loader = loaders.get(loaderId); - - return loader.read(deserializationContext, data); - } - catch(Exception e) - { - e.printStackTrace(); - throw e; - } - } - - @Nullable - public static IModelGeometry deserializeGeometry(JsonDeserializationContext deserializationContext, JsonObject object) { - if (!object.has("loader")) { - return null; - } - - ResourceLocation loader = new ResourceLocation(GsonHelper.getAsString(object,"loader")); - return getModel(loader, deserializationContext, object); - } - - /* Explanation: - * This takes anything that looks like a valid resourcepack texture location, and tries to extract a resourcelocation out of it. - * 1. it will ignore anything up to and including an /assets/ folder, - * 2. it will take the next path component as a namespace, - * 3. it will match but skip the /textures/ part of the path, - * 4. it will take the rest of the path up to but excluding the .png extension as the resource path - * It's a best-effort situation, to allow model files exported by modelling software to be used without post-processing. - * Example: - * C:\Something\Or Other\src\main\resources\assets\mymodid\textures\item\my_thing.png - * ........................................--------_______----------_____________---- - * - * Result after replacing '\' to '/': mymodid:item/my_thing - */ - private static final Pattern FILESYSTEM_PATH_TO_RESLOC = - Pattern.compile("(?:.*[\\\\/]assets[\\\\/](?[a-z_-]+)[\\\\/]textures[\\\\/])?(?[a-z_\\\\/-]+)\\.png"); - - public static Material resolveTexture(@Nullable String tex, IModelConfiguration owner) - { - if (tex == null) - return blockMaterial(WHITE_TEXTURE); - if (tex.startsWith("#")) - return owner.resolveTexture(tex); - - // Attempt to convert a common (windows/linux/mac) filesystem path to a ResourceLocation. - // This makes no promises, if it doesn't work, too bad, fix your mtl file. - Matcher match = FILESYSTEM_PATH_TO_RESLOC.matcher(tex); - if (match.matches()) - { - String namespace = match.group("namespace"); - String path = match.group("path").replace("\\", "/"); - if (namespace != null) - return blockMaterial(new ResourceLocation(namespace, path)); - return blockMaterial(path); - } - - return blockMaterial(tex); - } - - @SuppressWarnings("deprecation") - public static Material blockMaterial(String location) - { - return new Material(TextureAtlas.LOCATION_BLOCKS, new ResourceLocation(location)); - } - - @SuppressWarnings("deprecation") - public static Material blockMaterial(ResourceLocation location) - { - return new Material(TextureAtlas.LOCATION_BLOCKS, location); - } - - @Nullable - public static ModelState deserializeModelTransforms(JsonDeserializationContext deserializationContext, JsonObject modelData) - { - if (!modelData.has("transform")) - return null; - - return deserializeTransform(deserializationContext, modelData.get("transform")).orElse(null); - } - - public static Optional deserializeTransform(JsonDeserializationContext context, JsonElement transformData) - { - if (!transformData.isJsonObject()) - { - try - { - Transformation base = context.deserialize(transformData, Transformation.class); - return Optional.of(new SimpleModelState(ImmutableMap.of(), base.blockCenterToCorner())); - } - catch (JsonParseException e) - { - throw new JsonParseException("transform: expected a string, object or valid base transformation, got: " + transformData); - } - } - else - { - JsonObject transform = transformData.getAsJsonObject(); - EnumMap transforms = Maps.newEnumMap(ItemTransforms.TransformType.class); - - for (var type : ItemTransforms.TransformType.values()) - { - var fallbackType = type; - while (fallbackType.fallback() != null && !transform.has(fallbackType.getSerializeName())) { - fallbackType = fallbackType.fallback(); - } - if(transform.has(fallbackType.getSerializeName())) - { - Transformation t = context.deserialize(transform.remove(fallbackType.getSerializeName()), Transformation.class); - transforms.put(type, t.blockCenterToCorner()); - } - } - - int k = transform.entrySet().size(); - if(transform.has("matrix")) k--; - if(transform.has("translation")) k--; - if(transform.has("rotation")) k--; - if(transform.has("scale")) k--; - if(transform.has("post-rotation")) k--; - if(transform.has("origin")) k--; - if(k > 0) - { - throw new JsonParseException("transform: allowed keys: 'matrix', 'translation', 'rotation', 'scale', 'post-rotation', 'origin', " - + Arrays.stream(ItemTransforms.TransformType.values()).map(v -> "'" + v.getSerializeName() + "'").collect(Collectors.joining(", "))); - } - Transformation base = Transformation.identity(); - if(!transform.entrySet().isEmpty()) - { - base = context.deserialize(transform, Transformation.class); - } - ModelState state = new SimpleModelState(Maps.immutableEnumMap(transforms), base); - return Optional.of(state); - } - } - - public static BakedModel bakeHelper(BlockModel blockModel, ModelBakery modelBakery, BlockModel otherModel, Function spriteGetter, ModelState modelTransform, ResourceLocation modelLocation, boolean guiLight3d) - { - BakedModel model; - IModelGeometry customModel = blockModel.customData.getCustomGeometry(); - ModelState customModelState = blockModel.customData.getCustomModelState(); - if (customModelState != null) - modelTransform = new CompositeModelState(modelTransform, customModelState, modelTransform.isUvLocked()); - - if (customModel != null) - model = customModel.bake(blockModel.customData, modelBakery, spriteGetter, modelTransform, blockModel.getOverrides(modelBakery, otherModel, spriteGetter), modelLocation); - else - { - // handle vanilla item models here, since vanilla has a shortcut for them - if (blockModel.getRootModel() == ModelBakery.GENERATION_MARKER) { - model = ITEM_MODEL_GENERATOR.generateBlockModel(spriteGetter, blockModel).bake(modelBakery, blockModel, spriteGetter, modelTransform, modelLocation, guiLight3d); - } - else - { - model = blockModel.bakeVanilla(modelBakery, otherModel, spriteGetter, modelTransform, modelLocation, guiLight3d); - } - } - - if (customModelState != null && !model.doesHandlePerspectives()) - model = new PerspectiveMapWrapper(model, customModelState); - - return model; - } - - public static class VanillaProxy implements ISimpleModelGeometry - { - private final List elements; - - public VanillaProxy(List list) - { - this.elements = list; - } - - @Override - public void addQuads(IModelConfiguration owner, IModelBuilder modelBuilder, ModelBakery bakery, Function spriteGetter, ModelState modelTransform, ResourceLocation modelLocation) - { - for(BlockElement blockpart : elements) { - for(Direction direction : blockpart.faces.keySet()) { - BlockElementFace blockpartface = blockpart.faces.get(direction); - TextureAtlasSprite textureatlassprite1 = spriteGetter.apply(owner.resolveTexture(blockpartface.texture)); - if (blockpartface.cullForDirection == null) { - modelBuilder.addGeneralQuad(BlockModel.makeBakedQuad(blockpart, blockpartface, textureatlassprite1, direction, modelTransform, modelLocation)); - } else { - modelBuilder.addFaceQuad( - modelTransform.getRotation().rotateTransform(blockpartface.cullForDirection), - BlockModel.makeBakedQuad(blockpart, blockpartface, textureatlassprite1, direction, modelTransform, modelLocation)); - } - } - } - } - - @Override - public Collection getTextures(IModelConfiguration owner, Function modelGetter, Set> missingTextureErrors) - { - Set textures = Sets.newHashSet(); - - for(BlockElement part : elements) { - for(BlockElementFace face : part.faces.values()) { - Material texture = owner.resolveTexture(face.texture); - if (Objects.equals(texture, MissingTextureAtlasSprite.getLocation().toString())) { - missingTextureErrors.add(Pair.of(face.texture, owner.getModelName())); - } - - textures.add(texture); - } - } - - return textures; - } - - public static class Loader implements IModelLoader - { - public static final Loader INSTANCE = new Loader(); - - private Loader() - { - } - - @Override - public void onResourceManagerReload(ResourceManager resourceManager) - { - - } - - @Override - public VanillaProxy read(JsonDeserializationContext deserializationContext, JsonObject modelContents) - { - List list = this.getModelElements(deserializationContext, modelContents); - return new VanillaProxy(list); - } - - private List getModelElements(JsonDeserializationContext deserializationContext, JsonObject object) { - List list = Lists.newArrayList(); - if (object.has("elements")) { - for(JsonElement jsonelement : GsonHelper.getAsJsonArray(object, "elements")) { - list.add(deserializationContext.deserialize(jsonelement, BlockElement.class)); - } - } - - return list; - } - } - } - - public static class ExpandedBlockModelDeserializer extends BlockModel.Deserializer - { - public static final Gson INSTANCE = (new GsonBuilder()) - .registerTypeAdapter(BlockModel.class, new ExpandedBlockModelDeserializer()) - .registerTypeAdapter(BlockElement.class, new BlockElement.Deserializer()) - .registerTypeAdapter(BlockElementFace.class, new BlockElementFace.Deserializer()) - .registerTypeAdapter(BlockFaceUV.class, new BlockFaceUV.Deserializer()) - .registerTypeAdapter(ItemTransform.class, new ItemTransform.Deserializer()) - .registerTypeAdapter(ItemTransforms.class, new ItemTransforms.Deserializer()) - .registerTypeAdapter(ItemOverride.class, new ItemOverride.Deserializer()) - .registerTypeAdapter(Transformation.class, new TransformationHelper.Deserializer()) - .create(); - - public BlockModel deserialize(JsonElement element, Type targetType, JsonDeserializationContext deserializationContext) throws JsonParseException { - BlockModel model = super.deserialize(element, targetType, deserializationContext); - JsonObject jsonobject = element.getAsJsonObject(); - IModelGeometry geometry = deserializeGeometry(deserializationContext, jsonobject); - - List elements = model.getElements(); - if (geometry != null) { - elements.clear(); - model.customData.setCustomGeometry(geometry); - } - - ModelState modelState = deserializeModelTransforms(deserializationContext, jsonobject); - if (modelState != null) - { - model.customData.setCustomModelState(modelState); - } - - if (jsonobject.has("visibility")) - { - JsonObject visibility = GsonHelper.getAsJsonObject(jsonobject, "visibility"); - for(Map.Entry part : visibility.entrySet()) - { - model.customData.visibilityData.setVisibilityState(part.getKey(), part.getValue().getAsBoolean()); - } - } - - return model; - } - } -} diff --git a/src/main/java/net/minecraftforge/client/model/ModelLoadingException.java b/src/main/java/net/minecraftforge/client/model/ModelLoadingException.java deleted file mode 100644 index 95f14a88f18..00000000000 --- a/src/main/java/net/minecraftforge/client/model/ModelLoadingException.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright (c) Forge Development LLC and contributors - * SPDX-License-Identifier: LGPL-2.1-only - */ - -package net.minecraftforge.client.model; - -public class ModelLoadingException extends RuntimeException -{ - public ModelLoadingException(String message) - { - super(message); - } - - public ModelLoadingException(String message, Throwable cause) - { - super(message, cause); - } - - private static final long serialVersionUID = 1L; -} diff --git a/src/main/java/net/minecraftforge/client/model/MultiLayerModel.java b/src/main/java/net/minecraftforge/client/model/MultiLayerModel.java deleted file mode 100644 index de1b3cc7e45..00000000000 --- a/src/main/java/net/minecraftforge/client/model/MultiLayerModel.java +++ /dev/null @@ -1,270 +0,0 @@ -/* - * Copyright (c) Forge Development LLC and contributors - * SPDX-License-Identifier: LGPL-2.1-only - */ - -package net.minecraftforge.client.model; - -import java.util.*; - -import com.google.common.collect.*; -import com.google.gson.JsonDeserializationContext; -import com.google.gson.JsonObject; -import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.datafixers.util.Pair; -import net.minecraft.util.RandomSource; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.client.renderer.RenderType; -import com.mojang.math.Transformation; -import net.minecraft.client.renderer.block.model.ItemTransforms.TransformType; -import net.minecraft.client.renderer.texture.TextureAtlasSprite; -import net.minecraft.world.item.ItemStack; -import net.minecraft.server.packs.resources.ResourceManager; -import net.minecraft.core.Direction; -import net.minecraft.util.GsonHelper; -import net.minecraft.resources.ResourceLocation; -import net.minecraftforge.client.ForgeRenderTypes; -import net.minecraftforge.client.MinecraftForgeClient; - -import net.minecraftforge.client.model.data.IDynamicBakedModel; -import net.minecraftforge.client.model.data.IModelData; -import net.minecraftforge.client.model.geometry.IModelGeometry; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - -import java.util.function.Function; -import java.util.stream.Collectors; - -import net.minecraft.client.renderer.block.model.BakedQuad; -import net.minecraft.client.renderer.block.model.BlockModel; -import net.minecraft.client.renderer.block.model.ItemOverrides; -import net.minecraft.client.resources.model.BakedModel; -import net.minecraft.client.resources.model.Material; -import net.minecraft.client.resources.model.ModelBakery; -import net.minecraft.client.resources.model.ModelState; -import net.minecraft.client.resources.model.UnbakedModel; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * A model that can be rendered in multiple {@link RenderType}. - */ -public final class MultiLayerModel implements IModelGeometry -{ - private static final Logger LOGGER = LogManager.getLogger(); - - private final ImmutableList> models; - private final boolean convertRenderTypes; - - public MultiLayerModel(Map models) - { - this(models.entrySet().stream().map(kv -> Pair.of(kv.getKey(), kv.getValue())).collect(ImmutableList.toImmutableList()), true); - } - - public MultiLayerModel(ImmutableList> models, boolean convertRenderTypes) - { - this.models = models; - this.convertRenderTypes = convertRenderTypes; - } - - @Override - public Collection getTextures(IModelConfiguration owner, Function modelGetter, Set> missingTextureErrors) - { - Set materials = Sets.newHashSet(); - materials.add(owner.resolveTexture("particle")); - for (Pair m : models) - materials.addAll(m.getSecond().getMaterials(modelGetter, missingTextureErrors)); - return materials; - } - - private static ImmutableList> buildModels(List> models, ModelState modelTransform, - ModelBakery bakery, Function spriteGetter, ResourceLocation modelLocation) - { - ImmutableList.Builder> builder = ImmutableList.builder(); - for(Pair entry : models) - { - builder.add(Pair.of(entry.getFirst(), entry.getSecond().bake(bakery, spriteGetter, modelTransform, modelLocation))); - } - return builder.build(); - } - - @Override - public BakedModel bake(IModelConfiguration owner, ModelBakery bakery, Function spriteGetter, ModelState modelTransform, ItemOverrides overrides, ResourceLocation modelLocation) - { - return new MultiLayerBakedModel( - owner.useSmoothLighting(), owner.isShadedInGui(), owner.isSideLit(), - spriteGetter.apply(owner.resolveTexture("particle")), overrides, convertRenderTypes, - buildModels(models, modelTransform, bakery, spriteGetter, modelLocation), - PerspectiveMapWrapper.getTransforms(new CompositeModelState(owner.getCombinedTransform(), modelTransform)) - ); - } - - private static final class MultiLayerBakedModel implements IDynamicBakedModel - { - private final ImmutableMap models; - private final ImmutableMap cameraTransforms; - protected final boolean ambientOcclusion; - protected final boolean gui3d; - protected final boolean isSideLit; - protected final TextureAtlasSprite particle; - protected final ItemOverrides overrides; - private final List missing = ImmutableList.of(); - private final boolean convertRenderTypes; - private final List> itemLayers; - - public MultiLayerBakedModel( - boolean ambientOcclusion, boolean isGui3d, boolean isSideLit, TextureAtlasSprite particle, ItemOverrides overrides, - boolean convertRenderTypes, List> models, - ImmutableMap cameraTransforms) - { - this.isSideLit = isSideLit; - this.cameraTransforms = cameraTransforms; - this.ambientOcclusion = ambientOcclusion; - this.gui3d = isGui3d; - this.particle = particle; - this.overrides = overrides; - this.convertRenderTypes = convertRenderTypes; - this.models = ImmutableMap.copyOf(models.stream().collect(Collectors.toMap(Pair::getFirst, Pair::getSecond))); - this.itemLayers = models.stream().map(kv -> { - RenderType rt = kv.getFirst(); - if (convertRenderTypes) rt = ITEM_RENDER_TYPE_MAPPING.getOrDefault(rt, rt); - return Pair.of(kv.getSecond(), rt); - }).collect(Collectors.toList()); - } - - @NotNull - @Override - public List getQuads(@Nullable BlockState state, @Nullable Direction side, @NotNull RandomSource rand, @NotNull IModelData extraData) - { - RenderType layer = MinecraftForgeClient.getRenderType(); - if (layer == null) - { - ImmutableList.Builder builder = ImmutableList.builder(); - for (BakedModel model : models.values()) - { - builder.addAll(model.getQuads(state, side, rand, extraData)); - } - return builder.build(); - } - // support for item layer rendering - if (state == null && convertRenderTypes) - layer = ITEM_RENDER_TYPE_MAPPING.inverse().getOrDefault(layer, layer); - if (models.containsKey(layer)) - return models.get(layer).getQuads(state, side, rand, extraData); - else - return missing; - } - - @Override - public boolean useAmbientOcclusion() - { - return ambientOcclusion; - } - - @Override - public boolean useAmbientOcclusion(BlockState state) - { - return ambientOcclusion; - } - - @Override - public boolean isGui3d() - { - return gui3d; - } - - @Override - public boolean usesBlockLight() - { - return isSideLit; - } - - @Override - public boolean isCustomRenderer() - { - return false; - } - - @Override - public TextureAtlasSprite getParticleIcon() - { - return particle; - } - - @Override - public boolean doesHandlePerspectives() - { - return true; - } - - @Override - public BakedModel handlePerspective(TransformType cameraTransformType, PoseStack poseStack) - { - return PerspectiveMapWrapper.handlePerspective(this, cameraTransforms, cameraTransformType, poseStack); - } - - @Override - public ItemOverrides getOverrides() - { - return ItemOverrides.EMPTY; - } - - @Override - public boolean isLayered() - { - return true; - } - - @Override - public List> getLayerModels(ItemStack itemStack, boolean fabulous) - { - return itemLayers; - } - - public static final BiMap ITEM_RENDER_TYPE_MAPPING = HashBiMap.create(); - static { - ITEM_RENDER_TYPE_MAPPING.put(RenderType.solid(), ForgeRenderTypes.ITEM_LAYERED_SOLID.get()); - ITEM_RENDER_TYPE_MAPPING.put(RenderType.cutout(), ForgeRenderTypes.ITEM_LAYERED_CUTOUT.get()); - ITEM_RENDER_TYPE_MAPPING.put(RenderType.cutoutMipped(), ForgeRenderTypes.ITEM_LAYERED_CUTOUT_MIPPED.get()); - ITEM_RENDER_TYPE_MAPPING.put(RenderType.translucent(), ForgeRenderTypes.ITEM_LAYERED_TRANSLUCENT.get()); - } - } - - public static final class Loader implements IModelLoader - { - public static final ImmutableBiMap BLOCK_LAYERS = ImmutableBiMap.builder() - .put("solid", RenderType.solid()) - .put("cutout", RenderType.cutout()) - .put("cutout_mipped", RenderType.cutoutMipped()) - .put("translucent", RenderType.translucent()) - .put("tripwire", RenderType.tripwire()) - .build(); - - public static final Loader INSTANCE = new Loader(); - - private Loader() {} - - @Override - public void onResourceManagerReload(ResourceManager resourceManager) - { - - } - - @Override - public MultiLayerModel read(JsonDeserializationContext deserializationContext, JsonObject modelContents) - { - ImmutableList.Builder> builder = ImmutableList.builder(); - JsonObject layersObject = GsonHelper.getAsJsonObject(modelContents, "layers"); - for(Map.Entry layer : BLOCK_LAYERS.entrySet()) // block layers - { - String layerName = layer.getKey(); // mc overrides toString to return the ID for the layer - if(layersObject.has(layerName)) - { - builder.add(Pair.of(layer.getValue(), deserializationContext.deserialize(GsonHelper.getAsJsonObject(layersObject, layerName), BlockModel.class))); - } - } - boolean convertRenderTypes = GsonHelper.getAsBoolean(modelContents, "convert_render_types", true); - return new MultiLayerModel(builder.build(), convertRenderTypes); - } - } -} diff --git a/src/main/java/net/minecraftforge/client/model/PerspectiveMapWrapper.java b/src/main/java/net/minecraftforge/client/model/PerspectiveMapWrapper.java deleted file mode 100644 index 5ee4ad393f6..00000000000 --- a/src/main/java/net/minecraftforge/client/model/PerspectiveMapWrapper.java +++ /dev/null @@ -1,170 +0,0 @@ -/* - * Copyright (c) Forge Development LLC and contributors - * SPDX-License-Identifier: LGPL-2.1-only - */ - -package net.minecraftforge.client.model; - -import java.util.EnumMap; - -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMap; -import com.mojang.blaze3d.vertex.PoseStack; -import net.minecraft.util.RandomSource; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.client.renderer.texture.TextureAtlasSprite; -import net.minecraft.client.multiplayer.ClientLevel; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.item.ItemStack; -import net.minecraft.core.Direction; -import com.mojang.math.Transformation; -import net.minecraftforge.client.model.data.IDynamicBakedModel; -import net.minecraftforge.client.model.data.IModelData; -import net.minecraftforge.common.model.TransformationHelper; - -import java.util.List; - -import net.minecraft.client.renderer.block.model.BakedQuad; -import net.minecraft.client.renderer.block.model.ItemOverrides; -import net.minecraft.client.renderer.block.model.ItemTransforms; -import net.minecraft.client.resources.model.BakedModel; -import net.minecraft.client.resources.model.ModelState; -import org.jetbrains.annotations.Nullable; - -public class PerspectiveMapWrapper implements IDynamicBakedModel -{ - private final BakedModel parent; - private final ImmutableMap transforms; - private final OverrideListWrapper overrides = new OverrideListWrapper(); - - public PerspectiveMapWrapper(BakedModel parent, ImmutableMap transforms) - { - this.parent = parent; - this.transforms = transforms; - } - - public PerspectiveMapWrapper(BakedModel parent, ModelState state) - { - this(parent, getTransforms(state)); - } - - public static ImmutableMap getTransforms(ModelState state) - { - EnumMap map = new EnumMap<>(ItemTransforms.TransformType.class); - for(ItemTransforms.TransformType type : ItemTransforms.TransformType.values()) - { - Transformation tr = state.getPartTransformation(type); - if(!tr.isIdentity()) - { - map.put(type, tr); - } - } - return ImmutableMap.copyOf(map); - } - - @SuppressWarnings("deprecation") - public static ImmutableMap getTransforms(ItemTransforms transforms) - { - EnumMap map = new EnumMap<>(ItemTransforms.TransformType.class); - for(ItemTransforms.TransformType type : ItemTransforms.TransformType.values()) - { - if (transforms.hasTransform(type)) - { - map.put(type, TransformationHelper.toTransformation(transforms.getTransform(type))); - } - } - return ImmutableMap.copyOf(map); - } - - @SuppressWarnings("deprecation") - public static ImmutableMap getTransformsWithFallback(ModelState state, ItemTransforms transforms) - { - EnumMap map = new EnumMap<>(ItemTransforms.TransformType.class); - for(ItemTransforms.TransformType type : ItemTransforms.TransformType.values()) - { - Transformation tr = state.getPartTransformation(type); - if(!tr.isIdentity()) - { - map.put(type, tr); - } - else if (transforms.hasTransform(type)) - { - map.put(type, TransformationHelper.toTransformation(transforms.getTransform(type))); - } - } - return ImmutableMap.copyOf(map); - } - - public static BakedModel handlePerspective(BakedModel model, ImmutableMap transforms, ItemTransforms.TransformType cameraTransformType, PoseStack mat) - { - Transformation tr = transforms.getOrDefault(cameraTransformType, Transformation.identity()); - if (!tr.isIdentity()) - { - tr.push(mat); - } - return model; - } - - public static BakedModel handlePerspective(BakedModel model, ModelState state, ItemTransforms.TransformType cameraTransformType, PoseStack mat) - { - Transformation tr = state.getPartTransformation(cameraTransformType); - if (!tr.isIdentity()) - { - tr.push(mat); - } - return model; - } - - @Override public boolean useAmbientOcclusion() { return parent.useAmbientOcclusion(); } - @Override public boolean useAmbientOcclusion(BlockState state) { return parent.useAmbientOcclusion(state); } - @Override public boolean isGui3d() { return parent.isGui3d(); } - @Override public boolean usesBlockLight() { return parent.usesBlockLight(); } - @Override public boolean isCustomRenderer() { return parent.isCustomRenderer(); } - @Override public TextureAtlasSprite getParticleIcon() { return parent.getParticleIcon(); } - @SuppressWarnings("deprecation") - @Override public ItemTransforms getTransforms() { return parent.getTransforms(); } - @Override public List getQuads(@Nullable BlockState state, @Nullable Direction side, RandomSource rand, IModelData extraData) - { - return parent.getQuads(state, side, rand, extraData); - } - - @Override - public ItemOverrides getOverrides() - { - return overrides; - } - - @Override - public boolean doesHandlePerspectives() - { - return true; - } - - @Override - public BakedModel handlePerspective(ItemTransforms.TransformType cameraTransformType, PoseStack poseStack) - { - return handlePerspective(this, transforms, cameraTransformType, poseStack); - } - - private class OverrideListWrapper extends ItemOverrides - { - public OverrideListWrapper() - { - super(); - } - - @Nullable - @Override - public BakedModel resolve(BakedModel model, ItemStack stack, @Nullable ClientLevel level, @Nullable LivingEntity entity, int seed) - { - model = parent.getOverrides().resolve(parent, stack, level, entity, seed); - return new PerspectiveMapWrapper(model, transforms); - } - - @Override - public ImmutableList getOverrides() - { - return parent.getOverrides().getOverrides(); - } - } -} diff --git a/src/main/java/net/minecraftforge/client/model/QuadTransformer.java b/src/main/java/net/minecraftforge/client/model/QuadTransformer.java deleted file mode 100644 index e8291aaaa50..00000000000 --- a/src/main/java/net/minecraftforge/client/model/QuadTransformer.java +++ /dev/null @@ -1,217 +0,0 @@ -/* - * Copyright (c) Forge Development LLC and contributors - * SPDX-License-Identifier: LGPL-2.1-only - */ - -package net.minecraftforge.client.model; - -import java.util.Arrays; -import java.util.Collections; -import java.util.List; - -import com.google.common.collect.Lists; - -import com.mojang.math.Transformation; -import com.mojang.math.Vector3f; -import com.mojang.math.Vector4f; -import net.minecraft.client.renderer.block.model.BakedQuad; -import com.mojang.blaze3d.vertex.DefaultVertexFormat; -import com.mojang.blaze3d.vertex.VertexFormat; -import com.mojang.blaze3d.vertex.VertexFormatElement; - -public class QuadTransformer -{ - private static final int POSITION = findPositionOffset(DefaultVertexFormat.BLOCK); - private static final int NORMAL = findNormalOffset(DefaultVertexFormat.BLOCK); - private final Transformation transform; - - public QuadTransformer(Transformation transform) - { - this.transform = transform; - } - - private void processVertices(int[] inData, int[] outData) - { - int stride = DefaultVertexFormat.BLOCK.getVertexSize(); - int count = (inData.length * 4) / stride; - for (int i=0;i> 24)) / 127.0f; - float y = ((byte)((normalIn << 8) >> 24)) / 127.0f; - float z = ((byte)((normalIn << 16) >> 24)) / 127.0f; - - Vector3f pos = new Vector3f(x, y, z); - transform.transformNormal(pos); - pos.normalize(); - - int normalOut = ((((byte)(x / 127.0f)) & 0xFF) << 24) | - ((((byte)(y / 127.0f)) & 0xFF) << 16) | - ((((byte)(z / 127.0f)) & 0xFF) << 8) | - (normalIn & 0xFF); - - putAtByteOffset(outData, offset, normalOut); - } - } - } - - private static int getAtByteOffset(int[] inData, int offset) - { - int index = offset / 4; - int lsb = inData[index]; - - int shift = (offset % 4) * 8; - if (shift == 0) - return inData[index]; - - int msb = inData[index+1]; - - return (lsb >>> shift) | (msb << (32-shift)); - } - - private static void putAtByteOffset(int[] outData, int offset, int value) - { - int index = offset / 4; - int shift = (offset % 4) * 8; - - if (shift == 0) - { - outData[index] = value; - return; - } - - int lsbMask = 0xFFFFFFFF >>> (32-shift); - int msbMask = 0xFFFFFFFF << shift; - - outData[index] = (outData[index] & lsbMask) | (value << shift); - outData[index+1] = (outData[index+1] & msbMask) | (value >>> (32-shift)); - } - - private static int findPositionOffset(VertexFormat fmt) - { - int index; - VertexFormatElement element = null; - for (index = 0; index < fmt.getElements().size(); index++) - { - VertexFormatElement el = fmt.getElements().get(index); - if (el.getUsage() == VertexFormatElement.Usage.POSITION) - { - element = el; - break; - } - } - if (index == fmt.getElements().size() || element == null) - throw new RuntimeException("Expected vertex format to have a POSITION attribute"); - if (element.getType() != VertexFormatElement.Type.FLOAT) - throw new RuntimeException("Expected POSITION attribute to have data type FLOAT"); - if (element.getByteSize() < 3) - throw new RuntimeException("Expected POSITION attribute to have at least 3 dimensions"); - return fmt.getOffset(index); - } - - private static int findNormalOffset(VertexFormat fmt) - { - int index; - VertexFormatElement element = null; - for (index = 0; index < fmt.getElements().size(); index++) - { - VertexFormatElement el = fmt.getElements().get(index); - if (el.getUsage() == VertexFormatElement.Usage.NORMAL) - { - element = el; - break; - } - } - if (index == fmt.getElements().size() || element == null) - throw new IllegalStateException("BLOCK format does not have normals?"); - if (element.getType() != VertexFormatElement.Type.BYTE) - throw new RuntimeException("Expected NORMAL attribute to have data type BYTE"); - if (element.getByteSize() < 3) - throw new RuntimeException("Expected NORMAL attribute to have at least 3 dimensions"); - return fmt.getOffset(index); - } - - /** - * Processes a single quad, producing a new quad. - * @param input A single quad to transform. - * @return A new BakedQuad object with the new position. - */ - public BakedQuad processOne(BakedQuad input) - { - int[] inData = input.getVertices(); - int[] outData = Arrays.copyOf(inData, inData.length); - processVertices(inData, outData); - - return new BakedQuad(outData, input.getTintIndex(), input.getDirection(), input.getSprite(), input.isShade()); - } - - /** - * Processes a single quad, modifying the input quad. - * @param input A single quad to transform. - * @return The input BakedQuad object with the new position applied. - */ - public BakedQuad processOneInPlace(BakedQuad input) - { - int[] data = input.getVertices(); - processVertices(data, data); - return input; - } - - /** - * Processes multiple quads, producing a new array of new quads. - * @param inputs The list of quads to transform - * @return A new array of new BakedQuad objects. - */ - public List processMany(List inputs) - { - if(inputs.size() == 0) - return Collections.emptyList(); - - List outputs = Lists.newArrayList(); - for(BakedQuad input : inputs) - { - int[] inData = input.getVertices(); - int[] outData = Arrays.copyOf(inData, inData.length); - processVertices(inData, outData); - - outputs.add(new BakedQuad(outData, input.getTintIndex(), input.getDirection(), input.getSprite(), input.isShade())); - } - return outputs; - } - - /** - * Processes multiple quads in place, modifying the input quads. - * @param inputs The list of quads to transform - */ - public void processManyInPlace(List inputs) - { - if(inputs.size() == 0) - return; - - for(BakedQuad input : inputs) - { - int[] data = input.getVertices(); - processVertices(data, data); - } - } -} diff --git a/src/main/java/net/minecraftforge/client/model/SeparatePerspectiveModel.java b/src/main/java/net/minecraftforge/client/model/SeparatePerspectiveModel.java deleted file mode 100644 index 263940a1b79..00000000000 --- a/src/main/java/net/minecraftforge/client/model/SeparatePerspectiveModel.java +++ /dev/null @@ -1,217 +0,0 @@ -/* - * Copyright (c) Forge Development LLC and contributors - * SPDX-License-Identifier: LGPL-2.1-only - */ - -package net.minecraftforge.client.model; - -import com.google.common.collect.ImmutableBiMap; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.Maps; -import com.google.common.collect.Sets; -import com.google.gson.JsonDeserializationContext; -import com.google.gson.JsonObject; -import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.datafixers.util.Pair; -import net.minecraft.util.RandomSource; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.client.renderer.texture.TextureAtlasSprite; -import net.minecraft.server.packs.resources.ResourceManager; -import net.minecraft.core.Direction; -import net.minecraft.util.GsonHelper; -import net.minecraft.resources.ResourceLocation; -import net.minecraftforge.client.model.geometry.IModelGeometry; - -import java.util.*; -import java.util.function.Function; - -import net.minecraft.client.renderer.block.model.BakedQuad; -import net.minecraft.client.renderer.block.model.BlockModel; -import net.minecraft.client.renderer.block.model.ItemOverrides; -import net.minecraft.client.renderer.block.model.ItemTransforms; -import net.minecraft.client.resources.model.Material; -import net.minecraft.client.resources.model.ModelBakery; -import net.minecraft.client.resources.model.ModelState; -import net.minecraft.client.resources.model.UnbakedModel; -import org.jetbrains.annotations.Nullable; - -public class SeparatePerspectiveModel implements IModelGeometry -{ - private final BlockModel baseModel; - private final ImmutableMap perspectives; - - public SeparatePerspectiveModel(BlockModel baseModel, ImmutableMap perspectives) - { - this.baseModel = baseModel; - this.perspectives = perspectives; - } - - @Override - public net.minecraft.client.resources.model.BakedModel bake(IModelConfiguration owner, ModelBakery bakery, Function spriteGetter, ModelState modelTransform, ItemOverrides overrides, ResourceLocation modelLocation) - { - return new BakedModel( - owner.useSmoothLighting(), owner.isShadedInGui(), owner.isSideLit(), - spriteGetter.apply(owner.resolveTexture("particle")), overrides, - baseModel.bake(bakery, baseModel, spriteGetter, modelTransform, modelLocation, owner.isSideLit()), - ImmutableMap.copyOf(Maps.transformValues(perspectives, value -> { - return value.bake(bakery, value, spriteGetter, modelTransform, modelLocation, owner.isSideLit()); - })) - ); - } - - @Override - public Collection getTextures(IModelConfiguration owner, Function modelGetter, Set> missingTextureErrors) - { - Set textures = Sets.newHashSet(); - textures.addAll(baseModel.getMaterials(modelGetter, missingTextureErrors)); - for(BlockModel model : perspectives.values()) - textures.addAll(model.getMaterials(modelGetter, missingTextureErrors)); - return textures; - } - - public static class BakedModel implements net.minecraft.client.resources.model.BakedModel - { - private final boolean isAmbientOcclusion; - private final boolean isGui3d; - private final boolean isSideLit; - private final TextureAtlasSprite particle; - private final ItemOverrides overrides; - private final net.minecraft.client.resources.model.BakedModel baseModel; - private final ImmutableMap perspectives; - - public BakedModel(boolean isAmbientOcclusion, boolean isGui3d, boolean isSideLit, TextureAtlasSprite particle, ItemOverrides overrides, net.minecraft.client.resources.model.BakedModel baseModel, ImmutableMap perspectives) - { - this.isAmbientOcclusion = isAmbientOcclusion; - this.isGui3d = isGui3d; - this.isSideLit = isSideLit; - this.particle = particle; - this.overrides = overrides; - this.baseModel = baseModel; - this.perspectives = perspectives; - } - - @Override - public List getQuads(@Nullable BlockState state, @Nullable Direction side, RandomSource rand) - { - return Collections.emptyList(); - } - - @Override - public boolean useAmbientOcclusion() - { - return isAmbientOcclusion; - } - - @Override - public boolean isGui3d() - { - return isGui3d; - } - - @Override - public boolean usesBlockLight() - { - return isSideLit; - } - - @Override - public boolean isCustomRenderer() - { - return false; - } - - @Override - public TextureAtlasSprite getParticleIcon() - { - return particle; - } - - @Override - public ItemOverrides getOverrides() - { - return overrides; - } - - @Override - public boolean doesHandlePerspectives() - { - return true; - } - - @Override - public ItemTransforms getTransforms() - { - return ItemTransforms.NO_TRANSFORMS; - } - - @Override - public net.minecraft.client.resources.model.BakedModel handlePerspective(ItemTransforms.TransformType cameraTransformType, PoseStack poseStack) - { - if (perspectives.containsKey(cameraTransformType)) - { - net.minecraft.client.resources.model.BakedModel p = perspectives.get(cameraTransformType); - return p.handlePerspective(cameraTransformType, poseStack); - } - return baseModel.handlePerspective(cameraTransformType, poseStack); - } - } - - public static class Loader implements IModelLoader - { - public static final Loader INSTANCE = new Loader(); - - @Deprecated(forRemoval = true, since = "1.18.2") - public static final ImmutableBiMap PERSPECTIVES = ImmutableBiMap.builder() - .put("none", ItemTransforms.TransformType.NONE) - .put("third_person_left_hand", ItemTransforms.TransformType.THIRD_PERSON_LEFT_HAND) - .put("third_person_right_hand", ItemTransforms.TransformType.THIRD_PERSON_RIGHT_HAND) - .put("first_person_left_hand", ItemTransforms.TransformType.FIRST_PERSON_LEFT_HAND) - .put("first_person_right_hand", ItemTransforms.TransformType.FIRST_PERSON_RIGHT_HAND) - .put("head", ItemTransforms.TransformType.HEAD) - .put("gui", ItemTransforms.TransformType.GUI) - .put("ground", ItemTransforms.TransformType.GROUND) - .put("fixed", ItemTransforms.TransformType.FIXED) - .build(); - - @Deprecated(forRemoval = true, since = "1.18.2") - private static final ImmutableBiMap BACKWARD_COMPATIBILITY = ImmutableBiMap.builder() - .put("third_person_left_hand", ItemTransforms.TransformType.THIRD_PERSON_LEFT_HAND) - .put("third_person_right_hand", ItemTransforms.TransformType.THIRD_PERSON_RIGHT_HAND) - .put("first_person_left_hand", ItemTransforms.TransformType.FIRST_PERSON_LEFT_HAND) - .put("first_person_right_hand", ItemTransforms.TransformType.FIRST_PERSON_RIGHT_HAND) - .build(); - - @Override - public void onResourceManagerReload(final ResourceManager p_10758_) { - - } - - @Override - public SeparatePerspectiveModel read(JsonDeserializationContext deserializationContext, JsonObject modelContents) - { - BlockModel baseModel = deserializationContext.deserialize(GsonHelper.getAsJsonObject(modelContents, "base"), BlockModel.class); - - JsonObject perspectiveData = GsonHelper.getAsJsonObject(modelContents, "perspectives"); - - Map perspectives = new HashMap<>(); - for(Map.Entry entry : BACKWARD_COMPATIBILITY.entrySet()) - { - if (perspectiveData.has(entry.getKey())) - { - BlockModel perspectiveModel = deserializationContext.deserialize(GsonHelper.getAsJsonObject(perspectiveData, entry.getKey()), BlockModel.class); - perspectives.put(entry.getValue(), perspectiveModel); - } - } - for(ItemTransforms.TransformType perspective : ItemTransforms.TransformType.values()) - { - if (perspectiveData.has(perspective.getSerializeName())) - { - BlockModel perspectiveModel = deserializationContext.deserialize(GsonHelper.getAsJsonObject(perspectiveData, perspective.getSerializeName()), BlockModel.class); - perspectives.put(perspective, perspectiveModel); - } - } - - return new SeparatePerspectiveModel(baseModel, ImmutableMap.copyOf(perspectives)); - } - } -} diff --git a/src/main/java/net/minecraftforge/client/model/SeparateTransformsModel.java b/src/main/java/net/minecraftforge/client/model/SeparateTransformsModel.java new file mode 100644 index 00000000000..291eed28b93 --- /dev/null +++ b/src/main/java/net/minecraftforge/client/model/SeparateTransformsModel.java @@ -0,0 +1,220 @@ +/* + * Copyright (c) Forge Development LLC and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.minecraftforge.client.model; + +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonObject; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.datafixers.util.Pair; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.block.model.BakedQuad; +import net.minecraft.client.renderer.block.model.BlockModel; +import net.minecraft.client.renderer.block.model.ItemOverrides; +import net.minecraft.client.renderer.block.model.ItemTransforms; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.resources.model.BakedModel; +import net.minecraft.client.resources.model.Material; +import net.minecraft.client.resources.model.ModelBakery; +import net.minecraft.client.resources.model.ModelState; +import net.minecraft.client.resources.model.UnbakedModel; +import net.minecraft.core.Direction; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.GsonHelper; +import net.minecraft.util.RandomSource; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraftforge.client.ChunkRenderTypeSet; +import net.minecraftforge.client.model.data.ModelData; +import net.minecraftforge.client.model.geometry.IGeometryBakingContext; +import net.minecraftforge.client.model.geometry.IGeometryLoader; +import net.minecraftforge.client.model.geometry.IUnbakedGeometry; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.Function; + +/** + * A model composed of multiple sub-models which are picked based on the {@link ItemTransforms.TransformType} being used. + */ +public class SeparateTransformsModel implements IUnbakedGeometry +{ + private static final Logger LOGGER = LogManager.getLogger(); + + private final BlockModel baseModel; + private final ImmutableMap perspectives; + private final boolean deprecatedLoader; + + public SeparateTransformsModel(BlockModel baseModel, ImmutableMap perspectives) + { + this(baseModel, perspectives, false); + } + + private SeparateTransformsModel(BlockModel baseModel, ImmutableMap perspectives, boolean deprecatedLoader) + { + this.baseModel = baseModel; + this.perspectives = perspectives; + this.deprecatedLoader = deprecatedLoader; + } + + @Override + public BakedModel bake(IGeometryBakingContext context, ModelBakery bakery, Function spriteGetter, ModelState modelState, ItemOverrides overrides, ResourceLocation modelLocation) + { + if (deprecatedLoader) + LOGGER.warn("Model \"" + modelLocation + "\" is using the deprecated loader \"forge:separate-perspective\" instead of \"forge:separate_transforms\". This loader will be removed in 1.20."); + + return new Baked( + context.useAmbientOcclusion(), context.isGui3d(), context.useBlockLight(), + spriteGetter.apply(context.getMaterial("particle")), overrides, + baseModel.bake(bakery, baseModel, spriteGetter, modelState, modelLocation, context.useBlockLight()), + ImmutableMap.copyOf(Maps.transformValues(perspectives, value -> { + return value.bake(bakery, value, spriteGetter, modelState, modelLocation, context.useBlockLight()); + })) + ); + } + + @Override + public Collection getMaterials(IGeometryBakingContext context, Function modelGetter, Set> missingTextureErrors) + { + Set textures = Sets.newHashSet(); + if (context.hasMaterial("particle")) + textures.add(context.getMaterial("particle")); + textures.addAll(baseModel.getMaterials(modelGetter, missingTextureErrors)); + for (BlockModel model : perspectives.values()) + textures.addAll(model.getMaterials(modelGetter, missingTextureErrors)); + return textures; + } + + public static class Baked implements IDynamicBakedModel + { + private final boolean isAmbientOcclusion; + private final boolean isGui3d; + private final boolean isSideLit; + private final TextureAtlasSprite particle; + private final ItemOverrides overrides; + private final BakedModel baseModel; + private final ImmutableMap perspectives; + + public Baked(boolean isAmbientOcclusion, boolean isGui3d, boolean isSideLit, TextureAtlasSprite particle, ItemOverrides overrides, BakedModel baseModel, ImmutableMap perspectives) + { + this.isAmbientOcclusion = isAmbientOcclusion; + this.isGui3d = isGui3d; + this.isSideLit = isSideLit; + this.particle = particle; + this.overrides = overrides; + this.baseModel = baseModel; + this.perspectives = perspectives; + } + + @NotNull + @Override + public List getQuads(@Nullable BlockState state, @Nullable Direction side, @NotNull RandomSource rand, @NotNull ModelData data, @Nullable RenderType renderType) + { + return baseModel.getQuads(state, side, rand, data, renderType); + } + + @Override + public boolean useAmbientOcclusion() + { + return isAmbientOcclusion; + } + + @Override + public boolean isGui3d() + { + return isGui3d; + } + + @Override + public boolean usesBlockLight() + { + return isSideLit; + } + + @Override + public boolean isCustomRenderer() + { + return false; + } + + @Override + public TextureAtlasSprite getParticleIcon() + { + return particle; + } + + @Override + public ItemOverrides getOverrides() + { + return overrides; + } + + @Override + public ItemTransforms getTransforms() + { + return ItemTransforms.NO_TRANSFORMS; + } + + @Override + public BakedModel applyTransform(ItemTransforms.TransformType cameraTransformType, PoseStack poseStack, boolean applyLeftHandTransform) + { + if (perspectives.containsKey(cameraTransformType)) + { + BakedModel p = perspectives.get(cameraTransformType); + return p.applyTransform(cameraTransformType, poseStack, applyLeftHandTransform); + } + return baseModel.applyTransform(cameraTransformType, poseStack, applyLeftHandTransform); + } + + @Override + public ChunkRenderTypeSet getRenderTypes(@NotNull BlockState state, @NotNull RandomSource rand, @NotNull ModelData data) + { + return baseModel.getRenderTypes(state, rand, data); + } + } + + public static final class Loader implements IGeometryLoader + { + public static final Loader INSTANCE = new Loader(false); + @Deprecated(forRemoval = true, since = "1.19") + public static final Loader INSTANCE_DEPRECATED = new Loader(true); + + private final boolean deprecated; + + private Loader(boolean deprecated) + { + this.deprecated = deprecated; + } + + @Override + public SeparateTransformsModel read(JsonObject jsonObject, JsonDeserializationContext deserializationContext) + { + BlockModel baseModel = deserializationContext.deserialize(GsonHelper.getAsJsonObject(jsonObject, "base"), BlockModel.class); + + JsonObject perspectiveData = GsonHelper.getAsJsonObject(jsonObject, "perspectives"); + + Map perspectives = new HashMap<>(); + for (ItemTransforms.TransformType transform : ItemTransforms.TransformType.values()) + { + if (perspectiveData.has(transform.getSerializeName())) + { + BlockModel perspectiveModel = deserializationContext.deserialize(GsonHelper.getAsJsonObject(perspectiveData, transform.getSerializeName()), BlockModel.class); + perspectives.put(transform, perspectiveModel); + } + } + + return new SeparateTransformsModel(baseModel, ImmutableMap.copyOf(perspectives), deprecated); + } + } +} diff --git a/src/main/java/net/minecraftforge/client/model/SimpleModelState.java b/src/main/java/net/minecraftforge/client/model/SimpleModelState.java index 1d6bea7de5a..24f55fb074f 100644 --- a/src/main/java/net/minecraftforge/client/model/SimpleModelState.java +++ b/src/main/java/net/minecraftforge/client/model/SimpleModelState.java @@ -5,46 +5,37 @@ package net.minecraftforge.client.model; -import net.minecraft.client.resources.model.ModelState; - -import com.google.common.collect.ImmutableMap; import com.mojang.math.Transformation; +import net.minecraft.client.resources.model.ModelState; /** - * Simple implementation of IModelState via a map and a default value. + * Simple implementation of {@link ModelState}. */ public final class SimpleModelState implements ModelState { - public static final SimpleModelState IDENTITY = new SimpleModelState(Transformation.identity()); - - private final ImmutableMap map; - private final Transformation base; - - public SimpleModelState(ImmutableMap map) - { - this(map, Transformation.identity()); - } + private final Transformation transformation; + private final boolean uvLocked; - public SimpleModelState(Transformation base) + public SimpleModelState(Transformation transformation, boolean uvLocked) { - this(ImmutableMap.of(), base); + this.transformation = transformation; + this.uvLocked = uvLocked; } - public SimpleModelState(ImmutableMap map, Transformation base) + public SimpleModelState(Transformation transformation) { - this.map = map; - this.base = base; + this(transformation, false); } @Override public Transformation getRotation() { - return base; + return transformation; } @Override - public Transformation getPartTransformation(Object part) + public boolean isUvLocked() { - return map.getOrDefault(part, Transformation.identity()); + return uvLocked; } } diff --git a/src/main/java/net/minecraftforge/client/model/StandaloneModelConfiguration.java b/src/main/java/net/minecraftforge/client/model/StandaloneModelConfiguration.java deleted file mode 100644 index ee78654b2d6..00000000000 --- a/src/main/java/net/minecraftforge/client/model/StandaloneModelConfiguration.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright (c) Forge Development LLC and contributors - * SPDX-License-Identifier: LGPL-2.1-only - */ - -package net.minecraftforge.client.model; - -import net.minecraft.client.renderer.block.model.ItemTransforms; -import net.minecraft.client.resources.model.BlockModelRotation; -import net.minecraft.client.resources.model.Material; -import net.minecraft.client.resources.model.ModelState; -import net.minecraft.client.resources.model.UnbakedModel; -import net.minecraft.resources.ResourceLocation; -import net.minecraftforge.client.textures.UnitSprite; -import org.jetbrains.annotations.Nullable; - -import java.util.Map; - -/** - * Helper to allow baking models outwise the context of block/item model loading. - */ -public class StandaloneModelConfiguration implements IModelConfiguration -{ - public static final ResourceLocation LOCATION = new ResourceLocation("forge", "standalone"); - - public static final StandaloneModelConfiguration INSTANCE = new StandaloneModelConfiguration(LOCATION, Map.of()); - - public static StandaloneModelConfiguration create(ResourceLocation modelName) - { - return new StandaloneModelConfiguration(modelName, Map.of()); - } - - public static StandaloneModelConfiguration create(Map textures) - { - return new StandaloneModelConfiguration(LOCATION, textures); - } - - public static StandaloneModelConfiguration create(ResourceLocation modelName, Map textures) - { - return new StandaloneModelConfiguration(modelName, textures); - } - - private final Map textures; - - public StandaloneModelConfiguration(ResourceLocation modelName, Map textures) - { - - this.textures = textures; - } - - @Nullable - @Override - public UnbakedModel getOwnerModel() - { - return null; - } - - @Override - public String getModelName() - { - return LOCATION.toString(); - } - - @Override - public boolean isTexturePresent(String name) - { - return textures.containsKey(name); - } - - @Override - public Material resolveTexture(String name) - { - return new Material(UnitSprite.LOCATION, textures.getOrDefault(name, UnitSprite.LOCATION)); - } - - @Override - public boolean isShadedInGui() - { - return true; - } - - @Override - public boolean isSideLit() - { - return true; - } - - @Override - public boolean useSmoothLighting() - { - return true; - } - - @Override - public ItemTransforms getCameraTransforms() - { - return ItemTransforms.NO_TRANSFORMS; - } - - @Override - public ModelState getCombinedTransform() - { - return BlockModelRotation.X0_Y0; - } -} diff --git a/src/main/java/net/minecraftforge/client/model/b3d/package-info.java b/src/main/java/net/minecraftforge/client/model/b3d/package-info.java deleted file mode 100644 index 27ab5f30d83..00000000000 --- a/src/main/java/net/minecraftforge/client/model/b3d/package-info.java +++ /dev/null @@ -1,12 +0,0 @@ -/* - * Copyright (c) Forge Development LLC and contributors - * SPDX-License-Identifier: LGPL-2.1-only - */ - -@ParametersAreNonnullByDefault -@MethodsReturnNonnullByDefault -package net.minecraftforge.client.model.b3d; - -import net.minecraft.MethodsReturnNonnullByDefault; - -import javax.annotation.ParametersAreNonnullByDefault; diff --git a/src/main/java/net/minecraftforge/client/model/data/EmptyModelData.java b/src/main/java/net/minecraftforge/client/model/data/EmptyModelData.java deleted file mode 100644 index 98c140a6f47..00000000000 --- a/src/main/java/net/minecraftforge/client/model/data/EmptyModelData.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) Forge Development LLC and contributors - * SPDX-License-Identifier: LGPL-2.1-only - */ - -package net.minecraftforge.client.model.data; - -public enum EmptyModelData implements IModelData -{ - INSTANCE; - - @Override - public boolean hasProperty(ModelProperty prop) { return false; } - - @Override - public T getData(ModelProperty prop) { return null; } - - @Override - public T setData(ModelProperty prop, T data) { return null; } -} diff --git a/src/main/java/net/minecraftforge/client/model/data/IModelData.java b/src/main/java/net/minecraftforge/client/model/data/IModelData.java deleted file mode 100644 index 6eba11b5afa..00000000000 --- a/src/main/java/net/minecraftforge/client/model/data/IModelData.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) Forge Development LLC and contributors - * SPDX-License-Identifier: LGPL-2.1-only - */ - -package net.minecraftforge.client.model.data; - -import org.jetbrains.annotations.Nullable; - -public interface IModelData -{ - /** - * Check if this data has a property, even if the value is {@code null}. Can be - * used by code that intends to fill in data for a render pipeline, such as the - * forge animation system. - *

- * IMPORTANT: {@link #getData(ModelProperty)} can return {@code null} - * even if this method returns {@code true}. - * - * @param prop The property to check for inclusion in this model data - * @return {@code true} if this data has the given property, even if no value is present - */ - boolean hasProperty(ModelProperty prop); - - @Nullable - T getData(ModelProperty prop); - - @Nullable - T setData(ModelProperty prop, T data); -} diff --git a/src/main/java/net/minecraftforge/client/model/data/ModelData.java b/src/main/java/net/minecraftforge/client/model/data/ModelData.java new file mode 100644 index 00000000000..a5bbadf913b --- /dev/null +++ b/src/main/java/net/minecraftforge/client/model/data/ModelData.java @@ -0,0 +1,99 @@ +/* + * Copyright (c) Forge Development LLC and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.minecraftforge.client.model.data; + +import com.google.common.base.Preconditions; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.resources.model.BakedModel; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.util.RandomSource; +import net.minecraft.world.level.BlockAndTintGetter; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.Nullable; + +import java.util.Collections; +import java.util.IdentityHashMap; +import java.util.Map; +import java.util.Set; + +/** + * A container for data to be passed to {@link BakedModel} instances. + *

+ * All objects stored in here MUST BE IMMUTABLE OR THREAD-SAFE. + * Properties will be accessed from another thread. + * + * @see ModelProperty + * @see BlockEntity#getModelData() + * @see BakedModel#getQuads(BlockState, Direction, RandomSource, ModelData, RenderType) + * @see BakedModel#getModelData(BlockAndTintGetter, BlockPos, BlockState, ModelData) + */ +public final class ModelData +{ + public static final ModelData EMPTY = ModelData.builder().build(); + + private final Map, Object> properties; + + private ModelData(Map, Object> properties) + { + this.properties = properties; + } + + public Set> getProperties() + { + return properties.keySet(); + } + + public boolean has(ModelProperty property) + { + return properties.containsKey(property); + } + + @Nullable + public T get(ModelProperty property) + { + return (T) properties.get(property); + } + + public Builder derive() + { + return new Builder(this); + } + + public static Builder builder() + { + return new Builder(null); + } + + public static final class Builder + { + private final Map, Object> properties = new IdentityHashMap<>(); + + private Builder(@Nullable ModelData parent) + { + if (parent != null) + { + properties.putAll(parent.properties); + } + } + + @Contract("_, _ -> this") + public Builder with(ModelProperty property, T value) + { + Preconditions.checkState(property.test(value), "The provided value is invalid for this property."); + properties.put(property, value); + return this; + } + + @Contract("-> new") + public ModelData build() + { + return new ModelData(Collections.unmodifiableMap(properties)); + } + } +} diff --git a/src/main/java/net/minecraftforge/client/model/data/ModelDataManager.java b/src/main/java/net/minecraftforge/client/model/data/ModelDataManager.java new file mode 100644 index 00000000000..f215fcff186 --- /dev/null +++ b/src/main/java/net/minecraftforge/client/model/data/ModelDataManager.java @@ -0,0 +1,102 @@ +/* + * Copyright (c) Forge Development LLC and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.minecraftforge.client.model.data; + +import com.google.common.base.Preconditions; +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.event.world.ChunkEvent; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.common.Mod.EventBusSubscriber; +import net.minecraftforge.fml.common.Mod.EventBusSubscriber.Bus; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +/** + * A manager for the lifecycle of all the {@link ModelData} instances in a {@link Level}. + *

+ * Users should not be instantiating or using this themselves unless they know what they're doing. + */ +@ApiStatus.Internal +@EventBusSubscriber(modid = "forge", bus = Bus.FORGE, value = Dist.CLIENT) +public class ModelDataManager +{ + private final Level level; + private final Map> needModelDataRefresh = new ConcurrentHashMap<>(); + private final Map> modelDataCache = new ConcurrentHashMap<>(); + + public ModelDataManager(Level level) + { + this.level = level; + } + + public void requestRefresh(@NotNull BlockEntity blockEntity) + { + Preconditions.checkNotNull(blockEntity, "Block entity must not be null"); + needModelDataRefresh.computeIfAbsent(new ChunkPos(blockEntity.getBlockPos()), $ -> Collections.synchronizedSet(new HashSet<>())) + .add(blockEntity.getBlockPos()); + } + + private void refreshAt(ChunkPos chunk) + { + Set needUpdate = needModelDataRefresh.remove(chunk); + + if (needUpdate != null) + { + Map data = modelDataCache.computeIfAbsent(chunk, $ -> new ConcurrentHashMap<>()); + for (BlockPos pos : needUpdate) + { + BlockEntity toUpdate = level.getBlockEntity(pos); + if (toUpdate != null && !toUpdate.isRemoved()) + { + data.put(pos, toUpdate.getModelData()); + } + else + { + data.remove(pos); + } + } + } + } + + public @Nullable ModelData getAt(BlockPos pos) + { + return getAt(new ChunkPos(pos)).get(pos); + } + + public Map getAt(ChunkPos pos) + { + Preconditions.checkArgument(level.isClientSide, "Cannot request model data for server level"); + refreshAt(pos); + return modelDataCache.getOrDefault(pos, Collections.emptyMap()); + } + + @SubscribeEvent + public static void onChunkUnload(ChunkEvent.Unload event) + { + var level = event.getChunk().getWorldForge(); + if (level == null) + return; + + var modelDataManager = level.getModelDataManager(); + if (modelDataManager == null) + return; + + ChunkPos chunk = event.getChunk().getPos(); + modelDataManager.needModelDataRefresh.remove(chunk); + modelDataManager.modelDataCache.remove(chunk); + } +} diff --git a/src/main/java/net/minecraftforge/client/model/data/ModelDataMap.java b/src/main/java/net/minecraftforge/client/model/data/ModelDataMap.java deleted file mode 100644 index 841138c07bb..00000000000 --- a/src/main/java/net/minecraftforge/client/model/data/ModelDataMap.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (c) Forge Development LLC and contributors - * SPDX-License-Identifier: LGPL-2.1-only - */ - -package net.minecraftforge.client.model.data; - -import java.util.IdentityHashMap; -import java.util.Map; - -import com.google.common.base.Preconditions; - -public class ModelDataMap implements IModelData -{ - private final Map, Object> backingMap; - - private ModelDataMap(Map, Object> map) - { - this.backingMap = new IdentityHashMap<>(map); - } - - protected ModelDataMap() - { - this.backingMap = new IdentityHashMap<>(); - } - - @Override - public boolean hasProperty(ModelProperty prop) - { - return backingMap.containsKey(prop); - } - - @SuppressWarnings("unchecked") - @Override - public T getData(ModelProperty prop) - { - return (T) backingMap.get(prop); - } - - @SuppressWarnings("unchecked") - @Override - public T setData(ModelProperty prop, T data) - { - Preconditions.checkArgument(prop.test(data), "Value is invalid for this property"); - return (T) backingMap.put(prop, data); - } - - public static class Builder - { - private final Map, Object> defaults = new IdentityHashMap<>(); - - public Builder withProperty(ModelProperty prop) - { - return withInitial(prop, null); - } - - public Builder withInitial(ModelProperty prop, T data) - { - this.defaults.put(prop, data); - return this; - } - - public ModelDataMap build() - { - return new ModelDataMap(defaults); - } - } -} diff --git a/src/main/java/net/minecraftforge/client/model/data/ModelProperty.java b/src/main/java/net/minecraftforge/client/model/data/ModelProperty.java index 4ef5adbfd71..0125f12405d 100644 --- a/src/main/java/net/minecraftforge/client/model/data/ModelProperty.java +++ b/src/main/java/net/minecraftforge/client/model/data/ModelProperty.java @@ -5,24 +5,34 @@ package net.minecraftforge.client.model.data; +import com.google.common.base.Predicates; + import java.util.function.Predicate; -import com.google.common.base.Predicates; +/** + * A property to be used in {@link ModelData}. + *

+ * May optionally validate incoming values. + * + * @see ModelData + */ +public class ModelProperty implements Predicate +{ + private final Predicate predicate; -public class ModelProperty implements Predicate { - - private final Predicate pred; - - public ModelProperty() { + public ModelProperty() + { this(Predicates.alwaysTrue()); } - - public ModelProperty(Predicate pred) { - this.pred = pred; + + public ModelProperty(Predicate predicate) + { + this.predicate = predicate; } @Override - public boolean test(T t) { - return pred.test(t); + public boolean test(T value) + { + return predicate.test(value); } } diff --git a/src/main/java/net/minecraftforge/client/model/data/MultipartModelData.java b/src/main/java/net/minecraftforge/client/model/data/MultipartModelData.java index e8b8756b19f..eafbb24be2b 100644 --- a/src/main/java/net/minecraftforge/client/model/data/MultipartModelData.java +++ b/src/main/java/net/minecraftforge/client/model/data/MultipartModelData.java @@ -5,87 +5,63 @@ package net.minecraftforge.client.model.data; -import net.minecraft.world.level.block.state.BlockState; import net.minecraft.client.resources.model.BakedModel; -import net.minecraft.core.BlockPos; -import net.minecraft.world.level.BlockAndTintGetter; -import org.apache.commons.lang3.tuple.Pair; import org.jetbrains.annotations.Nullable; -import java.util.HashMap; -import java.util.List; +import java.util.IdentityHashMap; import java.util.Map; -import java.util.function.Predicate; -public class MultipartModelData implements IModelData +public class MultipartModelData { - public static final ModelProperty MULTIPART_DATA = new ModelProperty<>(); + public static final ModelProperty PROPERTY = new ModelProperty<>(); - public static IModelData create(List, BakedModel>> selectors, BlockAndTintGetter level, BlockPos pos, BlockState state, IModelData tileData) - { - MultipartModelData multipartData = new MultipartModelData(tileData); - for (Pair, BakedModel> selector : selectors) - { - if (selector.getLeft().test(state)) - { - BakedModel part = selector.getRight(); - IModelData partData = part.getModelData(level, pos, state, tileData); - multipartData.setPartData(part, partData); - } - } - return multipartData; - } + private final Map partData; - public static IModelData resolve(BakedModel part, IModelData modelData) + private MultipartModelData(Map partData) { - MultipartModelData multipartData = modelData.getData(MultipartModelData.MULTIPART_DATA); - if (multipartData != null) - return multipartData.getPartData(part, modelData); - return modelData; + this.partData = partData; } - private final IModelData tileData; - private final Map partData = new HashMap<>(); - - public MultipartModelData(IModelData tileData) + @Nullable + public ModelData get(BakedModel model) { - this.tileData = tileData; + return partData.get(model); } - public void setPartData(BakedModel part, IModelData data) + /** + * Helper to get the data from a {@link ModelData} instance. + * + * @param modelData The object to get data from + * @param model The model to get data for + * @return The data for the part, or the one passed in if not found + */ + public static ModelData resolve(ModelData modelData, BakedModel model) { - partData.put(part, data); + var multipartData = modelData.get(PROPERTY); + if (multipartData == null) + return modelData; + var partData = multipartData.get(model); + return partData != null ? partData : modelData; } - @Nullable - public IModelData getPartData(BakedModel part, final IModelData defaultData) + public static Builder builder() { - return partData.getOrDefault(part, defaultData); + return new Builder(); } - @Override - public boolean hasProperty(ModelProperty prop) + public static final class Builder { - return prop == MULTIPART_DATA || tileData.hasProperty(prop); - } + private final Map partData = new IdentityHashMap<>(); - @SuppressWarnings("unchecked") - @Nullable - @Override - public T getData(ModelProperty prop) - { - if (prop == MULTIPART_DATA) - return (T)this; - return tileData.getData(prop); - } + public Builder with(BakedModel model, ModelData data) + { + partData.put(model, data); + return this; + } - @SuppressWarnings("unchecked") - @Nullable - @Override - public T setData(ModelProperty prop, T data) - { - if (prop == MULTIPART_DATA) - return (T)this; - return tileData.setData(prop, data); + public MultipartModelData build() + { + return new MultipartModelData(partData); + } } } diff --git a/src/main/java/net/minecraftforge/client/model/generators/BlockStateProvider.java b/src/main/java/net/minecraftforge/client/model/generators/BlockStateProvider.java index edd93b82419..b9e2ac22922 100644 --- a/src/main/java/net/minecraftforge/client/model/generators/BlockStateProvider.java +++ b/src/main/java/net/minecraftforge/client/model/generators/BlockStateProvider.java @@ -72,7 +72,7 @@ public abstract class BlockStateProvider implements DataProvider { private static final Gson GSON = (new GsonBuilder()).setPrettyPrinting().disableHtmlEscaping().create(); @VisibleForTesting - protected final Map registeredBlocks = new LinkedHashMap<>(); + protected final Map registeredBlocks = new LinkedHashMap<>(); private final DataGenerator generator; private final String modid; @@ -102,7 +102,7 @@ public void run(CachedOutput cache) throws IOException { registerStatesAndModels(); models().generateAll(cache); itemModels().generateAll(cache); - for (Map.Entry entry : registeredBlocks.entrySet()) { + for (Map.Entry entry : registeredBlocks.entrySet()) { saveBlockState(cache, entry.getValue().toJson(), entry.getKey()); } } @@ -111,7 +111,7 @@ public void run(CachedOutput cache) throws IOException { public VariantBlockStateBuilder getVariantBuilder(Block b) { if (registeredBlocks.containsKey(b)) { - IGeneratedBlockstate old = registeredBlocks.get(b); + IGeneratedBlockState old = registeredBlocks.get(b); Preconditions.checkState(old instanceof VariantBlockStateBuilder); return (VariantBlockStateBuilder) old; } else { @@ -123,7 +123,7 @@ public VariantBlockStateBuilder getVariantBuilder(Block b) { public MultiPartBlockStateBuilder getMultipartBuilder(Block b) { if (registeredBlocks.containsKey(b)) { - IGeneratedBlockstate old = registeredBlocks.get(b); + IGeneratedBlockState old = registeredBlocks.get(b); Preconditions.checkState(old instanceof MultiPartBlockStateBuilder); return (MultiPartBlockStateBuilder) old; } else { diff --git a/src/main/java/net/minecraftforge/client/model/generators/IGeneratedBlockstate.java b/src/main/java/net/minecraftforge/client/model/generators/IGeneratedBlockState.java similarity index 87% rename from src/main/java/net/minecraftforge/client/model/generators/IGeneratedBlockstate.java rename to src/main/java/net/minecraftforge/client/model/generators/IGeneratedBlockState.java index 391342635f3..a7f5212a87b 100644 --- a/src/main/java/net/minecraftforge/client/model/generators/IGeneratedBlockstate.java +++ b/src/main/java/net/minecraftforge/client/model/generators/IGeneratedBlockState.java @@ -9,7 +9,7 @@ import com.google.gson.JsonObject; @VisibleForTesting -public interface IGeneratedBlockstate { - +public interface IGeneratedBlockState +{ JsonObject toJson(); } diff --git a/src/main/java/net/minecraftforge/client/model/generators/ModelBuilder.java b/src/main/java/net/minecraftforge/client/model/generators/ModelBuilder.java index 11d62c3ee22..862f51872fc 100644 --- a/src/main/java/net/minecraftforge/client/model/generators/ModelBuilder.java +++ b/src/main/java/net/minecraftforge/client/model/generators/ModelBuilder.java @@ -54,6 +54,7 @@ public class ModelBuilder> extends ModelFile { protected final TransformsBuilder transforms = new TransformsBuilder(); protected final ExistingFileHelper existingFileHelper; + protected String renderType = null; protected boolean ambientOcclusion = true; protected GuiLight guiLight = null; @@ -139,6 +140,39 @@ public T texture(String key, ResourceLocation texture) { return self(); } + /** + * Set the render type for this model. + * + * @param renderType the render type. Must be registered via + * {@link net.minecraftforge.client.event.RegisterNamedRenderTypesEvent} + * @return this builder + * @throws NullPointerException if {@code renderType} is {@code null} + */ + public T renderType(String renderType) { + Preconditions.checkNotNull(renderType, "Render type must not be null"); + ResourceLocation asLoc; + if (renderType.contains(":")) { + asLoc = new ResourceLocation(renderType); + } else { + asLoc = new ResourceLocation(getLocation().getNamespace(), renderType); + } + return renderType(asLoc); + } + + /** + * Set the render type for this model. + * + * @param renderType the render type. Must be registered via + * {@link net.minecraftforge.client.event.RegisterNamedRenderTypesEvent} + * @return this builder + * @throws NullPointerException if {@code renderType} is {@code null} + */ + public T renderType(ResourceLocation renderType) { + Preconditions.checkNotNull(renderType, "Render type must not be null"); + this.renderType = renderType.toString(); + return self(); + } + public TransformsBuilder transforms() { return transforms; } @@ -174,8 +208,7 @@ public ElementBuilder element(int index) { } /** - * Gets the number of elements in this model builder - * @return the number of elements in this model builder + * {@return the number of elements in this model builder} */ public int getElementCount() { @@ -212,6 +245,10 @@ public JsonObject toJson() { root.addProperty("gui_light", this.guiLight.getSerializedName()); } + if (this.renderType != null) { + root.addProperty("render_type", this.renderType); + } + Map transforms = this.transforms.build(); if (!transforms.isEmpty()) { JsonObject display = new JsonObject(); @@ -219,15 +256,19 @@ public JsonObject toJson() { JsonObject transform = new JsonObject(); ItemTransform vec = e.getValue(); if (vec.equals(ItemTransform.NO_TRANSFORM)) continue; - if (!vec.rotation.equals(ItemTransform.Deserializer.DEFAULT_ROTATION)) { - transform.add("rotation", serializeVector3f(vec.rotation)); - } + var hasRightRotation = !vec.rightRotation.equals(ItemTransform.Deserializer.DEFAULT_ROTATION); if (!vec.translation.equals(ItemTransform.Deserializer.DEFAULT_TRANSLATION)) { transform.add("translation", serializeVector3f(e.getValue().translation)); } + if (!vec.rotation.equals(ItemTransform.Deserializer.DEFAULT_ROTATION)) { + transform.add(hasRightRotation ? "left_rotation" : "rotation", serializeVector3f(vec.rotation)); + } if (!vec.scale.equals(ItemTransform.Deserializer.DEFAULT_SCALE)) { transform.add("scale", serializeVector3f(e.getValue().scale)); } + if (hasRightRotation) { + transform.add("right_rotation", serializeVector3f(vec.rightRotation)); + } display.add(e.getKey().getSerializeName(), transform); } root.add("display", display); @@ -596,47 +637,10 @@ private FaceRotation(int rotation) { } } - // Since vanilla doesn't keep the name in TransformType... - @Deprecated(forRemoval = true, since = "1.18.2") - public enum Perspective { - - THIRDPERSON_RIGHT(TransformType.THIRD_PERSON_RIGHT_HAND, "thirdperson_righthand"), - THIRDPERSON_LEFT(TransformType.THIRD_PERSON_LEFT_HAND, "thirdperson_lefthand"), - FIRSTPERSON_RIGHT(TransformType.FIRST_PERSON_RIGHT_HAND, "firstperson_righthand"), - FIRSTPERSON_LEFT(TransformType.FIRST_PERSON_LEFT_HAND, "firstperson_lefthand"), - HEAD(TransformType.HEAD, "head"), - GUI(TransformType.GUI, "gui"), - GROUND(TransformType.GROUND, "ground"), - FIXED(TransformType.FIXED, "fixed"), - ; - - public final TransformType vanillaType; - final String name; - - private Perspective(TransformType vanillaType, String name) { - this.vanillaType = vanillaType; - this.name = name; - } - } - public class TransformsBuilder { private final Map transforms = new LinkedHashMap<>(); - /** - * Begin building a new transform for the given perspective. - * - * @param type the perspective to create or return the builder for - * @return the builder for the given perspective - * @throws NullPointerException if {@code type} is {@code null} - * - * @deprecated See {@link #transform(TransformType)} - */ - @Deprecated(forRemoval = true, since = "1.18.2") - public TransformVecBuilder transform(Perspective type) { - return transform(type.vanillaType); - } - /** * Begin building a new transform for the given perspective. * @@ -661,6 +665,7 @@ public class TransformVecBuilder { private Vector3f rotation = ItemTransform.Deserializer.DEFAULT_ROTATION.copy(); private Vector3f translation = ItemTransform.Deserializer.DEFAULT_TRANSLATION.copy(); private Vector3f scale = ItemTransform.Deserializer.DEFAULT_SCALE.copy(); + private Vector3f rightRotation = ItemTransform.Deserializer.DEFAULT_ROTATION.copy(); TransformVecBuilder(TransformType type) { // param unused for functional match @@ -671,6 +676,10 @@ public TransformVecBuilder rotation(float x, float y, float z) { return this; } + public TransformVecBuilder leftRotation(float x, float y, float z) { + return rotation(x, y, z); + } + public TransformVecBuilder translation(float x, float y, float z) { this.translation = new Vector3f(x, y, z); return this; @@ -685,8 +694,13 @@ public TransformVecBuilder scale(float x, float y, float z) { return this; } + public TransformVecBuilder rightRotation(float x, float y, float z) { + this.rightRotation = new Vector3f(x, y, z); + return this; + } + ItemTransform build() { - return new ItemTransform(rotation, translation, scale); + return new ItemTransform(rotation, translation, scale, rightRotation); } public TransformsBuilder end() { return TransformsBuilder.this; } diff --git a/src/main/java/net/minecraftforge/client/model/generators/ModelProvider.java b/src/main/java/net/minecraftforge/client/model/generators/ModelProvider.java index 3d5394fbd57..014e7f64ab6 100644 --- a/src/main/java/net/minecraftforge/client/model/generators/ModelProvider.java +++ b/src/main/java/net/minecraftforge/client/model/generators/ModelProvider.java @@ -356,7 +356,7 @@ public T carpet(String name, ResourceLocation wool) { } /** - * Gets a model builder that's not directly saved to disk. Meant for use in custom model loaders. + * {@return a model builder that's not directly saved to disk. Meant for use in custom model loaders.} */ public T nested() { diff --git a/src/main/java/net/minecraftforge/client/model/generators/MultiPartBlockStateBuilder.java b/src/main/java/net/minecraftforge/client/model/generators/MultiPartBlockStateBuilder.java index db6e5f9379a..7406e51109f 100644 --- a/src/main/java/net/minecraftforge/client/model/generators/MultiPartBlockStateBuilder.java +++ b/src/main/java/net/minecraftforge/client/model/generators/MultiPartBlockStateBuilder.java @@ -21,7 +21,8 @@ import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.state.properties.Property; -public final class MultiPartBlockStateBuilder implements IGeneratedBlockstate { +public final class MultiPartBlockStateBuilder implements IGeneratedBlockState +{ private final List parts = new ArrayList<>(); private final Block owner; diff --git a/src/main/java/net/minecraftforge/client/model/generators/VariantBlockStateBuilder.java b/src/main/java/net/minecraftforge/client/model/generators/VariantBlockStateBuilder.java index 729da576bd6..c5dd22ace65 100644 --- a/src/main/java/net/minecraftforge/client/model/generators/VariantBlockStateBuilder.java +++ b/src/main/java/net/minecraftforge/client/model/generators/VariantBlockStateBuilder.java @@ -51,7 +51,8 @@ * * @see BlockStateProvider */ -public class VariantBlockStateBuilder implements IGeneratedBlockstate { +public class VariantBlockStateBuilder implements IGeneratedBlockState +{ private final Block owner; private final Map models = new LinkedHashMap<>(); diff --git a/src/main/java/net/minecraftforge/client/model/generators/loaders/CompositeModelBuilder.java b/src/main/java/net/minecraftforge/client/model/generators/loaders/CompositeModelBuilder.java index fa22d758dfd..f5e20e6c3cc 100644 --- a/src/main/java/net/minecraftforge/client/model/generators/loaders/CompositeModelBuilder.java +++ b/src/main/java/net/minecraftforge/client/model/generators/loaders/CompositeModelBuilder.java @@ -6,14 +6,14 @@ package net.minecraftforge.client.model.generators.loaders; import com.google.common.base.Preconditions; +import com.google.gson.JsonArray; import com.google.gson.JsonObject; import net.minecraft.resources.ResourceLocation; import net.minecraftforge.client.model.generators.CustomLoaderBuilder; import net.minecraftforge.client.model.generators.ModelBuilder; import net.minecraftforge.common.data.ExistingFileHelper; -import java.util.LinkedHashMap; -import java.util.Map; +import java.util.*; public class CompositeModelBuilder> extends CustomLoaderBuilder { @@ -23,17 +23,31 @@ public static > CompositeModelBuilder begin(T paren } private final Map childModels = new LinkedHashMap<>(); + private final List itemRenderOrder = new ArrayList<>(); protected CompositeModelBuilder(T parent, ExistingFileHelper existingFileHelper) { super(new ResourceLocation("forge:composite"), parent, existingFileHelper); } - public CompositeModelBuilder submodel(String name, T modelBuilder) + public CompositeModelBuilder child(String name, T modelBuilder) { Preconditions.checkNotNull(name, "name must not be null"); Preconditions.checkNotNull(modelBuilder, "modelBuilder must not be null"); childModels.put(name, modelBuilder); + itemRenderOrder.add(name); + return this; + } + + public CompositeModelBuilder itemRenderOrder(String... names) + { + Preconditions.checkNotNull(names, "names must not be null"); + Preconditions.checkArgument(names.length > 0, "names must contain at least one element"); + for (String name : names) + if (!childModels.containsKey(name)) + throw new IllegalArgumentException("names contains \"" + name + "\", which is not a child of this model"); + itemRenderOrder.clear(); + itemRenderOrder.addAll(Arrays.asList(names)); return this; } @@ -42,12 +56,18 @@ public JsonObject toJson(JsonObject json) { json = super.toJson(json); - JsonObject parts = new JsonObject(); + JsonObject children = new JsonObject(); for(Map.Entry entry : childModels.entrySet()) { - parts.add(entry.getKey(), entry.getValue().toJson()); + children.add(entry.getKey(), entry.getValue().toJson()); + } + json.add("children", children); + + JsonArray itemRenderOrder = new JsonArray(); + for (String name : this.itemRenderOrder) { + itemRenderOrder.add(name); } - json.add("parts", parts); + json.add("item_render_order", itemRenderOrder); return json; } diff --git a/src/main/java/net/minecraftforge/client/model/generators/loaders/DynamicBucketModelBuilder.java b/src/main/java/net/minecraftforge/client/model/generators/loaders/DynamicFluidContainerModelBuilder.java similarity index 61% rename from src/main/java/net/minecraftforge/client/model/generators/loaders/DynamicBucketModelBuilder.java rename to src/main/java/net/minecraftforge/client/model/generators/loaders/DynamicFluidContainerModelBuilder.java index f52f7a1a570..db130256778 100644 --- a/src/main/java/net/minecraftforge/client/model/generators/loaders/DynamicBucketModelBuilder.java +++ b/src/main/java/net/minecraftforge/client/model/generators/loaders/DynamicFluidContainerModelBuilder.java @@ -14,11 +14,11 @@ import net.minecraftforge.common.data.ExistingFileHelper; import net.minecraftforge.registries.ForgeRegistries; -public class DynamicBucketModelBuilder> extends CustomLoaderBuilder +public class DynamicFluidContainerModelBuilder> extends CustomLoaderBuilder { - public static > DynamicBucketModelBuilder begin(T parent, ExistingFileHelper existingFileHelper) + public static > DynamicFluidContainerModelBuilder begin(T parent, ExistingFileHelper existingFileHelper) { - return new DynamicBucketModelBuilder<>(parent, existingFileHelper); + return new DynamicFluidContainerModelBuilder<>(parent, existingFileHelper); } private ResourceLocation fluid; @@ -27,37 +27,37 @@ public static > DynamicBucketModelBuilder begin(T p private Boolean coverIsMask; private Boolean applyFluidLuminosity; - protected DynamicBucketModelBuilder(T parent, ExistingFileHelper existingFileHelper) + protected DynamicFluidContainerModelBuilder(T parent, ExistingFileHelper existingFileHelper) { super(new ResourceLocation("forge:bucket"), parent, existingFileHelper); } - public DynamicBucketModelBuilder fluid(Fluid fluid) + public DynamicFluidContainerModelBuilder fluid(Fluid fluid) { Preconditions.checkNotNull(fluid, "fluid must not be null"); this.fluid = ForgeRegistries.FLUIDS.getKey(fluid); return this; } - public DynamicBucketModelBuilder flipGas(boolean flip) + public DynamicFluidContainerModelBuilder flipGas(boolean flip) { this.flipGas = flip; return this; } - public DynamicBucketModelBuilder applyTint(boolean tint) + public DynamicFluidContainerModelBuilder applyTint(boolean tint) { this.applyTint = tint; return this; } - public DynamicBucketModelBuilder coverIsMask(boolean coverIsMask) + public DynamicFluidContainerModelBuilder coverIsMask(boolean coverIsMask) { this.coverIsMask = coverIsMask; return this; } - public DynamicBucketModelBuilder applyFluidLuminosity(boolean applyFluidLuminosity) + public DynamicFluidContainerModelBuilder applyFluidLuminosity(boolean applyFluidLuminosity) { this.applyFluidLuminosity = applyFluidLuminosity; return this; @@ -73,16 +73,16 @@ public JsonObject toJson(JsonObject json) json.addProperty("fluid", fluid.toString()); if (flipGas != null) - json.addProperty("flipGas", flipGas); + json.addProperty("flip_gas", flipGas); if (applyTint != null) - json.addProperty("applyTint", applyTint); + json.addProperty("apply_tint", applyTint); if (coverIsMask != null) - json.addProperty("coverIsMask", coverIsMask); + json.addProperty("cover_is_mask", coverIsMask); if (applyFluidLuminosity != null) - json.addProperty("applyFluidLuminosity", applyFluidLuminosity); + json.addProperty("apply_fluid_luminosity", applyFluidLuminosity); return json; } diff --git a/src/main/java/net/minecraftforge/client/model/generators/loaders/ItemLayersModelBuilder.java b/src/main/java/net/minecraftforge/client/model/generators/loaders/ItemLayersModelBuilder.java index c6917d636ec..b0bdeb6c9e9 100644 --- a/src/main/java/net/minecraftforge/client/model/generators/loaders/ItemLayersModelBuilder.java +++ b/src/main/java/net/minecraftforge/client/model/generators/loaders/ItemLayersModelBuilder.java @@ -8,13 +8,14 @@ import com.google.common.base.Preconditions; import com.google.gson.JsonArray; import com.google.gson.JsonObject; +import it.unimi.dsi.fastutil.ints.IntOpenHashSet; +import it.unimi.dsi.fastutil.ints.IntSet; import net.minecraft.resources.ResourceLocation; import net.minecraftforge.client.model.generators.CustomLoaderBuilder; import net.minecraftforge.client.model.generators.ModelBuilder; import net.minecraftforge.common.data.ExistingFileHelper; -import java.util.LinkedHashSet; -import java.util.Set; +import java.util.*; public class ItemLayersModelBuilder> extends CustomLoaderBuilder { @@ -23,17 +24,83 @@ public static > ItemLayersModelBuilder begin(T pare return new ItemLayersModelBuilder<>(parent, existingFileHelper); } - private final Set fullbright = new LinkedHashSet<>(); + private final IntSet emissiveLayers = new IntOpenHashSet(); + private final Map renderTypes = new LinkedHashMap<>(); + private final IntSet layersWithRenderTypes = new IntOpenHashSet(); protected ItemLayersModelBuilder(T parent, ExistingFileHelper existingFileHelper) { - super(new ResourceLocation("forge:item-layers"), parent, existingFileHelper); + super(new ResourceLocation("forge:item_layers"), parent, existingFileHelper); } - public ItemLayersModelBuilder fullbright(int layer) + /** + * Marks a set of layers to be rendered emissively. + * + * @param layers the layers that will render unlit + * @return this builder + * @throws NullPointerException if {@code layers} is {@code null} + * @throws IllegalArgumentException if {@code layers} is empty + * @throws IllegalArgumentException if any entry in {@code layers} is smaller than 0 + */ + public ItemLayersModelBuilder emissive(int... layers) { - Preconditions.checkArgument(layer >= 0, "layer must be >= 0"); - fullbright.add(layer); + Preconditions.checkNotNull(layers, "Layers must not be null"); + Preconditions.checkArgument(layers.length > 0, "At least one layer must be specified"); + Preconditions.checkArgument(Arrays.stream(layers).allMatch(i -> i >= 0), "All layers must be >= 0"); + Arrays.stream(layers).forEach(emissiveLayers::add); + return this; + } + + /** + * Set the render type for a set of layers. + * + * @param renderType the render type. Must be registered via + * {@link net.minecraftforge.client.event.RegisterNamedRenderTypesEvent} + * @param layers the layers that will use this render type + * @return this builder + * @throws NullPointerException if {@code renderType} is {@code null} + * @throws NullPointerException if {@code layers} is {@code null} + * @throws IllegalArgumentException if {@code layers} is empty + * @throws IllegalArgumentException if any entry in {@code layers} is smaller than 0 + * @throws IllegalArgumentException if any entry in {@code layers} already has a render type + */ + public ItemLayersModelBuilder renderType(String renderType, int... layers) + { + Preconditions.checkNotNull(renderType, "Render type must not be null"); + ResourceLocation asLoc; + if (renderType.contains(":")) + asLoc = new ResourceLocation(renderType); + else + asLoc = new ResourceLocation(parent.getLocation().getNamespace(), renderType); + return renderType(asLoc, layers); + } + + /** + * Set the render type for a set of layers. + * + * @param renderType the render type. Must be registered via + * {@link net.minecraftforge.client.event.RegisterNamedRenderTypesEvent} + * @param layers the layers that will use this render type + * @return this builder + * @throws NullPointerException if {@code renderType} is {@code null} + * @throws NullPointerException if {@code layers} is {@code null} + * @throws IllegalArgumentException if {@code layers} is empty + * @throws IllegalArgumentException if any entry in {@code layers} is smaller than 0 + * @throws IllegalArgumentException if any entry in {@code layers} already has a render type + */ + public ItemLayersModelBuilder renderType(ResourceLocation renderType, int... layers) + { + Preconditions.checkNotNull(renderType, "Render type must not be null"); + Preconditions.checkNotNull(layers, "Layers must not be null"); + Preconditions.checkArgument(layers.length > 0, "At least one layer must be specified"); + Preconditions.checkArgument(Arrays.stream(layers).allMatch(i -> i >= 0), "All layers must be >= 0"); + var alreadyAssigned = Arrays.stream(layers).filter(layersWithRenderTypes::contains).toArray(); + Preconditions.checkArgument(alreadyAssigned.length == 0, "Attempted to re-assign layer render types: " + Arrays.toString(alreadyAssigned)); + var renderTypeLayers = renderTypes.computeIfAbsent(renderType, $ -> new IntOpenHashSet()); + Arrays.stream(layers).forEach(layer -> { + renderTypeLayers.add(layer); + layersWithRenderTypes.add(layer); + }); return this; } @@ -42,12 +109,17 @@ public JsonObject toJson(JsonObject json) { json = super.toJson(json); - JsonArray parts = new JsonArray(); - for(int entry : fullbright) - { - parts.add(entry); - } - json.add("fullbright_layers", parts); + JsonArray unlitLayers = new JsonArray(); + this.emissiveLayers.intStream().sorted().forEach(unlitLayers::add); + json.add("emissive_layers", unlitLayers); + + JsonObject renderTypes = new JsonObject(); + this.renderTypes.forEach((renderType, layers) -> { + JsonArray array = new JsonArray(); + layers.intStream().sorted().forEach(array::add); + renderTypes.add(renderType.toString(), array); + }); + json.add("render_types", renderTypes); return json; } diff --git a/src/main/java/net/minecraftforge/client/model/generators/loaders/MultiLayerModelBuilder.java b/src/main/java/net/minecraftforge/client/model/generators/loaders/MultiLayerModelBuilder.java deleted file mode 100644 index bb39ea714a0..00000000000 --- a/src/main/java/net/minecraftforge/client/model/generators/loaders/MultiLayerModelBuilder.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) Forge Development LLC and contributors - * SPDX-License-Identifier: LGPL-2.1-only - */ - -package net.minecraftforge.client.model.generators.loaders; - -import com.google.common.base.Preconditions; -import com.google.gson.JsonObject; -import net.minecraft.client.renderer.RenderType; -import net.minecraft.resources.ResourceLocation; -import net.minecraftforge.client.model.MultiLayerModel; -import net.minecraftforge.client.model.generators.CustomLoaderBuilder; -import net.minecraftforge.client.model.generators.ModelBuilder; -import net.minecraftforge.common.data.ExistingFileHelper; - -import java.util.LinkedHashMap; -import java.util.Map; - -public class MultiLayerModelBuilder> extends CustomLoaderBuilder -{ - public static > MultiLayerModelBuilder begin(T parent, ExistingFileHelper existingFileHelper) - { - return new MultiLayerModelBuilder<>(parent, existingFileHelper); - } - - private final Map childModels = new LinkedHashMap<>(); - - protected MultiLayerModelBuilder(T parent, ExistingFileHelper existingFileHelper) - { - super(new ResourceLocation("forge:multi-layer"), parent, existingFileHelper); - } - - public MultiLayerModelBuilder submodel(RenderType layer, T modelBuilder) - { - Preconditions.checkNotNull(layer, "layer must not be null"); - Preconditions.checkArgument(MultiLayerModel.Loader.BLOCK_LAYERS.containsValue(layer), "layer must be supported by MultiLayerModel"); - Preconditions.checkNotNull(modelBuilder, "modelBuilder must not be null"); - childModels.put(MultiLayerModel.Loader.BLOCK_LAYERS.inverse().get(layer), modelBuilder); - return this; - } - - @Override - public JsonObject toJson(JsonObject json) - { - json = super.toJson(json); - - JsonObject parts = new JsonObject(); - for(Map.Entry entry : childModels.entrySet()) - { - parts.add(entry.getKey(), entry.getValue().toJson()); - } - json.add("layers", parts); - - return json; - } -} diff --git a/src/main/java/net/minecraftforge/client/model/generators/loaders/OBJLoaderBuilder.java b/src/main/java/net/minecraftforge/client/model/generators/loaders/OBJLoaderBuilder.java deleted file mode 100644 index 70dbf124179..00000000000 --- a/src/main/java/net/minecraftforge/client/model/generators/loaders/OBJLoaderBuilder.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright (c) Forge Development LLC and contributors - * SPDX-License-Identifier: LGPL-2.1-only - */ - -package net.minecraftforge.client.model.generators.loaders; - -import com.google.common.base.Preconditions; -import com.google.gson.JsonObject; -import net.minecraft.server.packs.PackType; -import net.minecraft.resources.ResourceLocation; -import net.minecraftforge.client.model.generators.CustomLoaderBuilder; -import net.minecraftforge.client.model.generators.ModelBuilder; -import net.minecraftforge.common.data.ExistingFileHelper; - -public class OBJLoaderBuilder> extends CustomLoaderBuilder -{ - public static > OBJLoaderBuilder begin(T parent, ExistingFileHelper existingFileHelper) - { - return new OBJLoaderBuilder<>(parent, existingFileHelper); - } - - private ResourceLocation modelLocation; - private Boolean detectCullableFaces; - private Boolean diffuseLighting; - private Boolean flipV; - private Boolean ambientToFullbright; - private ResourceLocation materialLibraryOverrideLocation; - - protected OBJLoaderBuilder(T parent, ExistingFileHelper existingFileHelper) - { - super(new ResourceLocation("forge:obj"), parent, existingFileHelper); - } - - public OBJLoaderBuilder modelLocation(ResourceLocation modelLocation) - { - Preconditions.checkNotNull(modelLocation, "modelLocation must not be null"); - Preconditions.checkArgument(existingFileHelper.exists(modelLocation, PackType.CLIENT_RESOURCES), - "OBJ Model %s does not exist in any known resource pack", modelLocation); - this.modelLocation = modelLocation; - return this; - } - - public OBJLoaderBuilder detectCullableFaces(boolean detectCullableFaces) - { - this.detectCullableFaces = detectCullableFaces; - return this; - } - - public OBJLoaderBuilder diffuseLighting(boolean diffuseLighting) - { - this.diffuseLighting = diffuseLighting; - return this; - } - - public OBJLoaderBuilder flipV(boolean flipV) - { - this.flipV = flipV; - return this; - } - - public OBJLoaderBuilder ambientToFullbright(boolean ambientToFullbright) - { - this.ambientToFullbright = ambientToFullbright; - return this; - } - - public OBJLoaderBuilder overrideMaterialLibrary(ResourceLocation materialLibraryOverrideLocation) - { - Preconditions.checkNotNull(materialLibraryOverrideLocation, "materialLibraryOverrideLocation must not be null"); - Preconditions.checkArgument(existingFileHelper.exists(materialLibraryOverrideLocation, PackType.CLIENT_RESOURCES), - "OBJ Model %s does not exist in any known resource pack", materialLibraryOverrideLocation); - this.materialLibraryOverrideLocation = materialLibraryOverrideLocation; - return this; - } - - @Override - public JsonObject toJson(JsonObject json) - { - json = super.toJson(json); - - Preconditions.checkNotNull(modelLocation, "modelLocation must not be null"); - - json.addProperty("model", modelLocation.toString()); - - if (detectCullableFaces != null) - json.addProperty("detectCullableFaces", detectCullableFaces); - - if (diffuseLighting != null) - json.addProperty("diffuseLighting", diffuseLighting); - - if (flipV != null) - json.addProperty("flip-v", flipV); - - if (ambientToFullbright != null) - json.addProperty("ambientToFullbright", ambientToFullbright); - - if (materialLibraryOverrideLocation != null) - json.addProperty("materialLibraryOverride", materialLibraryOverrideLocation.toString()); - - return json; - } -} diff --git a/src/main/java/net/minecraftforge/client/model/generators/loaders/ObjModelBuilder.java b/src/main/java/net/minecraftforge/client/model/generators/loaders/ObjModelBuilder.java new file mode 100644 index 00000000000..43cfc30050e --- /dev/null +++ b/src/main/java/net/minecraftforge/client/model/generators/loaders/ObjModelBuilder.java @@ -0,0 +1,103 @@ +/* + * Copyright (c) Forge Development LLC and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.minecraftforge.client.model.generators.loaders; + +import com.google.common.base.Preconditions; +import com.google.gson.JsonObject; +import net.minecraft.server.packs.PackType; +import net.minecraft.resources.ResourceLocation; +import net.minecraftforge.client.model.generators.CustomLoaderBuilder; +import net.minecraftforge.client.model.generators.ModelBuilder; +import net.minecraftforge.common.data.ExistingFileHelper; + +public class ObjModelBuilder> extends CustomLoaderBuilder +{ + public static > ObjModelBuilder begin(T parent, ExistingFileHelper existingFileHelper) + { + return new ObjModelBuilder<>(parent, existingFileHelper); + } + + private ResourceLocation modelLocation; + private Boolean automaticCulling; + private Boolean shadeQuads; + private Boolean flipV; + private Boolean emissiveAmbient; + private ResourceLocation mtlOverride; + + protected ObjModelBuilder(T parent, ExistingFileHelper existingFileHelper) + { + super(new ResourceLocation("forge:obj"), parent, existingFileHelper); + } + + public ObjModelBuilder modelLocation(ResourceLocation modelLocation) + { + Preconditions.checkNotNull(modelLocation, "modelLocation must not be null"); + Preconditions.checkArgument(existingFileHelper.exists(modelLocation, PackType.CLIENT_RESOURCES), + "OBJ Model %s does not exist in any known resource pack", modelLocation); + this.modelLocation = modelLocation; + return this; + } + + public ObjModelBuilder automaticCulling(boolean automaticCulling) + { + this.automaticCulling = automaticCulling; + return this; + } + + public ObjModelBuilder shadeQuads(boolean shadeQuads) + { + this.shadeQuads = shadeQuads; + return this; + } + + public ObjModelBuilder flipV(boolean flipV) + { + this.flipV = flipV; + return this; + } + + public ObjModelBuilder emissiveAmbient(boolean ambientEmissive) + { + this.emissiveAmbient = ambientEmissive; + return this; + } + + public ObjModelBuilder overrideMaterialLibrary(ResourceLocation mtlOverride) + { + Preconditions.checkNotNull(mtlOverride, "mtlOverride must not be null"); + Preconditions.checkArgument(existingFileHelper.exists(mtlOverride, PackType.CLIENT_RESOURCES), + "OBJ Model %s does not exist in any known resource pack", mtlOverride); + this.mtlOverride = mtlOverride; + return this; + } + + @Override + public JsonObject toJson(JsonObject json) + { + json = super.toJson(json); + + Preconditions.checkNotNull(modelLocation, "modelLocation must not be null"); + + json.addProperty("model", modelLocation.toString()); + + if (automaticCulling != null) + json.addProperty("automatic_culling", automaticCulling); + + if (shadeQuads != null) + json.addProperty("shade_quads", shadeQuads); + + if (flipV != null) + json.addProperty("flip_v", flipV); + + if (emissiveAmbient != null) + json.addProperty("emissive_ambient", emissiveAmbient); + + if (mtlOverride != null) + json.addProperty("mtl_override", mtlOverride.toString()); + + return json; + } +} diff --git a/src/main/java/net/minecraftforge/client/model/generators/loaders/SeparatePerspectiveModelBuilder.java b/src/main/java/net/minecraftforge/client/model/generators/loaders/SeparateTransformsModelBuilder.java similarity index 67% rename from src/main/java/net/minecraftforge/client/model/generators/loaders/SeparatePerspectiveModelBuilder.java rename to src/main/java/net/minecraftforge/client/model/generators/loaders/SeparateTransformsModelBuilder.java index c9537582478..e5d30091063 100644 --- a/src/main/java/net/minecraftforge/client/model/generators/loaders/SeparatePerspectiveModelBuilder.java +++ b/src/main/java/net/minecraftforge/client/model/generators/loaders/SeparateTransformsModelBuilder.java @@ -9,7 +9,6 @@ import com.google.gson.JsonObject; import net.minecraft.client.renderer.block.model.ItemTransforms; import net.minecraft.resources.ResourceLocation; -import net.minecraftforge.client.model.SeparatePerspectiveModel; import net.minecraftforge.client.model.generators.CustomLoaderBuilder; import net.minecraftforge.client.model.generators.ModelBuilder; import net.minecraftforge.common.data.ExistingFileHelper; @@ -17,29 +16,29 @@ import java.util.LinkedHashMap; import java.util.Map; -public class SeparatePerspectiveModelBuilder> extends CustomLoaderBuilder +public class SeparateTransformsModelBuilder> extends CustomLoaderBuilder { - public static > SeparatePerspectiveModelBuilder begin(T parent, ExistingFileHelper existingFileHelper) + public static > SeparateTransformsModelBuilder begin(T parent, ExistingFileHelper existingFileHelper) { - return new SeparatePerspectiveModelBuilder<>(parent, existingFileHelper); + return new SeparateTransformsModelBuilder<>(parent, existingFileHelper); } private T base; private final Map childModels = new LinkedHashMap<>(); - protected SeparatePerspectiveModelBuilder(T parent, ExistingFileHelper existingFileHelper) + protected SeparateTransformsModelBuilder(T parent, ExistingFileHelper existingFileHelper) { - super(new ResourceLocation("forge:separate-perspective"), parent, existingFileHelper); + super(new ResourceLocation("forge:separate_transforms"), parent, existingFileHelper); } - public SeparatePerspectiveModelBuilder base(T modelBuilder) + public SeparateTransformsModelBuilder base(T modelBuilder) { Preconditions.checkNotNull(modelBuilder, "modelBuilder must not be null"); base = modelBuilder; return this; } - public SeparatePerspectiveModelBuilder perspective(ItemTransforms.TransformType perspective, T modelBuilder) + public SeparateTransformsModelBuilder perspective(ItemTransforms.TransformType perspective, T modelBuilder) { Preconditions.checkNotNull(perspective, "layer must not be null"); Preconditions.checkNotNull(modelBuilder, "modelBuilder must not be null"); diff --git a/src/main/java/net/minecraftforge/client/model/BlockModelConfiguration.java b/src/main/java/net/minecraftforge/client/model/geometry/BlockGeometryBakingContext.java similarity index 57% rename from src/main/java/net/minecraftforge/client/model/BlockModelConfiguration.java rename to src/main/java/net/minecraftforge/client/model/geometry/BlockGeometryBakingContext.java index 9e56877491e..91e8810c577 100644 --- a/src/main/java/net/minecraftforge/client/model/BlockModelConfiguration.java +++ b/src/main/java/net/minecraftforge/client/model/geometry/BlockGeometryBakingContext.java @@ -3,48 +3,52 @@ * SPDX-License-Identifier: LGPL-2.1-only */ -package net.minecraftforge.client.model; +package net.minecraftforge.client.model.geometry; import com.mojang.datafixers.util.Pair; -import net.minecraft.client.renderer.texture.TextureAtlasSprite; -import net.minecraft.resources.ResourceLocation; -import net.minecraftforge.client.model.geometry.IModelGeometry; -import net.minecraftforge.client.model.geometry.IModelGeometryPart; - -import java.util.*; -import java.util.function.Function; - +import com.mojang.math.Transformation; import net.minecraft.client.renderer.block.model.BlockModel; import net.minecraft.client.renderer.block.model.ItemOverrides; import net.minecraft.client.renderer.block.model.ItemTransforms; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.client.resources.model.BakedModel; import net.minecraft.client.resources.model.Material; import net.minecraft.client.resources.model.ModelBakery; import net.minecraft.client.resources.model.ModelState; import net.minecraft.client.resources.model.UnbakedModel; +import net.minecraft.resources.ResourceLocation; +import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; -public class BlockModelConfiguration implements IModelConfiguration +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import java.util.function.Function; + +/** + * A {@linkplain IGeometryBakingContext geometry baking context} that is bound to a {@link BlockModel}. + *

+ * Users should not be instantiating this themselves. + */ +public class BlockGeometryBakingContext implements IGeometryBakingContext { public final BlockModel owner; public final VisibilityData visibilityData = new VisibilityData(); @Nullable - private IModelGeometry customGeometry; + private IUnbakedGeometry customGeometry; + @Nullable + private Transformation rootTransform; @Nullable - private ModelState customModelState; + private ResourceLocation renderTypeHint; - public BlockModelConfiguration(BlockModel owner) + @ApiStatus.Internal + public BlockGeometryBakingContext(BlockModel owner) { this.owner = owner; } - @Nullable - @Override - public UnbakedModel getOwnerModel() - { - return owner; - } - @Override public String getModelName() { @@ -57,97 +61,104 @@ public boolean hasCustomGeometry() } @Nullable - public IModelGeometry getCustomGeometry() + public IUnbakedGeometry getCustomGeometry() { return owner.parent != null && customGeometry == null ? owner.parent.customData.getCustomGeometry() : customGeometry; } - public void setCustomGeometry(IModelGeometry geometry) + public void setCustomGeometry(IUnbakedGeometry geometry) { this.customGeometry = geometry; } - @Nullable - public ModelState getCustomModelState() - { - return owner.parent != null && customModelState == null ? owner.parent.customData.getCustomModelState() : customModelState; - } - - public void setCustomModelState(ModelState modelState) - { - this.customModelState = modelState; - } - @Override - public boolean getPartVisibility(IModelGeometryPart part, boolean fallback) + public boolean isComponentVisible(String part, boolean fallback) { return owner.parent != null && !visibilityData.hasCustomVisibility(part) ? - owner.parent.customData.getPartVisibility(part, fallback): + owner.parent.customData.isComponentVisible(part, fallback) : visibilityData.isVisible(part, fallback); } @Override - public boolean isTexturePresent(String name) + public boolean hasMaterial(String name) { return owner.hasTexture(name); } @Override - public Material resolveTexture(String name) + public Material getMaterial(String name) { return owner.getMaterial(name); } @Override - public boolean isShadedInGui() { + public boolean isGui3d() + { return true; } @Override - public boolean isSideLit() + public boolean useBlockLight() { return owner.getGuiLight().lightLikeBlock(); } @Override - public boolean useSmoothLighting() + public boolean useAmbientOcclusion() { return owner.hasAmbientOcclusion(); } @Override - public ItemTransforms getCameraTransforms() + public ItemTransforms getTransforms() { return owner.getTransforms(); } @Override - public ModelState getCombinedTransform() + public Transformation getRootTransform() { - ModelState state = getCustomModelState(); + if (rootTransform != null) + return rootTransform; + return owner.parent != null ? owner.parent.customData.getRootTransform() : Transformation.identity(); + } - return state != null - ? new SimpleModelState(PerspectiveMapWrapper.getTransformsWithFallback(state, getCameraTransforms()), state.getRotation()) - : new SimpleModelState(PerspectiveMapWrapper.getTransforms(getCameraTransforms())); + public void setRootTransform(Transformation rootTransform) + { + this.rootTransform = rootTransform; + } + + @Nullable + @Override + public ResourceLocation getRenderTypeHint() + { + if (renderTypeHint != null) + return renderTypeHint; + return owner.parent != null ? owner.parent.customData.getRenderTypeHint() : null; + } + + public void setRenderTypeHint(ResourceLocation renderTypeHint) + { + this.renderTypeHint = renderTypeHint; } - public void copyFrom(BlockModelConfiguration other) + public void copyFrom(BlockGeometryBakingContext other) { this.customGeometry = other.customGeometry; - this.customModelState = other.customModelState; + this.rootTransform = other.rootTransform; this.visibilityData.copyFrom(other.visibilityData); } public Collection getTextureDependencies(Function modelGetter, Set> missingTextureErrors) { - IModelGeometry geometry = getCustomGeometry(); + IUnbakedGeometry geometry = getCustomGeometry(); return geometry == null ? Collections.emptySet() : - geometry.getTextures(this, modelGetter, missingTextureErrors); + geometry.getMaterials(this, modelGetter, missingTextureErrors); } public BakedModel bake(ModelBakery bakery, Function bakedTextureGetter, ModelState modelTransform, ItemOverrides overrides, ResourceLocation modelLocation) { - IModelGeometry geometry = getCustomGeometry(); + IUnbakedGeometry geometry = getCustomGeometry(); if (geometry == null) throw new IllegalStateException("Can not use custom baking without custom geometry"); return geometry.bake(this, bakery, bakedTextureGetter, modelTransform, overrides, modelLocation); @@ -157,14 +168,14 @@ public static class VisibilityData { private final Map data = new HashMap<>(); - public boolean hasCustomVisibility(IModelGeometryPart part) + public boolean hasCustomVisibility(String part) { - return data.containsKey(part.name()); + return data.containsKey(part); } - public boolean isVisible(IModelGeometryPart part, boolean fallback) + public boolean isVisible(String part, boolean fallback) { - return data.getOrDefault(part.name(), fallback); + return data.getOrDefault(part, fallback); } public void setVisibilityState(String partName, boolean type) diff --git a/src/main/java/net/minecraftforge/client/model/geometry/GeometryLoaderManager.java b/src/main/java/net/minecraftforge/client/model/geometry/GeometryLoaderManager.java new file mode 100644 index 00000000000..f366e4c0484 --- /dev/null +++ b/src/main/java/net/minecraftforge/client/model/geometry/GeometryLoaderManager.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) Forge Development LLC and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.minecraftforge.client.model.geometry; + +import com.google.common.collect.ImmutableMap; +import net.minecraft.resources.ResourceLocation; +import net.minecraftforge.client.event.ModelEvent; +import net.minecraftforge.client.model.ElementsModel; +import net.minecraftforge.fml.ModLoader; +import net.minecraftforge.fml.ModLoadingContext; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.Nullable; + +import java.util.HashMap; +import java.util.stream.Collectors; + +/** + * Manager for {@linkplain IGeometryLoader geometry loaders}. + *

+ * Provides a lookup. + */ +public final class GeometryLoaderManager +{ + private static ImmutableMap> LOADERS; + private static String LOADER_LIST; + + /** + * Finds the {@link IGeometryLoader} for a given name, or null if not found. + */ + @Nullable + public static IGeometryLoader get(ResourceLocation name) + { + return LOADERS.get(name); + } + + /** + * Retrieves a comma-separated list of all active loaders, for use in error messages. + */ + public static String getLoaderList() + { + return LOADER_LIST; + } + + @ApiStatus.Internal + public static void init() + { + var loaders = new HashMap>(); + loaders.put(new ResourceLocation("minecraft:elements"), ElementsModel.Loader.INSTANCE_DEPRECATED); // TODO: Deprecated. To be removed in 1.20 + var event = new ModelEvent.RegisterGeometryLoaders(loaders); + ModLoader.get().postEventWithWrapInModOrder(event, (mc, e) -> ModLoadingContext.get().setActiveContainer(mc), (mc, e) -> ModLoadingContext.get().setActiveContainer(null)); + LOADERS = ImmutableMap.copyOf(loaders); + LOADER_LIST = loaders.keySet().stream().map(ResourceLocation::toString).collect(Collectors.joining(", ")); + } + + private GeometryLoaderManager() + { + } +} diff --git a/src/main/java/net/minecraftforge/client/model/geometry/IGeometryBakingContext.java b/src/main/java/net/minecraftforge/client/model/geometry/IGeometryBakingContext.java new file mode 100644 index 00000000000..8df243e43d5 --- /dev/null +++ b/src/main/java/net/minecraftforge/client/model/geometry/IGeometryBakingContext.java @@ -0,0 +1,94 @@ +/* + * Copyright (c) Forge Development LLC and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.minecraftforge.client.model.geometry; + +import com.mojang.math.Transformation; +import net.minecraft.client.renderer.block.model.ItemTransforms; +import net.minecraft.client.resources.model.Material; +import net.minecraft.resources.ResourceLocation; +import net.minecraftforge.client.NamedRenderTypeManager; +import net.minecraftforge.client.RenderTypeGroup; +import org.jetbrains.annotations.Nullable; + +/** + * The context in which a geometry is being baked, providing information such as lighting and + * {@linkplain ItemTransforms transforms}, and allowing the user to create {@linkplain Material materials} and query + * {@linkplain RenderTypeGroup render types}. + * + * @see StandaloneGeometryBakingContext + * @see BlockGeometryBakingContext + */ +public interface IGeometryBakingContext +{ + /** + * {@return the name of the model being baked for logging and caching purposes.} + */ + String getModelName(); + + /** + * Checks if a material is present in the model. + * + * @param name The name of the material + * @return true if the material is present, false otherwise + */ + boolean hasMaterial(String name); + + /** + * Resolves the final texture name, taking into account texture aliases and replacements. + * + * @param name The name of the material + * @return The material, or the missing texture if not found + */ + Material getMaterial(String name); + + /** + * {@return true if this model should render in 3D in a GUI, false otherwise} + */ + boolean isGui3d(); + + /** + * {@return true if block lighting should be used for this model, false otherwise} + */ + boolean useBlockLight(); + + /** + * {@return true if per-vertex ambient occlusion should be used for this model, false otherwise} + */ + boolean useAmbientOcclusion(); + + /** + * {@return the transforms for display in item form.} + */ + ItemTransforms getTransforms(); + + /** + * {@return the root transformation to be applied to all variants of this model, regardless of item transforms.} + */ + Transformation getRootTransform(); + + /** + * {@return a hint of the render type this model should use. Custom loaders may ignore this.} + */ + @Nullable + ResourceLocation getRenderTypeHint(); + + /** + * Queries the visibility of a component of this model. + * + * @param component The component for which to query visibility + * @param fallback The default visibility if an override isn't found + * @return The visibility of the component + */ + boolean isComponentVisible(String component, boolean fallback); + + /** + * {@return a {@link RenderTypeGroup} with the given name, or the empty group if not found.} + */ + default RenderTypeGroup getRenderType(ResourceLocation name) + { + return NamedRenderTypeManager.get(name); + } +} diff --git a/src/main/java/net/minecraftforge/client/model/geometry/IGeometryLoader.java b/src/main/java/net/minecraftforge/client/model/geometry/IGeometryLoader.java new file mode 100644 index 00000000000..17ad5d34b97 --- /dev/null +++ b/src/main/java/net/minecraftforge/client/model/geometry/IGeometryLoader.java @@ -0,0 +1,27 @@ +/* + * Copyright (c) Forge Development LLC and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.minecraftforge.client.model.geometry; + +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; +import net.minecraft.server.packs.resources.ResourceManagerReloadListener; +import net.minecraftforge.client.event.ModelEvent.RegisterGeometryLoaders; +import net.minecraftforge.client.event.RegisterClientReloadListenersEvent; + +/** + * A loader for custom {@linkplain IUnbakedGeometry model geometries}. + *

+ * If you do any caching, you should implement {@link ResourceManagerReloadListener} and register it with + * {@link RegisterClientReloadListenersEvent}. + * + * @see RegisterGeometryLoaders + * @see RegisterClientReloadListenersEvent + */ +public interface IGeometryLoader> +{ + T read(JsonObject jsonObject, JsonDeserializationContext deserializationContext) throws JsonParseException; +} diff --git a/src/main/java/net/minecraftforge/client/model/geometry/IModelGeometryPart.java b/src/main/java/net/minecraftforge/client/model/geometry/IModelGeometryPart.java deleted file mode 100644 index 2c86885284d..00000000000 --- a/src/main/java/net/minecraftforge/client/model/geometry/IModelGeometryPart.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (c) Forge Development LLC and contributors - * SPDX-License-Identifier: LGPL-2.1-only - */ - -package net.minecraftforge.client.model.geometry; - -import com.mojang.datafixers.util.Pair; -import net.minecraft.client.resources.model.ModelState; -import net.minecraft.client.resources.model.UnbakedModel; -import net.minecraft.client.resources.model.ModelBakery; -import net.minecraft.client.resources.model.Material; -import net.minecraft.client.renderer.texture.TextureAtlasSprite; -import net.minecraft.resources.ResourceLocation; -import net.minecraftforge.client.model.IModelBuilder; -import net.minecraftforge.client.model.IModelConfiguration; - -import java.util.Collection; -import java.util.Collections; -import java.util.Set; -import java.util.function.Function; - -public interface IModelGeometryPart -{ - String name(); - - void addQuads(IModelConfiguration owner, IModelBuilder modelBuilder, ModelBakery bakery, Function spriteGetter, ModelState modelTransform, ResourceLocation modelLocation); - - default Collection getTextures(IModelConfiguration owner, Function modelGetter, Set> missingTextureErrors) { - // No texture dependencies - return Collections.emptyList(); - } -} diff --git a/src/main/java/net/minecraftforge/client/model/geometry/IMultipartModelGeometry.java b/src/main/java/net/minecraftforge/client/model/geometry/IMultipartModelGeometry.java deleted file mode 100644 index 7afc9596e26..00000000000 --- a/src/main/java/net/minecraftforge/client/model/geometry/IMultipartModelGeometry.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) Forge Development LLC and contributors - * SPDX-License-Identifier: LGPL-2.1-only - */ - -package net.minecraftforge.client.model.geometry; - -import com.google.common.collect.Sets; -import com.mojang.datafixers.util.Pair; -import net.minecraft.client.resources.model.ModelState; -import net.minecraft.client.resources.model.UnbakedModel; -import net.minecraft.client.resources.model.ModelBakery; -import net.minecraft.client.resources.model.Material; -import net.minecraft.client.renderer.texture.TextureAtlasSprite; -import net.minecraft.resources.ResourceLocation; -import net.minecraftforge.client.model.IModelBuilder; -import net.minecraftforge.client.model.IModelConfiguration; - -import java.util.Collection; -import java.util.Optional; -import java.util.Set; -import java.util.function.Function; - -public interface IMultipartModelGeometry> extends ISimpleModelGeometry -{ - @Override - Collection getParts(); - - Optional getPart(String name); - - @Override - default void addQuads(IModelConfiguration owner, IModelBuilder modelBuilder, ModelBakery bakery, Function spriteGetter, ModelState modelTransform, ResourceLocation modelLocation) - { - getParts().stream().filter(part -> owner.getPartVisibility(part)) - .forEach(part -> part.addQuads(owner, modelBuilder, bakery, spriteGetter, modelTransform, modelLocation)); - } - - @Override - default Collection getTextures(IModelConfiguration owner, Function modelGetter, Set> missingTextureErrors) - { - Set combined = Sets.newHashSet(); - for (IModelGeometryPart part : getParts()) - combined.addAll(part.getTextures(owner, modelGetter, missingTextureErrors)); - return combined; - } -} diff --git a/src/main/java/net/minecraftforge/client/model/geometry/ISimpleModelGeometry.java b/src/main/java/net/minecraftforge/client/model/geometry/ISimpleModelGeometry.java deleted file mode 100644 index 362684fffa2..00000000000 --- a/src/main/java/net/minecraftforge/client/model/geometry/ISimpleModelGeometry.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (c) Forge Development LLC and contributors - * SPDX-License-Identifier: LGPL-2.1-only - */ - -package net.minecraftforge.client.model.geometry; - -import com.mojang.datafixers.util.Pair; -import net.minecraft.client.renderer.texture.TextureAtlasSprite; -import net.minecraft.resources.ResourceLocation; -import net.minecraftforge.client.model.IModelBuilder; -import net.minecraftforge.client.model.IModelConfiguration; - -import java.util.Collection; -import java.util.Set; -import java.util.function.Function; - -import net.minecraft.client.renderer.block.model.ItemOverrides; -import net.minecraft.client.resources.model.BakedModel; -import net.minecraft.client.resources.model.Material; -import net.minecraft.client.resources.model.ModelBakery; -import net.minecraft.client.resources.model.ModelState; -import net.minecraft.client.resources.model.UnbakedModel; - -public interface ISimpleModelGeometry> extends IModelGeometry -{ - @Override - default BakedModel bake(IModelConfiguration owner, ModelBakery bakery, Function spriteGetter, ModelState modelTransform, ItemOverrides overrides, ResourceLocation modelLocation) - { - TextureAtlasSprite particle = spriteGetter.apply(owner.resolveTexture("particle")); - - IModelBuilder builder = IModelBuilder.of(owner, overrides, particle); - - addQuads(owner, builder, bakery, spriteGetter, modelTransform, modelLocation); - - return builder.build(); - } - - void addQuads(IModelConfiguration owner, IModelBuilder modelBuilder, ModelBakery bakery, Function spriteGetter, ModelState modelTransform, ResourceLocation modelLocation); - - @Override - Collection getTextures(IModelConfiguration owner, Function modelGetter, Set> missingTextureErrors); -} diff --git a/src/main/java/net/minecraftforge/client/model/geometry/IModelGeometry.java b/src/main/java/net/minecraftforge/client/model/geometry/IUnbakedGeometry.java similarity index 50% rename from src/main/java/net/minecraftforge/client/model/geometry/IModelGeometry.java rename to src/main/java/net/minecraftforge/client/model/geometry/IUnbakedGeometry.java index b3327a54ee6..227d364752a 100644 --- a/src/main/java/net/minecraftforge/client/model/geometry/IModelGeometry.java +++ b/src/main/java/net/minecraftforge/client/model/geometry/IUnbakedGeometry.java @@ -6,38 +6,30 @@ package net.minecraftforge.client.model.geometry; import com.mojang.datafixers.util.Pair; -import net.minecraft.client.renderer.texture.TextureAtlasSprite; -import net.minecraft.resources.ResourceLocation; -import net.minecraftforge.client.model.IModelConfiguration; - -import java.util.Collection; -import java.util.Collections; -import java.util.Optional; -import java.util.Set; -import java.util.function.Function; - import net.minecraft.client.renderer.block.model.ItemOverrides; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.client.resources.model.BakedModel; import net.minecraft.client.resources.model.Material; import net.minecraft.client.resources.model.ModelBakery; import net.minecraft.client.resources.model.ModelState; import net.minecraft.client.resources.model.UnbakedModel; +import net.minecraft.resources.ResourceLocation; + +import java.util.Collection; +import java.util.Set; +import java.util.function.Function; /** * General interface for any model that can be baked, superset of vanilla {@link UnbakedModel}. - * Models can be baked to different vertex formats and with different state. + *

+ * Instances of this class ar usually created via {@link IGeometryLoader}. + * + * @see IGeometryLoader + * @see IGeometryBakingContext */ -public interface IModelGeometry> +public interface IUnbakedGeometry> { - default Collection getParts() { - return Collections.emptyList(); - } - - default Optional getPart(String name) { - return Optional.empty(); - } - - BakedModel bake(IModelConfiguration owner, ModelBakery bakery, Function spriteGetter, ModelState modelTransform, ItemOverrides overrides, ResourceLocation modelLocation); + BakedModel bake(IGeometryBakingContext context, ModelBakery bakery, Function spriteGetter, ModelState modelState, ItemOverrides overrides, ResourceLocation modelLocation); - Collection getTextures(IModelConfiguration owner, Function modelGetter, Set> missingTextureErrors); + Collection getMaterials(IGeometryBakingContext context, Function modelGetter, Set> missingTextureErrors); } diff --git a/src/main/java/net/minecraftforge/client/model/geometry/SimpleUnbakedGeometry.java b/src/main/java/net/minecraftforge/client/model/geometry/SimpleUnbakedGeometry.java new file mode 100644 index 00000000000..5a73213363a --- /dev/null +++ b/src/main/java/net/minecraftforge/client/model/geometry/SimpleUnbakedGeometry.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) Forge Development LLC and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.minecraftforge.client.model.geometry; + +import com.mojang.datafixers.util.Pair; +import net.minecraft.client.renderer.block.model.BakedQuad; +import net.minecraft.client.renderer.block.model.ItemOverrides; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.resources.model.BakedModel; +import net.minecraft.client.resources.model.Material; +import net.minecraft.client.resources.model.ModelBakery; +import net.minecraft.client.resources.model.ModelState; +import net.minecraft.client.resources.model.UnbakedModel; +import net.minecraft.resources.ResourceLocation; +import net.minecraftforge.client.RenderTypeGroup; +import net.minecraftforge.client.model.IModelBuilder; + +import java.util.Collection; +import java.util.Set; +import java.util.function.Function; + +/** + * Base class for implementations of {@link IUnbakedGeometry} which do not wish to handle model creation themselves, + * instead supplying {@linkplain BakedQuad baked quads} through a builder. + */ +public abstract class SimpleUnbakedGeometry> implements IUnbakedGeometry +{ + @Override + public BakedModel bake(IGeometryBakingContext context, ModelBakery bakery, Function spriteGetter, ModelState modelState, ItemOverrides overrides, ResourceLocation modelLocation) + { + TextureAtlasSprite particle = spriteGetter.apply(context.getMaterial("particle")); + + var renderTypeHint = context.getRenderTypeHint(); + var renderTypes = renderTypeHint != null ? context.getRenderType(renderTypeHint) : RenderTypeGroup.EMPTY; + IModelBuilder builder = IModelBuilder.of(context.useAmbientOcclusion(), context.useBlockLight(), context.isGui3d(), + context.getTransforms(), overrides, particle, renderTypes); + + addQuads(context, builder, bakery, spriteGetter, modelState, modelLocation); + + return builder.build(); + } + + protected abstract void addQuads(IGeometryBakingContext owner, IModelBuilder modelBuilder, ModelBakery bakery, Function spriteGetter, ModelState modelTransform, ResourceLocation modelLocation); + + @Override + public abstract Collection getMaterials(IGeometryBakingContext context, Function modelGetter, Set> missingTextureErrors); +} diff --git a/src/main/java/net/minecraftforge/client/model/geometry/StandaloneGeometryBakingContext.java b/src/main/java/net/minecraftforge/client/model/geometry/StandaloneGeometryBakingContext.java new file mode 100644 index 00000000000..623225d19e9 --- /dev/null +++ b/src/main/java/net/minecraftforge/client/model/geometry/StandaloneGeometryBakingContext.java @@ -0,0 +1,233 @@ +/* + * Copyright (c) Forge Development LLC and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.minecraftforge.client.model.geometry; + +import com.google.common.base.Predicates; +import com.mojang.math.Transformation; +import it.unimi.dsi.fastutil.objects.Object2BooleanMap; +import net.minecraft.client.renderer.block.model.ItemTransforms; +import net.minecraft.client.renderer.texture.MissingTextureAtlasSprite; +import net.minecraft.client.resources.model.Material; +import net.minecraft.resources.ResourceLocation; +import net.minecraftforge.client.textures.UnitTextureAtlasSprite; +import org.jetbrains.annotations.Nullable; + +import java.util.Map; +import java.util.function.BiPredicate; +import java.util.function.Function; +import java.util.function.Predicate; + +/** + * A {@linkplain IGeometryBakingContext geometry baking context} that is not bound to block/item model loading. + */ +public class StandaloneGeometryBakingContext implements IGeometryBakingContext +{ + public static final ResourceLocation LOCATION = new ResourceLocation("forge", "standalone"); + + public static final StandaloneGeometryBakingContext INSTANCE = create(LOCATION); + + public static StandaloneGeometryBakingContext create(ResourceLocation modelName) + { + return builder().build(modelName); + } + + public static StandaloneGeometryBakingContext create(Map textures) + { + return create(LOCATION, textures); + } + + public static StandaloneGeometryBakingContext create(ResourceLocation modelName, Map textures) + { + return builder().withTextures(textures, MissingTextureAtlasSprite.getLocation()).build(modelName); + } + + private final ResourceLocation modelName; + private final Predicate textureCheck; + private final Function textureLookup; + private final boolean isGui3d; + private final boolean useBlockLight; + private final boolean useAmbientOcclusion; + private final ItemTransforms transforms; + private final Transformation rootTransform; + @Nullable + private final ResourceLocation renderTypeHint; + private final BiPredicate visibilityTest; + + private StandaloneGeometryBakingContext(ResourceLocation modelName, Predicate textureCheck, + Function textureLookup, boolean isGui3d, + boolean useBlockLight, boolean useAmbientOcclusion, + ItemTransforms transforms, Transformation rootTransform, + @Nullable ResourceLocation renderTypeHint, + BiPredicate visibilityTest) + { + this.modelName = modelName; + this.textureCheck = textureCheck; + this.textureLookup = textureLookup; + this.isGui3d = isGui3d; + this.useBlockLight = useBlockLight; + this.useAmbientOcclusion = useAmbientOcclusion; + this.transforms = transforms; + this.rootTransform = rootTransform; + this.renderTypeHint = renderTypeHint; + this.visibilityTest = visibilityTest; + } + + @Override + public String getModelName() + { + return modelName.toString(); + } + + @Override + public boolean hasMaterial(String name) + { + return textureCheck.test(name); + } + + @Override + public Material getMaterial(String name) + { + return new Material(UnitTextureAtlasSprite.LOCATION, textureLookup.apply(name)); + } + + @Override + public boolean isGui3d() + { + return isGui3d; + } + + @Override + public boolean useBlockLight() + { + return useBlockLight; + } + + @Override + public boolean useAmbientOcclusion() + { + return useAmbientOcclusion; + } + + @Override + public ItemTransforms getTransforms() + { + return transforms; + } + + @Override + public Transformation getRootTransform() + { + return rootTransform; + } + + @Nullable + @Override + public ResourceLocation getRenderTypeHint() + { + return renderTypeHint; + } + + @Override + public boolean isComponentVisible(String component, boolean fallback) + { + return visibilityTest.test(component, fallback); + } + + public static Builder builder() + { + return new Builder(); + } + + public static Builder builder(IGeometryBakingContext parent) + { + return new Builder(parent); + } + + public static final class Builder + { + private Predicate textureCheck = Predicates.alwaysFalse(); + private Function textureLookup = $ -> MissingTextureAtlasSprite.getLocation(); + private boolean isGui3d = true; + private boolean useBlockLight = true; + private boolean useAmbientOcclusion = true; + private ItemTransforms transforms = ItemTransforms.NO_TRANSFORMS; + private Transformation rootTransform = Transformation.identity(); + @Nullable + private ResourceLocation renderTypeHint; + private BiPredicate visibilityTest = (c, def) -> def; + + private Builder() + { + } + + private Builder(IGeometryBakingContext parent) + { + this.textureCheck = parent::hasMaterial; + this.textureLookup = name -> parent.getMaterial(name).texture(); + this.isGui3d = parent.isGui3d(); + this.useBlockLight = parent.useBlockLight(); + this.useAmbientOcclusion = parent.useAmbientOcclusion(); + this.transforms = parent.getTransforms(); + this.rootTransform = parent.getRootTransform(); + this.renderTypeHint = parent.getRenderTypeHint(); + this.visibilityTest = parent::isComponentVisible; + } + + public Builder withTextures(Map textures, ResourceLocation defaultTexture) + { + this.textureCheck = textures::containsKey; + this.textureLookup = name -> textures.getOrDefault(name, defaultTexture); + return this; + } + + public Builder withGui3d(boolean isGui3d) + { + this.isGui3d = isGui3d; + return this; + } + + public Builder withUseBlockLight(boolean useBlockLight) + { + this.useBlockLight = useBlockLight; + return this; + } + + public Builder withUseAmbientOcclusion(boolean useAmbientOcclusion) + { + this.useAmbientOcclusion = useAmbientOcclusion; + return this; + } + + public Builder withTransforms(ItemTransforms transforms) + { + this.transforms = transforms; + return this; + } + + public Builder withRootTransform(Transformation rootTransform) + { + this.rootTransform = rootTransform; + return this; + } + + public Builder withRenderTypeHint(ResourceLocation renderTypeHint) + { + this.renderTypeHint = renderTypeHint; + return this; + } + + public Builder withVisibleComponents(Object2BooleanMap parts) + { + this.visibilityTest = parts::getOrDefault; + return this; + } + + public StandaloneGeometryBakingContext build(ResourceLocation modelName) + { + return new StandaloneGeometryBakingContext(modelName, textureCheck, textureLookup, isGui3d, useBlockLight, useAmbientOcclusion, transforms, rootTransform, renderTypeHint, visibilityTest); + } + } +} diff --git a/src/main/java/net/minecraftforge/client/model/geometry/UnbakedGeometryHelper.java b/src/main/java/net/minecraftforge/client/model/geometry/UnbakedGeometryHelper.java new file mode 100644 index 00000000000..e1938610459 --- /dev/null +++ b/src/main/java/net/minecraftforge/client/model/geometry/UnbakedGeometryHelper.java @@ -0,0 +1,233 @@ +/* + * Copyright (c) Forge Development LLC and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.minecraftforge.client.model.geometry; + +import com.mojang.math.Transformation; +import com.mojang.math.Vector3f; +import net.minecraft.Util; +import net.minecraft.client.renderer.block.model.BakedQuad; +import net.minecraft.client.renderer.block.model.BlockElement; +import net.minecraft.client.renderer.block.model.BlockElementFace; +import net.minecraft.client.renderer.block.model.BlockFaceUV; +import net.minecraft.client.renderer.block.model.BlockModel; +import net.minecraft.client.renderer.block.model.FaceBakery; +import net.minecraft.client.renderer.block.model.ItemModelGenerator; +import net.minecraft.client.renderer.texture.MissingTextureAtlasSprite; +import net.minecraft.client.renderer.texture.TextureAtlas; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.resources.model.BakedModel; +import net.minecraft.client.resources.model.Material; +import net.minecraft.client.resources.model.ModelBakery; +import net.minecraft.client.resources.model.ModelState; +import net.minecraft.core.Direction; +import net.minecraft.resources.ResourceLocation; +import net.minecraftforge.client.RenderTypeGroup; +import net.minecraftforge.client.model.IModelBuilder; +import net.minecraftforge.client.model.SimpleModelState; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.BitSet; +import java.util.HashMap; +import java.util.List; +import java.util.function.Function; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Helper for dealing with unbaked models and geometries. + */ +public class UnbakedGeometryHelper +{ + private static final ItemModelGenerator ITEM_MODEL_GENERATOR = new ItemModelGenerator(); + private static final FaceBakery FACE_BAKERY = new FaceBakery(); + + /** + * Explanation: + * This takes anything that looks like a valid resourcepack texture location, and tries to extract a resourcelocation out of it. + * 1. it will ignore anything up to and including an /assets/ folder, + * 2. it will take the next path component as a namespace, + * 3. it will match but skip the /textures/ part of the path, + * 4. it will take the rest of the path up to but excluding the .png extension as the resource path + * It's a best-effort situation, to allow model files exported by modelling software to be used without post-processing. + * Example: + * C:\Something\Or Other\src\main\resources\assets\mymodid\textures\item\my_thing.png + * ........................................--------_______----------_____________---- + * + * Result after replacing '\' to '/': mymodid:item/my_thing + */ + private static final Pattern FILESYSTEM_PATH_TO_RESLOC = + Pattern.compile("(?:.*[\\\\/]assets[\\\\/](?[a-z_-]+)[\\\\/]textures[\\\\/])?(?[a-z_\\\\/-]+)\\.png"); + + /** + * Resolves a material that may have been defined with a filesystem path instead of a proper {@link ResourceLocation}. + *

+ * The target atlas will always be {@link TextureAtlas#LOCATION_BLOCKS}. + */ + public static Material resolveDirtyMaterial(@Nullable String tex, IGeometryBakingContext owner) + { + if (tex == null) + return new Material(TextureAtlas.LOCATION_BLOCKS, MissingTextureAtlasSprite.getLocation()); + if (tex.startsWith("#")) + return owner.getMaterial(tex); + + // Attempt to convert a common (windows/linux/mac) filesystem path to a ResourceLocation. + // This makes no promises, if it doesn't work, too bad, fix your mtl file. + Matcher match = FILESYSTEM_PATH_TO_RESLOC.matcher(tex); + if (match.matches()) + { + String namespace = match.group("namespace"); + String path = match.group("path").replace("\\", "/"); + tex = namespace != null ? namespace + ":" + path : path; + } + + return new Material(TextureAtlas.LOCATION_BLOCKS, new ResourceLocation(tex)); + } + + /** + * Helper for baking {@link BlockModel} instances. Handles baking custom geometries and deferring item model baking. + */ + @ApiStatus.Internal + public static BakedModel bake(BlockModel blockModel, ModelBakery modelBakery, BlockModel owner, Function spriteGetter, ModelState modelState, ResourceLocation modelLocation, boolean guiLight3d) + { + IUnbakedGeometry customModel = blockModel.customData.getCustomGeometry(); + if (customModel != null) + return customModel.bake(blockModel.customData, modelBakery, spriteGetter, modelState, blockModel.getOverrides(modelBakery, owner, spriteGetter), modelLocation); + + Transformation rootTransform = blockModel.customData.getRootTransform(); + if (!rootTransform.isIdentity()) + modelState = new SimpleModelState(modelState.getRotation().compose(rootTransform), modelState.isUvLocked()); + + // Handle vanilla item models here, since vanilla has a shortcut for them + if (blockModel.getRootModel() == ModelBakery.GENERATION_MARKER) + return ITEM_MODEL_GENERATOR.generateBlockModel(spriteGetter, blockModel).bake(modelBakery, blockModel, spriteGetter, modelState, modelLocation, guiLight3d); + + var renderTypeHint = blockModel.customData.getRenderTypeHint(); + var renderTypes = renderTypeHint != null ? blockModel.customData.getRenderType(renderTypeHint) : RenderTypeGroup.EMPTY; + return blockModel.bakeVanilla(modelBakery, owner, spriteGetter, modelState, modelLocation, guiLight3d, renderTypes); + } + + /** + * Creates a list of {@linkplain BlockElement block elements} in the shape of the specified sprite. + * These can later be baked using the same, or another texture. + *

+ * The {@link Direction#NORTH} and {@link Direction#SOUTH} faces take up the whole surface. + */ + public static List createUnbakedItemElements(int layerIndex, TextureAtlasSprite sprite) + { + return ITEM_MODEL_GENERATOR.processFrames(layerIndex, "layer" + layerIndex, sprite); + } + + /** + * Creates a list of {@linkplain BlockElement block elements} in the shape of the specified sprite. + * These can later be baked using the same, or another texture. + *

+ * The {@link Direction#NORTH} and {@link Direction#SOUTH} faces take up only the pixels the texture uses. + */ + public static List createUnbakedItemMaskElements(int layerIndex, TextureAtlasSprite sprite) + { + var elements = createUnbakedItemElements(layerIndex, sprite); + elements.remove(0); // Remove north and south faces + + int width = sprite.getWidth(), height = sprite.getHeight(); + var bits = new BitSet(width * height); + + // For every frame in the texture, mark all the opaque pixels (this is what vanilla does too) + sprite.getUniqueFrames().forEach(frame -> { + for (int x = 0; x < width; x++) + for (int y = 0; y < height; y++) + if (!sprite.isTransparent(frame, x, y)) + bits.set(x + y * width); + }); + + // Scan in search of opaque pixels + for (int y = 0; y < height; y++) + { + int xStart = -1; + for (int x = 0; x < width; x++) + { + var opaque = bits.get(x + y * width); + if (opaque == (xStart == -1)) // (opaque && -1) || (!opaque && !-1) + { + if (xStart == -1) + { + // We have found the start of a new segment, continue + xStart = x; + continue; + } + + // The segment is over, expand down as far as possible + int yEnd = y + 1; + expand: + for (; yEnd < height; yEnd++) + for (int x2 = xStart; x2 <= x; x2++) + if (!bits.get(x2 + yEnd * width)) + break expand; + + // Mark all pixels in the area as visited + for (int i = xStart; i < x; i++) + for (int j = y; j < yEnd; j++) + bits.clear(i + j * width); + + // Create element + elements.add(new BlockElement( + new Vector3f(16 * xStart / (float) width, 16 - 16 * yEnd / (float) height, 7.5F), + new Vector3f(16 * x / (float) width, 16 - 16 * y / (float) height, 8.5F), + Util.make(new HashMap<>(), map -> { + for (Direction direction : Direction.values()) + map.put(direction, new BlockElementFace(null, layerIndex, "layer" + layerIndex, new BlockFaceUV(null, 0))); + }), + null, + true + )); + + // Reset xStart + xStart = -1; + } + } + } + return elements; + } + + /** + * Bakes a list of {@linkplain BlockElement block elements} and feeds the baked quads to a {@linkplain IModelBuilder model builder}. + */ + public static void bakeElements(IModelBuilder builder, List elements, Function spriteGetter, ModelState modelState, ResourceLocation modelLocation) + { + for (BlockElement element : elements) + { + element.faces.forEach((side, face) -> { + var sprite = spriteGetter.apply(new Material(TextureAtlas.LOCATION_BLOCKS, new ResourceLocation(face.texture))); + var quad = bakeElementFace(element, face, sprite, side, modelState, modelLocation); + if (face.cullForDirection == null) + builder.addUnculledFace(quad); + else + builder.addCulledFace(Direction.rotate(modelState.getRotation().getMatrix(), face.cullForDirection), quad); + }); + } + } + + /** + * Bakes a list of {@linkplain BlockElement block elements} and returns the list of baked quads. + */ + public static List bakeElements(List elements, Function spriteGetter, ModelState modelState, ResourceLocation modelLocation) + { + if (elements.isEmpty()) + return List.of(); + var list = new ArrayList(); + bakeElements(IModelBuilder.collecting(list), elements, spriteGetter, modelState, modelLocation); + return list; + } + + /** + * Turns a single {@link BlockElementFace} into a {@link BakedQuad}. + */ + public static BakedQuad bakeElementFace(BlockElement element, BlockElementFace face, TextureAtlasSprite sprite, Direction direction, ModelState state, ResourceLocation modelLocation) + { + return FACE_BAKERY.bakeQuad(element.from, element.to, face, sprite, direction, state, element.rotation, element.shade, modelLocation); + } +} diff --git a/src/main/java/net/minecraftforge/client/model/lighting/FlatQuadLighter.java b/src/main/java/net/minecraftforge/client/model/lighting/FlatQuadLighter.java new file mode 100644 index 00000000000..7aa273bc903 --- /dev/null +++ b/src/main/java/net/minecraftforge/client/model/lighting/FlatQuadLighter.java @@ -0,0 +1,75 @@ +/* + * Copyright (c) Forge Development LLC and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.minecraftforge.client.model.lighting; + +import net.minecraft.client.color.block.BlockColors; +import net.minecraft.client.renderer.LevelRenderer; +import net.minecraft.client.renderer.block.model.BakedQuad; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.level.BlockAndTintGetter; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; + +/** + * Implementation of {@link QuadLighter} that lights {@link BakedQuad quads} with flat lighting. + */ +public class FlatQuadLighter extends QuadLighter +{ + private static final Direction[] SIDES = Direction.values(); + + private static final float MAX_POSITION = 1f - 1e-2f; + private static final byte MAX_NORMAL = 127; + + private boolean isFullCube; + private final int[] packedLight = new int[7]; + + public FlatQuadLighter(BlockColors colors) + { + super(colors); + } + + @Override + protected void computeLightingAt(BlockAndTintGetter level, BlockPos pos, BlockState state) + { + isFullCube = Block.isShapeFullBlock(state.getCollisionShape(level, pos)); + for (Direction side : SIDES) + { + packedLight[side.ordinal()] = LevelRenderer.getLightColor(level, pos.relative(side)); + } + packedLight[6] = LevelRenderer.getLightColor(level, pos); + } + + @Override + protected float calculateBrightness(float[] position) + { + return 1.0f; // No shading in flat lighting + } + + @Override + protected int calculateLightmap(float[] position, byte[] normal) + { + if ((isFullCube || position[1] < -MAX_POSITION) && normal[1] <= -MAX_NORMAL) + return packedLight[Direction.DOWN.ordinal()]; + + if ((isFullCube || position[1] > MAX_POSITION) && normal[1] >= MAX_NORMAL) + return packedLight[Direction.UP.ordinal()]; + + if ((isFullCube || position[2] < -MAX_POSITION) && normal[2] <= -MAX_NORMAL) + return packedLight[Direction.NORTH.ordinal()]; + + if ((isFullCube || position[2] > MAX_POSITION) && normal[2] >= MAX_NORMAL) + return packedLight[Direction.SOUTH.ordinal()]; + + if ((isFullCube || position[0] < -MAX_POSITION) && normal[0] <= -MAX_NORMAL) + return packedLight[Direction.WEST.ordinal()]; + + if ((isFullCube || position[0] > MAX_POSITION) && normal[0] >= MAX_NORMAL) + return packedLight[Direction.EAST.ordinal()]; + + return packedLight[6]; + } +} diff --git a/src/main/java/net/minecraftforge/client/model/lighting/ForgeModelBlockRenderer.java b/src/main/java/net/minecraftforge/client/model/lighting/ForgeModelBlockRenderer.java new file mode 100644 index 00000000000..9ff79069348 --- /dev/null +++ b/src/main/java/net/minecraftforge/client/model/lighting/ForgeModelBlockRenderer.java @@ -0,0 +1,109 @@ +/* + * Copyright (c) Forge Development LLC and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.minecraftforge.client.model.lighting; + +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import net.minecraft.client.color.block.BlockColors; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.block.ModelBlockRenderer; +import net.minecraft.client.renderer.block.model.BakedQuad; +import net.minecraft.client.resources.model.BakedModel; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.util.RandomSource; +import net.minecraft.world.level.BlockAndTintGetter; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraftforge.client.model.data.ModelData; +import net.minecraftforge.common.ForgeConfig; + +import java.util.List; + +/** + * Wrapper around {@link ModelBlockRenderer} to allow rendering blocks via Forge's lighting pipeline. + */ +public class ForgeModelBlockRenderer extends ModelBlockRenderer +{ + private static final Direction[] SIDES = Direction.values(); + + private final ThreadLocal flatLighter, smoothLighter; + + public ForgeModelBlockRenderer(BlockColors colors) + { + super(colors); + this.flatLighter = ThreadLocal.withInitial(() -> new FlatQuadLighter(colors)); + this.smoothLighter = ThreadLocal.withInitial(() -> new SmoothQuadLighter(colors)); + } + + @Override + public void tesselateWithoutAO(BlockAndTintGetter level, BakedModel model, BlockState state, BlockPos pos, PoseStack poseStack, VertexConsumer vertexConsumer, boolean checkSides, RandomSource rand, long seed, int packedOverlay, ModelData modelData, RenderType renderType) + { + if (ForgeConfig.CLIENT.experimentalForgeLightPipelineEnabled.get()) + { + render(vertexConsumer, flatLighter.get(), level, model, state, pos, poseStack, checkSides, rand, seed, packedOverlay, modelData, renderType); + } + else + { + super.tesselateWithoutAO(level, model, state, pos, poseStack, vertexConsumer, checkSides, rand, seed, packedOverlay, modelData, renderType); + } + } + + @Override + public void tesselateWithAO(BlockAndTintGetter level, BakedModel model, BlockState state, BlockPos pos, PoseStack poseStack, VertexConsumer vertexConsumer, boolean checkSides, RandomSource rand, long seed, int packedOverlay, ModelData modelData, RenderType renderType) + { + if (ForgeConfig.CLIENT.experimentalForgeLightPipelineEnabled.get()) + { + render(vertexConsumer, smoothLighter.get(), level, model, state, pos, poseStack, checkSides, rand, seed, packedOverlay, modelData, renderType); + } + else + { + super.tesselateWithAO(level, model, state, pos, poseStack, vertexConsumer, checkSides, rand, seed, packedOverlay, modelData, renderType); + } + } + + public static boolean render(VertexConsumer vertexConsumer, QuadLighter lighter, BlockAndTintGetter level, BakedModel model, BlockState state, BlockPos pos, PoseStack poseStack, boolean checkSides, RandomSource rand, long seed, int packedOverlay, ModelData modelData, RenderType renderType) + { + var pose = poseStack.last(); + var empty = true; + + rand.setSeed(seed); + List quads = model.getQuads(state, null, rand, modelData, renderType); + if (!quads.isEmpty()) + { + empty = false; + lighter.setup(level, pos, state); + for (BakedQuad quad : quads) + { + lighter.process(vertexConsumer, pose, quad, packedOverlay); + } + } + + for (Direction side : SIDES) + { + if (checkSides && !Block.shouldRenderFace(state, level, pos, side, pos.relative(side))) + { + continue; + } + rand.setSeed(seed); + quads = model.getQuads(state, side, rand, modelData, renderType); + if (!quads.isEmpty()) + { + if (empty) + { + empty = false; + lighter.setup(level, pos, state); + } + for (BakedQuad quad : quads) + { + lighter.process(vertexConsumer, pose, quad, packedOverlay); + } + } + } + lighter.reset(); + return !empty; + } +} diff --git a/src/main/java/net/minecraftforge/client/model/lighting/QuadLighter.java b/src/main/java/net/minecraftforge/client/model/lighting/QuadLighter.java new file mode 100644 index 00000000000..209d2ce6c7f --- /dev/null +++ b/src/main/java/net/minecraftforge/client/model/lighting/QuadLighter.java @@ -0,0 +1,153 @@ +/* + * Copyright (c) Forge Development LLC and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.minecraftforge.client.model.lighting; + +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.mojang.math.Vector3f; +import net.minecraft.client.color.block.BlockColors; +import net.minecraft.client.renderer.block.model.BakedQuad; +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.BlockAndTintGetter; +import net.minecraft.world.level.block.state.BlockState; + +import java.util.Objects; + +import static net.minecraftforge.client.model.IQuadTransformer.*; + +/** + * Base class for all quad lighting providers. + *

+ * Contains all the shared elements needed for {@link BakedQuad} processing and defers lighting logic to inheritors. + * + * @see FlatQuadLighter + * @see SmoothQuadLighter + */ +public abstract class QuadLighter +{ + private static final float[] WHITE = new float[] { 1.0f, 1.0f, 1.0f }; + + private final BlockColors colors; + + private int currentHash = 0; + private BlockAndTintGetter level; + private BlockPos pos; + private BlockState state; + private int cachedTintIndex = -1; + private final float[] cachedTintColor = new float[3]; + + // Arrays used for quad processing, initialized once and then used repeatedly to avoid GC pressure + private final float[] brightness = new float[4]; + private final int[] lightmap = new int[4]; + private final float[][] positions = new float[4][3]; + private final byte[][] normals = new byte[4][3]; + private final int[] packedLightmaps = new int[4]; + + protected QuadLighter(BlockColors colors) + { + this.colors = colors; + } + + protected abstract void computeLightingAt(BlockAndTintGetter level, BlockPos pos, BlockState state); + + protected abstract float calculateBrightness(float[] position); + + protected abstract int calculateLightmap(float[] position, byte[] normal); + + public final void setup(BlockAndTintGetter level, BlockPos pos, BlockState state) + { + var hash = Objects.hash(level, pos, state); + if (this.level != null && this.currentHash == hash) + { + return; // If we are drawing a block at the same position as before, don't re-compute anything + } + this.currentHash = hash; + this.level = level; + this.pos = pos; + this.state = state; + this.cachedTintIndex = -1; + computeLightingAt(level, pos, state); + } + + public final void reset() + { + this.level = null; // Invalidates part of the state to force a re-computation + } + + public final void process(VertexConsumer consumer, PoseStack.Pose pose, BakedQuad quad, int overlay) + { + var vertices = quad.getVertices(); + for (int i = 0; i < 4; i++) + { + int offset = i * STRIDE; + positions[i][0] = Float.intBitsToFloat(vertices[offset + POSITION]); + positions[i][1] = Float.intBitsToFloat(vertices[offset + POSITION + 1]); + positions[i][2] = Float.intBitsToFloat(vertices[offset + POSITION + 2]); + int packedNormal = vertices[offset + NORMAL]; + normals[i][0] = (byte) (packedNormal & 0xFF); + normals[i][1] = (byte) ((packedNormal >> 8) & 0xFF); + normals[i][2] = (byte) ((packedNormal >> 16) & 0xFF); + packedLightmaps[i] = vertices[offset + UV2]; + } + if (normals[0][0] == 0 && normals[0][1] == 0 && normals[0][2] == 0) + { + Vector3f a = new Vector3f(positions[0]); + Vector3f ab = new Vector3f(positions[1]); + Vector3f ac = new Vector3f(positions[2]); + ac.sub(a); + ab.sub(a); + ab.cross(ac); + ab.normalize(); + for (int v = 0; v < 4; v++) + { + normals[v][0] = (byte) (ab.x() * 127); + normals[v][1] = (byte) (ab.y() * 127); + normals[v][2] = (byte) (ab.z() * 127); + } + } + + for (int i = 0; i < 4; i++) + { + var position = positions[i]; + var normal = normals[i]; + int packedLightmap = packedLightmaps[i]; + + var adjustedPosition = new float[] { + position[0] - 0.5f + ((normal[0] / 127f) * 0.5f), + position[1] - 0.5f + ((normal[1] / 127f) * 0.5f), + position[2] - 0.5f + ((normal[2] / 127f) * 0.5f) + }; + + var shade = level.getShade(normals[i][0] / 127f, normals[i][1] / 127f, normals[i][2] / 127f, quad.isShade()); + brightness[i] = calculateBrightness(adjustedPosition) * shade; + int newLightmap = calculateLightmap(adjustedPosition, normal); + lightmap[i] = Math.max(packedLightmap & 0xFFFF, newLightmap & 0xFFFF) | + (Math.max((packedLightmap >> 16) & 0xFFFF, (newLightmap >> 16) & 0xFFFF) << 16); + } + + var color = quad.isTinted() ? getColorFast(quad.getTintIndex()) : WHITE; + consumer.putBulkData(pose, quad, brightness, color[0], color[1], color[2], lightmap, overlay, true); + } + + private float[] getColorFast(int tintIndex) + { + if (tintIndex != cachedTintIndex) + { + var packedColor = colors.getColor(state, level, pos, tintIndex); + cachedTintIndex = tintIndex; + cachedTintColor[0] = ((packedColor >> 16) & 0xFF) / 255F; + cachedTintColor[1] = ((packedColor >> 8) & 0xFF) / 255F; + cachedTintColor[2] = (packedColor & 0xFF) / 255F; + } + return cachedTintColor; + } + + public static float calculateShade(float normalX, float normalY, float normalZ, boolean constantAmbientLight) + { + float yFactor = constantAmbientLight ? 0.9F : ((3.0F + normalY) / 4.0F); + return Math.min(normalX * normalX * 0.6F + normalY * normalY * yFactor + normalZ * normalZ * 0.8F, 1.0F); + } +} diff --git a/src/main/java/net/minecraftforge/client/model/lighting/SmoothQuadLighter.java b/src/main/java/net/minecraftforge/client/model/lighting/SmoothQuadLighter.java new file mode 100644 index 00000000000..248ce63bc6b --- /dev/null +++ b/src/main/java/net/minecraftforge/client/model/lighting/SmoothQuadLighter.java @@ -0,0 +1,256 @@ +/* + * Copyright (c) Forge Development LLC and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.minecraftforge.client.model.lighting; + +import net.minecraft.client.color.block.BlockColors; +import net.minecraft.client.renderer.LevelRenderer; +import net.minecraft.client.renderer.LightTexture; +import net.minecraft.client.renderer.block.model.BakedQuad; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.util.Mth; +import net.minecraft.world.level.BlockAndTintGetter; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.shapes.Shapes; + +/** + * Implementation of {@link QuadLighter} that lights {@link BakedQuad baked quads} using ambient occlusion and + * light interpolation. + */ +public class SmoothQuadLighter extends QuadLighter +{ + private static final Direction[] SIDES = Direction.values(); + + private final BlockPos.MutableBlockPos pos = new BlockPos.MutableBlockPos(); + private final boolean[][][] t = new boolean[3][3][3]; + private final int[][][] s = new int[3][3][3]; + private final int[][][] b = new int[3][3][3]; + private final float[][][][] skyLight = new float[3][2][2][2]; + private final float[][][][] blockLight = new float[3][2][2][2]; + private final float[][][] ao = new float[3][3][3]; + + public SmoothQuadLighter(BlockColors colors) + { + super(colors); + } + + @Override + protected void computeLightingAt(BlockAndTintGetter level, BlockPos origin, BlockState state) + { + for (int x = 0; x <= 2; x++) + { + for (int y = 0; y <= 2; y++) + { + for (int z = 0; z <= 2; z++) + { + pos.setWithOffset(origin, x - 1, y - 1, z - 1); + BlockState neighborState = level.getBlockState(pos); + t[x][y][z] = neighborState.getLightBlock(level, pos) < 15; + int brightness = LevelRenderer.getLightColor(level, pos); + s[x][y][z] = LightTexture.sky(brightness); + b[x][y][z] = LightTexture.block(brightness); + ao[x][y][z] = neighborState.getShadeBrightness(level, pos); + } + } + } + for (Direction side : SIDES) + { + pos.setWithOffset(origin, side); + BlockState neighborState = level.getBlockState(pos); + + BlockState thisStateShape = state.canOcclude() && state.useShapeForLightOcclusion() ? state : Blocks.AIR.defaultBlockState(); + BlockState otherStateShape = neighborState.canOcclude() && neighborState.useShapeForLightOcclusion() ? neighborState : Blocks.AIR.defaultBlockState(); + + if (neighborState.getLightBlock(level, pos) == 15 || Shapes.faceShapeOccludes(thisStateShape.getFaceOcclusionShape(level, origin, side), otherStateShape.getFaceOcclusionShape(level, pos, side.getOpposite()))) + { + int x = side.getStepX() + 1; + int y = side.getStepY() + 1; + int z = side.getStepZ() + 1; + s[x][y][z] = Math.max(s[1][1][1] - 1, s[x][y][z]); + b[x][y][z] = Math.max(b[1][1][1] - 1, b[x][y][z]); + } + } + for (int x = 0; x < 2; x++) + { + for (int y = 0; y < 2; y++) + { + for (int z = 0; z < 2; z++) + { + int x1 = x * 2; + int y1 = y * 2; + int z1 = z * 2; + + int sxyz = s[x1][y1][z1]; + int bxyz = b[x1][y1][z1]; + boolean txyz = t[x1][y1][z1]; + + int sxz = s[x1][1][z1], sxy = s[x1][y1][1], syz = s[1][y1][z1]; + int bxz = b[x1][1][z1], bxy = b[x1][y1][1], byz = b[1][y1][z1]; + boolean txz = t[x1][1][z1], txy = t[x1][y1][1], tyz = t[1][y1][z1]; + + int sx = s[x1][1][1], sy = s[1][y1][1], sz = s[1][1][z1]; + int bx = b[x1][1][1], by = b[1][y1][1], bz = b[1][1][z1]; + boolean tx = t[x1][1][1], ty = t[1][y1][1], tz = t[1][1][z1]; + + skyLight[0][x][y][z] = combine(sx, sxz, sxy, txz || txy ? sxyz : sx, + tx, txz, txy, txz || txy ? txyz : tx); + blockLight[0][x][y][z] = combine(bx, bxz, bxy, txz || txy ? bxyz : bx, + tx, txz, txy, txz || txy ? txyz : tx); + + skyLight[1][x][y][z] = combine(sy, sxy, syz, txy || tyz ? sxyz : sy, + ty, txy, tyz, txy || tyz ? txyz : ty); + blockLight[1][x][y][z] = combine(by, bxy, byz, txy || tyz ? bxyz : by, + ty, txy, tyz, txy || tyz ? txyz : ty); + + skyLight[2][x][y][z] = combine(sz, syz, sxz, tyz || txz ? sxyz : sz, + tz, tyz, txz, tyz || txz ? txyz : tz); + blockLight[2][x][y][z] = combine(bz, byz, bxz, tyz || txz ? bxyz : bz, + tz, tyz, txz, tyz || txz ? txyz : tz); + } + } + } + } + + @Override + protected float calculateBrightness(float[] position) + { + float x = position[0], y = position[1], z = position[2]; + int sx = x < 0 ? 1 : 2; + int sy = y < 0 ? 1 : 2; + int sz = z < 0 ? 1 : 2; + + if (x < 0) x++; + if (y < 0) y++; + if (z < 0) z++; + + float a = 0; + a += ao[sx - 1][sy - 1][sz - 1] * (1 - x) * (1 - y) * (1 - z); + a += ao[sx - 1][sy - 1][sz - 0] * (1 - x) * (1 - y) * (0 + z); + a += ao[sx - 1][sy - 0][sz - 1] * (1 - x) * (0 + y) * (1 - z); + a += ao[sx - 1][sy - 0][sz - 0] * (1 - x) * (0 + y) * (0 + z); + a += ao[sx - 0][sy - 1][sz - 1] * (0 + x) * (1 - y) * (1 - z); + a += ao[sx - 0][sy - 1][sz - 0] * (0 + x) * (1 - y) * (0 + z); + a += ao[sx - 0][sy - 0][sz - 1] * (0 + x) * (0 + y) * (1 - z); + a += ao[sx - 0][sy - 0][sz - 0] * (0 + x) * (0 + y) * (0 + z); + + a = Mth.clamp(a, 0, 1); + return a; + } + + @Override + protected int calculateLightmap(float[] position, byte[] normal) + { + var block = (int) (calcLightmap(blockLight, position[0], position[1], position[2]) * 0xF0); + var sky = (int) (calcLightmap(skyLight, position[0], position[1], position[2]) * 0xF0); + return block | (sky << 16); + } + + private float combine(int c, int s1, int s2, int s3, boolean t0, boolean t1, boolean t2, boolean t3) + { + if (c == 0 && !t0) c = Math.max(0, Math.max(s1, s2) - 1); + if (s1 == 0 && !t1) s1 = Math.max(0, c - 1); + if (s2 == 0 && !t2) s2 = Math.max(0, c - 1); + if (s3 == 0 && !t3) s3 = Math.max(0, Math.max(s1, s2) - 1); + return (c + s1 + s2 + s3) / (0xF * 4f); + } + + protected float calcLightmap(float[][][][] light, float x, float y, float z) + { + x *= 2; + y *= 2; + z *= 2; + float l2 = x * x + y * y + z * z; + if (l2 > 6 - 2e-2f) + { + float s = (float) Math.sqrt((6 - 2e-2f) / l2); + x *= s; + y *= s; + z *= s; + } + float ax = x > 0 ? x : -x; + float ay = y > 0 ? y : -y; + float az = z > 0 ? z : -z; + float e1 = 1 + 1e-4f; + if (ax > 2 - 1e-4f && ay <= e1 && az <= e1) + { + x = x < 0 ? -2 + 1e-4f : 2 - 1e-4f; + } + else if (ay > 2 - 1e-4f && az <= e1 && ax <= e1) + { + y = y < 0 ? -2 + 1e-4f : 2 - 1e-4f; + } + else if (az > 2 - 1e-4f && ax <= e1 && ay <= e1) + { + z = z < 0 ? -2 + 1e-4f : 2 - 1e-4f; + } + ax = x > 0 ? x : -x; + ay = y > 0 ? y : -y; + az = z > 0 ? z : -z; + if (ax <= e1 && ay + az > 3f - 1e-4f) + { + float s = (3f - 1e-4f) / (ay + az); + y *= s; + z *= s; + } + else if (ay <= e1 && az + ax > 3f - 1e-4f) + { + float s = (3f - 1e-4f) / (az + ax); + z *= s; + x *= s; + } + else if (az <= e1 && ax + ay > 3f - 1e-4f) + { + float s = (3f - 1e-4f) / (ax + ay); + x *= s; + y *= s; + } + else if (ax + ay + az > 4 - 1e-4f) + { + float s = (4 - 1e-4f) / (ax + ay + az); + x *= s; + y *= s; + z *= s; + } + + float l = 0; + float s = 0; + + for (int ix = 0; ix <= 1; ix++) + { + for (int iy = 0; iy <= 1; iy++) + { + for (int iz = 0; iz <= 1; iz++) + { + float vx = x * (1 - ix * 2); + float vy = y * (1 - iy * 2); + float vz = z * (1 - iz * 2); + + float s3 = vx + vy + vz + 4; + float sx = vy + vz + 3; + float sy = vz + vx + 3; + float sz = vx + vy + 3; + + float bx = (2 * vx + vy + vz + 6) / (s3 * sy * sz * (vx + 2)); + s += bx; + l += bx * light[0][ix][iy][iz]; + + float by = (2 * vy + vz + vx + 6) / (s3 * sz * sx * (vy + 2)); + s += by; + l += by * light[1][ix][iy][iz]; + + float bz = (2 * vz + vx + vy + 6) / (s3 * sx * sy * (vz + 2)); + s += bz; + l += bz * light[2][ix][iy][iz]; + } + } + } + + l /= s; + l = Mth.clamp(l, 0, 1); + return l; + } +} diff --git a/src/main/java/net/minecraftforge/client/model/obj/OBJLoader.java b/src/main/java/net/minecraftforge/client/model/obj/OBJLoader.java deleted file mode 100644 index fcc2b695213..00000000000 --- a/src/main/java/net/minecraftforge/client/model/obj/OBJLoader.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright (c) Forge Development LLC and contributors - * SPDX-License-Identifier: LGPL-2.1-only - */ - -package net.minecraftforge.client.model.obj; - -import com.google.common.collect.Maps; -import com.google.gson.JsonDeserializationContext; -import com.google.gson.JsonObject; -import net.minecraft.client.Minecraft; -import net.minecraft.server.packs.resources.Resource; -import net.minecraft.server.packs.resources.ResourceManager; -import net.minecraft.util.GsonHelper; -import net.minecraft.resources.ResourceLocation; -import net.minecraftforge.client.model.IModelLoader; -import org.jetbrains.annotations.Nullable; - -import java.io.FileNotFoundException; -import java.util.*; - -public class OBJLoader implements IModelLoader -{ - public static OBJLoader INSTANCE = new OBJLoader(); - - private final Map modelCache = Maps.newHashMap(); - private final Map materialCache = Maps.newHashMap(); - - private ResourceManager manager = Minecraft.getInstance().getResourceManager(); - - @Override - public void onResourceManagerReload(ResourceManager resourceManager) - { - modelCache.clear(); - materialCache.clear(); - manager = resourceManager; - } - - @Override - public OBJModel read(JsonDeserializationContext deserializationContext, JsonObject modelContents) - { - if (!modelContents.has("model")) - throw new RuntimeException("OBJ Loader requires a 'model' key that points to a valid .OBJ model."); - - String modelLocation = modelContents.get("model").getAsString(); - - boolean detectCullableFaces = GsonHelper.getAsBoolean(modelContents, "detectCullableFaces", true); - boolean diffuseLighting = GsonHelper.getAsBoolean(modelContents, "diffuseLighting", false); - boolean flipV = GsonHelper.getAsBoolean(modelContents, "flip-v", false); - boolean ambientToFullbright = GsonHelper.getAsBoolean(modelContents, "ambientToFullbright", true); - @Nullable - String materialLibraryOverrideLocation = modelContents.has("materialLibraryOverride") ? GsonHelper.getAsString(modelContents, "materialLibraryOverride") : null; - - return loadModel(new OBJModel.ModelSettings(new ResourceLocation(modelLocation), detectCullableFaces, diffuseLighting, flipV, ambientToFullbright, materialLibraryOverrideLocation)); - } - - public OBJModel loadModel(OBJModel.ModelSettings settings) - { - return modelCache.computeIfAbsent(settings, (data) -> { - Resource resource = manager.getResource(settings.modelLocation()).orElseThrow(); - try(LineReader rdr = new LineReader(resource)) - { - return new OBJModel(rdr, settings); - } - catch (FileNotFoundException e) - { - throw new RuntimeException("Could not find OBJ model", e); - } - catch (Exception e) - { - throw new RuntimeException("Could not read OBJ model", e); - } - }); - } - - public MaterialLibrary loadMaterialLibrary(ResourceLocation materialLocation) - { - return materialCache.computeIfAbsent(materialLocation, (location) -> { - Resource resource = manager.getResource(location).orElseThrow(); - try(LineReader rdr = new LineReader(resource)) - { - return new MaterialLibrary(rdr); - } - catch (FileNotFoundException e) - { - throw new RuntimeException("Could not find OBJ material library", e); - } - catch (Exception e) - { - throw new RuntimeException("Could not read OBJ material library", e); - } - }); - } -} diff --git a/src/main/java/net/minecraftforge/client/model/obj/ObjLoader.java b/src/main/java/net/minecraftforge/client/model/obj/ObjLoader.java new file mode 100644 index 00000000000..3c2bf40eb88 --- /dev/null +++ b/src/main/java/net/minecraftforge/client/model/obj/ObjLoader.java @@ -0,0 +1,130 @@ +/* + * Copyright (c) Forge Development LLC and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.minecraftforge.client.model.obj; + +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Maps; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; +import net.minecraft.client.Minecraft; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.packs.resources.Resource; +import net.minecraft.server.packs.resources.ResourceManager; +import net.minecraft.server.packs.resources.ResourceManagerReloadListener; +import net.minecraft.util.GsonHelper; +import net.minecraftforge.client.model.geometry.IGeometryLoader; + +import java.io.FileNotFoundException; +import java.util.Map; + +/** + * A loader for {@link ObjModel OBJ models}. + *

+ * Allows the user to enable automatic face culling, toggle quad shading, flip UVs, render emissively and specify a + * {@link ObjMaterialLibrary material library} override. + */ +public class ObjLoader implements IGeometryLoader, ResourceManagerReloadListener +{ + public static ObjLoader INSTANCE = new ObjLoader(); + + private final Map modelCache = Maps.newHashMap(); + private final Map materialCache = Maps.newHashMap(); + + private ResourceManager manager = Minecraft.getInstance().getResourceManager(); + + @Override + public void onResourceManagerReload(ResourceManager resourceManager) + { + modelCache.clear(); + materialCache.clear(); + manager = resourceManager; + } + + @Override + public ObjModel read(JsonObject jsonObject, JsonDeserializationContext deserializationContext) + { + if (!jsonObject.has("model")) + throw new JsonParseException("OBJ Loader requires a 'model' key that points to a valid .OBJ model."); + + String modelLocation = jsonObject.get("model").getAsString(); + + boolean automaticCulling = GsonHelper.getAsBoolean(jsonObject, "automatic_culling", true); + boolean shadeQuads = GsonHelper.getAsBoolean(jsonObject, "shade_quads", true); + boolean flipV = GsonHelper.getAsBoolean(jsonObject, "flip_v", false); + boolean emissiveAmbient = GsonHelper.getAsBoolean(jsonObject, "emissive_ambient", true); + String mtlOverride = GsonHelper.getAsString(jsonObject, "mtl_override", null); + + // TODO: Deprecated names. To be removed in 1.20 + var deprecationWarningsBuilder = ImmutableMap.builder(); + if (jsonObject.has("detectCullableFaces")) + { + automaticCulling = GsonHelper.getAsBoolean(jsonObject, "detectCullableFaces"); + deprecationWarningsBuilder.put("detectCullableFaces", "automatic_culling"); + } + if (jsonObject.has("diffuseLighting")) + { + shadeQuads = GsonHelper.getAsBoolean(jsonObject, "diffuseLighting"); + deprecationWarningsBuilder.put("diffuseLighting", "shade_quads"); + } + if (jsonObject.has("flip-v")) + { + flipV = GsonHelper.getAsBoolean(jsonObject, "flip-v"); + deprecationWarningsBuilder.put("flip-v", "flip_v"); + } + if (jsonObject.has("ambientToFullbright")) + { + emissiveAmbient = GsonHelper.getAsBoolean(jsonObject, "ambientToFullbright"); + deprecationWarningsBuilder.put("ambientToFullbright", "emissive_ambient"); + } + if (jsonObject.has("materialLibraryOverride")) + { + mtlOverride = GsonHelper.getAsString(jsonObject, "materialLibraryOverride"); + deprecationWarningsBuilder.put("materialLibraryOverride", "mtl_override"); + } + + return loadModel(new ObjModel.ModelSettings(new ResourceLocation(modelLocation), automaticCulling, shadeQuads, flipV, emissiveAmbient, mtlOverride), deprecationWarningsBuilder.build()); + } + + public ObjModel loadModel(ObjModel.ModelSettings settings) + { + return loadModel(settings, Map.of()); + } + + private ObjModel loadModel(ObjModel.ModelSettings settings, Map deprecationWarnings) + { + return modelCache.computeIfAbsent(settings, (data) -> { + Resource resource = manager.getResource(settings.modelLocation()).orElseThrow(); + try (ObjTokenizer tokenizer = new ObjTokenizer(resource.open())) + { + return ObjModel.parse(tokenizer, settings, deprecationWarnings); + } catch (FileNotFoundException e) + { + throw new RuntimeException("Could not find OBJ model", e); + } catch (Exception e) + { + throw new RuntimeException("Could not read OBJ model", e); + } + }); + } + + public ObjMaterialLibrary loadMaterialLibrary(ResourceLocation materialLocation) + { + return materialCache.computeIfAbsent(materialLocation, (location) -> { + Resource resource = manager.getResource(location).orElseThrow(); + try (ObjTokenizer rdr = new ObjTokenizer(resource.open())) + { + return new ObjMaterialLibrary(rdr); + } catch (FileNotFoundException e) + { + throw new RuntimeException("Could not find OBJ material library", e); + } catch (Exception e) + { + throw new RuntimeException("Could not read OBJ material library", e); + } + }); + } +} diff --git a/src/main/java/net/minecraftforge/client/model/obj/MaterialLibrary.java b/src/main/java/net/minecraftforge/client/model/obj/ObjMaterialLibrary.java similarity index 78% rename from src/main/java/net/minecraftforge/client/model/obj/MaterialLibrary.java rename to src/main/java/net/minecraftforge/client/model/obj/ObjMaterialLibrary.java index 3785cb894ec..df967b78969 100644 --- a/src/main/java/net/minecraftforge/client/model/obj/MaterialLibrary.java +++ b/src/main/java/net/minecraftforge/client/model/obj/ObjMaterialLibrary.java @@ -6,31 +6,34 @@ package net.minecraftforge.client.model.obj; import com.google.common.collect.Maps; -import joptsimple.internal.Strings; import com.mojang.math.Vector4f; +import joptsimple.internal.Strings; import java.io.IOException; import java.util.Arrays; import java.util.Map; import java.util.NoSuchElementException; -public class MaterialLibrary +/** + * An OBJ material library (MTL), composed of named {@link Material materials}. + */ +public class ObjMaterialLibrary { - public static final MaterialLibrary EMPTY = new MaterialLibrary(); + public static final ObjMaterialLibrary EMPTY = new ObjMaterialLibrary(); final Map materials = Maps.newHashMap(); - private MaterialLibrary() + private ObjMaterialLibrary() { } - public MaterialLibrary(LineReader reader) throws IOException + public ObjMaterialLibrary(ObjTokenizer reader) throws IOException { Material currentMaterial = null; String[] line; - while((line = reader.readAndSplitLine(true)) != null) + while ((line = reader.readAndSplitLine(true)) != null) { - switch(line[0]) + switch (line[0]) { case "newmtl": { @@ -41,16 +44,16 @@ public MaterialLibrary(LineReader reader) throws IOException } case "Ka": - currentMaterial.ambientColor = OBJModel.parseVector4(line); + currentMaterial.ambientColor = ObjModel.parseVector4(line); break; case "map_Ka": // Ignores all options params - currentMaterial.ambientColorMap = line[line.length-1]; + currentMaterial.ambientColorMap = line[line.length - 1]; break; case "Kd": - currentMaterial.diffuseColor = OBJModel.parseVector4(line); + currentMaterial.diffuseColor = ObjModel.parseVector4(line); break; case "forge_TintIndex": @@ -59,11 +62,11 @@ public MaterialLibrary(LineReader reader) throws IOException case "map_Kd": // Ignores all options params - currentMaterial.diffuseColorMap = line[line.length-1]; + currentMaterial.diffuseColorMap = line[line.length - 1]; break; case "Ks": - currentMaterial.specularColor = OBJModel.parseVector4(line); + currentMaterial.specularColor = ObjModel.parseVector4(line); break; case "Ns": @@ -72,7 +75,7 @@ public MaterialLibrary(LineReader reader) throws IOException case "map_Ks": // Ignores all options params - currentMaterial.specularColorMap = line[line.length-1]; + currentMaterial.specularColorMap = line[line.length - 1]; break; case "d": @@ -97,11 +100,11 @@ public Material getMaterial(String mat) public static class Material { public final String name; - public Vector4f ambientColor = new Vector4f(0,0,0,1); + public Vector4f ambientColor = new Vector4f(0, 0, 0, 1); public String ambientColorMap; - public Vector4f diffuseColor = new Vector4f(1,1,1,1); + public Vector4f diffuseColor = new Vector4f(1, 1, 1, 1); public String diffuseColorMap; - public Vector4f specularColor = new Vector4f(0,0,0,1); + public Vector4f specularColor = new Vector4f(0, 0, 0, 1); public float specularHighlight = 0; public String specularColorMap; diff --git a/src/main/java/net/minecraftforge/client/model/obj/OBJModel.java b/src/main/java/net/minecraftforge/client/model/obj/ObjModel.java similarity index 51% rename from src/main/java/net/minecraftforge/client/model/obj/OBJModel.java rename to src/main/java/net/minecraftforge/client/model/obj/ObjModel.java index b31d2214bcd..a1c92a8bfb9 100644 --- a/src/main/java/net/minecraftforge/client/model/obj/OBJModel.java +++ b/src/main/java/net/minecraftforge/client/model/obj/ObjModel.java @@ -5,47 +5,61 @@ package net.minecraftforge.client.model.obj; -import com.google.common.collect.ImmutableList; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Sets; +import com.mojang.math.Transformation; +import com.mojang.math.Vector3f; +import com.mojang.math.Vector4f; import joptsimple.internal.Strings; +import net.minecraft.client.renderer.LightTexture; +import net.minecraft.client.renderer.block.model.BakedQuad; import net.minecraft.client.renderer.texture.TextureAtlasSprite; -import com.mojang.blaze3d.vertex.VertexFormatElement; +import net.minecraft.client.resources.model.Material; +import net.minecraft.client.resources.model.ModelBakery; +import net.minecraft.client.resources.model.ModelState; +import net.minecraft.client.resources.model.UnbakedModel; import net.minecraft.core.Direction; import net.minecraft.resources.ResourceLocation; import net.minecraft.util.Mth; -import com.mojang.math.Transformation; import net.minecraft.world.phys.Vec2; -import com.mojang.math.Vector3f; -import com.mojang.math.Vector4f; -import net.minecraftforge.client.model.*; -import net.minecraftforge.client.model.geometry.IModelGeometryPart; -import net.minecraftforge.client.model.geometry.IMultipartModelGeometry; -import net.minecraftforge.client.model.pipeline.BakedQuadBuilder; -import net.minecraftforge.client.model.pipeline.IVertexConsumer; -import net.minecraftforge.client.model.renderable.SimpleRenderable; -import net.minecraftforge.client.textures.UnitSprite; +import net.minecraftforge.client.model.IModelBuilder; +import net.minecraftforge.client.model.geometry.IGeometryBakingContext; +import net.minecraftforge.client.model.geometry.SimpleUnbakedGeometry; +import net.minecraftforge.client.model.geometry.UnbakedGeometryHelper; +import net.minecraftforge.client.model.pipeline.QuadBakingVertexConsumer; +import net.minecraftforge.client.model.renderable.CompositeRenderable; +import net.minecraftforge.client.textures.UnitTextureAtlasSprite; import org.apache.commons.lang3.tuple.Pair; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.io.IOException; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.Stream; -import net.minecraft.client.renderer.block.model.BakedQuad; -import net.minecraft.client.resources.model.Material; -import net.minecraft.client.resources.model.ModelBakery; -import net.minecraft.client.resources.model.ModelState; -import net.minecraft.client.resources.model.UnbakedModel; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -public class OBJModel implements IMultipartModelGeometry +/** + * A model loaded from an OBJ file. + *

+ * Supports positions, texture coordinates, normals and colors. The {@link ObjMaterialLibrary material library} + * has support for numerous features, including support for {@link ResourceLocation} textures (non-standard). + */ +public class ObjModel extends SimpleUnbakedGeometry { - private static Vector4f COLOR_WHITE = new Vector4f(1, 1, 1, 1); - private static Vec2[] DEFAULT_COORDS = { + private static final Logger LOGGER = LogManager.getLogger(); + + private static final Vector4f COLOR_WHITE = new Vector4f(1, 1, 1, 1); + private static final Vec2[] DEFAULT_COORDS = { new Vec2(0, 0), new Vec2(0, 1), new Vec2(1, 1), @@ -59,37 +73,50 @@ public class OBJModel implements IMultipartModelGeometry private final List normals = Lists.newArrayList(); private final List colors = Lists.newArrayList(); - public final boolean detectCullableFaces; - public final boolean diffuseLighting; + public final boolean automaticCulling; + public final boolean shadeQuads; public final boolean flipV; - public final boolean ambientToFullbright; + public final boolean emissiveAmbient; + @Nullable + public final String mtlOverride; public final ResourceLocation modelLocation; - @Nullable - public final String materialLibraryOverrideLocation; - + private final Map deprecationWarnings; - OBJModel(LineReader reader, ModelSettings settings) throws IOException + private ObjModel(ModelSettings settings, Map deprecationWarnings) { this.modelLocation = settings.modelLocation; - this.detectCullableFaces = settings.detectCullableFaces; - this.diffuseLighting = settings.diffuseLighting; + this.automaticCulling = settings.automaticCulling; + this.shadeQuads = settings.shadeQuads; this.flipV = settings.flipV; - this.ambientToFullbright = settings.ambientToFullbright; - this.materialLibraryOverrideLocation = settings.materialLibraryOverrideLocation; + this.emissiveAmbient = settings.emissiveAmbient; + this.mtlOverride = settings.mtlOverride; + this.deprecationWarnings = deprecationWarnings; + } + + public static ObjModel parse(ObjTokenizer tokenizer, ModelSettings settings) throws IOException + { + return parse(tokenizer, settings, Map.of()); + } + + static ObjModel parse(ObjTokenizer tokenizer, ModelSettings settings, Map deprecationWarnings) throws IOException + { + var modelLocation = settings.modelLocation; + var materialLibraryOverrideLocation = settings.mtlOverride; + var model = new ObjModel(settings, deprecationWarnings); // for relative references to material libraries String modelDomain = modelLocation.getNamespace(); String modelPath = modelLocation.getPath(); int lastSlash = modelPath.lastIndexOf('/'); if (lastSlash >= 0) - modelPath = modelPath.substring(0,lastSlash+1); // include the '/' + modelPath = modelPath.substring(0, lastSlash + 1); // include the '/' else modelPath = ""; - MaterialLibrary mtllib = MaterialLibrary.EMPTY; - MaterialLibrary.Material currentMat = null; + ObjMaterialLibrary mtllib = ObjMaterialLibrary.EMPTY; + ObjMaterialLibrary.Material currentMat = null; String currentSmoothingGroup = null; ModelGroup currentGroup = null; ModelObject currentObject = null; @@ -101,15 +128,15 @@ public class OBJModel implements IMultipartModelGeometry { String lib = materialLibraryOverrideLocation; if (lib.contains(":")) - mtllib = OBJLoader.INSTANCE.loadMaterialLibrary(new ResourceLocation(lib)); + mtllib = ObjLoader.INSTANCE.loadMaterialLibrary(new ResourceLocation(lib)); else - mtllib = OBJLoader.INSTANCE.loadMaterialLibrary(new ResourceLocation(modelDomain, modelPath + lib)); + mtllib = ObjLoader.INSTANCE.loadMaterialLibrary(new ResourceLocation(modelDomain, modelPath + lib)); } String[] line; - while((line = reader.readAndSplitLine(true)) != null) + while ((line = tokenizer.readAndSplitLine(true)) != null) { - switch(line[0]) + switch (line[0]) { case "mtllib": // Loads material library { @@ -118,16 +145,16 @@ public class OBJModel implements IMultipartModelGeometry String lib = line[1]; if (lib.contains(":")) - mtllib = OBJLoader.INSTANCE.loadMaterialLibrary(new ResourceLocation(lib)); + mtllib = ObjLoader.INSTANCE.loadMaterialLibrary(new ResourceLocation(lib)); else - mtllib = OBJLoader.INSTANCE.loadMaterialLibrary(new ResourceLocation(modelDomain, modelPath + lib)); + mtllib = ObjLoader.INSTANCE.loadMaterialLibrary(new ResourceLocation(modelDomain, modelPath + lib)); break; } case "usemtl": // Sets the current material (starts new mesh) { String mat = Strings.join(Arrays.copyOfRange(line, 1, line.length), " "); - MaterialLibrary.Material newMat = mtllib.getMaterial(mat); + ObjMaterialLibrary.Material newMat = mtllib.getMaterial(mat); if (!Objects.equals(newMat, currentMat)) { currentMat = newMat; @@ -145,23 +172,23 @@ public class OBJModel implements IMultipartModelGeometry } case "v": // Vertex - positions.add(parseVector4To3(line)); + model.positions.add(parseVector4To3(line)); break; case "vt": // Vertex texcoord - texCoords.add(parseVector2(line)); + model.texCoords.add(parseVector2(line)); break; case "vn": // Vertex normal - normals.add(parseVector3(line)); + model.normals.add(parseVector3(line)); break; case "vc": // Vertex color (non-standard) - colors.add(parseVector4(line)); + model.colors.add(parseVector4(line)); break; case "f": // Face { if (currentMesh == null) { - currentMesh = new ModelMesh(currentMat, currentSmoothingGroup); + currentMesh = model.new ModelMesh(currentMat, currentSmoothingGroup); if (currentObject != null) { currentObject.meshes.add(currentMesh); @@ -170,32 +197,32 @@ public class OBJModel implements IMultipartModelGeometry { if (currentGroup == null) { - currentGroup = new ModelGroup(""); - parts.put("", currentGroup); + currentGroup = model.new ModelGroup(""); + model.parts.put("", currentGroup); } currentGroup.meshes.add(currentMesh); } } - int[][] vertices = new int[line.length-1][]; - for(int i=0;i Strings.isNullOrEmpty(num) ? 0 : Integer.parseInt(num)).toArray(); - if (vertex[0] < 0) vertex[0] = positions.size() + vertex[0]; + if (vertex[0] < 0) vertex[0] = model.positions.size() + vertex[0]; else vertex[0]--; if (vertex.length > 1) { - if (vertex[1] < 0) vertex[1] = texCoords.size() + vertex[1]; + if (vertex[1] < 0) vertex[1] = model.texCoords.size() + vertex[1]; else vertex[1]--; if (vertex.length > 2) { - if (vertex[2] < 0) vertex[2] = normals.size() + vertex[2]; + if (vertex[2] < 0) vertex[2] = model.normals.size() + vertex[2]; else vertex[2]--; if (vertex.length > 3) { - if (vertex[3] < 0) vertex[3] = colors.size() + vertex[3]; + if (vertex[3] < 0) vertex[3] = model.colors.size() + vertex[3]; else vertex[3]--; } } @@ -232,13 +259,13 @@ public class OBJModel implements IMultipartModelGeometry String name = line[1]; if (objAboveGroup) { - currentObject = new ModelObject(currentGroup.name() + "/" + name); + currentObject = model.new ModelObject(currentGroup.name() + "/" + name); currentGroup.parts.put(name, currentObject); } else { - currentGroup = new ModelGroup(name); - parts.put(name, currentGroup); + currentGroup = model.new ModelGroup(name); + model.parts.put(name, currentGroup); currentObject = null; } // Start new mesh @@ -253,13 +280,13 @@ public class OBJModel implements IMultipartModelGeometry { objAboveGroup = true; - currentGroup = new ModelGroup(name); - parts.put(name, currentGroup); + currentGroup = model.new ModelGroup(name); + model.parts.put(name, currentGroup); currentObject = null; } else { - currentObject = new ModelObject(currentGroup.name() + "/" + name); + currentObject = model.new ModelObject(currentGroup.name() + "/" + name); currentGroup.parts.put(name, currentObject); } // Start new mesh @@ -268,78 +295,81 @@ public class OBJModel implements IMultipartModelGeometry } } } + return model; } - public static Vector3f parseVector4To3(String[] line) + private static Vector3f parseVector4To3(String[] line) { - switch (line.length) { - case 1: return new Vector3f(0,0,0); - case 2: return new Vector3f(Float.parseFloat(line[1]), 0, 0); - case 3: return new Vector3f(Float.parseFloat(line[1]), Float.parseFloat(line[2]), 0); - case 4: return new Vector3f(Float.parseFloat(line[1]), Float.parseFloat(line[2]), Float.parseFloat(line[3])); - default: - { - Vector4f vec4 = parseVector4(line); - return new Vector3f( - vec4.x() / vec4.w(), - vec4.y() / vec4.w(), - vec4.z() / vec4.w() - ); - } - } + Vector4f vec4 = parseVector4(line); + return new Vector3f( + vec4.x() / vec4.w(), + vec4.y() / vec4.w(), + vec4.z() / vec4.w() + ); } - public static Vec2 parseVector2(String[] line) + private static Vec2 parseVector2(String[] line) { - switch (line.length) { - case 1: return new Vec2(0,0); - case 2: return new Vec2(Float.parseFloat(line[1]), 0); - default: return new Vec2(Float.parseFloat(line[1]), Float.parseFloat(line[2])); - } + return switch (line.length) + { + case 1 -> new Vec2(0, 0); + case 2 -> new Vec2(Float.parseFloat(line[1]), 0); + default -> new Vec2(Float.parseFloat(line[1]), Float.parseFloat(line[2])); + }; } - public static Vector3f parseVector3(String[] line) + private static Vector3f parseVector3(String[] line) { - switch (line.length) { - case 1: return new Vector3f(0,0,0); - case 2: return new Vector3f(Float.parseFloat(line[1]), 0, 0); - case 3: return new Vector3f(Float.parseFloat(line[1]), Float.parseFloat(line[2]), 0); - default: return new Vector3f(Float.parseFloat(line[1]), Float.parseFloat(line[2]), Float.parseFloat(line[3])); - } + return switch (line.length) + { + case 1 -> new Vector3f(0, 0, 0); + case 2 -> new Vector3f(Float.parseFloat(line[1]), 0, 0); + case 3 -> new Vector3f(Float.parseFloat(line[1]), Float.parseFloat(line[2]), 0); + default -> new Vector3f(Float.parseFloat(line[1]), Float.parseFloat(line[2]), Float.parseFloat(line[3])); + }; } - public static Vector4f parseVector4(String[] line) + static Vector4f parseVector4(String[] line) { - switch (line.length) { - case 1: return new Vector4f(0,0,0,1); - case 2: return new Vector4f(Float.parseFloat(line[1]), 0, 0,1); - case 3: return new Vector4f(Float.parseFloat(line[1]), Float.parseFloat(line[2]), 0,1); - case 4: return new Vector4f(Float.parseFloat(line[1]), Float.parseFloat(line[2]), Float.parseFloat(line[3]),1); - default: return new Vector4f(Float.parseFloat(line[1]), Float.parseFloat(line[2]), Float.parseFloat(line[3]), Float.parseFloat(line[4])); - } + return switch (line.length) + { + case 1 -> new Vector4f(0, 0, 0, 1); + case 2 -> new Vector4f(Float.parseFloat(line[1]), 0, 0, 1); + case 3 -> new Vector4f(Float.parseFloat(line[1]), Float.parseFloat(line[2]), 0, 1); + case 4 -> new Vector4f(Float.parseFloat(line[1]), Float.parseFloat(line[2]), Float.parseFloat(line[3]), 1); + default -> new Vector4f(Float.parseFloat(line[1]), Float.parseFloat(line[2]), Float.parseFloat(line[3]), Float.parseFloat(line[4])); + }; } @Override - public Collection getParts() + protected void addQuads(IGeometryBakingContext owner, IModelBuilder modelBuilder, ModelBakery bakery, Function spriteGetter, ModelState modelTransform, ResourceLocation modelLocation) { - return parts.values(); + for (var entry : deprecationWarnings.entrySet()) + LOGGER.warn("Model \"" + modelLocation + "\" is using the deprecated \"" + entry.getKey() + "\" field in its OBJ model instead of \"" + entry.getValue() + "\". This field will be removed in 1.20."); + + parts.values().stream().filter(part -> owner.isComponentVisible(part.name(), true)) + .forEach(part -> part.addQuads(owner, modelBuilder, bakery, spriteGetter, modelTransform, modelLocation)); } @Override - public Optional getPart(String name) + public Collection getMaterials(IGeometryBakingContext context, Function modelGetter, Set> missingTextureErrors) { - return Optional.ofNullable(parts.get(name)); + Set combined = Sets.newHashSet(); + for (ModelGroup part : parts.values()) + combined.addAll(part.getTextures(context, modelGetter, missingTextureErrors)); + return combined; } - private Pair makeQuad(int[][] indices, int tintIndex, Vector4f colorTint, Vector4f ambientColor, TextureAtlasSprite texture, Transformation transform) + private Pair makeQuad(int[][] indices, int tintIndex, Vector4f colorTint, Vector4f ambientColor, TextureAtlasSprite texture, Transformation transform) { boolean needsNormalRecalculation = false; for (int[] ints : indices) { needsNormalRecalculation |= ints.length < 3; } - Vector3f faceNormal = new Vector3f(0,0,0); - if (needsNormalRecalculation) { + Vector3f faceNormal = new Vector3f(0, 0, 0); + if (needsNormalRecalculation) + { Vector3f a = positions.get(indices[0][0]); Vector3f ab = positions.get(indices[1][0]); Vector3f ac = positions.get(indices[2][0]); @@ -352,34 +382,35 @@ private Pair makeQuad(int[][] indices, int tintIndex, Vecto faceNormal = abs; } - Vector4f[] pos = new Vector4f[4]; - Vector3f[] norm = new Vector3f[4]; - - BakedQuadBuilder builder = new BakedQuadBuilder(texture); + var quad = new BakedQuad[1]; + var quadBaker = new QuadBakingVertexConsumer(q -> quad[0] = q); - builder.setQuadTint(tintIndex); + quadBaker.setSprite(texture); + quadBaker.setTintIndex(tintIndex); - Vec2 uv2 = new Vec2(0, 0); - if (ambientToFullbright) + int uv2 = 0; + if (emissiveAmbient) { int fakeLight = (int) ((ambientColor.x() + ambientColor.y() + ambientColor.z()) * 15 / 3.0f); - uv2 = new Vec2((fakeLight << 4) / 32767.0f, (fakeLight << 4) / 32767.0f); - builder.setApplyDiffuseLighting(fakeLight == 0); + uv2 = LightTexture.pack(fakeLight, fakeLight); + quadBaker.setShade(fakeLight == 0 && shadeQuads); } else { - builder.setApplyDiffuseLighting(diffuseLighting); + quadBaker.setShade(shadeQuads); } boolean hasTransform = !transform.isIdentity(); // The incoming transform is referenced on the center of the block, but our coords are referenced on the corner Transformation transformation = hasTransform ? transform.blockCenterToCorner() : transform; - for(int i=0;i<4;i++) + Vector4f[] pos = new Vector4f[4]; + Vector3f[] norm = new Vector3f[4]; + + for (int i = 0; i < 4; i++) { - int[] index = indices[Math.min(i,indices.length-1)]; - Vector3f pos0 = positions.get(index[0]); - Vector4f position = new Vector4f(pos0); + int[] index = indices[Math.min(i, indices.length - 1)]; + Vector4f position = new Vector4f(positions.get(index[0])); Vec2 texCoord = index.length >= 2 && texCoords.size() > 0 ? texCoords.get(index[1]) : DEFAULT_COORDS[i]; Vector3f norm0 = !needsNormalRecalculation && index.length >= 3 && normals.size() > 0 ? normals.get(index[2]) : faceNormal; Vector3f normal = norm0; @@ -389,121 +420,90 @@ private Pair makeQuad(int[][] indices, int tintIndex, Vecto normal = norm0.copy(); transformation.transformPosition(position); transformation.transformNormal(normal); - }; + } Vector4f tintedColor = new Vector4f( color.x() * colorTint.x(), color.y() * colorTint.y(), color.z() * colorTint.z(), color.w() * colorTint.w()); - putVertexData(builder, position, texCoord, normal, tintedColor, uv2, texture); + quadBaker.vertex(position.x(), position.y(), position.z()); + quadBaker.color(tintedColor.x(), tintedColor.y(), tintedColor.z(), tintedColor.w()); + quadBaker.uv( + texture.getU(texCoord.x * 16), + texture.getV((flipV ? 1 - texCoord.y : texCoord.y) * 16) + ); + quadBaker.uv2(uv2); + quadBaker.normal(normal.x(), normal.y(), normal.z()); + if (i == 0) + { + quadBaker.setDirection(Direction.getNearest(normal.x(), normal.y(), normal.z())); + } + quadBaker.endVertex(); pos[i] = position; norm[i] = normal; } - builder.setQuadOrientation(Direction.getNearest(norm[0].x(), norm[0].y(),norm[0].z())); - Direction cull = null; - if (detectCullableFaces) + if (automaticCulling) { if (Mth.equal(pos[0].x(), 0) && // vertex.position.x - Mth.equal(pos[1].x(), 0) && - Mth.equal(pos[2].x(), 0) && - Mth.equal(pos[3].x(), 0) && - norm[0].x() < 0) // vertex.normal.x + Mth.equal(pos[1].x(), 0) && + Mth.equal(pos[2].x(), 0) && + Mth.equal(pos[3].x(), 0) && + norm[0].x() < 0) // vertex.normal.x { cull = Direction.WEST; } else if (Mth.equal(pos[0].x(), 1) && // vertex.position.x - Mth.equal(pos[1].x(), 1) && - Mth.equal(pos[2].x(), 1) && - Mth.equal(pos[3].x(), 1) && - norm[0].x() > 0) // vertex.normal.x + Mth.equal(pos[1].x(), 1) && + Mth.equal(pos[2].x(), 1) && + Mth.equal(pos[3].x(), 1) && + norm[0].x() > 0) // vertex.normal.x { cull = Direction.EAST; } else if (Mth.equal(pos[0].z(), 0) && // vertex.position.z - Mth.equal(pos[1].z(), 0) && - Mth.equal(pos[2].z(), 0) && - Mth.equal(pos[3].z(), 0) && - norm[0].z() < 0) // vertex.normal.z + Mth.equal(pos[1].z(), 0) && + Mth.equal(pos[2].z(), 0) && + Mth.equal(pos[3].z(), 0) && + norm[0].z() < 0) // vertex.normal.z { cull = Direction.NORTH; // can never remember } else if (Mth.equal(pos[0].z(), 1) && // vertex.position.z - Mth.equal(pos[1].z(), 1) && - Mth.equal(pos[2].z(), 1) && - Mth.equal(pos[3].z(), 1) && - norm[0].z() > 0) // vertex.normal.z + Mth.equal(pos[1].z(), 1) && + Mth.equal(pos[2].z(), 1) && + Mth.equal(pos[3].z(), 1) && + norm[0].z() > 0) // vertex.normal.z { cull = Direction.SOUTH; } else if (Mth.equal(pos[0].y(), 0) && // vertex.position.y - Mth.equal(pos[1].y(), 0) && - Mth.equal(pos[2].y(), 0) && - Mth.equal(pos[3].y(), 0) && - norm[0].y() < 0) // vertex.normal.z + Mth.equal(pos[1].y(), 0) && + Mth.equal(pos[2].y(), 0) && + Mth.equal(pos[3].y(), 0) && + norm[0].y() < 0) // vertex.normal.z { cull = Direction.DOWN; // can never remember } else if (Mth.equal(pos[0].y(), 1) && // vertex.position.y - Mth.equal(pos[1].y(), 1) && - Mth.equal(pos[2].y(), 1) && - Mth.equal(pos[3].y(), 1) && - norm[0].y() > 0) // vertex.normal.y + Mth.equal(pos[1].y(), 1) && + Mth.equal(pos[2].y(), 1) && + Mth.equal(pos[3].y(), 1) && + norm[0].y() > 0) // vertex.normal.y { cull = Direction.UP; } } - return Pair.of(builder.build(), cull); - } - - private void putVertexData(IVertexConsumer consumer, Vector4f position0, Vec2 texCoord0, Vector3f normal0, Vector4f color0, Vec2 uv2, TextureAtlasSprite texture) - { - ImmutableList elements = consumer.getVertexFormat().getElements(); - for(int j=0;j modelBuilder, ModelBakery bakery, Function spriteGetter, ModelState modelTransform, ResourceLocation modelLocation) + public void addQuads(IGeometryBakingContext owner, IModelBuilder modelBuilder, ModelBakery bakery, Function spriteGetter, ModelState modelTransform, ResourceLocation modelLocation) { - for(ModelMesh mesh : meshes) + for (ModelMesh mesh : meshes) { mesh.addQuads(owner, modelBuilder, spriteGetter, modelTransform); } } - public void bake(SimpleRenderable.PartBuilder builder, IModelConfiguration configuration) + public void bake(CompositeRenderable.PartBuilder builder, IGeometryBakingContext configuration) { for (ModelMesh mesh : this.meshes) { @@ -547,14 +545,13 @@ public void bake(SimpleRenderable.PartBuilder builder, IModelConfiguration co } } - @Override - public Collection getTextures(IModelConfiguration owner, Function modelGetter, Set> missingTextureErrors) + public Collection getTextures(IGeometryBakingContext owner, Function modelGetter, Set> missingTextureErrors) { return meshes.stream() - .flatMap(mesh -> mesh.mat != null - ? Stream.of(ModelLoaderRegistry.resolveTexture(mesh.mat.diffuseColorMap, owner)) - : Stream.of()) - .collect(Collectors.toSet()); + .flatMap(mesh -> mesh.mat != null + ? Stream.of(UnbakedGeometryHelper.resolveDirtyMaterial(mesh.mat.diffuseColorMap, owner)) + : Stream.of()) + .collect(Collectors.toSet()); } } @@ -567,26 +564,21 @@ public class ModelGroup extends ModelObject super(name); } - public Collection getParts() - { - return parts.values(); - } - @Override - public void addQuads(IModelConfiguration owner, IModelBuilder modelBuilder, ModelBakery bakery, Function spriteGetter, ModelState modelTransform, ResourceLocation modelLocation) + public void addQuads(IGeometryBakingContext owner, IModelBuilder modelBuilder, ModelBakery bakery, Function spriteGetter, ModelState modelTransform, ResourceLocation modelLocation) { super.addQuads(owner, modelBuilder, bakery, spriteGetter, modelTransform, modelLocation); - getParts().stream().filter(owner::getPartVisibility) - .forEach(part -> part.addQuads(owner, modelBuilder, bakery, spriteGetter, modelTransform, modelLocation)); + parts.values().stream().filter(part -> owner.isComponentVisible(part.name(), true)) + .forEach(part -> part.addQuads(owner, modelBuilder, bakery, spriteGetter, modelTransform, modelLocation)); } @Override - public void bake(SimpleRenderable.PartBuilder builder, IModelConfiguration configuration) + public void bake(CompositeRenderable.PartBuilder builder, IGeometryBakingContext configuration) { super.bake(builder, configuration); - for(var entry : parts.entrySet()) + for (var entry : parts.entrySet()) { var name = entry.getKey(); var part = entry.getValue(); @@ -595,11 +587,11 @@ public void bake(SimpleRenderable.PartBuilder builder, IModelConfiguration co } @Override - public Collection getTextures(IModelConfiguration owner, Function modelGetter, Set> missingTextureErrors) + public Collection getTextures(IGeometryBakingContext owner, Function modelGetter, Set> missingTextureErrors) { Set combined = Sets.newHashSet(); combined.addAll(super.getTextures(owner, modelGetter, missingTextureErrors)); - for (IModelGeometryPart part : getParts()) + for (ModelObject part : parts.values()) combined.addAll(part.getTextures(owner, modelGetter, missingTextureErrors)); return combined; } @@ -608,22 +600,22 @@ public Collection getTextures(IModelConfiguration owner, Function faces = Lists.newArrayList(); - public ModelMesh(@Nullable MaterialLibrary.Material currentMat, @Nullable String currentSmoothingGroup) + public ModelMesh(@Nullable ObjMaterialLibrary.Material currentMat, @Nullable String currentSmoothingGroup) { this.mat = currentMat; this.smoothingGroup = currentSmoothingGroup; } - public void addQuads(IModelConfiguration owner, IModelBuilder modelBuilder, Function spriteGetter, ModelState modelTransform) + public void addQuads(IGeometryBakingContext owner, IModelBuilder modelBuilder, Function spriteGetter, ModelState modelTransform) { if (mat == null) return; - TextureAtlasSprite texture = spriteGetter.apply(ModelLoaderRegistry.resolveTexture(mat.diffuseColorMap, owner)); + TextureAtlasSprite texture = spriteGetter.apply(UnbakedGeometryHelper.resolveDirtyMaterial(mat.diffuseColorMap, owner)); int tintIndex = mat.diffuseTintIndex; Vector4f colorTint = mat.diffuseColor; @@ -631,15 +623,15 @@ public void addQuads(IModelConfiguration owner, IModelBuilder modelBuilder, F { Pair quad = makeQuad(face, tintIndex, colorTint, mat.ambientColor, texture, modelTransform.getRotation()); if (quad.getRight() == null) - modelBuilder.addGeneralQuad(quad.getLeft()); + modelBuilder.addUnculledFace(quad.getLeft()); else - modelBuilder.addFaceQuad(quad.getRight(), quad.getLeft()); + modelBuilder.addCulledFace(quad.getRight(), quad.getLeft()); } } - public void bake(SimpleRenderable.PartBuilder builder, IModelConfiguration configuration) + public void bake(CompositeRenderable.PartBuilder builder, IGeometryBakingContext configuration) { - MaterialLibrary.Material mat = this.mat; + ObjMaterialLibrary.Material mat = this.mat; if (mat == null) return; int tintIndex = mat.diffuseTintIndex; @@ -647,13 +639,13 @@ public void bake(SimpleRenderable.PartBuilder builder, IModelConfiguration co final List quads = new ArrayList<>(); - for(var face : this.faces) + for (var face : this.faces) { - var pair = makeQuad(face, tintIndex, colorTint, mat.ambientColor, UnitSprite.INSTANCE, Transformation.identity()); + var pair = makeQuad(face, tintIndex, colorTint, mat.ambientColor, UnitTextureAtlasSprite.INSTANCE, Transformation.identity()); quads.add(pair.getLeft()); } - ResourceLocation textureLocation = ModelLoaderRegistry.resolveTexture(mat.diffuseColorMap, configuration).texture(); + ResourceLocation textureLocation = UnbakedGeometryHelper.resolveDirtyMaterial(mat.diffuseColorMap, configuration).texture(); ResourceLocation texturePath = new ResourceLocation(textureLocation.getNamespace(), "textures/" + textureLocation.getPath() + ".png"); builder.addMesh(texturePath, quads); @@ -661,7 +653,7 @@ public void bake(SimpleRenderable.PartBuilder builder, IModelConfiguration co } public record ModelSettings(@NotNull ResourceLocation modelLocation, - boolean detectCullableFaces, boolean diffuseLighting, boolean flipV, - boolean ambientToFullbright, @Nullable String materialLibraryOverrideLocation) - {} + boolean automaticCulling, boolean shadeQuads, boolean flipV, + boolean emissiveAmbient, @Nullable String mtlOverride) + { } } diff --git a/src/main/java/net/minecraftforge/client/model/obj/LineReader.java b/src/main/java/net/minecraftforge/client/model/obj/ObjTokenizer.java similarity index 81% rename from src/main/java/net/minecraftforge/client/model/obj/LineReader.java rename to src/main/java/net/minecraftforge/client/model/obj/ObjTokenizer.java index 26831fe8a32..3bcc36b2db7 100644 --- a/src/main/java/net/minecraftforge/client/model/obj/LineReader.java +++ b/src/main/java/net/minecraftforge/client/model/obj/ObjTokenizer.java @@ -7,24 +7,28 @@ import com.google.common.base.Charsets; import joptsimple.internal.Strings; -import net.minecraft.server.packs.resources.Resource; import org.jetbrains.annotations.Nullable; import java.io.BufferedReader; import java.io.IOException; +import java.io.InputStream; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.Arrays; import java.util.List; -public class LineReader implements AutoCloseable +/** + * A tokenizer for OBJ and MTL files. + *

+ * Joins split lines and ignores comments. + */ +public class ObjTokenizer implements AutoCloseable { - InputStreamReader lineStream; - BufferedReader lineReader; + private final BufferedReader lineReader; - public LineReader(Resource resource) throws IOException { - this.lineStream = new InputStreamReader(resource.open(), Charsets.UTF_8); - this.lineReader = new BufferedReader(lineStream); + public ObjTokenizer(InputStream inputStream) + { + this.lineReader = new BufferedReader(new InputStreamReader(inputStream, Charsets.UTF_8)); } @Nullable @@ -74,9 +78,8 @@ public String[] readAndSplitLine(boolean ignoreEmptyLines) throws IOException } @Override - public void close() throws Exception + public void close() throws IOException { lineReader.close(); - lineStream.close(); } } diff --git a/src/main/java/net/minecraftforge/client/model/pipeline/BakedQuadBuilder.java b/src/main/java/net/minecraftforge/client/model/pipeline/BakedQuadBuilder.java deleted file mode 100644 index 280ea6ff846..00000000000 --- a/src/main/java/net/minecraftforge/client/model/pipeline/BakedQuadBuilder.java +++ /dev/null @@ -1,181 +0,0 @@ -/* - * Copyright (c) Forge Development LLC and contributors - * SPDX-License-Identifier: LGPL-2.1-only - */ - -package net.minecraftforge.client.model.pipeline; - -import com.google.common.collect.ImmutableList; - -import net.minecraft.client.renderer.block.model.BakedQuad; -import net.minecraft.client.renderer.texture.TextureAtlasSprite; -import com.mojang.blaze3d.vertex.DefaultVertexFormat; -import com.mojang.blaze3d.vertex.VertexFormat; -import com.mojang.blaze3d.vertex.VertexFormatElement; -import net.minecraft.core.Direction; - -/** - * Allows easier building of BakedQuad objects. During building, data is stored - * unpacked as floats, but is packed into the typical int array format on build. - */ -public class BakedQuadBuilder implements IVertexConsumer -{ - private static final int SIZE = DefaultVertexFormat.BLOCK.getElements().size(); - - private final float[][][] unpackedData = new float[4][SIZE][4]; - private int tint = -1; - private Direction orientation; - private TextureAtlasSprite texture; - private boolean applyDiffuseLighting = true; - - private int vertices = 0; - private int elements = 0; - private boolean full = false; - private boolean contractUVs = false; - - public BakedQuadBuilder() {} - - public BakedQuadBuilder(TextureAtlasSprite texture) - { - this.texture = texture; - } - - public void setContractUVs(boolean value) - { - this.contractUVs = value; - } - - @Override - public VertexFormat getVertexFormat() - { - return DefaultVertexFormat.BLOCK; - } - - @Override - public void setQuadTint(int tint) - { - this.tint = tint; - } - - @Override - public void setQuadOrientation(Direction orientation) - { - this.orientation = orientation; - } - - @Override - public void setTexture(TextureAtlasSprite texture) - { - this.texture = texture; - } - - @Override - public void setApplyDiffuseLighting(boolean diffuse) - { - this.applyDiffuseLighting = diffuse; - } - - @Override - public void put(int element, float... data) - { - for(int i = 0; i < 4; i++) - { - if(i < data.length) - { - unpackedData[vertices][element][i] = data[i]; - } - else - { - unpackedData[vertices][element][i] = 0; - } - } - elements++; - if(elements == SIZE) - { - vertices++; - elements = 0; - } - if(vertices == 4) - { - full = true; - } - } - - private final float eps = 1f / 0x100; - - public BakedQuad build() - { - if(!full) - { - throw new IllegalStateException("not enough data"); - } - if(texture == null) - { - throw new IllegalStateException("texture not set"); - } - if(contractUVs) - { - float tX = texture.getWidth() / (texture.getU1() - texture.getU0()); - float tY = texture.getHeight() / (texture.getV1() - texture.getV0()); - float tS = tX > tY ? tX : tY; - float ep = 1f / (tS * 0x100); - int uve = 0; - ImmutableList elements = DefaultVertexFormat.BLOCK.getElements(); - while(uve < elements.size()) - { - VertexFormatElement e = elements.get(uve); - if(e.getUsage() == VertexFormatElement.Usage.UV && e.getIndex() == 0) - { - break; - } - uve++; - } - if(uve == elements.size()) - { - throw new IllegalStateException("Can't contract UVs: format doesn't contain UVs"); - } - float[] uvc = new float[4]; - for(int v = 0; v < 4; v++) - { - for(int i = 0; i < 4; i++) - { - uvc[i] += unpackedData[v][uve][i] / 4; - } - } - for(int v = 0; v < 4; v++) - { - for (int i = 0; i < 4; i++) - { - float uo = unpackedData[v][uve][i]; - float un = uo * (1 - eps) + uvc[i] * eps; - float ud = uo - un; - float aud = ud; - if(aud < 0) aud = -aud; - if(aud < ep) // not moving a fraction of a pixel - { - float udc = uo - uvc[i]; - if(udc < 0) udc = -udc; - if(udc < 2 * ep) // center is closer than 2 fractions of a pixel, don't move too close - { - un = (uo + uvc[i]) / 2; - } - else // move at least by a fraction - { - un = uo + (ud < 0 ? ep : -ep); - } - } - unpackedData[v][uve][i] = un; - } - } - } - int[] packed = new int[DefaultVertexFormat.BLOCK.getIntegerSize() * 4]; - for (int v = 0; v < 4; v++) - { - for (int e = 0; e < SIZE; e++) - { - LightUtil.pack(unpackedData[v][e], packed, DefaultVertexFormat.BLOCK, v, e); - } - } - return new BakedQuad(packed, tint, orientation, texture, applyDiffuseLighting); - } -} diff --git a/src/main/java/net/minecraftforge/client/model/pipeline/BlockInfo.java b/src/main/java/net/minecraftforge/client/model/pipeline/BlockInfo.java deleted file mode 100644 index c183d9e17c3..00000000000 --- a/src/main/java/net/minecraftforge/client/model/pipeline/BlockInfo.java +++ /dev/null @@ -1,236 +0,0 @@ -/* - * Copyright (c) Forge Development LLC and contributors - * SPDX-License-Identifier: LGPL-2.1-only - */ - -package net.minecraftforge.client.model.pipeline; - -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.client.renderer.LightTexture; -import net.minecraft.client.renderer.LevelRenderer; -import net.minecraft.client.color.block.BlockColors; -import net.minecraft.core.Direction; -import net.minecraft.core.BlockPos; -import net.minecraft.world.phys.shapes.Shapes; -import net.minecraft.world.level.BlockAndTintGetter; - -public class BlockInfo -{ - private static final Direction[] SIDES = Direction.values(); - - private final BlockColors colors; - private BlockAndTintGetter level; - private BlockState state; - private BlockPos blockPos; - - private final boolean[][][] t = new boolean[3][3][3]; - private final int[][][] s = new int[3][3][3]; - private final int[][][] b = new int[3][3][3]; - private final float[][][][] skyLight = new float[3][2][2][2]; - private final float[][][][] blockLight = new float[3][2][2][2]; - private final float[][][] ao = new float[3][3][3]; - - private final int[] packed = new int[7]; - - private boolean full; - - private int cachedTint = -1; - private int cachedMultiplier = -1; - - public BlockInfo(BlockColors colors) - { - this.colors = colors; - } - - public int getColorMultiplier(int tint) - { - if(cachedTint == tint) return cachedMultiplier; - cachedTint = tint; - cachedMultiplier = colors.getColor(state, level, blockPos, tint); - return cachedMultiplier; - } - - public void setLevel(BlockAndTintGetter level) - { - this.level = level; - cachedTint = -1; - cachedMultiplier = -1; - } - - public void setState(BlockState state) - { - this.state = state; - cachedTint = -1; - cachedMultiplier = -1; - } - - public void setBlockPos(BlockPos blockPos) - { - this.blockPos = blockPos; - cachedTint = -1; - cachedMultiplier = -1; - } - - public void reset() - { - this.level = null; - this.state = null; - this.blockPos = null; - cachedTint = -1; - cachedMultiplier = -1; - } - - private float combine(int c, int s1, int s2, int s3, boolean t0, boolean t1, boolean t2, boolean t3) - { - if (c == 0 && !t0) c = Math.max(0, Math.max(s1, s2) - 1); - if (s1 == 0 && !t1) s1 = Math.max(0, c - 1); - if (s2 == 0 && !t2) s2 = Math.max(0, c - 1); - if (s3 == 0 && !t3) s3 = Math.max(0, Math.max(s1, s2) - 1); - return (c + s1 + s2 + s3) / (0xF * 4f); - } - - public void updateLightMatrix() - { - for(int x = 0; x <= 2; x++) - { - for(int y = 0; y <= 2; y++) - { - for(int z = 0; z <= 2; z++) - { - BlockPos pos = blockPos.offset(x - 1, y - 1, z - 1); - BlockState state = level.getBlockState(pos); - t[x][y][z] = state.getLightBlock(level, pos) < 15; - int brightness = LevelRenderer.getLightColor(level, pos); - s[x][y][z] = LightTexture.sky(brightness); - b[x][y][z] = LightTexture.block(brightness); - ao[x][y][z] = state.getShadeBrightness(level, pos); - } - } - } - for(Direction side : SIDES) - { - BlockPos pos = blockPos.relative(side); - BlockState state = level.getBlockState(pos); - - BlockState thisStateShape = this.state.canOcclude() && this.state.useShapeForLightOcclusion() ? this.state : Blocks.AIR.defaultBlockState(); - BlockState otherStateShape = state.canOcclude() && state.useShapeForLightOcclusion() ? state : Blocks.AIR.defaultBlockState(); - - if(state.getLightBlock(level, pos) == 15 || Shapes.faceShapeOccludes(thisStateShape.getFaceOcclusionShape(level, blockPos, side), otherStateShape.getFaceOcclusionShape(level, pos, side.getOpposite()))) - { - int x = side.getStepX() + 1; - int y = side.getStepY() + 1; - int z = side.getStepZ() + 1; - s[x][y][z] = Math.max(s[1][1][1] - 1, s[x][y][z]); - b[x][y][z] = Math.max(b[1][1][1] - 1, b[x][y][z]); - } - } - for(int x = 0; x < 2; x++) - { - for(int y = 0; y < 2; y++) - { - for(int z = 0; z < 2; z++) - { - int x1 = x * 2; - int y1 = y * 2; - int z1 = z * 2; - - int sxyz = s[x1][y1][z1]; - int bxyz = b[x1][y1][z1]; - boolean txyz = t[x1][y1][z1]; - - int sxz = s[x1][1][z1], sxy = s[x1][y1][1], syz = s[1][y1][z1]; - int bxz = b[x1][1][z1], bxy = b[x1][y1][1], byz = b[1][y1][z1]; - boolean txz = t[x1][1][z1], txy = t[x1][y1][1], tyz = t[1][y1][z1]; - - int sx = s[x1][1][1], sy = s[1][y1][1], sz = s[1][1][z1]; - int bx = b[x1][1][1], by = b[1][y1][1], bz = b[1][1][z1]; - boolean tx = t[x1][1][1], ty = t[1][y1][1], tz = t[1][1][z1]; - - skyLight [0][x][y][z] = combine(sx, sxz, sxy, txz || txy ? sxyz : sx, - tx, txz, txy, txz || txy ? txyz : tx); - blockLight[0][x][y][z] = combine(bx, bxz, bxy, txz || txy ? bxyz : bx, - tx, txz, txy, txz || txy ? txyz : tx); - - skyLight [1][x][y][z] = combine(sy, sxy, syz, txy || tyz ? sxyz : sy, - ty, txy, tyz, txy || tyz ? txyz : ty); - blockLight[1][x][y][z] = combine(by, bxy, byz, txy || tyz ? bxyz : by, - ty, txy, tyz, txy || tyz ? txyz : ty); - - skyLight [2][x][y][z] = combine(sz, syz, sxz, tyz || txz ? sxyz : sz, - tz, tyz, txz, tyz || txz ? txyz : tz); - blockLight[2][x][y][z] = combine(bz, byz, bxz, tyz || txz ? bxyz : bz, - tz, tyz, txz, tyz || txz ? txyz : tz); - } - } - } - } - - public void updateFlatLighting() - { - full = Block.isShapeFullBlock(state.getCollisionShape(level, blockPos)); - packed[0] = LevelRenderer.getLightColor(level, blockPos); - - for (Direction side : SIDES) - { - int i = side.ordinal() + 1; - packed[i] = LevelRenderer.getLightColor(level, blockPos.relative(side)); - } - } - - public BlockAndTintGetter getLevel() - { - return level; - } - - public BlockState getState() - { - return state; - } - - public BlockPos getBlockPos() - { - return blockPos; - } - - public boolean[][][] getTranslucent() - { - return t; - } - - public float[][][][] getSkyLight() - { - return skyLight; - } - - public float[][][][] getBlockLight() - { - return blockLight; - } - - public float[][][] getAo() - { - return ao; - } - - public int[] getPackedLight() - { - return packed; - } - - public boolean isFullCube() - { - return full; - } - - public int getCachedTint() - { - return cachedTint; - } - - public int getCachedMultiplier() - { - return cachedMultiplier; - } -} diff --git a/src/main/java/net/minecraftforge/client/model/pipeline/ForgeBlockModelRenderer.java b/src/main/java/net/minecraftforge/client/model/pipeline/ForgeBlockModelRenderer.java deleted file mode 100644 index b6d9e013136..00000000000 --- a/src/main/java/net/minecraftforge/client/model/pipeline/ForgeBlockModelRenderer.java +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright (c) Forge Development LLC and contributors - * SPDX-License-Identifier: LGPL-2.1-only - */ - -package net.minecraftforge.client.model.pipeline; - -import java.util.List; -import java.util.Random; - -import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.blaze3d.vertex.VertexConsumer; -import net.minecraft.util.RandomSource; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.client.renderer.block.ModelBlockRenderer; -import net.minecraft.client.renderer.block.model.BakedQuad; -import net.minecraft.client.resources.model.BakedModel; -import net.minecraft.client.color.block.BlockColors; -import net.minecraft.core.Direction; -import net.minecraft.core.BlockPos; -import net.minecraft.world.level.BlockAndTintGetter; -import net.minecraftforge.client.model.data.IModelData; -import net.minecraftforge.common.ForgeConfig; - -public class ForgeBlockModelRenderer extends ModelBlockRenderer -{ - private final ThreadLocal lighterFlat; - private final ThreadLocal lighterSmooth; - private final ThreadLocal consumerFlat = ThreadLocal.withInitial(VertexBufferConsumer::new); - private final ThreadLocal consumerSmooth = ThreadLocal.withInitial(VertexBufferConsumer::new); - - public ForgeBlockModelRenderer(BlockColors colors) - { - super(colors); - lighterFlat = ThreadLocal.withInitial(() -> new VertexLighterFlat(colors)); - lighterSmooth = ThreadLocal.withInitial(() -> new VertexLighterSmoothAo(colors)); - } - - @Override - public void tesselateWithoutAO(BlockAndTintGetter level, BakedModel model, BlockState state, BlockPos pos, PoseStack poseStack, VertexConsumer buffer, boolean checkSides, RandomSource rand, long seed, int packedOverlay, IModelData modelData) - { - if(ForgeConfig.CLIENT.experimentalForgeLightPipelineEnabled.get()) - { - VertexBufferConsumer consumer = consumerFlat.get(); - consumer.setBuffer(buffer); - consumer.setPackedOverlay(packedOverlay); - - VertexLighterFlat lighter = lighterFlat.get(); - lighter.setParent(consumer); - lighter.setTransform(poseStack.last()); - - render(lighter, level, model, state, pos, poseStack, checkSides, rand, seed, modelData); - } - else - { - super.tesselateWithoutAO(level, model, state, pos, poseStack, buffer, checkSides, rand, seed, packedOverlay, modelData); - } - } - - @Override - public void tesselateWithAO(BlockAndTintGetter level, BakedModel model, BlockState state, BlockPos pos, PoseStack poseStack, VertexConsumer buffer, boolean checkSides, RandomSource rand, long seed, int packedOverlay, IModelData modelData) - { - if(ForgeConfig.CLIENT.experimentalForgeLightPipelineEnabled.get()) - { - VertexBufferConsumer consumer = consumerSmooth.get(); - consumer.setBuffer(buffer); - consumer.setPackedOverlay(packedOverlay); - - VertexLighterSmoothAo lighter = lighterSmooth.get(); - lighter.setParent(consumer); - lighter.setTransform(poseStack.last()); - - render(lighter, level, model, state, pos, poseStack, checkSides, rand, seed, modelData); - } - else - { - super.tesselateWithAO(level, model, state, pos, poseStack, buffer, checkSides, rand, seed, packedOverlay, modelData); - } - } - - public static boolean render(VertexLighterFlat lighter, BlockAndTintGetter level, BakedModel model, BlockState state, BlockPos pos, PoseStack poseStack, boolean checkSides, RandomSource rand, long seed, IModelData modelData) - { - lighter.setWorld(level); - lighter.setState(state); - lighter.setBlockPos(pos); - boolean empty = true; - rand.setSeed(seed); - List quads = model.getQuads(state, null, rand, modelData); - if(!quads.isEmpty()) - { - lighter.updateBlockInfo(); - empty = false; - for(BakedQuad quad : quads) - { - quad.pipe(lighter); - } - } - for(Direction side : Direction.values()) - { - rand.setSeed(seed); - quads = model.getQuads(state, side, rand, modelData); - if(!quads.isEmpty()) - { - if(!checkSides || Block.shouldRenderFace(state, level, pos, side, pos.relative(side))) - { - if(empty) lighter.updateBlockInfo(); - empty = false; - for(BakedQuad quad : quads) - { - quad.pipe(lighter); - } - } - } - } - lighter.resetBlockInfo(); - return !empty; - } -} diff --git a/src/main/java/net/minecraftforge/client/model/pipeline/IVertexConsumer.java b/src/main/java/net/minecraftforge/client/model/pipeline/IVertexConsumer.java deleted file mode 100644 index 01b4436b9a1..00000000000 --- a/src/main/java/net/minecraftforge/client/model/pipeline/IVertexConsumer.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (c) Forge Development LLC and contributors - * SPDX-License-Identifier: LGPL-2.1-only - */ - -package net.minecraftforge.client.model.pipeline; - -import net.minecraft.client.renderer.texture.TextureAtlasSprite; -import com.mojang.blaze3d.vertex.VertexFormat; -import net.minecraft.core.Direction; - -/** - * Assumes that the data length is not less than e.getElements().size(). - * Also assumes that element index passed will increment from 0 to format.getElements().size() - 1. - * Normal, Color and UV are assumed to be in 0-1 range. - */ -public interface IVertexConsumer -{ - /** - * @return the format that should be used for passed data. - */ - VertexFormat getVertexFormat(); - - void setQuadTint(int tint); - void setQuadOrientation(Direction orientation); - void setApplyDiffuseLighting(boolean diffuse); - void setTexture(TextureAtlasSprite texture); - void put(int element, float... data); -} diff --git a/src/main/java/net/minecraftforge/client/model/pipeline/IVertexProducer.java b/src/main/java/net/minecraftforge/client/model/pipeline/IVertexProducer.java deleted file mode 100644 index d105b26050e..00000000000 --- a/src/main/java/net/minecraftforge/client/model/pipeline/IVertexProducer.java +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Copyright (c) Forge Development LLC and contributors - * SPDX-License-Identifier: LGPL-2.1-only - */ - -package net.minecraftforge.client.model.pipeline; - - -public interface IVertexProducer -{ - /** - * @param consumer consumer to receive the vertex data this producer can provide - */ - void pipe(IVertexConsumer consumer); -} diff --git a/src/main/java/net/minecraftforge/client/model/pipeline/LightUtil.java b/src/main/java/net/minecraftforge/client/model/pipeline/LightUtil.java deleted file mode 100644 index 31d5e362a10..00000000000 --- a/src/main/java/net/minecraftforge/client/model/pipeline/LightUtil.java +++ /dev/null @@ -1,331 +0,0 @@ -/* - * Copyright (c) Forge Development LLC and contributors - * SPDX-License-Identifier: LGPL-2.1-only - */ - -package net.minecraftforge.client.model.pipeline; - -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; - -import org.apache.commons.lang3.tuple.Pair; - -import net.minecraft.client.renderer.block.model.BakedQuad; -import com.mojang.blaze3d.vertex.DefaultVertexFormat; -import com.mojang.blaze3d.vertex.VertexFormat; -import com.mojang.blaze3d.vertex.VertexFormatElement; -import net.minecraft.core.Direction; - -public class LightUtil -{ - public static float diffuseLight(float x, float y, float z) - { - return Math.min(x * x * 0.6f + y * y * ((3f + y) / 4f) + z * z * 0.8f, 1f); - } - - public static float diffuseLight(Direction side) - { - switch(side) - { - case DOWN: - return .5f; - case UP: - return 1f; - case NORTH: - case SOUTH: - return .8f; - default: - return .6f; - } - } - - public static Direction toSide(float x, float y, float z) - { - if(Math.abs(x) > Math.abs(y)) - { - if(Math.abs(x) > Math.abs(z)) - { - if(x < 0) return Direction.WEST; - return Direction.EAST; - } - else - { - if(z < 0) return Direction.NORTH; - return Direction.SOUTH; - } - } - else - { - if(Math.abs(y) > Math.abs(z)) - { - if(y < 0) return Direction.DOWN; - return Direction.UP; - } - else - { - if(z < 0) return Direction.NORTH; - return Direction.SOUTH; - } - } - } - - private static final ConcurrentMap, int[]> formatMaps = new ConcurrentHashMap<>(); - - public static void putBakedQuad(IVertexConsumer consumer, BakedQuad quad) - { - consumer.setTexture(quad.getSprite()); - consumer.setQuadOrientation(quad.getDirection()); - if(quad.isTinted()) - { - consumer.setQuadTint(quad.getTintIndex()); - } - consumer.setApplyDiffuseLighting(quad.isShade()); - float[] data = new float[4]; - VertexFormat formatFrom = consumer.getVertexFormat(); - VertexFormat formatTo = DefaultVertexFormat.BLOCK; - int countFrom = formatFrom.getElements().size(); - int countTo = formatTo.getElements().size(); - int[] eMap = mapFormats(formatFrom, formatTo); - for(int v = 0; v < 4; v++) - { - for(int e = 0; e < countFrom; e++) - { - if(eMap[e] != countTo) - { - unpack(quad.getVertices(), data, formatTo, v, eMap[e]); - consumer.put(e, data); - } - else - { - consumer.put(e); - } - } - } - } - - private static final VertexFormat DEFAULT_FROM = VertexLighterFlat.withNormal(DefaultVertexFormat.BLOCK); - private static final VertexFormat DEFAULT_TO = DefaultVertexFormat.BLOCK; - private static final int[] DEFAULT_MAPPING = generateMapping(DEFAULT_FROM, DEFAULT_TO); - public static int[] mapFormats(VertexFormat from, VertexFormat to) - { - //Speedup: in 99.99% this is the mapping, no need to go make a pair, and go through the slower hash map - if (from.equals(DEFAULT_FROM) && to.equals(DEFAULT_TO)) - return DEFAULT_MAPPING; - return formatMaps.computeIfAbsent(Pair.of(from, to), pair -> generateMapping(pair.getLeft(), pair.getRight())); - } - - private static int[] generateMapping(VertexFormat from, VertexFormat to) - { - int fromCount = from.getElements().size(); - int toCount = to.getElements().size(); - int[] eMap = new int[fromCount]; - - for(int e = 0; e < fromCount; e++) - { - VertexFormatElement expected = from.getElements().get(e); - int e2; - for(e2 = 0; e2 < toCount; e2++) - { - VertexFormatElement current = to.getElements().get(e2); - if(expected.getUsage() == current.getUsage() && expected.getIndex() == current.getIndex()) - { - break; - } - } - eMap[e] = e2; - } - return eMap; - } - - public static void unpack(int[] from, float[] to, VertexFormat formatFrom, int v, int e) - { - int length = 4 < to.length ? 4 : to.length; - VertexFormatElement element = formatFrom.getElements().get(e); - int vertexStart = v * formatFrom.getVertexSize() + formatFrom.getOffset(e); - int count = element.getElementCount(); - VertexFormatElement.Type type = element.getType(); - VertexFormatElement.Usage usage = element.getUsage(); - int size = type.getSize(); - int mask = (256 << (8 * (size - 1))) - 1; - for(int i = 0; i < length; i++) - { - if(i < count) - { - int pos = vertexStart + size * i; - int index = pos >> 2; - int offset = pos & 3; - int bits = from[index]; - bits = bits >>> (offset * 8); - if((pos + size - 1) / 4 != index) - { - bits |= from[index + 1] << ((4 - offset) * 8); - } - bits &= mask; - if(type == VertexFormatElement.Type.FLOAT) - { - to[i] = Float.intBitsToFloat(bits); - } - else if(type == VertexFormatElement.Type.UBYTE || type == VertexFormatElement.Type.USHORT) - { - to[i] = (float)bits / mask; - } - else if(type == VertexFormatElement.Type.UINT) - { - to[i] = (float)((double)(bits & 0xFFFFFFFFL) / 0xFFFFFFFFL); - } - else if(type == VertexFormatElement.Type.BYTE) - { - to[i] = ((float)(byte)bits) / (mask >> 1); - } - else if(type == VertexFormatElement.Type.SHORT) - { - to[i] = ((float)(short)bits) / (mask >> 1); - } - else if(type == VertexFormatElement.Type.INT) - { - to[i] = (float)((double)(bits & 0xFFFFFFFFL) / (0xFFFFFFFFL >> 1)); - } - } - else - { - to[i] = (i == 3 && usage == VertexFormatElement.Usage.POSITION) ? 1 : 0; - } - } - } - - public static void pack(float[] from, int[] to, VertexFormat formatTo, int v, int e) - { - VertexFormatElement element = formatTo.getElements().get(e); - int vertexStart = v * formatTo.getVertexSize() + formatTo.getOffset(e); - int count = element.getElementCount(); - VertexFormatElement.Type type = element.getType(); - int size = type.getSize(); - int mask = (256 << (8 * (size - 1))) - 1; - for(int i = 0; i < 4; i++) - { - if(i < count) - { - int pos = vertexStart + size * i; - int index = pos >> 2; - int offset = pos & 3; - int bits = 0; - float f = i < from.length ? from[i] : 0; - if(type == VertexFormatElement.Type.FLOAT) - { - bits = Float.floatToRawIntBits(f); - } - else if( - type == VertexFormatElement.Type.UBYTE || - type == VertexFormatElement.Type.USHORT || - type == VertexFormatElement.Type.UINT - ) - { - bits = Math.round(f * mask); - } - else - { - bits = Math.round(f * (mask >> 1)); - } - to[index] &= ~(mask << (offset * 8)); - to[index] |= (((bits & mask) << (offset * 8))); - // TODO handle overflow into to[index + 1] - } - } - } - - public static int getLightOffset(int v) - { - return (v * 8) + 6; - } - - public static void setLightData(BakedQuad q, int light) - { - int[] data = q.getVertices(); - for (int i = 0; i < 4; i++) - { - data[getLightOffset(i)] = light; - } - } - - private static final class ItemPipeline - { - final VertexBufferConsumer bufferConsumer; - final ItemConsumer itemConsumer; - - ItemPipeline() - { - this.bufferConsumer = new VertexBufferConsumer(); - this.itemConsumer = new ItemConsumer(bufferConsumer); - } - } - - private static final ThreadLocal itemPipeline = ThreadLocal.withInitial(ItemPipeline::new); - - // renders quad in any Vertex Format, but is slower - /*public static void renderQuadColorSlow(IVertexBuilder buffer, BakedQuad quad, float r, float g, float b, float a) - { - ItemPipeline pipeline = itemPipeline.get(); - pipeline.bufferConsumer.setBuffer(buffer); - ItemConsumer cons = pipeline.itemConsumer; - - cons.setAuxColor(r, g, b, a); - quad.pipe(cons); - } - - public static void renderQuadColor(IVertexBuilder builder, MatrixStack.Entry entry, BakedQuad quad, float r, float g, float b, float a, int light, int overlaylight) - { - if (quad.getFormat().equals(DefaultVertexFormats.BLOCK)) - { - builder.addVertexData(entry, quad, r, g, b, a, light, overlaylight); - } - else - { - renderQuadColorSlow(builder, quad, r, g, b, a); - } - }*/ - - public static class ItemConsumer extends VertexTransformer - { - private int vertices = 0; - - private float[] auxColor = new float[]{1, 1, 1, 1}; - private float[] buf = new float[4]; - - public ItemConsumer(IVertexConsumer parent) - { - super(parent); - } - - public void setAuxColor(float... auxColor) - { - System.arraycopy(auxColor, 0, this.auxColor, 0, this.auxColor.length); - } - - @Override - public void put(int element, float... data) - { - if(getVertexFormat().getElements().get(element).getUsage() == VertexFormatElement.Usage.COLOR) - { - System.arraycopy(auxColor, 0, buf, 0, buf.length); - int n = Math.min(4, data.length); - for(int i = 0; i < n; i++) - { - buf[i] *= data[i]; - } - super.put(element, buf); - } - else - { - super.put(element, data); - } - if(element == getVertexFormat().getElements().size() - 1) - { - vertices++; - if(vertices == 4) - { - vertices = 0; - } - } - } - } -} diff --git a/src/main/java/net/minecraftforge/client/model/pipeline/QuadBakingVertexConsumer.java b/src/main/java/net/minecraftforge/client/model/pipeline/QuadBakingVertexConsumer.java new file mode 100644 index 00000000000..08fcc503b4c --- /dev/null +++ b/src/main/java/net/minecraftforge/client/model/pipeline/QuadBakingVertexConsumer.java @@ -0,0 +1,164 @@ +/* + * Copyright (c) Forge Development LLC and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.minecraftforge.client.model.pipeline; + +import com.mojang.blaze3d.vertex.DefaultVertexFormat; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.mojang.blaze3d.vertex.VertexFormatElement; +import net.minecraft.Util; +import net.minecraft.client.renderer.block.model.BakedQuad; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.core.Direction; +import net.minecraftforge.client.textures.UnitTextureAtlasSprite; + +import java.util.IdentityHashMap; +import java.util.Map; +import java.util.function.Consumer; + +import static net.minecraftforge.client.model.IQuadTransformer.*; + +/** + * Vertex consumer that outputs {@linkplain BakedQuad baked quads}. + *

+ * This consumer accepts data in {@link com.mojang.blaze3d.vertex.DefaultVertexFormat#BLOCK} and is not picky about + * ordering or missing elements, but will not automatically populate missing data (color will be black, for example). + */ +public class QuadBakingVertexConsumer implements VertexConsumer +{ + private final Map ELEMENT_OFFSETS = Util.make(new IdentityHashMap<>(), map -> { + int i = 0; + for (var element : DefaultVertexFormat.BLOCK.getElements()) + map.put(element, DefaultVertexFormat.BLOCK.getOffset(i++) / 4); // Int offset + }); + private static final int QUAD_DATA_SIZE = STRIDE * 4; + + private final Consumer quadConsumer; + + private int vertexIndex = 0; + private int[] quadData = new int[QUAD_DATA_SIZE]; + + private int tintIndex; + private Direction direction = Direction.DOWN; + private TextureAtlasSprite sprite = UnitTextureAtlasSprite.INSTANCE; + private boolean shade; + + public QuadBakingVertexConsumer(Consumer quadConsumer) + { + this.quadConsumer = quadConsumer; + } + + @Override + public VertexConsumer vertex(double x, double y, double z) + { + int offset = vertexIndex * STRIDE + POSITION; + quadData[offset] = Float.floatToRawIntBits((float) x); + quadData[offset + 1] = Float.floatToRawIntBits((float) y); + quadData[offset + 2] = Float.floatToRawIntBits((float) z); + return this; + } + + @Override + public VertexConsumer normal(float x, float y, float z) + { + int offset = vertexIndex * STRIDE + NORMAL; + quadData[offset] = ((int) (x * 127.0f) & 0xFF) | + (((int) (y * 127.0f) & 0xFF) << 8) | + (((int) (z * 127.0f) & 0xFF) << 16); + return this; + } + + @Override + public VertexConsumer color(int r, int g, int b, int a) + { + int offset = vertexIndex * STRIDE + COLOR; + quadData[offset] = ((a & 0xFF) << 24) | + ((b & 0xFF) << 16) | + ((g & 0xFF) << 8) | + (r & 0xFF); + return this; + } + + @Override + public VertexConsumer uv(float u, float v) + { + int offset = vertexIndex * STRIDE + UV0; + quadData[offset] = Float.floatToRawIntBits(u); + quadData[offset + 1] = Float.floatToRawIntBits(v); + return this; + } + + @Override + public VertexConsumer overlayCoords(int u, int v) + { + if (UV1 >= 0) // Vanilla doesn't support this, but it may be added by a 3rd party + { + int offset = vertexIndex * STRIDE + UV1; + quadData[offset] = (u & 0xFFFF) | ((v & 0xFFFF) << 16); + } + return this; + } + + @Override + public VertexConsumer uv2(int u, int v) + { + int offset = vertexIndex * STRIDE + UV2; + quadData[offset] = (u & 0xFFFF) | ((v & 0xFFFF) << 16); + return this; + } + + @Override + public VertexConsumer misc(VertexFormatElement element, int... rawData) + { + Integer baseOffset = ELEMENT_OFFSETS.get(element); + if (baseOffset != null) + { + int offset = vertexIndex * STRIDE + baseOffset; + System.arraycopy(rawData, 0, quadData, offset, rawData.length); + } + return this; + } + + @Override + public void endVertex() + { + if (++vertexIndex != 4) + return; + // We have a full quad, pass it to the consumer and reset + quadConsumer.accept(new BakedQuad(quadData, tintIndex, direction, sprite, shade)); + vertexIndex = 0; + quadData = new int[QUAD_DATA_SIZE]; + } + + @Override + public void defaultColor(int r, int g, int b, int a) + { + } + + @Override + public void unsetDefaultColor() + { + } + + public void setTintIndex(int tintIndex) + { + this.tintIndex = tintIndex; + } + + public void setDirection(Direction direction) + { + this.direction = direction; + } + + public void setSprite(TextureAtlasSprite sprite) + { + this.sprite = sprite; + } + + public void setShade(boolean shade) + { + this.shade = shade; + } +} diff --git a/src/main/java/net/minecraftforge/client/model/pipeline/QuadGatheringTransformer.java b/src/main/java/net/minecraftforge/client/model/pipeline/QuadGatheringTransformer.java deleted file mode 100644 index dcee349ffe4..00000000000 --- a/src/main/java/net/minecraftforge/client/model/pipeline/QuadGatheringTransformer.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) Forge Development LLC and contributors - * SPDX-License-Identifier: LGPL-2.1-only - */ - -package net.minecraftforge.client.model.pipeline; - -import com.mojang.blaze3d.vertex.VertexFormat; - -public abstract class QuadGatheringTransformer implements IVertexConsumer -{ - protected IVertexConsumer parent; - protected VertexFormat format; - protected int vertices = 0; - - protected byte[] dataLength = null; - protected float[][][] quadData = null; - - public void setParent(IVertexConsumer parent) - { - this.parent = parent; - } - - public void setVertexFormat(VertexFormat format) - { - this.format = format; - dataLength = new byte[format.getElements().size()]; - quadData = new float[format.getElements().size()][4][4]; - } - - @Override - public VertexFormat getVertexFormat() - { - return format; - } - - @Override - public void put(int element, float... data) - { - System.arraycopy(data, 0, quadData[element][vertices], 0, data.length); - if (vertices == 0) - { - dataLength[element] = (byte)data.length; - } - if (element == getVertexFormat().getElements().size() - 1) - { - vertices++; - } - if (vertices == 4) - { - vertices = 0; - processQuad(); - } - } - - protected abstract void processQuad(); -} diff --git a/src/main/java/net/minecraftforge/client/model/pipeline/RemappingVertexPipeline.java b/src/main/java/net/minecraftforge/client/model/pipeline/RemappingVertexPipeline.java new file mode 100644 index 00000000000..f7bc43f64d6 --- /dev/null +++ b/src/main/java/net/minecraftforge/client/model/pipeline/RemappingVertexPipeline.java @@ -0,0 +1,153 @@ +/* + * Copyright (c) Forge Development LLC and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.minecraftforge.client.model.pipeline; + +import com.mojang.blaze3d.vertex.DefaultVertexFormat; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.mojang.blaze3d.vertex.VertexFormat; +import com.mojang.blaze3d.vertex.VertexFormatElement; +import com.mojang.math.Vector3d; +import com.mojang.math.Vector3f; +import net.minecraft.client.renderer.texture.OverlayTexture; + +import java.util.Arrays; +import java.util.IdentityHashMap; +import java.util.Map; +import java.util.Set; + +/** + * Vertex pipeline element that remaps incoming data to another format. + */ +public class RemappingVertexPipeline implements VertexConsumer +{ + private static final Set KNOWN_ELEMENTS = Set.of(DefaultVertexFormat.ELEMENT_POSITION, + DefaultVertexFormat.ELEMENT_COLOR, DefaultVertexFormat.ELEMENT_UV, DefaultVertexFormat.ELEMENT_UV1, + DefaultVertexFormat.ELEMENT_UV2, DefaultVertexFormat.ELEMENT_NORMAL, DefaultVertexFormat.ELEMENT_PADDING); + private static final int[] EMPTY_INT_ARRAY = new int[0]; + + private final VertexConsumer parent; + private final VertexFormat targetFormat; + + private final Vector3d position = new Vector3d(0, 0, 0); + private final Vector3f normal = new Vector3f(0, 0, 0); + private final int[] color = new int[] { 255, 255, 255, 255 }; + private final float[] uv0 = new float[] { 0, 0 }; + private final int[] uv1 = new int[] { OverlayTexture.NO_WHITE_U, OverlayTexture.WHITE_OVERLAY_V }; + private final int[] uv2 = new int[] { 0, 0 }; + + private final Map miscElementIds; + private final int[][] misc; + + public RemappingVertexPipeline(VertexConsumer parent, VertexFormat targetFormat) + { + this.parent = parent; + this.targetFormat = targetFormat; + + this.miscElementIds = new IdentityHashMap<>(); + int i = 0; + for (var element : targetFormat.getElements()) + if (element.getUsage() != VertexFormatElement.Usage.PADDING && !KNOWN_ELEMENTS.contains(element)) + this.miscElementIds.put(element, i++); + this.misc = new int[i][]; + Arrays.fill(this.misc, EMPTY_INT_ARRAY); + } + + @Override + public VertexConsumer vertex(double x, double y, double z) + { + position.set(x, y, z); + return this; + } + + @Override + public VertexConsumer normal(float x, float y, float z) + { + normal.set(x, y, z); + return this; + } + + @Override + public VertexConsumer color(int r, int g, int b, int a) + { + color[0] = r; + color[1] = g; + color[2] = b; + color[3] = a; + return this; + } + + @Override + public VertexConsumer uv(float u, float v) + { + uv0[0] = u; + uv0[1] = v; + return this; + } + + @Override + public VertexConsumer overlayCoords(int u, int v) + { + uv1[0] = u; + uv1[1] = v; + return this; + } + + @Override + public VertexConsumer uv2(int u, int v) + { + uv2[0] = u; + uv2[1] = v; + return this; + } + + @Override + public VertexConsumer misc(VertexFormatElement element, int... values) + { + Integer id = miscElementIds.get(element); + if (id != null) + misc[id] = Arrays.copyOf(values, values.length); + return this; + } + + @Override + public void endVertex() + { + for (var element : targetFormat.getElements()) + { + // Ignore padding + if (element.getUsage() == VertexFormatElement.Usage.PADDING) + continue; + + // Try to match and output any of the supported elements, and if that fails, treat as misc + if (element.equals(DefaultVertexFormat.ELEMENT_POSITION)) + parent.vertex(position.x, position.y, position.z); + else if (element.equals(DefaultVertexFormat.ELEMENT_NORMAL)) + parent.normal(normal.x(), normal.y(), normal.z()); + else if (element.equals(DefaultVertexFormat.ELEMENT_COLOR)) + parent.color(color[0], color[1], color[2], color[3]); + else if (element.equals(DefaultVertexFormat.ELEMENT_UV0)) + parent.uv(uv0[0], uv0[1]); + else if (element.equals(DefaultVertexFormat.ELEMENT_UV1)) + parent.overlayCoords(uv1[0], uv1[1]); + else if (element.equals(DefaultVertexFormat.ELEMENT_UV2)) + parent.uv2(uv2[0], uv2[1]); + else + parent.misc(element, misc[miscElementIds.get(element)]); + } + } + + @Override + public void defaultColor(int r, int g, int b, int a) + { + parent.defaultColor(r, g, b, a); + } + + @Override + public void unsetDefaultColor() + { + parent.unsetDefaultColor(); + } +} diff --git a/src/main/java/net/minecraftforge/client/model/pipeline/TRSRTransformer.java b/src/main/java/net/minecraftforge/client/model/pipeline/TRSRTransformer.java deleted file mode 100644 index 1f09a465375..00000000000 --- a/src/main/java/net/minecraftforge/client/model/pipeline/TRSRTransformer.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) Forge Development LLC and contributors - * SPDX-License-Identifier: LGPL-2.1-only - */ - -package net.minecraftforge.client.model.pipeline; - -import com.mojang.math.Transformation; -import com.mojang.math.Vector3f; -import com.mojang.math.Vector4f; - -public class TRSRTransformer extends VertexTransformer -{ - private final Transformation transform; - - public TRSRTransformer(IVertexConsumer parent, Transformation transform) - { - super(parent); - this.transform = transform; - } - - @Override - public void put(int element, float... data) - { - switch (getVertexFormat().getElements().get(element).getUsage()) - { - case POSITION: - Vector4f pos = new Vector4f(data[0], data[1], data[2], data[3]); - transform.transformPosition(pos); - data[0] = pos.x(); - data[1] = pos.y(); - data[2] = pos.z(); - data[3] = pos.w(); - break; - case NORMAL: - Vector3f normal = new Vector3f(data); - transform.transformNormal(normal); - data[0] = normal.x(); - data[1] = normal.y(); - data[2] = normal.z(); - break; - } - super.put(element, data); - } -} diff --git a/src/main/java/net/minecraftforge/client/model/pipeline/TransformerConsumer.java b/src/main/java/net/minecraftforge/client/model/pipeline/TransformerConsumer.java deleted file mode 100644 index f7207b8d835..00000000000 --- a/src/main/java/net/minecraftforge/client/model/pipeline/TransformerConsumer.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (c) Forge Development LLC and contributors - * SPDX-License-Identifier: LGPL-2.1-only - */ - -package net.minecraftforge.client.model.pipeline; - -import com.mojang.blaze3d.vertex.VertexFormat; - -public abstract class TransformerConsumer implements IVertexConsumer { - private IVertexConsumer parent; - - protected TransformerConsumer(IVertexConsumer parent) - { - this.parent = parent; - } - - @Override - public VertexFormat getVertexFormat() - { - return parent.getVertexFormat(); - } - - @Override - public void put(int element, float... data) - { - float[] newData = transform(element, data); - parent.put(element, newData); - } - - protected abstract float[] transform(int element, float... data); -} diff --git a/src/main/java/net/minecraftforge/client/model/pipeline/TransformingVertexPipeline.java b/src/main/java/net/minecraftforge/client/model/pipeline/TransformingVertexPipeline.java new file mode 100644 index 00000000000..86e5e513192 --- /dev/null +++ b/src/main/java/net/minecraftforge/client/model/pipeline/TransformingVertexPipeline.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) Forge Development LLC and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.minecraftforge.client.model.pipeline; + +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.mojang.math.Transformation; +import com.mojang.math.Vector3f; +import com.mojang.math.Vector4f; + +/** + * Vertex pipeline element that applies a transformation to incoming geometry. + */ +public class TransformingVertexPipeline extends VertexConsumerWrapper +{ + private final Transformation transformation; + + public TransformingVertexPipeline(VertexConsumer parent, Transformation transformation) + { + super(parent); + this.transformation = transformation; + } + + @Override + public VertexConsumer vertex(double x, double y, double z) + { + var vec = new Vector4f((float) x, (float) y, (float) z, 1); + transformation.transformPosition(vec); + vec.perspectiveDivide(); + return super.vertex(vec.x(), vec.y(), vec.z()); + } + + @Override + public VertexConsumer normal(float x, float y, float z) + { + var vec = new Vector3f(x, y, z); + transformation.transformNormal(vec); + vec.normalize(); + return super.normal(vec.x(), vec.y(), vec.z()); + } + +} diff --git a/src/main/java/net/minecraftforge/client/model/pipeline/VertexBufferConsumer.java b/src/main/java/net/minecraftforge/client/model/pipeline/VertexBufferConsumer.java deleted file mode 100644 index a5644d21d76..00000000000 --- a/src/main/java/net/minecraftforge/client/model/pipeline/VertexBufferConsumer.java +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright (c) Forge Development LLC and contributors - * SPDX-License-Identifier: LGPL-2.1-only - */ - -package net.minecraftforge.client.model.pipeline; - -import com.mojang.blaze3d.vertex.VertexConsumer; - -import com.mojang.blaze3d.vertex.VertexFormatElement; -import net.minecraft.client.renderer.texture.TextureAtlasSprite; -import com.mojang.blaze3d.vertex.DefaultVertexFormat; -import com.mojang.blaze3d.vertex.VertexFormat; -import net.minecraft.core.Direction; -import org.jetbrains.annotations.Nullable; - -import java.util.List; - -/** - * Assumes VertexFormatElement is present in the BufferBuilder's vertex format. - */ -public class VertexBufferConsumer implements IVertexConsumer -{ - private VertexFormat format; - private List elements; - private VertexConsumer renderer; - private boolean overrideOverlayCoords; - private int overlayCoordU; - private int overlayCoordV; - - public VertexBufferConsumer() - { - setVertexFormat(DefaultVertexFormat.BLOCK); - } - - public VertexBufferConsumer(VertexConsumer buffer) - { - setBuffer(buffer); - } - - @Override - public final VertexFormat getVertexFormat() - { - return format; - } - - @Override - public void put(int e, float... data) - { - final float d0 = data.length <= 0 ? 0 : data[0]; - final float d1 = data.length <= 1 ? 0 : data[1]; - final float d2 = data.length <= 2 ? 0 : data[2]; - final float d3 = data.length <= 3 ? 0 : data[3]; - - var element = elements.get(e); - - switch (element.getUsage()) - { - case POSITION: // POSITION_3F - if (element.getIndex() == 0) - renderer.vertex(d0, d1, d2); - break; - case NORMAL: // NORMAL_3B - if (element.getIndex() == 0) - renderer.normal(d0, d1, d2); - break; - case COLOR: // COLOR_4UB - if (element.getIndex() == 0) - renderer.color(d0, d1, d2, d3); - break; - case UV: // TEX_2F - switch(element.getIndex()) - { - case 0 -> renderer.uv(d0, d1); - case 1 -> { - if (overrideOverlayCoords) - renderer.overlayCoords(overlayCoordU, overlayCoordV); - else - renderer.overlayCoords((int) (d0 * 32767f), (int) (d1 * 32767f)); - } - case 2 -> renderer.uv2((int) (d0 * 0xF0), (int) (d1 * 0xF0)); - } - break; - case PADDING: - break; - default: - throw new IllegalArgumentException("Vertex element out of bounds: " + e); - } - if(e == 5) - { - renderer.endVertex(); - } - } - - public void setBuffer(VertexConsumer buffer) - { - this.renderer = buffer; - setVertexFormat(buffer.getVertexFormat()); - } - - public void setVertexFormat(VertexFormat format) - { - this.format = format; - this.elements = this.format.getElements(); - } - - @Override - public void setQuadTint(int tint) {} - @Override - public void setQuadOrientation(Direction orientation) {} - @Override - public void setApplyDiffuseLighting(boolean diffuse) {} - @Override - public void setTexture(TextureAtlasSprite texture ) {} - - public void setPackedOverlay(int packedOverlay) - { - this.overrideOverlayCoords = true; - this.overlayCoordV = (packedOverlay >> 16) & 0xFFFF; - this.overlayCoordU = (packedOverlay) & 0xFFFF; - } -} diff --git a/src/main/java/net/minecraftforge/client/model/pipeline/VertexConsumerWrapper.java b/src/main/java/net/minecraftforge/client/model/pipeline/VertexConsumerWrapper.java new file mode 100644 index 00000000000..10f3d636076 --- /dev/null +++ b/src/main/java/net/minecraftforge/client/model/pipeline/VertexConsumerWrapper.java @@ -0,0 +1,91 @@ +/* + * Copyright (c) Forge Development LLC and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.minecraftforge.client.model.pipeline; + +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.mojang.blaze3d.vertex.VertexFormatElement; + +/** + * Wrapper for {@link VertexConsumer} which delegates all operations to its parent. + *

+ * Useful for defining custom pipeline elements that only process certain data. + */ +public abstract class VertexConsumerWrapper implements VertexConsumer +{ + protected final VertexConsumer parent; + + public VertexConsumerWrapper(VertexConsumer parent) + { + this.parent = parent; + } + + @Override + public VertexConsumer vertex(double x, double y, double z) + { + parent.vertex(x, y, z); + return this; + } + + @Override + public VertexConsumer color(int r, int g, int b, int a) + { + parent.color(r, g, b, a); + return this; + } + + @Override + public VertexConsumer uv(float u, float v) + { + parent.uv(u, v); + return this; + } + + @Override + public VertexConsumer overlayCoords(int u, int v) + { + parent.overlayCoords(u, v); + return this; + } + + @Override + public VertexConsumer uv2(int u, int v) + { + parent.uv2(u, v); + return this; + } + + @Override + public VertexConsumer normal(float x, float y, float z) + { + parent.normal(x, y, z); + return this; + } + + @Override + public VertexConsumer misc(VertexFormatElement element, int... values) + { + parent.misc(element, values); + return this; + } + + @Override + public void endVertex() + { + parent.endVertex(); + } + + @Override + public void defaultColor(int r, int g, int b, int a) + { + parent.defaultColor(r, g, b, a); + } + + @Override + public void unsetDefaultColor() + { + parent.unsetDefaultColor(); + } +} diff --git a/src/main/java/net/minecraftforge/client/model/pipeline/VertexLighterFlat.java b/src/main/java/net/minecraftforge/client/model/pipeline/VertexLighterFlat.java deleted file mode 100644 index a591114e1cf..00000000000 --- a/src/main/java/net/minecraftforge/client/model/pipeline/VertexLighterFlat.java +++ /dev/null @@ -1,322 +0,0 @@ -/* - * Copyright (c) Forge Development LLC and contributors - * SPDX-License-Identifier: LGPL-2.1-only - */ - -package net.minecraftforge.client.model.pipeline; - -import java.util.Map; -import java.util.Objects; - -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.Maps; -import com.mojang.blaze3d.vertex.PoseStack; - -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.client.renderer.LightTexture; -import net.minecraft.client.color.block.BlockColors; -import net.minecraft.client.renderer.texture.TextureAtlasSprite; -import com.mojang.blaze3d.vertex.DefaultVertexFormat; -import com.mojang.blaze3d.vertex.VertexFormat; -import com.mojang.blaze3d.vertex.VertexFormatElement; -import net.minecraft.core.Direction; -import net.minecraft.core.BlockPos; -import com.mojang.math.Vector3f; -import com.mojang.math.Vector4f; -import net.minecraft.world.level.BlockAndTintGetter; - -public class VertexLighterFlat extends QuadGatheringTransformer -{ - protected static final VertexFormatElement NORMAL_4F = new VertexFormatElement(0, VertexFormatElement.Type.FLOAT, VertexFormatElement.Usage.NORMAL, 4); - - // TODO 1.16/1.17 possibly refactor out the need for the "unpacked" format entirely. It's creating more headaches than solutions. - // This mess reverses the conversion to float bits done in LightUtil.unpack - private static final int LIGHTMAP_PACKING_FACTOR = ((256 << (8 * (DefaultVertexFormat.ELEMENT_UV2.getType().getSize() - 1))) - 1) >>> 1; - // Max lightmap value, for rescaling - private static final int LIGHTMAP_MAX = 0xF0; - // Inlined factor for rescaling input lightmap values, "rounded" up to the next float value to avoid precision loss when result is truncated to int - private static final float LIGHTMAP_RESCALE = Math.nextAfter((float) LIGHTMAP_PACKING_FACTOR / LIGHTMAP_MAX, LIGHTMAP_PACKING_FACTOR); - - protected final BlockInfo blockInfo; - private int tint = -1; - private boolean diffuse = true; - - protected int posIndex = -1; - protected int normalIndex = -1; - protected int colorIndex = -1; - protected int lightmapIndex = -1; - - protected VertexFormat baseFormat; - protected PoseStack.Pose pose; - - public VertexLighterFlat(BlockColors colors) - { - this.blockInfo = new BlockInfo(colors); - } - - @Override - public void setParent(IVertexConsumer parent) - { - super.setParent(parent); - setVertexFormat(parent.getVertexFormat()); - } - - public void setTransform(final PoseStack.Pose pose) - { - this.pose = pose; - } - - private void updateIndices() - { - for(int i = 0; i < getVertexFormat().getElements().size(); i++) - { - switch(getVertexFormat().getElements().get(i).getUsage()) - { - case POSITION: - posIndex = i; - break; - case NORMAL: - normalIndex = i; - break; - case COLOR: - colorIndex = i; - break; - case UV: - if(getVertexFormat().getElements().get(i).getIndex() == 2) - { - lightmapIndex = i; - } - break; - default: - } - } - if(posIndex == -1) - { - throw new IllegalArgumentException("vertex lighter needs format with position"); - } - if(lightmapIndex == -1) - { - throw new IllegalArgumentException("vertex lighter needs format with lightmap"); - } - if(colorIndex == -1) - { - throw new IllegalArgumentException("vertex lighter needs format with color"); - } - } - - @Override - public void setVertexFormat(VertexFormat format) - { - if (Objects.equals(format, baseFormat)) return; - baseFormat = format; - super.setVertexFormat(withNormal(format)); - updateIndices(); - } - - static VertexFormat withNormal(VertexFormat format) - { - //This is the case in 99.99%. Cache the value, so we don't have to redo it every time, and the speed up the equals check in LightUtil - if (format == DefaultVertexFormat.BLOCK) - return DefaultVertexFormat.BLOCK; - return withNormalUncached(format); - } - - private static VertexFormat withNormalUncached(VertexFormat format) - { - if (format == null || format.hasNormal()) - return format; - Map m = Maps.newHashMap(format.getElementMapping()); - m.put("Normal", NORMAL_4F); - return new VertexFormat(ImmutableMap.copyOf(m)); - } - - @Override - protected void processQuad() - { - float[][] position = quadData[posIndex]; - float[][] normal = null; - float[][] lightmap = quadData[lightmapIndex]; - float[][] color = quadData[colorIndex]; - - if (dataLength[normalIndex] >= 3 - && (quadData[normalIndex][0][0] != 0 - || quadData[normalIndex][0][1] != 0 - || quadData[normalIndex][0][2] != 0)) - { - normal = quadData[normalIndex]; - } - else // normals must be generated - { - normal = new float[4][4]; - Vector3f v1 = new Vector3f(position[3]); - Vector3f t = new Vector3f(position[1]); - Vector3f v2 = new Vector3f(position[2]); - v1.sub(t); - t.set(position[0]); - v2.sub(t); - v2.cross(v1); - v2.normalize(); - for(int v = 0; v < 4; v++) - { - normal[v][0] = v2.x(); - normal[v][1] = v2.y(); - normal[v][2] = v2.z(); - normal[v][3] = 0; - } - } - - int multiplier = -1; - if(tint != -1) - { - multiplier = blockInfo.getColorMultiplier(tint); - } - - VertexFormat format = parent.getVertexFormat(); - int count = format.getElements().size(); - - for(int v = 0; v < 4; v++) - { - float x = position[v][0] - .5f; - float y = position[v][1] - .5f; - float z = position[v][2] - .5f; - -// if(blockInfo.getState().getBlock().isFullCube(blockInfo.getState())) - { - x += normal[v][0] * .5f; - y += normal[v][1] * .5f; - z += normal[v][2] * .5f; - } - - float blockLight = lightmap[v][0] * LIGHTMAP_RESCALE, skyLight = lightmap[v][1] * LIGHTMAP_RESCALE; - updateLightmap(normal[v], lightmap[v], x, y, z); - if(dataLength[lightmapIndex] > 1) - { - if(blockLight > lightmap[v][0]) lightmap[v][0] = blockLight; - if(skyLight > lightmap[v][1]) lightmap[v][1] = skyLight; - } - updateColor(normal[v], color[v], x, y, z, tint, multiplier); - if(diffuse) - { - float d = LightUtil.diffuseLight(normal[v][0], normal[v][1], normal[v][2]); - for(int i = 0; i < 3; i++) - { - color[v][i] *= d; - } - } - - // no need for remapping cause all we could've done is add 1 element to the end - for(int e = 0; e < count; e++) - { - VertexFormatElement element = format.getElements().get(e); - switch(element.getUsage()) - { - case POSITION: - final Vector4f pos = new Vector4f( - position[v][0], position[v][1], position[v][2], 1); - pos.transform(pose.pose()); - - position[v][0] = pos.x(); - position[v][1] = pos.y(); - position[v][2] = pos.z(); - parent.put(e, position[v]); - break; - case NORMAL: - final Vector3f norm = new Vector3f(normal[v]); - norm.transform(pose.normal()); - - normal[v][0] = norm.x(); - normal[v][1] = norm.y(); - normal[v][2] = norm.z(); - parent.put(e, normal[v]); - break; - case COLOR: - parent.put(e, color[v]); - break; - case UV: - if(element.getIndex() == 2) - { - parent.put(e, lightmap[v]); - break; - } - // else fallthrough to default - default: - parent.put(e, quadData[e][v]); - } - } - } - tint = -1; - } - - protected void updateLightmap(float[] normal, float[] lightmap, float x, float y, float z) - { - final float e1 = 1f - 1e-2f; - final float e2 = 0.95f; - - boolean full = blockInfo.isFullCube(); - Direction side = null; - - if((full || y < -e1) && normal[1] < -e2) side = Direction.DOWN; - else if((full || y > e1) && normal[1] > e2) side = Direction.UP; - else if((full || z < -e1) && normal[2] < -e2) side = Direction.NORTH; - else if((full || z > e1) && normal[2] > e2) side = Direction.SOUTH; - else if((full || x < -e1) && normal[0] < -e2) side = Direction.WEST; - else if((full || x > e1) && normal[0] > e2) side = Direction.EAST; - - int i = side == null ? 0 : side.ordinal() + 1; - int brightness = blockInfo.getPackedLight()[i]; - - lightmap[0] = LightTexture.block(brightness) / (float) 0xF; - lightmap[1] = LightTexture.sky(brightness) / (float) 0xF; - } - - protected void updateColor(float[] normal, float[] color, float x, float y, float z, float tint, int multiplier) - { - if(tint != -1) - { - color[0] *= (float)(multiplier >> 0x10 & 0xFF) / 0xFF; - color[1] *= (float)(multiplier >> 0x8 & 0xFF) / 0xFF; - color[2] *= (float)(multiplier & 0xFF) / 0xFF; - } - } - - @Override - public void setQuadTint(int tint) - { - this.tint = tint; - } - @Override - public void setQuadOrientation(Direction orientation) {} - public void setQuadCulled() {} - @Override - public void setTexture(TextureAtlasSprite texture) {} - @Override - public void setApplyDiffuseLighting(boolean diffuse) - { - this.diffuse = diffuse; - } - - public void setWorld(BlockAndTintGetter level) - { - blockInfo.setLevel(level); - } - - public void setState(BlockState state) - { - blockInfo.setState(state); - } - - public void setBlockPos(BlockPos blockPos) - { - blockInfo.setBlockPos(blockPos); - } - - public void resetBlockInfo() - { - blockInfo.reset(); - } - - public void updateBlockInfo() - { - blockInfo.updateFlatLighting(); - } -} diff --git a/src/main/java/net/minecraftforge/client/model/pipeline/VertexLighterSmoothAo.java b/src/main/java/net/minecraftforge/client/model/pipeline/VertexLighterSmoothAo.java deleted file mode 100644 index c1d30b26cbd..00000000000 --- a/src/main/java/net/minecraftforge/client/model/pipeline/VertexLighterSmoothAo.java +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Copyright (c) Forge Development LLC and contributors - * SPDX-License-Identifier: LGPL-2.1-only - */ - -package net.minecraftforge.client.model.pipeline; - -import net.minecraft.client.color.block.BlockColors; -import net.minecraft.util.Mth; - - -public class VertexLighterSmoothAo extends VertexLighterFlat -{ - public VertexLighterSmoothAo(BlockColors colors) - { - super(colors); - } - - @Override - protected void updateLightmap(float[] normal, float[] lightmap, float x, float y, float z) - { - lightmap[0] = calcLightmap(blockInfo.getBlockLight(), x, y, z); - lightmap[1] = calcLightmap(blockInfo.getSkyLight(), x, y, z); - } - - @Override - protected void updateColor(float[] normal, float[] color, float x, float y, float z, float tint, int multiplier) - { - super.updateColor(normal, color, x, y, z, tint, multiplier); - float a = getAo(x, y, z); - color[0] *= a; - color[1] *= a; - color[2] *= a; - } - - protected float calcLightmap(float[][][][] light, float x, float y, float z) - { - x *= 2; - y *= 2; - z *= 2; - float l2 = x * x + y * y + z * z; - if(l2 > 6 - 2e-2f) - { - float s = (float)Math.sqrt((6 - 2e-2f) / l2); - x *= s; - y *= s; - z *= s; - } - float ax = x > 0 ? x : -x; - float ay = y > 0 ? y : -y; - float az = z > 0 ? z : -z; - float e1 = 1 + 1e-4f; - if(ax > 2 - 1e-4f && ay <= e1 && az <= e1) - { - x = x < 0 ? -2 + 1e-4f : 2 - 1e-4f; - } - else if(ay > 2 - 1e-4f && az <= e1 && ax <= e1) - { - y = y < 0 ? -2 + 1e-4f : 2 - 1e-4f; - } - else if(az > 2 - 1e-4f && ax <= e1 && ay <= e1) - { - z = z < 0 ? -2 + 1e-4f : 2 - 1e-4f; - } - ax = x > 0 ? x : -x; - ay = y > 0 ? y : -y; - az = z > 0 ? z : -z; - if(ax <= e1 && ay + az > 3f - 1e-4f) - { - float s = (3f - 1e-4f) / (ay + az); - y *= s; - z *= s; - } - else if(ay <= e1 && az + ax > 3f - 1e-4f) - { - float s = (3f - 1e-4f) / (az + ax); - z *= s; - x *= s; - } - else if(az <= e1 && ax + ay > 3f - 1e-4f) - { - float s = (3f - 1e-4f) / (ax + ay); - x *= s; - y *= s; - } - else if(ax + ay + az > 4 - 1e-4f) - { - float s = (4 - 1e-4f) / (ax + ay + az); - x *= s; - y *= s; - z *= s; - } - - float l = 0; - float s = 0; - - for(int ix = 0; ix <= 1; ix++) - { - for(int iy = 0; iy <= 1; iy++) - { - for(int iz = 0; iz <= 1; iz++) - { - float vx = x * (1 - ix * 2); - float vy = y * (1 - iy * 2); - float vz = z * (1 - iz * 2); - - float s3 = vx + vy + vz + 4; - float sx = vy + vz + 3; - float sy = vz + vx + 3; - float sz = vx + vy + 3; - - float bx = (2 * vx + vy + vz + 6) / (s3 * sy * sz * (vx + 2)); - s += bx; - l += bx * light[0][ix][iy][iz]; - - float by = (2 * vy + vz + vx + 6) / (s3 * sz * sx * (vy + 2)); - s += by; - l += by * light[1][ix][iy][iz]; - - float bz = (2 * vz + vx + vy + 6) / (s3 * sx * sy * (vz + 2)); - s += bz; - l += bz * light[2][ix][iy][iz]; - } - } - } - - l /= s; - l = Mth.clamp(l, 0, 1); - return l; - } - - protected float getAo(float x, float y, float z) - { - int sx = x < 0 ? 1 : 2; - int sy = y < 0 ? 1 : 2; - int sz = z < 0 ? 1 : 2; - - if(x < 0) x++; - if(y < 0) y++; - if(z < 0) z++; - - float a = 0; - float[][][] ao = blockInfo.getAo(); - a += ao[sx - 1][sy - 1][sz - 1] * (1 - x) * (1 - y) * (1 - z); - a += ao[sx - 1][sy - 1][sz - 0] * (1 - x) * (1 - y) * (0 + z); - a += ao[sx - 1][sy - 0][sz - 1] * (1 - x) * (0 + y) * (1 - z); - a += ao[sx - 1][sy - 0][sz - 0] * (1 - x) * (0 + y) * (0 + z); - a += ao[sx - 0][sy - 1][sz - 1] * (0 + x) * (1 - y) * (1 - z); - a += ao[sx - 0][sy - 1][sz - 0] * (0 + x) * (1 - y) * (0 + z); - a += ao[sx - 0][sy - 0][sz - 1] * (0 + x) * (0 + y) * (1 - z); - a += ao[sx - 0][sy - 0][sz - 0] * (0 + x) * (0 + y) * (0 + z); - - a = Mth.clamp(a, 0, 1); - return a; - } - - @Override - public void updateBlockInfo() - { - blockInfo.updateLightMatrix(); - } -} diff --git a/src/main/java/net/minecraftforge/client/model/pipeline/VertexTransformer.java b/src/main/java/net/minecraftforge/client/model/pipeline/VertexTransformer.java deleted file mode 100644 index 44bb57da6e4..00000000000 --- a/src/main/java/net/minecraftforge/client/model/pipeline/VertexTransformer.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) Forge Development LLC and contributors - * SPDX-License-Identifier: LGPL-2.1-only - */ - -package net.minecraftforge.client.model.pipeline; - -import net.minecraft.client.renderer.texture.TextureAtlasSprite; -import com.mojang.blaze3d.vertex.VertexFormat; -import net.minecraft.core.Direction; - -public class VertexTransformer implements IVertexConsumer -{ - protected final IVertexConsumer parent; - - public VertexTransformer(IVertexConsumer parent) - { - this.parent = parent; - } - - @Override - public VertexFormat getVertexFormat() - { - return parent.getVertexFormat(); - } - - @Override - public void setQuadTint(int tint) - { - parent.setQuadTint(tint); - } - - @Override - public void setTexture(TextureAtlasSprite texture) - { - parent.setTexture(texture); - } - - @Override - public void setQuadOrientation(Direction orientation) - { - parent.setQuadOrientation(orientation); - } - - @Override - public void setApplyDiffuseLighting(boolean diffuse) - { - parent.setApplyDiffuseLighting(diffuse); - } - - @Override - public void put(int element, float... data) - { - parent.put(element, data); - } -} diff --git a/src/main/java/net/minecraftforge/client/model/renderable/BakedModelRenderable.java b/src/main/java/net/minecraftforge/client/model/renderable/BakedModelRenderable.java new file mode 100644 index 00000000000..252e5684ea0 --- /dev/null +++ b/src/main/java/net/minecraftforge/client/model/renderable/BakedModelRenderable.java @@ -0,0 +1,97 @@ +/* + * Copyright (c) Forge Development LLC and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.minecraftforge.client.model.renderable; + +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.math.Vector4f; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.block.model.BakedQuad; +import net.minecraft.client.resources.model.BakedModel; +import net.minecraft.core.Direction; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.RandomSource; +import net.minecraft.util.Unit; +import net.minecraft.world.inventory.InventoryMenu; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraftforge.client.model.data.ModelData; +import org.jetbrains.annotations.Nullable; + +import java.util.Arrays; + +/** + * {@linkplain IRenderable Renderable} wrapper for {@linkplain BakedModel baked models}. + *

+ * The context can provide the {@link BlockState}, faces to be rendered, a {@link RandomSource} and seed, + * a {@link ModelData} instance, and a {@link Vector4f tint}. + * + * @see Context + */ +public class BakedModelRenderable implements IRenderable +{ + /** + * Constructs a {@link BakedModelRenderable} from the given model location. + * The model is expected to have been baked ahead of time. + * + * @see net.minecraftforge.client.event.ModelEvent.RegisterAdditional + */ + public static BakedModelRenderable of(ResourceLocation model) + { + return of(Minecraft.getInstance().getModelManager().getModel(model)); + } + + /** + * Constructs a {@link BakedModelRenderable} from the given baked model. + */ + public static BakedModelRenderable of(BakedModel model) + { + return new BakedModelRenderable(model); + } + + private final BakedModel model; + + private BakedModelRenderable(BakedModel model) + { + this.model = model; + } + + @Override + public void render(PoseStack poseStack, MultiBufferSource bufferSource, ITextureRenderTypeLookup textureRenderTypeLookup, int lightmap, int overlay, float partialTick, Context context) + { + var buffer = bufferSource.getBuffer(textureRenderTypeLookup.get(InventoryMenu.BLOCK_ATLAS)); + var tint = context.tint(); + var randomSource = context.randomSource(); + for (Direction direction : context.faces()) + { + randomSource.setSeed(context.seed()); + // Given the lack of context, the requested render type has to be null to ensure the model renders all of its geometry + for (BakedQuad quad : model.getQuads(context.state(), direction, randomSource, context.data(), null)) + buffer.putBulkData(poseStack.last(), quad, tint.x(), tint.y(), tint.z(), tint.w(), lightmap, overlay, true); + } + } + + public IRenderable withContext(ModelData modelData) + { + return withContext(new Context(modelData)); + } + + public IRenderable withModelDataContext() + { + return (poseStack, bufferSource, textureRenderTypeLookup, lightmap, overlay, partialTick, context) -> + render(poseStack, bufferSource, textureRenderTypeLookup, lightmap, overlay, partialTick, new Context(context)); + } + + public record Context(@Nullable BlockState state, Direction[] faces, RandomSource randomSource, long seed, ModelData data, Vector4f tint) + { + private static final Direction[] ALL_FACES_AND_NULL = Arrays.copyOf(Direction.values(), Direction.values().length + 1); + private static final Vector4f WHITE = new Vector4f(1, 1, 1, 1); + + public Context(ModelData data) + { + this(null, ALL_FACES_AND_NULL, RandomSource.create(), 42, data, WHITE); + } + } +} diff --git a/src/main/java/net/minecraftforge/client/model/renderable/BakedRenderable.java b/src/main/java/net/minecraftforge/client/model/renderable/BakedRenderable.java deleted file mode 100644 index 3de4be80fd5..00000000000 --- a/src/main/java/net/minecraftforge/client/model/renderable/BakedRenderable.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (c) Forge Development LLC and contributors - * SPDX-License-Identifier: LGPL-2.1-only - */ - -package net.minecraftforge.client.model.renderable; - -import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.blaze3d.vertex.VertexConsumer; -import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.RenderType; -import net.minecraft.client.renderer.block.model.BakedQuad; -import net.minecraft.client.resources.model.BakedModel; -import net.minecraft.core.Direction; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.util.RandomSource; -import net.minecraft.world.inventory.InventoryMenu; -import net.minecraftforge.client.model.data.IModelData; - -import java.util.Arrays; -import java.util.Random; -import java.util.function.Function; - -/** - * Wrapper to make it easier to draw baked models in renderers. - */ -public class BakedRenderable implements IRenderable -{ - private static final Direction[] MODEL_FACINGS = Arrays.copyOf(Direction.values(), Direction.values().length+1); - - /** - * Constructs a BakedRenderable from the given model location. - * The model is expected to have been baked ahead of time. - * You can ensure the model is baked by calling {@link net.minecraftforge.client.model.ForgeModelBakery#addSpecialModel(ResourceLocation)} - * from within {@link net.minecraftforge.client.event.ModelRegistryEvent}. - */ - public static BakedRenderable of(ResourceLocation model) - { - return of(Minecraft.getInstance().getModelManager().getModel(model)); - } - - /** - * Constructs a BakedRenderable from the given model. - */ - public static BakedRenderable of(BakedModel model) - { - return new BakedRenderable(model); - } - - private final RandomSource rand = RandomSource.create(); - private final BakedModel model; - - private BakedRenderable(BakedModel model) - { - this.model = model; - } - - @Override - public void render(PoseStack poseStack, MultiBufferSource bufferSource, Function renderTypeFunction, int lightmapCoord, int overlayCoord, float partialTicks, IModelData renderValues) - { - var rt = renderTypeFunction.apply(InventoryMenu.BLOCK_ATLAS); - VertexConsumer bb = bufferSource.getBuffer(rt); - for(Direction direction : MODEL_FACINGS) - { - for (BakedQuad quad : model.getQuads(null, direction, rand, renderValues)) - { - bb.putBulkData(poseStack.last(), quad, 1, 1, 1, 1, lightmapCoord, overlayCoord, true); - } - } - } -} diff --git a/src/main/java/net/minecraftforge/client/model/renderable/CompositeRenderable.java b/src/main/java/net/minecraftforge/client/model/renderable/CompositeRenderable.java new file mode 100644 index 00000000000..f8450771155 --- /dev/null +++ b/src/main/java/net/minecraftforge/client/model/renderable/CompositeRenderable.java @@ -0,0 +1,181 @@ +/* + * Copyright (c) Forge Development LLC and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.minecraftforge.client.model.renderable; + +import com.google.common.collect.ImmutableMap; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.math.Matrix4f; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.block.model.BakedQuad; +import net.minecraft.resources.ResourceLocation; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.List; + +/** + * A renderable object composed of a hierarchy of parts, each made up of a number of meshes. + *

+ * Each mesh renders a set of quads using a different texture. + * + * @see Builder + */ +public class CompositeRenderable implements IRenderable +{ + private final List components = new ArrayList<>(); + + private CompositeRenderable() + { + } + + @Override + public void render(PoseStack poseStack, MultiBufferSource bufferSource, ITextureRenderTypeLookup textureRenderTypeLookup, int lightmap, int overlay, float partialTick, Transforms context) + { + for (var component : components) + component.render(poseStack, bufferSource, textureRenderTypeLookup, lightmap, overlay, context); + } + + public static Builder builder() + { + return new Builder(); + } + + private static class Component + { + private final String name; + private final List children = new ArrayList<>(); + private final List meshes = new ArrayList<>(); + + public Component(String name) + { + this.name = name; + } + + public void render(PoseStack poseStack, MultiBufferSource bufferSource, ITextureRenderTypeLookup textureRenderTypeLookup, int lightmap, int overlay, Transforms context) + { + Matrix4f matrix = context.getTransform(name); + if (matrix != null) + { + poseStack.pushPose(); + poseStack.mulPoseMatrix(matrix); + } + + for (var part : children) + part.render(poseStack, bufferSource, textureRenderTypeLookup, lightmap, overlay, context); + + for (var mesh : meshes) + mesh.render(poseStack, bufferSource, textureRenderTypeLookup, lightmap, overlay); + + if (matrix != null) + poseStack.popPose(); + } + } + + private static class Mesh + { + private final ResourceLocation texture; + private final List quads = new ArrayList<>(); + + public Mesh(ResourceLocation texture) + { + this.texture = texture; + } + + public void render(PoseStack poseStack, MultiBufferSource bufferSource, ITextureRenderTypeLookup textureRenderTypeLookup, int lightmap, int overlay) + { + var consumer = bufferSource.getBuffer(textureRenderTypeLookup.get(texture)); + for (var quad : quads) + { + consumer.putBulkData(poseStack.last(), quad, 1, 1, 1, 1, lightmap, overlay, true); + } + } + } + + public static class Builder + { + private final CompositeRenderable renderable = new CompositeRenderable(); + + private Builder() + { + } + + public PartBuilder child(String name) + { + var child = new Component(name); + renderable.components.add(child); + return new PartBuilder<>(this, child); + } + + public CompositeRenderable get() + { + return renderable; + } + } + + public static class PartBuilder + { + private final T parent; + private final Component component; + + private PartBuilder(T parent, Component component) + { + this.parent = parent; + this.component = component; + } + + public PartBuilder> child(String name) + { + var child = new Component(component.name + "/" + name); + this.component.children.add(child); + return new PartBuilder<>(this, child); + } + + public PartBuilder addMesh(ResourceLocation texture, List quads) + { + var mesh = new Mesh(texture); + mesh.quads.addAll(quads); + component.meshes.add(mesh); + return this; + } + + public T end() + { + return parent; + } + } + + /** + * A context value that provides {@link Matrix4f} transforms for certain parts of the model. + */ + public static class Transforms + { + /** + * A default instance that has no transforms specified. + */ + public static final Transforms EMPTY = new Transforms(ImmutableMap.of()); + + /** + * Builds a MultipartTransforms object with the given mapping. + */ + public static Transforms of(ImmutableMap parts) + { + return new Transforms(parts); + } + + private final ImmutableMap parts; + + private Transforms(ImmutableMap parts) + { + this.parts = parts; + } + + @Nullable + public Matrix4f getTransform(String part) + { + return parts.get(part); + } + } +} diff --git a/src/main/java/net/minecraftforge/client/model/renderable/IMultipartRenderValues.java b/src/main/java/net/minecraftforge/client/model/renderable/IMultipartRenderValues.java deleted file mode 100644 index be2a626a698..00000000000 --- a/src/main/java/net/minecraftforge/client/model/renderable/IMultipartRenderValues.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (c) Forge Development LLC and contributors - * SPDX-License-Identifier: LGPL-2.1-only - */ - -package net.minecraftforge.client.model.renderable; - -import org.jetbrains.annotations.Nullable; - -/** - * A standard interface for renderable context values that support providing different values for parts of the model. - * @param the type of value to be used for each part - */ -public interface IMultipartRenderValues -{ - /** - * Returns the value for the given part. - * @param part the name of the part - * @return the context value for the part, or {@code null} - */ - @Nullable - T getPartValues(String part); -} diff --git a/src/main/java/net/minecraftforge/client/model/renderable/IRenderable.java b/src/main/java/net/minecraftforge/client/model/renderable/IRenderable.java index f94bc53798c..de1d2726532 100644 --- a/src/main/java/net/minecraftforge/client/model/renderable/IRenderable.java +++ b/src/main/java/net/minecraftforge/client/model/renderable/IRenderable.java @@ -7,40 +7,39 @@ import com.mojang.blaze3d.vertex.PoseStack; import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.RenderType; -import net.minecraft.resources.ResourceLocation; import net.minecraft.util.Unit; -import java.util.function.Function; - /** - * Defines a standard interface for things that can be rendered. - * @param the type of context object used by the rendering logic + * A standard interface for things that can be rendered to a {@link MultiBufferSource}. + * + * @param The type of context object used by the rendering logic */ @FunctionalInterface public interface IRenderable { /** * Draws the renderable by adding the geometry to the provided {@link MultiBufferSource} - * @param poseStack the pose stack - * @param bufferSource the target buffer source to dump the data into - * @param renderTypeFunction a function that provides a RenderType for the given texture - * @param lightmapCoord the lightmap coordinates representing the current lighting conditions. See {@link net.minecraft.client.renderer.LightTexture} - * @param overlayCoord the overlay coordinates representing the current overlay status. See {@link net.minecraft.client.renderer.texture.OverlayTexture} - * @param partialTicks the current time expressed in the fraction of a tick elapsed since the last client tick. - * @param renderValues the context data used for rendering + * + * @param poseStack The pose stack + * @param bufferSource The buffer source where the vertex data should be output + * @param textureRenderTypeLookup A function that provides a RenderType for the given texture + * @param lightmap The lightmap coordinates representing the current lighting conditions. See {@link net.minecraft.client.renderer.LightTexture} + * @param overlay The overlay coordinates representing the current overlay status. See {@link net.minecraft.client.renderer.texture.OverlayTexture} + * @param partialTick The current time expressed in the fraction of a tick elapsed since the last client tick + * @param context The context used for rendering */ - void render(PoseStack poseStack, MultiBufferSource bufferSource, Function renderTypeFunction, int lightmapCoord, int overlayCoord, float partialTicks, T renderValues); + void render(PoseStack poseStack, MultiBufferSource bufferSource, ITextureRenderTypeLookup textureRenderTypeLookup, int lightmap, int overlay, float partialTick, T context); /** - * Wraps the current renderable along with its configuration value. - * Useful for keeping a list of various renderables paired with their configuration values. - * @param renderValues the context data to be used for rendering - * @return a renderable that accepts {@link Unit#INSTANCE} as a configuration value, but uses the provided {@code renderValue} instead + * Wraps the current renderable along with a context. + * Useful for keeping a list of various renderables paired with their contexts. + * + * @param context The context used for rendering + * @return A renderable that accepts {@link Unit#INSTANCE} as context, but uses the provided {@code context} instead */ - default IRenderable withValues(T renderValues) + default IRenderable withContext(T context) { - return (poseStack, bufferSource, renderTypeFunction, lightmapCoord, overlayCoord, partialTicks, unused) -> - this.render(poseStack, bufferSource, renderTypeFunction, lightmapCoord, overlayCoord, partialTicks, renderValues); + return (poseStack, bufferSource, textureRenderTypeLookup, lightmap, overlay, partialTick, unused) -> + this.render(poseStack, bufferSource, textureRenderTypeLookup, lightmap, overlay, partialTick, context); } } diff --git a/src/main/java/net/minecraftforge/client/model/renderable/ITextureRenderTypeLookup.java b/src/main/java/net/minecraftforge/client/model/renderable/ITextureRenderTypeLookup.java new file mode 100644 index 00000000000..02b48b308c5 --- /dev/null +++ b/src/main/java/net/minecraftforge/client/model/renderable/ITextureRenderTypeLookup.java @@ -0,0 +1,18 @@ +/* + * Copyright (c) Forge Development LLC and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.minecraftforge.client.model.renderable; + +import net.minecraft.client.renderer.RenderType; +import net.minecraft.resources.ResourceLocation; + +/** + * A generic lookup for {@link RenderType} implementations that use the specified texture. + */ +@FunctionalInterface +public interface ITextureRenderTypeLookup +{ + RenderType get(ResourceLocation name); +} diff --git a/src/main/java/net/minecraftforge/client/model/renderable/MultipartTransforms.java b/src/main/java/net/minecraftforge/client/model/renderable/MultipartTransforms.java deleted file mode 100644 index 3e6ea6a3947..00000000000 --- a/src/main/java/net/minecraftforge/client/model/renderable/MultipartTransforms.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (c) Forge Development LLC and contributors - * SPDX-License-Identifier: LGPL-2.1-only - */ - -package net.minecraftforge.client.model.renderable; - -import com.google.common.collect.ImmutableMap; -import com.mojang.math.Matrix4f; -import org.jetbrains.annotations.Nullable; - -/** - * A context value that provides {@link Matrix4f} transforms for certain parts of the model. - */ -public class MultipartTransforms implements IMultipartRenderValues -{ - /** - * A default instance that has no transforms specified. - */ - public static final MultipartTransforms EMPTY = new MultipartTransforms(ImmutableMap.of()); - - /** - * Builds a MultipartTransforms object with the given mapping. - */ - public static MultipartTransforms of(ImmutableMap parts) - { - return new MultipartTransforms(parts); - } - - private final ImmutableMap parts; - - private MultipartTransforms(ImmutableMap parts) - { - this.parts = parts; - } - - @Nullable - @Override - public Matrix4f getPartValues(String part) - { - return parts.get(part); - } -} diff --git a/src/main/java/net/minecraftforge/client/model/renderable/SimpleRenderable.java b/src/main/java/net/minecraftforge/client/model/renderable/SimpleRenderable.java deleted file mode 100644 index 927247fe4ed..00000000000 --- a/src/main/java/net/minecraftforge/client/model/renderable/SimpleRenderable.java +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Copyright (c) Forge Development LLC and contributors - * SPDX-License-Identifier: LGPL-2.1-only - */ - -package net.minecraftforge.client.model.renderable; - -import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.math.Matrix4f; -import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.RenderType; -import net.minecraft.client.renderer.block.model.BakedQuad; -import net.minecraft.resources.ResourceLocation; - -import java.util.ArrayList; -import java.util.List; -import java.util.function.Function; - -/** - * Implements a simple renderable consisting of a hierarchy of parts, where each part can contain a number of meshes. - * Each mesh pairs a texture, with a set of quads. - */ -public class SimpleRenderable implements IRenderable -{ - private final List parts = new ArrayList<>(); - - private SimpleRenderable() - { - } - - public static Builder builder() - { - return new Builder(); - } - - @Override - public void render(PoseStack poseStack, MultiBufferSource bufferSource, Function renderTypeFunction, int lightmapCoord, int overlayCoord, float partialTicks, MultipartTransforms renderValues) - { - for(var part : parts) - { - part.render(poseStack, bufferSource, renderTypeFunction, lightmapCoord, overlayCoord, renderValues); - } - } - - private static class Part - { - private final String name; - private final List parts = new ArrayList<>(); - private final List meshes = new ArrayList<>(); - - public Part(String name) - { - this.name = name; - } - - public void render(PoseStack poseStack, MultiBufferSource bufferSource, Function renderTypeFunction, int lightmapCoord, int overlayCoord, MultipartTransforms renderValues) - { - Matrix4f matrix = renderValues.getPartValues(name); - if (matrix != null) - { - poseStack.pushPose(); - poseStack.mulPoseMatrix(matrix); - } - - for(var part : parts) - { - part.render(poseStack, bufferSource, renderTypeFunction, lightmapCoord, overlayCoord, renderValues); - } - - for(var mesh : meshes) - { - mesh.render(poseStack, bufferSource, renderTypeFunction, lightmapCoord, overlayCoord, renderValues); - } - - if (matrix != null) - { - poseStack.popPose(); - } - } - } - - private static class Mesh - { - private final ResourceLocation texture; - private final List quads = new ArrayList<>(); - - public Mesh(ResourceLocation texture) - { - this.texture = texture; - } - - public void render(PoseStack poseStack, MultiBufferSource bufferSource, Function renderTypeFunction, int lightmapCoord, int overlayCoord, MultipartTransforms renderValues) - { - var consumer = bufferSource.getBuffer(renderTypeFunction.apply(texture)); - for(var quad : quads) - { - consumer.putBulkData(poseStack.last(), quad, 1, 1, 1, 1, lightmapCoord, overlayCoord, true); - } - } - } - - public static class Builder - { - private final SimpleRenderable renderable = new SimpleRenderable(); - - private Builder() - { - } - - public PartBuilder child(String name) - { - var child = new Part(name); - renderable.parts.add(child); - return new PartBuilder<>(this, child); - } - - public SimpleRenderable get() - { - return renderable; - } - } - - public static class PartBuilder - { - private final T parent; - private final Part part; - - private PartBuilder(T parent, Part part) - { - this.parent = parent; - this.part = part; - } - - public PartBuilder> child(String name) - { - var child = new Part(part.name + "/" + name); - this.part.parts.add(child); - return new PartBuilder<>(this, child); - } - - public PartBuilder addMesh(ResourceLocation texture, List quads) - { - var mesh = new Mesh(texture); - mesh.quads.addAll(quads); - part.meshes.add(mesh); - return this; - } - - public T end() - { - return parent; - } - } -} diff --git a/src/main/java/net/minecraftforge/client/settings/KeyBindingMap.java b/src/main/java/net/minecraftforge/client/settings/KeyMappingLookup.java similarity index 84% rename from src/main/java/net/minecraftforge/client/settings/KeyBindingMap.java rename to src/main/java/net/minecraftforge/client/settings/KeyMappingLookup.java index a17c57541ae..795d3486edf 100644 --- a/src/main/java/net/minecraftforge/client/settings/KeyBindingMap.java +++ b/src/main/java/net/minecraftforge/client/settings/KeyMappingLookup.java @@ -5,8 +5,8 @@ package net.minecraftforge.client.settings; -import net.minecraft.client.KeyMapping; import com.mojang.blaze3d.platform.InputConstants; +import net.minecraft.client.KeyMapping; import org.jetbrains.annotations.Nullable; import java.util.ArrayList; @@ -16,7 +16,7 @@ import java.util.List; import java.util.Map; -public class KeyBindingMap +public class KeyMappingLookup { private static final EnumMap>> map = new EnumMap<>(KeyModifier.class); static @@ -28,22 +28,22 @@ public class KeyBindingMap } @Nullable - public KeyMapping lookupActive(InputConstants.Key keyCode) + public KeyMapping get(InputConstants.Key keyCode) { KeyModifier activeModifier = KeyModifier.getActiveModifier(); if (!activeModifier.matches(keyCode)) { - KeyMapping binding = getBinding(keyCode, activeModifier); + KeyMapping binding = get(keyCode, activeModifier); if (binding != null) { return binding; } } - return getBinding(keyCode, KeyModifier.NONE); + return get(keyCode, KeyModifier.NONE); } @Nullable - private KeyMapping getBinding(InputConstants.Key keyCode, KeyModifier keyModifier) + private KeyMapping get(InputConstants.Key keyCode, KeyModifier keyModifier) { Collection bindings = map.get(keyModifier).get(keyCode); if (bindings != null) @@ -59,7 +59,7 @@ private KeyMapping getBinding(InputConstants.Key keyCode, KeyModifier keyModifie return null; } - public List lookupAll(InputConstants.Key keyCode) + public List getAll(InputConstants.Key keyCode) { List matchingBindings = new ArrayList(); for (Map> bindingsMap : map.values()) @@ -73,7 +73,7 @@ public List lookupAll(InputConstants.Key keyCode) return matchingBindings; } - public void addKey(InputConstants.Key keyCode, KeyMapping keyBinding) + public void put(InputConstants.Key keyCode, KeyMapping keyBinding) { KeyModifier keyModifier = keyBinding.getKeyModifier(); Map> bindingsMap = map.get(keyModifier); @@ -86,7 +86,7 @@ public void addKey(InputConstants.Key keyCode, KeyMapping keyBinding) bindingsForKey.add(keyBinding); } - public void removeKey(KeyMapping keyBinding) + public void remove(KeyMapping keyBinding) { KeyModifier keyModifier = keyBinding.getKeyModifier(); InputConstants.Key keyCode = keyBinding.getKey(); @@ -102,7 +102,7 @@ public void removeKey(KeyMapping keyBinding) } } - public void clearMap() + public void clear() { for (Map> bindings : map.values()) { diff --git a/src/main/java/net/minecraftforge/client/textures/ForgeTextureMetadata.java b/src/main/java/net/minecraftforge/client/textures/ForgeTextureMetadata.java index 717cfa74fdd..93a05a5062e 100644 --- a/src/main/java/net/minecraftforge/client/textures/ForgeTextureMetadata.java +++ b/src/main/java/net/minecraftforge/client/textures/ForgeTextureMetadata.java @@ -9,7 +9,6 @@ import net.minecraft.server.packs.metadata.MetadataSectionSerializer; import net.minecraft.server.packs.resources.Resource; import net.minecraft.util.GsonHelper; -import net.minecraftforge.client.MinecraftForgeClient; import com.google.gson.JsonObject; import com.google.gson.JsonSyntaxException; @@ -68,7 +67,7 @@ public ForgeTextureMetadata fromJson(JsonObject json) if (json.has("loader")) { ResourceLocation loaderName = new ResourceLocation(GsonHelper.getAsString(json, "loader")); - loader = MinecraftForgeClient.getTextureAtlasSpriteLoader(loaderName); + loader = TextureAtlasSpriteLoaderManager.get(loaderName); if (loader == null) { throw new JsonSyntaxException("Unknown TextureAtlasSpriteLoader " + loaderName); diff --git a/src/main/java/net/minecraftforge/client/textures/ITextureAtlasSpriteLoader.java b/src/main/java/net/minecraftforge/client/textures/ITextureAtlasSpriteLoader.java index 9809351e5a2..1e9f09ad058 100644 --- a/src/main/java/net/minecraftforge/client/textures/ITextureAtlasSpriteLoader.java +++ b/src/main/java/net/minecraftforge/client/textures/ITextureAtlasSpriteLoader.java @@ -8,13 +8,13 @@ import com.mojang.blaze3d.platform.NativeImage; import net.minecraft.client.renderer.texture.TextureAtlas; import net.minecraft.client.renderer.texture.TextureAtlasSprite; -import net.minecraft.resources.ResourceLocation; import net.minecraft.server.packs.resources.Resource; import net.minecraft.server.packs.resources.ResourceManager; import org.jetbrains.annotations.NotNull; /** - * A loader for custom TextureAtlasSprite implementations.
+ * A loader for custom {@linkplain TextureAtlasSprite texture atlas sprites}. + *

* The loader can be specified in the corresponding .mcmeta file for a texture as follows: *

  * {
@@ -23,22 +23,16 @@
  *   }
  * }
  * 
- * @see net.minecraftforge.client.MinecraftForgeClient#registerTextureAtlasSpriteLoader(ResourceLocation, ITextureAtlasSpriteLoader) + * + * @see net.minecraftforge.client.event.RegisterTextureAtlasSpriteLoadersEvent */ public interface ITextureAtlasSpriteLoader { - /** - * Load a TextureAtlasSprite for the given resource. + * Load a {@link TextureAtlasSprite} for the given resource. */ @NotNull - TextureAtlasSprite load( - TextureAtlas atlas, - ResourceManager resourceManager, TextureAtlasSprite.Info textureInfo, - Resource resource, - int atlasWidth, int atlasHeight, - int spriteX, int spriteY, int mipmapLevel, - NativeImage image - ); - + TextureAtlasSprite load(TextureAtlas atlas, ResourceManager resourceManager, TextureAtlasSprite.Info textureInfo, + Resource resource, int atlasWidth, int atlasHeight, int spriteX, int spriteY, + int mipmapLevel, NativeImage image); } diff --git a/src/main/java/net/minecraftforge/client/textures/TextureAtlasSpriteLoaderManager.java b/src/main/java/net/minecraftforge/client/textures/TextureAtlasSpriteLoaderManager.java new file mode 100644 index 00000000000..478eedf2dc5 --- /dev/null +++ b/src/main/java/net/minecraftforge/client/textures/TextureAtlasSpriteLoaderManager.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) Forge Development LLC and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.minecraftforge.client.textures; + +import com.google.common.collect.ImmutableMap; +import net.minecraft.resources.ResourceLocation; +import net.minecraftforge.client.event.RegisterTextureAtlasSpriteLoadersEvent; +import net.minecraftforge.fml.ModLoader; +import net.minecraftforge.fml.ModLoadingContext; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.Nullable; + +import java.util.HashMap; + +/** + * Manager for {@link ITextureAtlasSpriteLoader} instances. + *

+ * Provides a lookup. + */ +public final class TextureAtlasSpriteLoaderManager +{ + private static ImmutableMap LOADERS; + + /** + * Finds the loader with the given name, or null if none is registered. + */ + @Nullable + public static ITextureAtlasSpriteLoader get(ResourceLocation name) + { + return LOADERS.get(name); + } + + @ApiStatus.Internal + public static void init() + { + var loaders = new HashMap(); + var event = new RegisterTextureAtlasSpriteLoadersEvent(loaders); + ModLoader.get().postEventWithWrapInModOrder(event, (mc, e) -> ModLoadingContext.get().setActiveContainer(mc), (mc, e) -> ModLoadingContext.get().setActiveContainer(null)); + LOADERS = ImmutableMap.copyOf(loaders); + } + + private TextureAtlasSpriteLoaderManager() + { + } +} diff --git a/src/main/java/net/minecraftforge/client/textures/UnitSprite.java b/src/main/java/net/minecraftforge/client/textures/UnitTextureAtlasSprite.java similarity index 70% rename from src/main/java/net/minecraftforge/client/textures/UnitSprite.java rename to src/main/java/net/minecraftforge/client/textures/UnitTextureAtlasSprite.java index 276ef0efd8b..5929dac7b2b 100644 --- a/src/main/java/net/minecraftforge/client/textures/UnitSprite.java +++ b/src/main/java/net/minecraftforge/client/textures/UnitTextureAtlasSprite.java @@ -9,21 +9,19 @@ import net.minecraft.client.renderer.texture.TextureAtlas; import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.client.resources.metadata.animation.AnimationMetadataSection; -import net.minecraft.client.resources.model.Material; import net.minecraft.resources.ResourceLocation; -import java.util.function.Function; - /** - * A helper that lets you bake quads that won't be used with an atlas. + * A helper sprite with UVs spanning the entire texture. + *

+ * Useful for baking quads that won't be used with an atlas. */ -public class UnitSprite extends TextureAtlasSprite +public class UnitTextureAtlasSprite extends TextureAtlasSprite { - public static final UnitSprite INSTANCE = new UnitSprite(); + public static final UnitTextureAtlasSprite INSTANCE = new UnitTextureAtlasSprite(); public static final ResourceLocation LOCATION = new ResourceLocation("forge", "unit"); - public static final Function GETTER = (x) -> INSTANCE; - private UnitSprite() + private UnitTextureAtlasSprite() { super(new TextureAtlas(LOCATION), new Info(LOCATION, 1, 1, AnimationMetadataSection.EMPTY), diff --git a/src/main/java/net/minecraftforge/common/ForgeMod.java b/src/main/java/net/minecraftforge/common/ForgeMod.java index 0d04f73dcf5..fd1491055b0 100644 --- a/src/main/java/net/minecraftforge/common/ForgeMod.java +++ b/src/main/java/net/minecraftforge/common/ForgeMod.java @@ -33,9 +33,7 @@ import net.minecraft.world.level.material.FluidState; import net.minecraft.world.level.pathfinder.BlockPathTypes; import net.minecraft.world.phys.Vec3; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.client.IFluidTypeRenderProperties; -import net.minecraftforge.client.model.ModelLoaderRegistry; +import net.minecraftforge.client.extensions.common.IClientFluidTypeExtensions; import net.minecraftforge.common.capabilities.RegisterCapabilitiesEvent; import net.minecraftforge.common.crafting.PartialNBTIngredient; import net.minecraftforge.common.crafting.DifferenceIngredient; @@ -61,7 +59,6 @@ import net.minecraftforge.fml.*; import net.minecraftforge.fml.config.ModConfig; import net.minecraftforge.fml.event.lifecycle.*; -import net.minecraftforge.fml.loading.FMLEnvironment; import net.minecraftforge.registries.*; import net.minecraftforge.network.NetworkConstants; import net.minecraftforge.event.server.ServerStoppingEvent; @@ -255,9 +252,9 @@ public void setItemMovement(ItemEntity entity) } @Override - public void initializeClient(Consumer consumer) + public void initializeClient(Consumer consumer) { - consumer.accept(new IFluidTypeRenderProperties() + consumer.accept(new IClientFluidTypeExtensions() { private static final ResourceLocation UNDERWATER_LOCATION = new ResourceLocation("textures/misc/underwater.png"), WATER_STILL = new ResourceLocation("block/water_still"), @@ -290,13 +287,13 @@ public ResourceLocation getRenderOverlayTexture(Minecraft mc) } @Override - public int getColorTint() + public int getTintColor() { return 0xFF3F76E4; } @Override - public int getColorTint(FluidState state, BlockAndTintGetter getter, BlockPos pos) + public int getTintColor(FluidState state, BlockAndTintGetter getter, BlockPos pos) { return BiomeColors.getAverageWaterColor(getter, pos) | 0xFF000000; } @@ -331,9 +328,9 @@ public void setItemMovement(ItemEntity entity) } @Override - public void initializeClient(Consumer consumer) + public void initializeClient(Consumer consumer) { - consumer.accept(new IFluidTypeRenderProperties() + consumer.accept(new IClientFluidTypeExtensions() { private static final ResourceLocation LAVA_STILL = new ResourceLocation("block/lava_still"), LAVA_FLOW = new ResourceLocation("block/lava_flow"); @@ -417,11 +414,6 @@ public ForgeMod() MinecraftForge.EVENT_BUS.addListener(this::mappingChanged); ForgeRegistries.ITEMS.tags().addOptionalTagDefaults(Tags.Items.ENCHANTING_FUELS, Set.of(ForgeRegistries.ITEMS.getDelegateOrThrow(Items.LAPIS_LAZULI))); - - if (FMLEnvironment.dist == Dist.CLIENT) - { - ModelLoaderRegistry.init(); - } } public void registerCapabilities(RegisterCapabilitiesEvent event) @@ -496,9 +488,9 @@ public void registerFluids(RegisterEvent event) event.register(ForgeRegistries.Keys.FLUID_TYPES, helper -> helper.register(MILK_TYPE.getId(), new FluidType(FluidType.Properties.create().density(1024).viscosity(1024)) { @Override - public void initializeClient(Consumer consumer) + public void initializeClient(Consumer consumer) { - consumer.accept(new IFluidTypeRenderProperties() + consumer.accept(new IClientFluidTypeExtensions() { private static final ResourceLocation MILK_STILL = new ResourceLocation("forge", "block/milk_still"), MILK_FLOW = new ResourceLocation("forge", "block/milk_flowing"); diff --git a/src/main/java/net/minecraftforge/common/ForgeSpawnEggItem.java b/src/main/java/net/minecraftforge/common/ForgeSpawnEggItem.java index efc0093194f..971f92673b5 100644 --- a/src/main/java/net/minecraftforge/common/ForgeSpawnEggItem.java +++ b/src/main/java/net/minecraftforge/common/ForgeSpawnEggItem.java @@ -16,7 +16,7 @@ import net.minecraft.world.level.block.DispenserBlock; import net.minecraft.world.level.gameevent.GameEvent; import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.client.event.ColorHandlerEvent; +import net.minecraftforge.client.event.RegisterColorHandlersEvent; import net.minecraftforge.eventbus.api.EventPriority; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.Mod; @@ -108,7 +108,7 @@ public static void onCommonSetup(FMLCommonSetupEvent event) private static class ColorRegisterHandler { @SubscribeEvent(priority = EventPriority.HIGHEST) - public static void registerSpawnEggColors(ColorHandlerEvent.Item event) + public static void registerSpawnEggColors(RegisterColorHandlersEvent.Item event) { MOD_EGGS.forEach(egg -> event.getItemColors().register((stack, layer) -> egg.getColor(layer), egg) diff --git a/src/main/java/net/minecraftforge/common/TierSortingRegistry.java b/src/main/java/net/minecraftforge/common/TierSortingRegistry.java index 09dfe53c01c..e20720a17c8 100644 --- a/src/main/java/net/minecraftforge/common/TierSortingRegistry.java +++ b/src/main/java/net/minecraftforge/common/TierSortingRegistry.java @@ -389,7 +389,7 @@ public static void init() MinecraftForge.EVENT_BUS.addListener(ClientEvents::clientLogInToServer); } - private static void clientLogInToServer(ClientPlayerNetworkEvent.LoggedInEvent event) + private static void clientLogInToServer(ClientPlayerNetworkEvent.LoggingIn event) { if (event.getConnection() == null || !event.getConnection().isMemoryConnection()) recalculateItemTiers(); diff --git a/src/main/java/net/minecraftforge/common/extensions/IForgeBlockEntity.java b/src/main/java/net/minecraftforge/common/extensions/IForgeBlockEntity.java index 3d36c752d73..79710227d02 100644 --- a/src/main/java/net/minecraftforge/common/extensions/IForgeBlockEntity.java +++ b/src/main/java/net/minecraftforge/common/extensions/IForgeBlockEntity.java @@ -20,9 +20,7 @@ import net.minecraft.core.BlockPos; import net.minecraft.world.phys.shapes.VoxelShape; import net.minecraft.world.level.Level; -import net.minecraftforge.client.model.ModelDataManager; -import net.minecraftforge.client.model.data.EmptyModelData; -import net.minecraftforge.client.model.data.IModelData; +import net.minecraftforge.client.model.data.ModelData; import net.minecraftforge.common.capabilities.ICapabilitySerializable; import org.jetbrains.annotations.NotNull; @@ -157,7 +155,11 @@ default void requestModelDataUpdate() Level level = te.getLevel(); if (level != null && level.isClientSide) { - ModelDataManager.requestModelDataRefresh(te); + var modelDataManager = level.getModelDataManager(); + if (modelDataManager != null) + { + modelDataManager.requestRefresh(te); + } } } @@ -168,8 +170,8 @@ default void requestModelDataUpdate() * Note that this method may be called on a chunk render thread instead of the main client thread * @return Your model data */ - default @NotNull IModelData getModelData() + default @NotNull ModelData getModelData() { - return EmptyModelData.INSTANCE; + return ModelData.EMPTY; } } diff --git a/src/main/java/net/minecraftforge/common/extensions/IForgeBlockGetter.java b/src/main/java/net/minecraftforge/common/extensions/IForgeBlockGetter.java index 16af2db774e..eee5e27fb97 100644 --- a/src/main/java/net/minecraftforge/common/extensions/IForgeBlockGetter.java +++ b/src/main/java/net/minecraftforge/common/extensions/IForgeBlockGetter.java @@ -11,6 +11,7 @@ import net.minecraft.world.level.Level; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.chunk.*; +import net.minecraftforge.client.model.data.ModelDataManager; import org.jetbrains.annotations.Nullable; public interface IForgeBlockGetter @@ -47,4 +48,14 @@ else if (this instanceof ImposterProtoChunk chunk) } return self().getBlockEntity(pos); } + + /** + * Retrieves the model data manager for this level. + * This will be {@code null} on a server level. + */ + @Nullable + default ModelDataManager getModelDataManager() + { + return null; + } } diff --git a/src/main/java/net/minecraftforge/common/util/ConcatenatedListView.java b/src/main/java/net/minecraftforge/common/util/ConcatenatedListView.java new file mode 100644 index 00000000000..d433147cdeb --- /dev/null +++ b/src/main/java/net/minecraftforge/common/util/ConcatenatedListView.java @@ -0,0 +1,148 @@ +/* + * Copyright (c) Forge Development LLC and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.minecraftforge.common.util; + +import com.google.common.collect.Iterables; +import com.google.common.collect.Lists; +import org.jetbrains.annotations.NotNull; + +import java.util.*; +import java.util.function.Supplier; + +/** + * A list that concatenates multiple other lists for efficient iteration.

+ * You may use this in place of creating a new list and calling {@link List#addAll(Collection)} + * for each of your collections.

+ * This list does not support modification operations, but the underlying lists may be mutated safely externally. + */ +public class ConcatenatedListView implements List +{ + public static List of(List> members) + { + return switch (members.size()) { + case 0 -> List.of(); + case 1 -> Collections.unmodifiableList(members.get(0)); + default -> new ConcatenatedListView<>(members); + }; + } + + private final List> lists; + + private ConcatenatedListView(List> lists) + { + this.lists = lists; + } + + @Override + public int size() + { + int size = 0; + for (var list : lists) + size += list.size(); + return size; + } + + @Override + public boolean isEmpty() + { + for (List list : lists) + if (!list.isEmpty()) + return false; + return true; + } + + @Override + public boolean contains(Object o) + { + for (var list : lists) + if (list.contains(o)) + return true; + return false; + } + + @Override + public T get(int index) + { + for (var list : lists) + { + int size = list.size(); + if (index < size) + return list.get(index); + index -= size; + } + throw new IndexOutOfBoundsException(index); + } + + @Override + public int indexOf(Object o) + { + int offset = 0; + for (var list : lists) + { + int foundIndex = list.indexOf(o); + if (foundIndex >= 0) + return offset + foundIndex; + offset += list.size(); + } + return -1; + } + + @Override + public int lastIndexOf(Object o) + { + int offset = 0; + for (var list : Lists.reverse(lists)) + { + int foundIndex = list.lastIndexOf(o); + if (foundIndex >= 0) + return offset + foundIndex; + offset += list.size(); + } + return -1; + } + + @NotNull + @Override + public Iterator iterator() + { + return Iterables.unmodifiableIterable(Iterables.concat(lists)).iterator(); + } + + @Override + public Spliterator spliterator() + { + return Iterables.unmodifiableIterable(Iterables.concat(lists)).spliterator(); + } + + // Delegate to a concatenated collection + private > C concatenate(Supplier collectionFactory) + { + var concat = collectionFactory.get(); + for (var list : lists) + concat.addAll(list); + return concat; + } + @NotNull @Override public Object[] toArray() { return concatenate(ArrayList::new).toArray(); } + @NotNull @Override public T1[] toArray(@NotNull T1[] a) { return concatenate(ArrayList::new).toArray(a); } + @Override public boolean containsAll(@NotNull Collection c) { return concatenate(HashSet::new).containsAll(c); } + + // No mutations allowed + @Override public boolean add(T t) { throw new UnsupportedOperationException(); } + @Override public void add(int index, T element) { throw new UnsupportedOperationException(); } + @Override public T set(int index, T element) { throw new UnsupportedOperationException(); } + @Override public boolean addAll(@NotNull Collection c) { throw new UnsupportedOperationException(); } + @Override public boolean addAll(int index, @NotNull Collection c) { throw new UnsupportedOperationException(); } + @Override public boolean remove(Object o) { throw new UnsupportedOperationException(); } + @Override public T remove(int index) { throw new UnsupportedOperationException(); } + @Override public boolean removeAll(@NotNull Collection c) { throw new UnsupportedOperationException(); } + @Override public boolean retainAll(@NotNull Collection c) { throw new UnsupportedOperationException(); } + @Override public void clear() { throw new UnsupportedOperationException(); } + + // Other unsupported operations - we could support these, but effort + @NotNull @Override public ListIterator listIterator() { throw new UnsupportedOperationException(); } + @NotNull @Override public ListIterator listIterator(int index) { throw new UnsupportedOperationException(); } + @NotNull @Override public List subList(int fromIndex, int toIndex) { throw new UnsupportedOperationException(); } +} diff --git a/src/main/java/net/minecraftforge/common/model/TransformationHelper.java b/src/main/java/net/minecraftforge/common/util/TransformationHelper.java similarity index 92% rename from src/main/java/net/minecraftforge/common/model/TransformationHelper.java rename to src/main/java/net/minecraftforge/common/util/TransformationHelper.java index 224a6548aa5..c0c564aa9f4 100644 --- a/src/main/java/net/minecraftforge/common/model/TransformationHelper.java +++ b/src/main/java/net/minecraftforge/common/util/TransformationHelper.java @@ -3,18 +3,16 @@ * SPDX-License-Identifier: LGPL-2.1-only */ -package net.minecraftforge.common.model; +package net.minecraftforge.common.util; import java.lang.reflect.Type; +import java.util.HashSet; import java.util.Map; +import java.util.Set; import com.google.gson.*; import net.minecraft.util.Mth; -import net.minecraft.client.renderer.block.model.ItemTransform; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; - import com.mojang.math.Matrix4f; import com.mojang.math.Quaternion; import com.mojang.math.Transformation; @@ -23,16 +21,6 @@ public final class TransformationHelper { - @Deprecated - @OnlyIn(Dist.CLIENT) - // TODO: this is used in 3 places, not a trivial refactor. Needs investigating. -C - public static Transformation toTransformation(ItemTransform transform) - { - if (transform.equals(ItemTransform.NO_TRANSFORM)) return Transformation.identity(); - - return new Transformation(transform.translation, quatFromXYZ(transform.rotation, true), transform.scale, null); - } - public static Quaternion quatFromXYZ(Vector3f xyz, boolean degrees) { return new Quaternion(xyz.x(), xyz.y(), xyz.z(), degrees); @@ -151,8 +139,7 @@ public Transformation deserialize(JsonElement json, Type typeOfT, JsonDeserializ { // matrix as a sole key ret = new Transformation(parseMatrix(obj.get("matrix"))); - obj.remove("matrix"); - if (obj.entrySet().size() != 0) + if (obj.entrySet().size() > 1) { throw new JsonParseException("TRSR: can't combine matrix and other keys"); } @@ -165,15 +152,21 @@ public Transformation deserialize(JsonElement json, Type typeOfT, JsonDeserializ // TODO: Default origin is opposing corner, due to a mistake. // This should probably be replaced with center in future versions. Vector3f origin = ORIGIN_OPPOSING_CORNER; // TODO: Changing this to ORIGIN_CENTER breaks models, function content needs changing too -C + Set elements = new HashSet<>(obj.keySet()); if (obj.has("translation")) { translation = new Vector3f(parseFloatArray(obj.get("translation"), 3, "Translation")); - obj.remove("translation"); + elements.remove("translation"); } if (obj.has("rotation")) { leftRot = parseRotation(obj.get("rotation")); - obj.remove("rotation"); + elements.remove("rotation"); + } + else if (obj.has("left_rotation")) + { + leftRot = parseRotation(obj.get("left_rotation")); + elements.remove("left_rotation"); } if (obj.has("scale")) { @@ -193,19 +186,24 @@ public Transformation deserialize(JsonElement json, Type typeOfT, JsonDeserializ { scale = new Vector3f(parseFloatArray(obj.get("scale"), 3, "Scale")); } - obj.remove("scale"); + elements.remove("scale"); + } + if (obj.has("right_rotation")) + { + rightRot = parseRotation(obj.get("right_rotation")); + elements.remove("right_rotation"); } - if (obj.has("post-rotation")) + else if (obj.has("post-rotation")) { rightRot = parseRotation(obj.get("post-rotation")); - obj.remove("post-rotation"); + elements.remove("post-rotation"); } if (obj.has("origin")) { origin = parseOrigin(obj); - obj.remove("origin"); + elements.remove("origin"); } - if (!obj.entrySet().isEmpty()) throw new JsonParseException("TRSR: can either have single 'matrix' key, or a combination of 'translation', 'rotation', 'scale', 'post-rotation', 'origin'"); + if (!elements.isEmpty()) throw new JsonParseException("TRSR: can either have single 'matrix' key, or a combination of 'translation', 'rotation' OR 'left_rotation', 'scale', 'post-rotation' (legacy) OR 'right_rotation', 'origin'. Found: " + String.join(", ", elements)); Transformation matrix = new Transformation(translation, leftRot, scale, rightRot); // Use a different origin if needed. diff --git a/src/main/java/net/minecraftforge/event/ForgeEventFactory.java b/src/main/java/net/minecraftforge/event/ForgeEventFactory.java index 5808abd62eb..eafe0f9a4c7 100644 --- a/src/main/java/net/minecraftforge/event/ForgeEventFactory.java +++ b/src/main/java/net/minecraftforge/event/ForgeEventFactory.java @@ -14,7 +14,6 @@ import com.mojang.brigadier.CommandDispatcher; import net.minecraft.commands.CommandBuildContext; -import net.minecraft.network.chat.ChatSender; import net.minecraft.server.MinecraftServer; import net.minecraft.server.ReloadableServerResources; import net.minecraft.server.players.PlayerList; @@ -60,7 +59,6 @@ import net.minecraft.core.BlockPos; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.phys.HitResult; -import net.minecraft.network.chat.ChatType; import net.minecraft.network.chat.Component; import net.minecraft.world.level.Explosion; import net.minecraft.world.level.GameRules; @@ -71,9 +69,6 @@ import net.minecraft.world.level.storage.ServerLevelData; import net.minecraft.world.level.storage.PlayerDataStorage; import net.minecraft.world.phys.Vec3; -import net.minecraftforge.client.MinecraftForgeClient; -import net.minecraftforge.client.event.ClientChatEvent; -import net.minecraftforge.client.event.ClientChatReceivedEvent; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.common.ToolAction; import net.minecraftforge.common.capabilities.CapabilityDispatcher; @@ -309,20 +304,6 @@ public static void firePlayerLoadingEvent(Player player, PlayerDataStorage playe MinecraftForge.EVENT_BUS.post(new PlayerEvent.LoadFromFile(player, playerFileData.getPlayerDataFolder(), uuidString)); } - @Nullable - public static Component onClientChat(ChatType type, Component message, ChatSender chatSender) - { - ClientChatReceivedEvent event = new ClientChatReceivedEvent(type, message, chatSender); - return MinecraftForge.EVENT_BUS.post(event) ? null : event.getMessage(); - } - - @NotNull - public static String onClientSendMessage(String message) - { - ClientChatEvent event = new ClientChatEvent(message); - return MinecraftForge.EVENT_BUS.post(event) ? "" : event.getMessage(); - } - @Nullable public static BlockState onToolUse(BlockState originalState, UseOnContext context, ToolAction toolAction, boolean simulate) { @@ -773,7 +754,6 @@ public static void firePlayerSmeltedEvent(Player player, ItemStack smelted) public static void onRenderTickStart(float timer) { - MinecraftForgeClient.setPartialTick(timer); MinecraftForge.EVENT_BUS.post(new TickEvent.RenderTickEvent(TickEvent.Phase.START, timer)); } diff --git a/src/main/java/net/minecraftforge/fluids/FluidType.java b/src/main/java/net/minecraftforge/fluids/FluidType.java index 16d9de42e12..c1d7d575314 100644 --- a/src/main/java/net/minecraftforge/fluids/FluidType.java +++ b/src/main/java/net/minecraftforge/fluids/FluidType.java @@ -34,7 +34,7 @@ import net.minecraft.world.level.pathfinder.BlockPathTypes; import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.Vec3; -import net.minecraftforge.client.IFluidTypeRenderProperties; +import net.minecraftforge.client.extensions.common.IClientFluidTypeExtensions; import net.minecraftforge.common.ForgeMod; import net.minecraftforge.common.SoundAction; import net.minecraftforge.common.SoundActions; @@ -883,7 +883,7 @@ private void initClient() } } - public void initializeClient(Consumer consumer) + public void initializeClient(Consumer consumer) { } diff --git a/src/main/java/net/minecraftforge/logging/ModelLoaderErrorMessage.java b/src/main/java/net/minecraftforge/logging/ModelLoaderErrorMessage.java deleted file mode 100644 index 12d427d8e58..00000000000 --- a/src/main/java/net/minecraftforge/logging/ModelLoaderErrorMessage.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright (c) Forge Development LLC and contributors - * SPDX-License-Identifier: LGPL-2.1-only - */ - -package net.minecraftforge.logging; - -import com.google.common.base.Joiner; -import com.google.common.collect.HashMultimap; -import com.google.common.collect.Multimap; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.client.renderer.block.BlockModelShaper; -import net.minecraft.client.resources.model.ModelResourceLocation; -import net.minecraftforge.client.model.ForgeModelBakery; -import net.minecraftforge.registries.ForgeRegistries; - -import org.apache.logging.log4j.message.SimpleMessage; - -import java.util.Collection; - -import static net.minecraftforge.client.model.ForgeModelBakery.getInventoryVariant; - -public class ModelLoaderErrorMessage extends SimpleMessage -{ - private final ModelResourceLocation resourceLocation; - private final Exception exception; - - private static Multimap reverseBlockMap = HashMultimap.create(); - private static Multimap reverseItemMap = HashMultimap.create(); - - private static void buildLookups() { - if (!reverseBlockMap.isEmpty()) return; - - ForgeRegistries.BLOCKS.getValues().stream() - .flatMap(block -> block.getStateDefinition().getPossibleStates().stream()) - .forEach(state -> reverseBlockMap.put(BlockModelShaper.stateToModelLocation(state), state)); - - ForgeRegistries.ITEMS.getKeys().forEach(key -> - { - ModelResourceLocation memory = getInventoryVariant(key.toString()); - reverseItemMap.put(memory, key.toString()); - }); - - } - - public ModelLoaderErrorMessage(ModelResourceLocation resourceLocation, Exception exception) - { - // if we're logging these error messages, this will get built for reference - buildLookups(); - this.resourceLocation = resourceLocation; - this.exception = exception; - } - - private void stuffs() { - String domain = resourceLocation.getNamespace(); - String errorMsg = "Exception loading model for variant " + resourceLocation; - Collection blocks = reverseBlockMap.get(resourceLocation); - if(!blocks.isEmpty()) - { - if(blocks.size() == 1) - { - errorMsg += " for blockstate \"" + blocks.iterator().next() + "\""; - } - else - { - errorMsg += " for blockstates [\"" + Joiner.on("\", \"").join(blocks) + "\"]"; - } - } - Collection items = reverseItemMap.get(resourceLocation); - if(!items.isEmpty()) - { - if(!blocks.isEmpty()) errorMsg += " and"; - if(items.size() == 1) - { - errorMsg += " for item \"" + items.iterator().next() + "\""; - } - else - { - errorMsg += " for items [\"" + Joiner.on("\", \"").join(items) + "\"]"; - } - } - if(exception instanceof ForgeModelBakery.ItemLoadingException) - { - ForgeModelBakery.ItemLoadingException ex = (ForgeModelBakery.ItemLoadingException)exception; -// LOGGER.error("{}, normal location exception: ", errorMsg, ex.normalException); -// LOGGER.error("{}, blockstate location exception: ", errorMsg, ex.blockstateException); - } - else - { -// LOGGER.error(errorMsg, entry.getValue()); - } -// ResourceLocation blockstateLocation = new ResourceLocation(resourceLocation.getResourceDomain(), resourceLocation.getResourcePath()); -// if(loadingExceptions.containsKey(blockstateLocation) && !printedBlockStateErrors.contains(blockstateLocation)) -// { -// LOGGER.error("Exception loading blockstate for the variant {}: ", location, loadingExceptions.get(blockstateLocation)); -// printedBlockStateErrors.add(blockstateLocation); -// } - } - @Override - public void formatTo(StringBuilder buffer) - { - - } -} diff --git a/src/main/resources/META-INF/accesstransformer.cfg b/src/main/resources/META-INF/accesstransformer.cfg index c1da5239021..e08320e5e9f 100644 --- a/src/main/resources/META-INF/accesstransformer.cfg +++ b/src/main/resources/META-INF/accesstransformer.cfg @@ -58,11 +58,12 @@ protected net.minecraft.client.gui.Gui m_168675_(F)V # renderSpyglassOverlay protected net.minecraft.client.gui.Gui m_168688_(Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/world/entity/player/Player;IIIIFIIIZ)V # renderHearts protected net.minecraft.client.gui.Gui m_168708_(Lnet/minecraft/resources/ResourceLocation;F)V # renderTextureOverlay protected net.minecraft.client.gui.Gui m_93007_(F)V # renderPortalOverlay -protected net.minecraft.client.gui.Gui m_93009_(FLcom/mojang/blaze3d/vertex/PoseStack;)V # renderHotbar -protected net.minecraft.client.gui.Gui m_93036_(Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/world/scores/Objective;)V # displayScoreboardSidebar +public net.minecraft.client.gui.Gui m_93009_(FLcom/mojang/blaze3d/vertex/PoseStack;)V # renderHotbar +public net.minecraft.client.gui.Gui m_93028_(Lcom/mojang/blaze3d/vertex/PoseStack;)V # renderEffects +public net.minecraft.client.gui.Gui m_93036_(Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/world/scores/Objective;)V # displayScoreboardSidebar protected net.minecraft.client.gui.Gui m_93039_(Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/gui/Font;III)V # drawBackdrop -protected net.minecraft.client.gui.Gui m_93067_(Lnet/minecraft/world/entity/Entity;)V # renderVignette -protected net.minecraft.client.gui.Gui m_93080_(Lcom/mojang/blaze3d/vertex/PoseStack;)V # renderCrosshair +public net.minecraft.client.gui.Gui m_93067_(Lnet/minecraft/world/entity/Entity;)V # renderVignette +public net.minecraft.client.gui.Gui m_93080_(Lcom/mojang/blaze3d/vertex/PoseStack;)V # renderCrosshair protected net.minecraft.client.gui.components.AbstractSelectionList$Entry f_93521_ # list protected net.minecraft.client.gui.components.DebugScreenOverlay f_94032_ # block protected net.minecraft.client.gui.components.DebugScreenOverlay f_94033_ # liquid @@ -107,6 +108,8 @@ public net.minecraft.client.renderer.block.model.BlockFaceUV$Deserializer public net.minecraft.client.renderer.block.model.BlockModel f_111417_ # textureMap public net.minecraft.client.renderer.block.model.BlockModel f_111418_ # parent public net.minecraft.client.renderer.block.model.BlockModel f_111424_ # hasAmbientOcclusion +public net.minecraft.client.renderer.block.model.BlockModel m_111437_(Lnet/minecraft/client/renderer/block/model/BlockElement;Lnet/minecraft/client/renderer/block/model/BlockElementFace;Lnet/minecraft/client/renderer/texture/TextureAtlasSprite;Lnet/minecraft/core/Direction;Lnet/minecraft/client/resources/model/ModelState;Lnet/minecraft/resources/ResourceLocation;)Lnet/minecraft/client/renderer/block/model/BakedQuad; # bakeFace +public net.minecraft.client.renderer.block.model.ItemModelGenerator m_111638_(ILjava/lang/String;Lnet/minecraft/client/renderer/texture/TextureAtlasSprite;)Ljava/util/List; # processFrames public net.minecraft.client.renderer.block.model.ItemOverride$Deserializer public net.minecraft.client.renderer.block.model.ItemOverride$Deserializer ()V # constructor protected net.minecraft.client.renderer.block.model.ItemOverrides ()V # constructor @@ -134,6 +137,7 @@ private-f net.minecraft.client.resources.model.ModelBakery f_119216_ # atlasPrep protected net.minecraft.client.resources.model.ModelBakery f_119234_ # UNREFERENCED_TEXTURES protected net.minecraft.client.resources.model.ModelBakery f_119243_ # resourceManager protected net.minecraft.client.resources.model.ModelBakery m_119364_(Lnet/minecraft/resources/ResourceLocation;)Lnet/minecraft/client/renderer/block/model/BlockModel; # loadBlockModel +public net.minecraft.client.resources.model.SimpleBakedModel$Builder (ZZZLnet/minecraft/client/renderer/block/model/ItemTransforms;Lnet/minecraft/client/renderer/block/model/ItemOverrides;)V # constructor public net.minecraft.client.sounds.SoundEngine f_120217_ # soundManager public net.minecraft.commands.arguments.selector.EntitySelectorParser m_121229_()V # finalizePredicates public net.minecraft.commands.arguments.selector.EntitySelectorParser m_121317_()V # parseOptions diff --git a/src/main/resources/forge.exc b/src/main/resources/forge.exc index 2553b3aa952..85da92cfb59 100644 --- a/src/main/resources/forge.exc +++ b/src/main/resources/forge.exc @@ -1,23 +1,30 @@ +com/mojang/blaze3d/vertex/VertexConsumer.putBulkData(Lcom/mojang/blaze3d/vertex/PoseStack$Pose;Lnet/minecraft/client/renderer/block/model/BakedQuad;[FFFFF[IIZ)V=|p_85996_,p_85997_,p_85998_,p_85999_,p_86000_,p_86001_,alpha,p_86002_,p_86003_,p_86004_ net/minecraft/advancements/Advancement$Builder.fromJson(Lcom/google/gson/JsonObject;Lnet/minecraft/advancements/critereon/DeserializationContext;Lnet/minecraftforge/common/crafting/conditions/ICondition$IContext;)Lnet/minecraft/advancements/Advancement$Builder;=|p_138381_,p_138382_,context net/minecraft/client/Options.processOptionsForge(Lnet/minecraft/client/Options$FieldAccess;)V=|p_168428_ net/minecraft/client/gui/screens/MenuScreens.getScreenFactory(Lnet/minecraft/world/inventory/MenuType;Lnet/minecraft/client/Minecraft;ILnet/minecraft/network/chat/Component;)Ljava/util/Optional;=|p_96202_,p_96203_,p_96204_,p_96205_ net/minecraft/client/gui/screens/worldselection/WorldOpenFlows.doLoadLevel(Lnet/minecraft/client/gui/screens/Screen;Ljava/lang/String;ZZZ)V=|p_233146_,p_233147_,p_233148_,p_233149_,confirmExperimentalWarning net/minecraft/client/renderer/ScreenEffectRenderer.getOverlayBlock(Lnet/minecraft/world/entity/player/Player;)Lorg/apache/commons/lang3/tuple/Pair;=|p_110717_ +net/minecraft/client/renderer/ScreenEffectRenderer.renderFluid(Lnet/minecraft/client/Minecraft;Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/resources/ResourceLocation;)V=|p_110726_,p_110727_,texture net/minecraft/client/renderer/ShaderInstance.(Lnet/minecraft/server/packs/resources/ResourceProvider;Lnet/minecraft/resources/ResourceLocation;Lcom/mojang/blaze3d/vertex/VertexFormat;)V=|p_173336_,shaderLocation,p_173338_ net/minecraft/client/renderer/block/BlockModelShaper.getTexture(Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/world/level/Level;Lnet/minecraft/core/BlockPos;)Lnet/minecraft/client/renderer/texture/TextureAtlasSprite;=|p_110883_,level,pos -net/minecraft/client/renderer/block/BlockRenderDispatcher.renderBatched(Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/BlockAndTintGetter;Lcom/mojang/blaze3d/vertex/PoseStack;Lcom/mojang/blaze3d/vertex/VertexConsumer;ZLnet/minecraft/util/RandomSource;Lnet/minecraftforge/client/model/data/IModelData;)V=|p_234356_,p_234357_,p_234358_,p_234359_,p_234360_,p_234361_,p_234362_,modelData -net/minecraft/client/renderer/block/BlockRenderDispatcher.renderBreakingTexture(Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/BlockAndTintGetter;Lcom/mojang/blaze3d/vertex/PoseStack;Lcom/mojang/blaze3d/vertex/VertexConsumer;Lnet/minecraftforge/client/model/data/IModelData;)V=|p_110919_,p_110920_,p_110921_,p_110922_,p_110923_,modelData -net/minecraft/client/renderer/block/BlockRenderDispatcher.renderSingleBlock(Lnet/minecraft/world/level/block/state/BlockState;Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/MultiBufferSource;IILnet/minecraftforge/client/model/data/IModelData;)V=|p_110913_,p_110914_,p_110915_,p_110916_,p_110917_,modelData -net/minecraft/client/renderer/block/model/BlockModel.bakeVanilla(Lnet/minecraft/client/resources/model/ModelBakery;Lnet/minecraft/client/renderer/block/model/BlockModel;Ljava/util/function/Function;Lnet/minecraft/client/resources/model/ModelState;Lnet/minecraft/resources/ResourceLocation;Z)Lnet/minecraft/client/resources/model/BakedModel;=|p_111450_,p_111451_,p_111452_,p_111453_,p_111454_,p_111455_ +net/minecraft/client/renderer/block/BlockRenderDispatcher.renderBatched(Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/BlockAndTintGetter;Lcom/mojang/blaze3d/vertex/PoseStack;Lcom/mojang/blaze3d/vertex/VertexConsumer;ZLnet/minecraft/util/RandomSource;Lnet/minecraftforge/client/model/data/ModelData;Lnet/minecraft/client/renderer/RenderType;)V=|p_234356_,p_234357_,p_234358_,p_234359_,p_234360_,p_234361_,p_234362_,modelData,renderType +net/minecraft/client/renderer/block/BlockRenderDispatcher.renderBreakingTexture(Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/BlockAndTintGetter;Lcom/mojang/blaze3d/vertex/PoseStack;Lcom/mojang/blaze3d/vertex/VertexConsumer;Lnet/minecraftforge/client/model/data/ModelData;)V=|p_110919_,p_110920_,p_110921_,p_110922_,p_110923_,modelData +net/minecraft/client/renderer/block/BlockRenderDispatcher.renderSingleBlock(Lnet/minecraft/world/level/block/state/BlockState;Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/MultiBufferSource;IILnet/minecraftforge/client/model/data/ModelData;Lnet/minecraft/client/renderer/RenderType;)V=|p_110913_,p_110914_,p_110915_,p_110916_,p_110917_,modelData,renderType +net/minecraft/client/renderer/block/ModelBlockRenderer.renderModel(Lcom/mojang/blaze3d/vertex/PoseStack$Pose;Lcom/mojang/blaze3d/vertex/VertexConsumer;Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/client/resources/model/BakedModel;FFFIILnet/minecraftforge/client/model/data/ModelData;Lnet/minecraft/client/renderer/RenderType;)V=|p_111068_,p_111069_,p_111070_,p_111071_,p_111072_,p_111073_,p_111074_,p_111075_,p_111076_,modelData,renderType +net/minecraft/client/renderer/block/ModelBlockRenderer.tesselateBlock(Lnet/minecraft/world/level/BlockAndTintGetter;Lnet/minecraft/client/resources/model/BakedModel;Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/core/BlockPos;Lcom/mojang/blaze3d/vertex/PoseStack;Lcom/mojang/blaze3d/vertex/VertexConsumer;ZLnet/minecraft/util/RandomSource;JILnet/minecraftforge/client/model/data/ModelData;Lnet/minecraft/client/renderer/RenderType;)V=|p_111048_,p_111049_,p_111050_,p_111051_,p_111052_,p_111053_,p_111054_,p_111055_,p_111056_,p_111057_,modelData,renderType +net/minecraft/client/renderer/block/ModelBlockRenderer.tesselateWithAO(Lnet/minecraft/world/level/BlockAndTintGetter;Lnet/minecraft/client/resources/model/BakedModel;Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/core/BlockPos;Lcom/mojang/blaze3d/vertex/PoseStack;Lcom/mojang/blaze3d/vertex/VertexConsumer;ZLnet/minecraft/util/RandomSource;JILnet/minecraftforge/client/model/data/ModelData;Lnet/minecraft/client/renderer/RenderType;)V=|p_111079_,p_111080_,p_111081_,p_111082_,p_111083_,p_111084_,p_111085_,p_111086_,p_111087_,p_111088_,modelData,renderType +net/minecraft/client/renderer/block/ModelBlockRenderer.tesselateWithoutAO(Lnet/minecraft/world/level/BlockAndTintGetter;Lnet/minecraft/client/resources/model/BakedModel;Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/core/BlockPos;Lcom/mojang/blaze3d/vertex/PoseStack;Lcom/mojang/blaze3d/vertex/VertexConsumer;ZLnet/minecraft/util/RandomSource;JILnet/minecraftforge/client/model/data/ModelData;Lnet/minecraft/client/renderer/RenderType;)V=|p_111091_,p_111092_,p_111093_,p_111094_,p_111095_,p_111096_,p_111097_,p_111098_,p_111099_,p_111100_,modelData,renderType +net/minecraft/client/renderer/block/model/BlockModel.bakeVanilla(Lnet/minecraft/client/resources/model/ModelBakery;Lnet/minecraft/client/renderer/block/model/BlockModel;Ljava/util/function/Function;Lnet/minecraft/client/resources/model/ModelState;Lnet/minecraft/resources/ResourceLocation;ZLnet/minecraftforge/client/RenderTypeGroup;)Lnet/minecraft/client/resources/model/BakedModel;=|p_111450_,p_111451_,p_111452_,p_111453_,p_111454_,p_111455_,renderTypes +net/minecraft/client/renderer/block/model/ItemTransform.(Lcom/mojang/math/Vector3f;Lcom/mojang/math/Vector3f;Lcom/mojang/math/Vector3f;Lcom/mojang/math/Vector3f;)V=|p_111760_,p_111761_,p_111762_,rightRotation net/minecraft/client/renderer/block/model/ItemTransforms.(Lnet/minecraft/client/renderer/block/model/ItemTransform;Lnet/minecraft/client/renderer/block/model/ItemTransform;Lnet/minecraft/client/renderer/block/model/ItemTransform;Lnet/minecraft/client/renderer/block/model/ItemTransform;Lnet/minecraft/client/renderer/block/model/ItemTransform;Lnet/minecraft/client/renderer/block/model/ItemTransform;Lnet/minecraft/client/renderer/block/model/ItemTransform;Lnet/minecraft/client/renderer/block/model/ItemTransform;Lcom/google/common/collect/ImmutableMap;)V=|p_111798_,p_111799_,p_111800_,p_111801_,p_111802_,p_111803_,p_111804_,p_111805_,moddedTransforms net/minecraft/client/renderer/chunk/ChunkRenderDispatcher$RenderChunk$ChunkCompileTask.(Lnet/minecraft/client/renderer/chunk/ChunkRenderDispatcher$RenderChunk;Lnet/minecraft/world/level/ChunkPos;DZ)V=|p_194422_,pos,p_194423_,p_194424_ net/minecraft/client/renderer/chunk/ChunkRenderDispatcher$RenderChunk$RebuildTask.(Lnet/minecraft/client/renderer/chunk/ChunkRenderDispatcher$RenderChunk;Lnet/minecraft/world/level/ChunkPos;DLnet/minecraft/client/renderer/chunk/RenderChunkRegion;Z)V=|p_194426_,pos,p_194427_,p_194428_,p_194429_ net/minecraft/client/renderer/chunk/ChunkRenderDispatcher$RenderChunk$ResortTransparencyTask.(Lnet/minecraft/client/renderer/chunk/ChunkRenderDispatcher$RenderChunk;Lnet/minecraft/world/level/ChunkPos;DLnet/minecraft/client/renderer/chunk/ChunkRenderDispatcher$CompiledChunk;)V=|p_112888_,pos,p_112889_,p_112890_ net/minecraft/client/renderer/chunk/ChunkRenderDispatcher.(Lnet/minecraft/client/multiplayer/ClientLevel;Lnet/minecraft/client/renderer/LevelRenderer;Ljava/util/concurrent/Executor;ZLnet/minecraft/client/renderer/ChunkBufferBuilderPack;I)V=|p_194405_,p_194406_,p_194407_,p_194408_,p_194409_,countRenderBuilders -net/minecraft/client/resources/model/ModelBakery.(Lnet/minecraft/server/packs/resources/ResourceManager;Lnet/minecraft/client/color/block/BlockColors;Z)V=|p_119247_,p_119248_,vanillaBakery -net/minecraft/client/resources/model/ModelBakery.processLoading(Lnet/minecraft/util/profiling/ProfilerFiller;I)V=|p_119249_,p_119250_ -net/minecraft/client/resources/model/MultiPartBakedModel.getQuads(Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/core/Direction;Lnet/minecraft/util/RandomSource;Lnet/minecraftforge/client/model/data/IModelData;)Ljava/util/List;=|p_235050_,p_235051_,p_235052_,modelData -net/minecraft/client/resources/model/WeightedBakedModel.getQuads(Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/core/Direction;Lnet/minecraft/util/RandomSource;Lnet/minecraftforge/client/model/data/IModelData;)Ljava/util/List;=|p_235058_,p_235059_,p_235060_,modelData +net/minecraft/client/resources/model/MultiPartBakedModel.getQuads(Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/core/Direction;Lnet/minecraft/util/RandomSource;Lnet/minecraftforge/client/model/data/ModelData;Lnet/minecraft/client/renderer/RenderType;)Ljava/util/List;=|p_235050_,p_235051_,p_235052_,modelData,renderType +net/minecraft/client/resources/model/SimpleBakedModel$Builder.build(Lnet/minecraftforge/client/RenderTypeGroup;)Lnet/minecraft/client/resources/model/BakedModel;=|renderTypes +net/minecraft/client/resources/model/SimpleBakedModel.(Ljava/util/List;Ljava/util/Map;ZZZLnet/minecraft/client/renderer/texture/TextureAtlasSprite;Lnet/minecraft/client/renderer/block/model/ItemTransforms;Lnet/minecraft/client/renderer/block/model/ItemOverrides;Lnet/minecraftforge/client/RenderTypeGroup;)V=|p_119489_,p_119490_,p_119491_,p_119492_,p_119493_,p_119494_,p_119495_,p_119496_,renderTypes +net/minecraft/client/resources/model/WeightedBakedModel.getQuads(Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/core/Direction;Lnet/minecraft/util/RandomSource;Lnet/minecraftforge/client/model/data/ModelData;Lnet/minecraft/client/renderer/RenderType;)Ljava/util/List;=|p_235058_,p_235059_,p_235060_,modelData,renderType net/minecraft/data/tags/BannerPatternTagsProvider.(Lnet/minecraft/data/DataGenerator;Ljava/lang/String;Lnet/minecraftforge/common/data/ExistingFileHelper;)V=|p_236411_,modId,existingFileHelper net/minecraft/data/tags/BiomeTagsProvider.(Lnet/minecraft/data/DataGenerator;Ljava/lang/String;Lnet/minecraftforge/common/data/ExistingFileHelper;)V=|p_211094_,modId,existingFileHelper net/minecraft/data/tags/BlockTagsProvider.(Lnet/minecraft/data/DataGenerator;Ljava/lang/String;Lnet/minecraftforge/common/data/ExistingFileHelper;)V=|p_126511_,modId,existingFileHelper diff --git a/src/test/java/net/minecraftforge/debug/block/FullPotsAccessorDemo.java b/src/test/java/net/minecraftforge/debug/block/FullPotsAccessorDemo.java index 551bb50119b..95c7c381009 100644 --- a/src/test/java/net/minecraftforge/debug/block/FullPotsAccessorDemo.java +++ b/src/test/java/net/minecraftforge/debug/block/FullPotsAccessorDemo.java @@ -9,7 +9,6 @@ import com.google.gson.JsonObject; import com.mojang.datafixers.util.Pair; import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.ItemBlockRenderTypes; import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.block.model.*; import net.minecraft.client.renderer.texture.TextureAtlasSprite; @@ -20,7 +19,6 @@ import net.minecraft.network.Connection; import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket; import net.minecraft.resources.ResourceLocation; -import net.minecraft.server.packs.resources.ResourceManager; import net.minecraft.stats.Stats; import net.minecraft.util.RandomSource; import net.minecraft.world.InteractionHand; @@ -39,14 +37,17 @@ import net.minecraft.world.phys.shapes.CollisionContext; import net.minecraft.world.phys.shapes.VoxelShape; import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.client.event.ModelRegistryEvent; +import net.minecraftforge.client.ChunkRenderTypeSet; +import net.minecraftforge.client.event.ModelEvent; import net.minecraftforge.client.model.*; import net.minecraftforge.client.model.data.*; -import net.minecraftforge.client.model.geometry.IModelGeometry; +import net.minecraftforge.client.model.geometry.IGeometryBakingContext; +import net.minecraftforge.client.model.geometry.IGeometryLoader; +import net.minecraftforge.client.model.geometry.IUnbakedGeometry; +import net.minecraftforge.common.util.ConcatenatedListView; import net.minecraftforge.eventbus.api.IEventBus; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.Mod; -import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; import net.minecraftforge.registries.RegistryObject; import net.minecraftforge.registries.DeferredRegister; @@ -167,13 +168,13 @@ private static class DioriteFlowerPotBlockEntity extends BlockEntity { public static final ModelProperty PLANT_PROPERTY = new ModelProperty<>(); - private final IModelData modelData = new ModelDataMap.Builder().build(); + private ModelData modelData; private Block plant = Blocks.AIR; public DioriteFlowerPotBlockEntity(BlockPos pos, BlockState state) { super(DIORITE_POT_BLOCK_ENTITY.get(), pos, state); - modelData.setData(PLANT_PROPERTY, plant); + modelData = ModelData.builder().with(PLANT_PROPERTY, plant).build(); } public void setPlant(Block plant) @@ -187,7 +188,7 @@ public void setPlant(Block plant) public Block getPlant() { return plant; } @Override - public IModelData getModelData() { return modelData; } + public ModelData getModelData() {return modelData; } @Override public CompoundTag getUpdateTag() @@ -199,7 +200,7 @@ public CompoundTag getUpdateTag() public void handleUpdateTag(CompoundTag tag) { super.handleUpdateTag(tag); - modelData.setData(PLANT_PROPERTY, plant); + modelData = modelData.derive().with(PLANT_PROPERTY, plant).build(); requestModelDataUpdate(); } @@ -237,42 +238,31 @@ protected void saveAdditional(CompoundTag tag) private static class ClientHandler { @SubscribeEvent - public static void onClientSetup(final FMLClientSetupEvent event) + public static void registerLoader(final ModelEvent.RegisterGeometryLoaders event) { - if (!ENABLED) { return; } - - ItemBlockRenderTypes.setRenderLayer(DIORITE_POT.get(), RenderType.cutout()); - } - - @SubscribeEvent - public static void registerLoader(final ModelRegistryEvent event) - { - ModelLoaderRegistry.registerLoader(new ResourceLocation(MOD_ID, "diorite_pot"), new DioritePotModelLoader()); + event.register("diorite_pot", new DioritePotGeometryLoader()); } - private static class DioritePotModelLoader implements IModelLoader + private static class DioritePotGeometryLoader implements IGeometryLoader { @Override - public void onResourceManagerReload(ResourceManager manager) { } - - @Override - public DioritePotModelGeometry read(JsonDeserializationContext context, JsonObject modelContents) + public DioritePotModelGeometry read(JsonObject jsonObject, JsonDeserializationContext deserializationContext) { - JsonObject wrappedModel = modelContents.getAsJsonObject("model"); - return new DioritePotModelGeometry(context.deserialize(wrappedModel, BlockModel.class)); + JsonObject wrappedModel = jsonObject.getAsJsonObject("model"); + return new DioritePotModelGeometry(deserializationContext.deserialize(wrappedModel, BlockModel.class)); } } - private record DioritePotModelGeometry(UnbakedModel wrappedModel) implements IModelGeometry + private record DioritePotModelGeometry(UnbakedModel wrappedModel) implements IUnbakedGeometry { @Override - public BakedModel bake(IModelConfiguration owner, ModelBakery bakery, Function spriteGetter, ModelState modelTransform, ItemOverrides overrides, ResourceLocation modelLocation) + public BakedModel bake(IGeometryBakingContext context, ModelBakery bakery, Function spriteGetter, ModelState modelState, ItemOverrides overrides, ResourceLocation modelLocation) { - return new DioritePotModel(wrappedModel.bake(bakery, spriteGetter, modelTransform, modelLocation)); + return new DioritePotModel(wrappedModel.bake(bakery, spriteGetter, modelState, modelLocation)); } @Override - public Collection getTextures(IModelConfiguration owner, Function modelGetter, Set> missingTextureErrors) + public Collection getMaterials(IGeometryBakingContext context, Function modelGetter, Set> missingTextureErrors) { return wrappedModel.getMaterials(modelGetter, missingTextureErrors); } @@ -280,6 +270,7 @@ public Collection getTextures(IMo private static class DioritePotModel extends BakedModelWrapper { + private static final ChunkRenderTypeSet CUTOUT = ChunkRenderTypeSet.of(RenderType.cutout()); private static final ResourceLocation POT_TEXTURE = new ResourceLocation("minecraft:block/flower_pot"); private static final ResourceLocation DIRT_TEXTURE = new ResourceLocation("minecraft:block/dirt"); @@ -287,30 +278,37 @@ private static class DioritePotModel extends BakedModelWrapper @NotNull @Override - public List getQuads(@Nullable BlockState state, @Nullable Direction side, @NotNull RandomSource rand, @NotNull IModelData extraData) + public List getQuads(@Nullable BlockState state, @Nullable Direction side, @NotNull RandomSource rand, @NotNull ModelData extraData, @Nullable RenderType renderType) { - List quads = new ArrayList<>(originalModel.getQuads(state, side, rand, extraData)); + List> quads = new ArrayList<>(); + quads.add(originalModel.getQuads(state, side, rand, extraData, renderType)); - Block plant = extraData.getData(DioriteFlowerPotBlockEntity.PLANT_PROPERTY); + Block plant = extraData.get(DioriteFlowerPotBlockEntity.PLANT_PROPERTY); if (plant != null && plant != Blocks.AIR) { - quads.addAll(getPlantQuads(plant, side, rand)); + quads.add(getPlantQuads(plant, side, rand, renderType)); } - return quads; + return ConcatenatedListView.of(quads); } - private List getPlantQuads(Block plant, @Nullable Direction face, RandomSource rand) + private List getPlantQuads(Block plant, @Nullable Direction face, RandomSource rand, @Nullable RenderType renderType) { BlockState potState = ((FlowerPotBlock) Blocks.FLOWER_POT).getFullPotsView().getOrDefault(ForgeRegistries.BLOCKS.getKey(plant), ForgeRegistries.BLOCKS.getDelegateOrThrow(Blocks.AIR)).get().defaultBlockState(); BakedModel potModel = Minecraft.getInstance().getBlockRenderer().getBlockModel(potState); - return potModel.getQuads(potState, face, rand, EmptyModelData.INSTANCE) + return potModel.getQuads(potState, face, rand, ModelData.EMPTY, renderType) .stream() .filter(q -> !q.getSprite().getName().equals(POT_TEXTURE)) .filter(q -> !q.getSprite().getName().equals(DIRT_TEXTURE)) .collect(Collectors.toList()); } + + @Override + public ChunkRenderTypeSet getRenderTypes(@NotNull BlockState state, @NotNull RandomSource rand, @NotNull ModelData data) + { + return CUTOUT; + } } } } diff --git a/src/test/java/net/minecraftforge/debug/client/CustomArmorModelTest.java b/src/test/java/net/minecraftforge/debug/client/CustomArmorModelTest.java index f317ec06fb1..59c157c8832 100644 --- a/src/test/java/net/minecraftforge/debug/client/CustomArmorModelTest.java +++ b/src/test/java/net/minecraftforge/debug/client/CustomArmorModelTest.java @@ -23,7 +23,7 @@ import net.minecraft.world.item.Item; import net.minecraft.world.item.Item.Properties; import net.minecraft.world.item.ItemStack; -import net.minecraftforge.client.IItemRenderProperties; +import net.minecraftforge.client.extensions.common.IClientItemExtensions; import net.minecraftforge.common.util.Lazy; import net.minecraftforge.eventbus.api.IEventBus; import net.minecraftforge.fml.common.Mod; @@ -62,12 +62,12 @@ public TintedArmorItem(ArmorMaterial material, EquipmentSlot slot, Properties pr } @Override - public void initializeClient(Consumer consumer) + public void initializeClient(Consumer consumer) { - consumer.accept(new IItemRenderProperties() + consumer.accept(new IClientItemExtensions() { @Override @NotNull - public Model getBaseArmorModel(LivingEntity entityLiving, ItemStack itemStack, EquipmentSlot armorSlot, HumanoidModel _default) + public Model getGenericArmorModel(LivingEntity entityLiving, ItemStack itemStack, EquipmentSlot armorSlot, HumanoidModel _default) { TintedArmorModel.INSTANCE.base = _default; return TintedArmorModel.INSTANCE; @@ -91,12 +91,12 @@ public String getArmorTexture(ItemStack stack, Entity entity, EquipmentSlot slot } @Override - public void initializeClient(Consumer consumer) + public void initializeClient(Consumer consumer) { - consumer.accept(new IItemRenderProperties() + consumer.accept(new IClientItemExtensions() { @Override - public HumanoidModel getArmorModel(LivingEntity entityLiving, ItemStack itemStack, EquipmentSlot armorSlot, HumanoidModel _default) + public HumanoidModel getHumanoidArmorModel(LivingEntity entityLiving, ItemStack itemStack, EquipmentSlot armorSlot, HumanoidModel _default) { return TintedArmorModel.ENDERMAN.get(); } diff --git a/src/test/java/net/minecraftforge/debug/client/CustomTASTest.java b/src/test/java/net/minecraftforge/debug/client/CustomTASTest.java index 05d04d0b9ef..44343ca5ef3 100644 --- a/src/test/java/net/minecraftforge/debug/client/CustomTASTest.java +++ b/src/test/java/net/minecraftforge/debug/client/CustomTASTest.java @@ -11,14 +11,12 @@ import net.minecraft.client.renderer.texture.TextureAtlas; import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.client.renderer.texture.Tickable; -import net.minecraft.resources.ResourceLocation; import net.minecraft.server.packs.resources.Resource; import net.minecraft.server.packs.resources.ResourceManager; import net.minecraft.world.item.Item; -import net.minecraftforge.client.MinecraftForgeClient; +import net.minecraftforge.client.event.RegisterTextureAtlasSpriteLoadersEvent; import net.minecraftforge.client.textures.ITextureAtlasSpriteLoader; import net.minecraftforge.fml.common.Mod; -import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; import net.minecraftforge.fml.loading.FMLLoader; import net.minecraftforge.registries.RegistryObject; @@ -40,15 +38,15 @@ public CustomTASTest() { if (FMLLoader.getDist().isClient()) { - FMLJavaModLoadingContext.get().getModEventBus().addListener(this::clientSetup); + FMLJavaModLoadingContext.get().getModEventBus().addListener(this::registerTextureAtlasSpriteLoaders); } ITEMS.register(FMLJavaModLoadingContext.get().getModEventBus()); } } - private void clientSetup(FMLClientSetupEvent event) + private void registerTextureAtlasSpriteLoaders(RegisterTextureAtlasSpriteLoadersEvent event) { - MinecraftForgeClient.registerTextureAtlasSpriteLoader(new ResourceLocation(MOD_ID, "tas_loader"), new TasLoader()); + event.register("tas_loader", new TasLoader()); } private static class TasLoader implements ITextureAtlasSpriteLoader diff --git a/src/test/java/net/minecraftforge/debug/client/CustomTooltipTest.java b/src/test/java/net/minecraftforge/debug/client/CustomTooltipTest.java index 1ddef2e6515..c9b3458981c 100644 --- a/src/test/java/net/minecraftforge/debug/client/CustomTooltipTest.java +++ b/src/test/java/net/minecraftforge/debug/client/CustomTooltipTest.java @@ -17,7 +17,6 @@ import net.minecraft.client.gui.screens.Screen; import net.minecraft.client.gui.screens.inventory.tooltip.ClientTooltipComponent; import net.minecraft.client.renderer.entity.ItemRenderer; -import net.minecraft.client.renderer.texture.TextureManager; import net.minecraft.network.chat.Component; import net.minecraft.server.packs.resources.ReloadableResourceManager; import net.minecraft.world.InteractionHand; @@ -31,7 +30,7 @@ import net.minecraft.world.item.TooltipFlag; import net.minecraft.world.level.Level; import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.client.MinecraftForgeClient; +import net.minecraftforge.client.event.RegisterClientTooltipComponentFactoriesEvent; import net.minecraftforge.client.event.RenderTooltipEvent; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.eventbus.api.SubscribeEvent; @@ -142,7 +141,6 @@ private static class ClientModBusEventHandler @SubscribeEvent public static void clientSetup(FMLClientSetupEvent event) { - MinecraftForgeClient.registerTooltipComponentFactory(CustomTooltip.class, CustomClientTooltip::new); event.enqueueWork(() -> { customFontManager = new FontManager(Minecraft.getInstance().textureManager); customFont = customFontManager.createFont(); @@ -151,6 +149,12 @@ public static void clientSetup(FMLClientSetupEvent event) }); } + @SubscribeEvent + public static void onRegisterClientTooltipComponentFactories(RegisterClientTooltipComponentFactoriesEvent event) + { + event.register(CustomTooltip.class, CustomClientTooltip::new); + } + } private static class ClientEventHandler diff --git a/src/test/java/net/minecraftforge/debug/client/GuiLayeringTest.java b/src/test/java/net/minecraftforge/debug/client/GuiLayeringTest.java index 8f65621bb24..8d3023be304 100644 --- a/src/test/java/net/minecraftforge/debug/client/GuiLayeringTest.java +++ b/src/test/java/net/minecraftforge/debug/client/GuiLayeringTest.java @@ -28,7 +28,7 @@ public class GuiLayeringTest public static class ClientEvents { @SubscribeEvent - public static void guiOpen(ScreenEvent.InitScreenEvent event) + public static void guiOpen(ScreenEvent.Init event) { if (event.getScreen() instanceof AbstractContainerScreen) { diff --git a/src/test/java/net/minecraftforge/debug/client/OverlayLayersTest.java b/src/test/java/net/minecraftforge/debug/client/OverlayLayersTest.java deleted file mode 100644 index 41b39c73e1b..00000000000 --- a/src/test/java/net/minecraftforge/debug/client/OverlayLayersTest.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (c) Forge Development LLC and contributors - * SPDX-License-Identifier: LGPL-2.1-only - */ - -package net.minecraftforge.debug.client; - -import net.minecraft.client.Minecraft; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.client.event.InputEvent; -import net.minecraftforge.client.event.RenderGameOverlayEvent; -import net.minecraftforge.client.gui.OverlayRegistry; -import net.minecraftforge.common.MinecraftForge; -import net.minecraftforge.fml.common.Mod; -import net.minecraftforge.fml.loading.FMLEnvironment; -import org.lwjgl.glfw.GLFW; - -import java.util.List; -import java.util.Locale; - -@Mod("overlay_layers_test") -public class OverlayLayersTest -{ - public static final boolean ENABLE = true; - private boolean visible = false; - - public OverlayLayersTest() - { - if (ENABLE && FMLEnvironment.dist == Dist.CLIENT) - { - MinecraftForge.EVENT_BUS.addListener(this::renderTextEvent); - MinecraftForge.EVENT_BUS.addListener(this::keyInputEvent); - } - } - - int overlayIndex = 0; - - public void renderTextEvent(RenderGameOverlayEvent.Text event) - { - if (event.getType() != RenderGameOverlayEvent.ElementType.TEXT || !visible) - return; - - List overlays = OverlayRegistry.orderedEntries(); - for(int i=0;i %s [%s] <" : " %s [%s] ", entry.getDisplayName(), entry.isEnabled())); - } - } - - public void keyInputEvent(InputEvent.KeyInputEvent event) - { - if (event.getAction() != GLFW.GLFW_PRESS || Minecraft.getInstance().level == null || Minecraft.getInstance().screen != null) - return; - - if (event.getKey() == GLFW.GLFW_KEY_H) - { - visible = !visible; - return; - } - if (!visible) - return; - if (event.getKey() == GLFW.GLFW_KEY_J) - { - List overlays = OverlayRegistry.orderedEntries(); - if (overlayIndex >= overlays.size()) - overlayIndex = 0; - else - overlayIndex = (overlayIndex + overlays.size() - 1) % overlays.size(); - } - else if (event.getKey() == GLFW.GLFW_KEY_K) - { - List overlays = OverlayRegistry.orderedEntries(); - if (overlayIndex >= overlays.size()) - overlayIndex = 0; - else - overlayIndex = (overlayIndex + 1) % overlays.size(); - } - else if (event.getKey() == GLFW.GLFW_KEY_I) - { - List overlays = OverlayRegistry.orderedEntries(); - if (overlayIndex >= overlays.size()) - overlayIndex = 0; - else - { - OverlayRegistry.OverlayEntry entry = overlays.get(overlayIndex); - OverlayRegistry.enableOverlay(entry.getOverlay(), !entry.isEnabled()); - } - } - } -} diff --git a/src/test/java/net/minecraftforge/debug/client/PotionSizeEventTest.java b/src/test/java/net/minecraftforge/debug/client/PotionSizeEventTest.java index e9d5e36f62c..8b58faa6b30 100644 --- a/src/test/java/net/minecraftforge/debug/client/PotionSizeEventTest.java +++ b/src/test/java/net/minecraftforge/debug/client/PotionSizeEventTest.java @@ -18,7 +18,7 @@ import java.util.Objects; /** - * Test mod for {@link net.minecraftforge.client.event.ScreenEvent.PotionSizeEvent}. When enabled, this mod forces the + * Test mod for {@link ScreenEvent.RenderInventoryMobEffects}. When enabled, this mod forces the * potion indicators in the {@linkplain net.minecraft.client.gui.screens.inventory.EffectRenderingInventoryScreen * inventory screen} to either render in compact mode when there are less than or equal to three active effects on the player, * or render in classic mode if there are more than three active effects. @@ -40,7 +40,7 @@ public PotionSizeEventTest() static final class ClientEventHandler { @SubscribeEvent - public static void onPotionSize(ScreenEvent.PotionSizeEvent event) + public static void onPotionSize(ScreenEvent.RenderInventoryMobEffects event) { if (!ENABLED) return; @@ -48,10 +48,10 @@ public static void onPotionSize(ScreenEvent.PotionSizeEvent event) if (player.getActiveEffects().size() <= 3) { - event.setResult(Event.Result.ALLOW); // Force compact mode for 3 or less active effects + event.setCompact(true); // Force compact mode for 3 or less active effects } else { - event.setResult(Event.Result.DENY); // Force classic mode for 4 or more active effects + event.setCompact(false); // Force classic mode for 4 or more active effects } } } diff --git a/src/test/java/net/minecraftforge/debug/client/model/MegaModelTest.java b/src/test/java/net/minecraftforge/debug/client/model/MegaModelTest.java new file mode 100644 index 00000000000..2f5f35e430b --- /dev/null +++ b/src/test/java/net/minecraftforge/debug/client/model/MegaModelTest.java @@ -0,0 +1,175 @@ +/* + * Copyright (c) Forge Development LLC and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.minecraftforge.debug.client.model; + +import com.mojang.math.Quaternion; +import com.mojang.math.Transformation; +import com.mojang.math.Vector3f; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.block.model.BakedQuad; +import net.minecraft.client.resources.model.BakedModel; +import net.minecraft.client.resources.model.ModelResourceLocation; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.util.Mth; +import net.minecraft.util.RandomSource; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.BlockItem; +import net.minecraft.world.item.CreativeModeTab; +import net.minecraft.world.item.Item; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.EntityBlock; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.material.Material; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.client.event.ModelEvent; +import net.minecraftforge.client.model.BakedModelWrapper; +import net.minecraftforge.client.model.IQuadTransformer; +import net.minecraftforge.client.model.data.ModelData; +import net.minecraftforge.client.model.data.ModelProperty; +import net.minecraftforge.eventbus.api.IEventBus; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; +import net.minecraftforge.registries.DeferredRegister; +import net.minecraftforge.registries.ForgeRegistries; +import net.minecraftforge.registries.RegistryObject; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; +import java.util.Set; + +/** + * Test mod that demos most Forge-provided model loaders in a single block + item, as well as in-JSON render states + * and the refactored immutable ModelData managed by the client level. The block can be found in the decoration tab. + *

+ * Additionally, some fields in the JSON have deprecated names, so those MUST be updated in 1.20, or the model will + * break. They have all been annotated accordingly. + *

    + *
  • As a block: Composite loader, using 3 child element models, each with a different render type, + * some using vanilla's elements loader, and some Forge's
  • + *
  • In the right hand: Fluid container with lava (emissive)
  • + *
  • In the left hand: Multi-layer item with chainmail chestplate + emissive bow
  • + *
+ *

+ * Clicking on the upper half of the block will make the model move up by a bit, and clicking on the lower half will + * move it down. + */ +@Mod(MegaModelTest.MOD_ID) +public class MegaModelTest +{ + public static final String MOD_ID = "mega_model_test"; + private static final DeferredRegister BLOCKS = DeferredRegister.create(ForgeRegistries.BLOCKS, MOD_ID); + private static final DeferredRegister ITEMS = DeferredRegister.create(ForgeRegistries.ITEMS, MOD_ID); + private static final DeferredRegister> BLOCK_ENTITIES = DeferredRegister.create(ForgeRegistries.BLOCK_ENTITIES, MOD_ID); + + private static final String REG_NAME = "test_block"; + public static final RegistryObject TEST_BLOCK = BLOCKS.register(REG_NAME, TestBlock::new); + public static final RegistryObject TEST_BLOCK_ITEM = ITEMS.register(REG_NAME, () -> new BlockItem(TEST_BLOCK.get(), new Item.Properties().tab(CreativeModeTab.TAB_DECORATIONS))); + public static final RegistryObject> TEST_BLOCK_ENTITY = BLOCK_ENTITIES.register(REG_NAME, () -> new BlockEntityType<>( + TestBlock.Entity::new, Set.of(TEST_BLOCK.get()), null + )); + + public MegaModelTest() + { + IEventBus modEventBus = FMLJavaModLoadingContext.get().getModEventBus(); + BLOCKS.register(modEventBus); + ITEMS.register(modEventBus); + BLOCK_ENTITIES.register(modEventBus); + } + + @Mod.EventBusSubscriber(value = Dist.CLIENT, modid = MOD_ID, bus = Mod.EventBusSubscriber.Bus.MOD) + public static class ClientEvents + { + + @SubscribeEvent + public static void onModelBakingCompleted(ModelEvent.BakingCompleted event) + { + var name = new ModelResourceLocation(MOD_ID, REG_NAME, ""); + event.getModels().computeIfPresent(name, (n, m) -> new TransformingModelWrapper(m)); + } + + } + + private static class TestBlock extends Block implements EntityBlock + { + public TestBlock() + { + super(Properties.of(Material.STONE)); + } + + @Nullable + @Override + public BlockEntity newBlockEntity(BlockPos pos, BlockState state) + { + return new Entity(pos, state); + } + + @Override + public InteractionResult use(BlockState state, Level level, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hit) + { + var entity = level.getBlockEntity(pos); + if (entity instanceof Entity e) + { + e.y += Mth.sign(hit.getLocation().y - pos.getY() - 0.5); + e.requestModelDataUpdate(); + level.sendBlockUpdated(pos, state, state, 8); + return InteractionResult.sidedSuccess(level.isClientSide()); + } + return super.use(state, level, pos, player, hand, hit); + } + + public static class Entity extends BlockEntity + { + public int y = 0; + + public Entity(BlockPos pos, BlockState state) + { + super(TEST_BLOCK_ENTITY.get(), pos, state); + } + + @Override + public @NotNull ModelData getModelData() + { + return ModelData.builder().with(TestData.PROPERTY, new TestData(new Transformation( + new Vector3f(0, y * 0.2f, 0), + Quaternion.ONE, + Transformation.identity().getScale(), + Quaternion.ONE + ))).build(); + } + } + } + + private record TestData(Transformation transform) + { + public static final ModelProperty PROPERTY = new ModelProperty<>(); + } + + private static class TransformingModelWrapper extends BakedModelWrapper + { + public TransformingModelWrapper(BakedModel originalModel) + { + super(originalModel); + } + + @Override + public @NotNull List getQuads(@Nullable BlockState state, @Nullable Direction side, @NotNull RandomSource rand, @NotNull ModelData data, @Nullable RenderType renderType) + { + var quads = super.getQuads(state, side, rand, data, renderType); + if (!data.has(TestData.PROPERTY)) + return quads; + return IQuadTransformer.applying(data.get(TestData.PROPERTY).transform()).process(quads); + } + } +} diff --git a/src/test/java/net/minecraftforge/debug/client/model/NewModelLoaderTest.java b/src/test/java/net/minecraftforge/debug/client/model/NewModelLoaderTest.java index c5cff8cad69..94e78b8762a 100644 --- a/src/test/java/net/minecraftforge/debug/client/model/NewModelLoaderTest.java +++ b/src/test/java/net/minecraftforge/debug/client/model/NewModelLoaderTest.java @@ -5,20 +5,17 @@ package net.minecraftforge.debug.client.model; -import com.google.common.collect.ImmutableList; import com.google.gson.JsonDeserializationContext; import com.google.gson.JsonObject; import com.mojang.datafixers.util.Pair; +import net.minecraft.client.renderer.block.model.BakedQuad; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.material.Material; import net.minecraft.client.renderer.texture.TextureAtlasSprite; -import com.mojang.blaze3d.vertex.DefaultVertexFormat; -import com.mojang.blaze3d.vertex.VertexFormatElement; import net.minecraft.data.DataGenerator; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EquipmentSlot; -import net.minecraft.server.packs.resources.ResourceManager; import net.minecraft.world.level.block.state.StateDefinition; import net.minecraft.world.level.block.state.properties.BlockStateProperties; import net.minecraft.core.Direction; @@ -27,20 +24,19 @@ import net.minecraft.world.phys.shapes.CollisionContext; import net.minecraft.world.phys.shapes.VoxelShape; import net.minecraft.world.level.BlockGetter; -import net.minecraftforge.client.event.ModelRegistryEvent; +import net.minecraftforge.client.event.ModelEvent; import net.minecraftforge.client.model.IModelBuilder; -import net.minecraftforge.client.model.IModelConfiguration; -import net.minecraftforge.client.model.IModelLoader; -import net.minecraftforge.client.model.ModelLoaderRegistry; +import net.minecraftforge.client.model.geometry.IGeometryBakingContext; +import net.minecraftforge.client.model.geometry.IGeometryLoader; import net.minecraftforge.client.model.generators.BlockModelBuilder; import net.minecraftforge.client.model.generators.BlockStateProvider; import net.minecraftforge.client.model.generators.ConfiguredModel; import net.minecraftforge.client.model.generators.ItemModelProvider; import net.minecraftforge.client.model.generators.loaders.ItemLayersModelBuilder; -import net.minecraftforge.client.model.generators.loaders.OBJLoaderBuilder; -import net.minecraftforge.client.model.generators.loaders.SeparatePerspectiveModelBuilder; -import net.minecraftforge.client.model.geometry.ISimpleModelGeometry; -import net.minecraftforge.client.model.pipeline.BakedQuadBuilder; +import net.minecraftforge.client.model.generators.loaders.ObjModelBuilder; +import net.minecraftforge.client.model.generators.loaders.SeparateTransformsModelBuilder; +import net.minecraftforge.client.model.geometry.SimpleUnbakedGeometry; +import net.minecraftforge.client.model.pipeline.QuadBakingVertexConsumer; import net.minecraftforge.common.data.ExistingFileHelper; import net.minecraftforge.eventbus.api.IEventBus; import net.minecraftforge.registries.RegistryObject; @@ -139,75 +135,45 @@ public NewModelLoaderTest() modEventBus.addListener(this::datagen); } - public void modelRegistry(ModelRegistryEvent event) + public void modelRegistry(ModelEvent.RegisterGeometryLoaders event) { - ModelLoaderRegistry.registerLoader(new ResourceLocation(MODID, "custom_loader"), new TestLoader()); + event.register("custom_loader", new TestLoader()); } - static class TestLoader implements IModelLoader + static class TestLoader implements IGeometryLoader { @Override - public void onResourceManagerReload(ResourceManager resourceManager) - { - } - - @Override - public TestModel read(JsonDeserializationContext deserializationContext, JsonObject modelContents) + public TestModel read(JsonObject jsonObject, JsonDeserializationContext deserializationContext) { return new TestModel(); } } - static class TestModel implements ISimpleModelGeometry + static class TestModel extends SimpleUnbakedGeometry { @Override - public void addQuads(IModelConfiguration owner, IModelBuilder modelBuilder, ModelBakery bakery, Function< net.minecraft.client.resources.model.Material, TextureAtlasSprite> spriteGetter, ModelState modelTransform, ResourceLocation modelLocation) + protected void addQuads(IGeometryBakingContext owner, IModelBuilder modelBuilder, ModelBakery bakery, Function< net.minecraft.client.resources.model.Material, TextureAtlasSprite> spriteGetter, ModelState modelTransform, ResourceLocation modelLocation) { - TextureAtlasSprite texture = spriteGetter.apply(owner.resolveTexture("particle")); - - BakedQuadBuilder builder = new BakedQuadBuilder(); + TextureAtlasSprite texture = spriteGetter.apply(owner.getMaterial("particle")); - builder.setTexture(texture); - builder.setQuadOrientation(Direction.UP); + var quad = new BakedQuad[1]; + var quadBaker = new QuadBakingVertexConsumer(q -> quad[0] = q); - putVertex(builder, 0,1,0.5f, texture.getU(0), texture.getV(0), 1, 1, 1); - putVertex(builder, 0,0,0.5f, texture.getU(0), texture.getV(16), 1, 1, 1); - putVertex(builder, 1,0,0.5f, texture.getU(16), texture.getV(16), 1, 1, 1); - putVertex(builder, 1,1,0.5f, texture.getU(16), texture.getV(0), 1, 1, 1); + quadBaker.setDirection(Direction.UP); + quadBaker.setSprite(texture); - modelBuilder.addGeneralQuad(builder.build()); - } + quadBaker.vertex(0, 1, 0.5f).color(255, 255, 255, 255).uv(texture.getU(0), texture.getV(0)).uv2(0).normal(0, 0, 0).endVertex(); + quadBaker.vertex(0, 0, 0.5f).color(255, 255, 255, 255).uv(texture.getU(0), texture.getV(16)).uv2(0).normal(0, 0, 0).endVertex(); + quadBaker.vertex(1, 0, 0.5f).color(255, 255, 255, 255).uv(texture.getU(16), texture.getV(16)).uv2(0).normal(0, 0, 0).endVertex(); + quadBaker.vertex(1, 1, 0.5f).color(255, 255, 255, 255).uv(texture.getU(16), texture.getV(0)).uv2(0).normal(0, 0, 0).endVertex(); - private void putVertex(BakedQuadBuilder builder, int x, float y, float z, float u, float v, float red, float green, float blue) - { - ImmutableList elements = DefaultVertexFormat.BLOCK.getElements(); - for(int i=0;i getTextures(IModelConfiguration owner, Function modelGetter, Set> missingTextureErrors) + public Collection< net.minecraft.client.resources.model.Material> getMaterials(IGeometryBakingContext context, Function modelGetter, Set> missingTextureErrors) { - return Collections.singleton(owner.resolveTexture("particle")); + return Collections.singleton(context.getMaterial("particle")); } } @@ -235,10 +201,10 @@ protected void registerModels() .texture("layer0", "minecraft:item/coal") .texture("layer1", "minecraft:item/stick") .customLoader(ItemLayersModelBuilder::begin) - .fullbright(1) + .emissive(1) .end(); withExistingParent(NewModelLoaderTest.separate_perspective.getId().getPath(), "forge:item/default") - .customLoader(SeparatePerspectiveModelBuilder::begin) + .customLoader(SeparateTransformsModelBuilder::begin) .base(nested().parent(getExistingFile(mcLoc("minecraft:item/coal")))) .perspective(ItemTransforms.TransformType.GUI, nested().parent(getExistingFile(mcLoc("minecraft:item/snowball")))) .perspective(ItemTransforms.TransformType.FIRST_PERSON_LEFT_HAND, nested().parent(getExistingFile(mcLoc("minecraft:item/bone")))) @@ -258,7 +224,7 @@ protected void registerStatesAndModels() { BlockModelBuilder model = models() .getBuilder(NewModelLoaderTest.obj_block.getId().getPath()) - .customLoader(OBJLoaderBuilder::begin) + .customLoader(ObjModelBuilder::begin) .modelLocation(new ResourceLocation("new_model_loader_test:models/item/sugar_glider.obj")) .flipV(true) .end() diff --git a/src/test/java/net/minecraftforge/debug/client/model/TRSRTransformerTest.java b/src/test/java/net/minecraftforge/debug/client/model/TRSRTransformerTest.java index cc4aafd18bb..372519cdce2 100644 --- a/src/test/java/net/minecraftforge/debug/client/model/TRSRTransformerTest.java +++ b/src/test/java/net/minecraftforge/debug/client/model/TRSRTransformerTest.java @@ -7,8 +7,7 @@ import java.util.List; -import com.google.common.collect.ImmutableList; - +import net.minecraft.client.renderer.RenderType; import net.minecraft.util.RandomSource; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.state.BlockState; @@ -26,12 +25,11 @@ import com.mojang.math.Transformation; import com.mojang.math.Vector3f; import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.client.event.ModelBakeEvent; -import net.minecraftforge.client.model.data.IDynamicBakedModel; -import net.minecraftforge.client.model.data.IModelData; -import net.minecraftforge.client.model.pipeline.BakedQuadBuilder; -import net.minecraftforge.client.model.pipeline.TRSRTransformer; -import net.minecraftforge.common.model.TransformationHelper; +import net.minecraftforge.client.event.ModelEvent; +import net.minecraftforge.client.model.IQuadTransformer; +import net.minecraftforge.client.model.IDynamicBakedModel; +import net.minecraftforge.client.model.data.ModelData; +import net.minecraftforge.common.util.TransformationHelper; import net.minecraftforge.eventbus.api.IEventBus; import net.minecraftforge.fml.DistExecutor; import net.minecraftforge.registries.RegistryObject; @@ -58,10 +56,10 @@ public TRSRTransformerTest() { ITEMS.register(mod); } - public void onModelBake(ModelBakeEvent e) { - for (ResourceLocation id : e.getModelRegistry().keySet()) { + public void onModelBake(ModelEvent.BakingCompleted e) { + for (ResourceLocation id : e.getModels().keySet()) { if (MODID.equals(id.getNamespace()) && "test".equals(id.getPath())) { - e.getModelRegistry().put(id, new MyBakedModel(e.getModelRegistry().get(id))); + e.getModels().put(id, new MyBakedModel(e.getModels().get(id))); } } } @@ -74,32 +72,14 @@ public MyBakedModel(BakedModel base) { } @Override - public List getQuads(@Nullable BlockState state, @Nullable Direction side, RandomSource rand, IModelData data) { - ImmutableList.Builder quads = new ImmutableList.Builder<>(); - + public List getQuads(@Nullable BlockState state, @Nullable Direction side, RandomSource rand, ModelData data, @Nullable RenderType renderType) { Quaternion rot = TransformationHelper.quatFromXYZ(new Vector3f(0, 45, 0), true); Vector3f translation = new Vector3f(0, 0.33f, 0); Transformation trans = new Transformation(translation, rot, null, null).blockCenterToCorner(); + var transformer = IQuadTransformer.applying(trans); - for (BakedQuad quad : base.getQuads(state, side, rand, data)) { - - if (true) - { - BakedQuadBuilder builder = new BakedQuadBuilder(); - - TRSRTransformer transformer = new TRSRTransformer(builder, trans); - - quad.pipe(transformer); - - quads.add(builder.build()); - } /* else { - QuadTransformer qt = new QuadTransformer(trans); - quads.add(qt.processOne(quad)); - }*/ - } - - return quads.build(); + return transformer.process(base.getQuads(state, side, rand, data, renderType)); } @Override diff --git a/src/test/java/net/minecraftforge/debug/client/rendering/LinearTextTextureFilteringTest.java b/src/test/java/net/minecraftforge/debug/client/rendering/LinearTextTextureFilteringTest.java index 17484b344e0..7671e142eee 100644 --- a/src/test/java/net/minecraftforge/debug/client/rendering/LinearTextTextureFilteringTest.java +++ b/src/test/java/net/minecraftforge/debug/client/rendering/LinearTextTextureFilteringTest.java @@ -7,7 +7,7 @@ import net.minecraft.client.gui.screens.TitleScreen; import net.minecraftforge.client.ForgeRenderTypes; -import net.minecraftforge.client.event.ScreenEvent.DrawScreenEvent; +import net.minecraftforge.client.event.ScreenEvent.Render; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.api.distmarker.Dist; @@ -20,7 +20,7 @@ public class LinearTextTextureFilteringTest static final boolean ENABLED = false; @SubscribeEvent - public static void onGuiRenderPre(DrawScreenEvent.Pre event) + public static void onGuiRenderPre(Render.Pre event) { if (ENABLED && event.getScreen() instanceof TitleScreen) { @@ -29,7 +29,7 @@ public static void onGuiRenderPre(DrawScreenEvent.Pre event) } @SubscribeEvent - public static void onGuiRenderPost(DrawScreenEvent.Post event) + public static void onGuiRenderPost(Render.Post event) { if (ENABLED && event.getScreen() instanceof TitleScreen) { diff --git a/src/test/java/net/minecraftforge/debug/client/rendering/NameplateRenderingEventTest.java b/src/test/java/net/minecraftforge/debug/client/rendering/NameplateRenderingEventTest.java index 91d40ee8d22..b2f54a078e1 100644 --- a/src/test/java/net/minecraftforge/debug/client/rendering/NameplateRenderingEventTest.java +++ b/src/test/java/net/minecraftforge/debug/client/rendering/NameplateRenderingEventTest.java @@ -9,7 +9,7 @@ import net.minecraft.world.entity.animal.Cow; import net.minecraft.world.entity.player.Player; import net.minecraft.ChatFormatting; -import net.minecraftforge.client.event.RenderNameplateEvent; +import net.minecraftforge.client.event.RenderNameTagEvent; import net.minecraftforge.eventbus.api.Event; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.Mod; @@ -24,7 +24,7 @@ public class NameplateRenderingEventTest static final boolean ENABLED = false; @SubscribeEvent - public static void onNameplateRender(RenderNameplateEvent event) + public static void onNameplateRender(RenderNameTagEvent event) { if(!ENABLED) diff --git a/src/test/java/net/minecraftforge/debug/client/rendering/RenderableTest.java b/src/test/java/net/minecraftforge/debug/client/rendering/RenderableTest.java index 9388c67f12a..e15c49b9888 100644 --- a/src/test/java/net/minecraftforge/debug/client/rendering/RenderableTest.java +++ b/src/test/java/net/minecraftforge/debug/client/rendering/RenderableTest.java @@ -17,20 +17,17 @@ import net.minecraft.server.packs.resources.SimplePreparableReloadListener; import net.minecraft.util.profiling.ProfilerFiller; import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.client.event.ModelRegistryEvent; +import net.minecraftforge.client.event.ModelEvent; import net.minecraftforge.client.event.RegisterClientReloadListenersEvent; import net.minecraftforge.client.event.RenderLevelLastEvent; -import net.minecraftforge.client.model.ForgeModelBakery; -import net.minecraftforge.client.model.StandaloneModelConfiguration; -import net.minecraftforge.client.model.data.EmptyModelData; -import net.minecraftforge.client.model.data.IModelData; -import net.minecraftforge.client.model.obj.OBJLoader; -import net.minecraftforge.client.model.obj.OBJModel; -import net.minecraftforge.client.model.renderable.BakedRenderable; +import net.minecraftforge.client.model.geometry.StandaloneGeometryBakingContext; +import net.minecraftforge.client.model.data.ModelData; +import net.minecraftforge.client.model.obj.ObjLoader; +import net.minecraftforge.client.model.obj.ObjModel; +import net.minecraftforge.client.model.renderable.BakedModelRenderable; +import net.minecraftforge.client.model.renderable.CompositeRenderable; import net.minecraftforge.client.model.renderable.IRenderable; -import net.minecraftforge.client.model.renderable.MultipartTransforms; import net.minecraftforge.common.MinecraftForge; -import net.minecraftforge.eventbus.api.Event; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; import net.minecraftforge.fml.loading.FMLEnvironment; @@ -59,8 +56,8 @@ private static class Client { private static ResourceLocation MODEL_LOC = new ResourceLocation("minecraft:block/diamond_block"); - private static IRenderable renderable; - private static IRenderable bakedRenderable; + private static IRenderable renderable; + private static IRenderable bakedRenderable; public static void init() { @@ -70,19 +67,19 @@ public static void init() MinecraftForge.EVENT_BUS.addListener(Client::renderLast); } - private static void registerModels(ModelRegistryEvent t) + private static void registerModels(ModelEvent.RegisterAdditional event) { - ForgeModelBakery.addSpecialModel(MODEL_LOC); + event.register(MODEL_LOC); } public static void registerReloadListeners(RegisterClientReloadListenersEvent event) { - event.registerReloadListener(new SimplePreparableReloadListener() + event.registerReloadListener(new SimplePreparableReloadListener() { @Override - protected OBJModel prepare(ResourceManager resourceManager, ProfilerFiller profilerFiller) + protected ObjModel prepare(ResourceManager resourceManager, ProfilerFiller profilerFiller) { - var settings = new OBJModel.ModelSettings( + var settings = new ObjModel.ModelSettings( new ResourceLocation("new_model_loader_test:models/item/sugar_glider.obj"), false, true, @@ -90,13 +87,13 @@ protected OBJModel prepare(ResourceManager resourceManager, ProfilerFiller profi false, null ); - return OBJLoader.INSTANCE.loadModel(settings); + return ObjLoader.INSTANCE.loadModel(settings); } @Override - protected void apply(OBJModel model, ResourceManager resourceManager, ProfilerFiller profilerFiller) + protected void apply(ObjModel model, ResourceManager resourceManager, ProfilerFiller profilerFiller) { - var config = StandaloneModelConfiguration.create(Map.of( + var config = StandaloneGeometryBakingContext.create(Map.of( "#qr", new ResourceLocation("minecraft:block/quartz_block_top") )); renderable = model.bakeRenderable(config); @@ -110,7 +107,7 @@ public static void renderLast(RenderLevelLastEvent event) { if (bakedRenderable == null) { - bakedRenderable = BakedRenderable.of(MODEL_LOC); + bakedRenderable = BakedModelRenderable.of(MODEL_LOC).withModelDataContext(); } var poseStack = event.getPoseStack(); @@ -130,13 +127,13 @@ public static void renderLast(RenderLevelLastEvent event) right.multiply(Quaternion.fromYXZ(0, 0, -(float)Math.sin(time * 0.05) * 0.1f)); map.put("object_9", right); - var transforms = MultipartTransforms.of(map.build()); + var transforms = CompositeRenderable.Transforms.of(map.build()); renderable.render(poseStack, bufferSource, RenderType::entitySolid, LightTexture.FULL_BRIGHT, OverlayTexture.NO_OVERLAY, event.getPartialTick(), transforms); poseStack.pushPose(); poseStack.translate(0,0.5f,0); - bakedRenderable.render(poseStack, bufferSource, RenderType::entitySolid, LightTexture.FULL_BRIGHT, OverlayTexture.NO_OVERLAY, event.getPartialTick(), EmptyModelData.INSTANCE); + bakedRenderable.render(poseStack, bufferSource, RenderType::entitySolid, LightTexture.FULL_BRIGHT, OverlayTexture.NO_OVERLAY, event.getPartialTick(), ModelData.EMPTY); poseStack.popPose(); bufferSource.endBatch(); diff --git a/src/test/java/net/minecraftforge/debug/client/rendering/ShaderFixTest.java b/src/test/java/net/minecraftforge/debug/client/rendering/ShaderFixTest.java index 1fdf43325c8..1b592f56649 100644 --- a/src/test/java/net/minecraftforge/debug/client/rendering/ShaderFixTest.java +++ b/src/test/java/net/minecraftforge/debug/client/rendering/ShaderFixTest.java @@ -5,21 +5,20 @@ package net.minecraftforge.debug.client.rendering; -import net.minecraft.client.player.LocalPlayer; import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.entity.EntityType; import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.client.event.RegisterEntitySpectatorShadersEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; -import net.minecraftforge.client.ClientRegistry; import net.minecraftforge.fml.common.Mod; -import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; @Mod("shader_fix_test") @Mod.EventBusSubscriber(value = Dist.CLIENT, bus = Mod.EventBusSubscriber.Bus.MOD) public class ShaderFixTest { @SubscribeEvent - public static void clientSetup(final FMLClientSetupEvent event) + public static void onRegisterEntitySpectatorShaders(final RegisterEntitySpectatorShadersEvent event) { - ClientRegistry.registerEntityShader(LocalPlayer.class, new ResourceLocation("shaders/post/desaturate.json")); + event.register(EntityType.PLAYER, new ResourceLocation("shaders/post/desaturate.json")); } } \ No newline at end of file diff --git a/src/test/java/net/minecraftforge/debug/fluid/FluidTypeTest.java b/src/test/java/net/minecraftforge/debug/fluid/FluidTypeTest.java index 105459ba14f..d9cd1310acf 100644 --- a/src/test/java/net/minecraftforge/debug/fluid/FluidTypeTest.java +++ b/src/test/java/net/minecraftforge/debug/fluid/FluidTypeTest.java @@ -28,9 +28,8 @@ import net.minecraft.world.level.material.FluidState; import net.minecraft.world.level.material.Material; import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.client.IFluidTypeRenderProperties; -import net.minecraftforge.client.RenderProperties; -import net.minecraftforge.client.event.ColorHandlerEvent; +import net.minecraftforge.client.extensions.common.IClientFluidTypeExtensions; +import net.minecraftforge.client.event.RegisterColorHandlersEvent; import net.minecraftforge.common.ForgeMod; import net.minecraftforge.eventbus.api.IEventBus; import net.minecraftforge.fluids.FluidInteractionRegistry; @@ -87,9 +86,9 @@ private static ForgeFlowingFluid.Properties fluidProperties() new FluidType(FluidType.Properties.create().supportsBoating(true).canHydrate(true)) { @Override - public void initializeClient(Consumer consumer) + public void initializeClient(Consumer consumer) { - consumer.accept(new IFluidTypeRenderProperties() + consumer.accept(new IClientFluidTypeExtensions() { private static final ResourceLocation STILL = new ResourceLocation("block/water_still"), FLOW = new ResourceLocation("block/water_flow"), @@ -121,7 +120,7 @@ public ResourceLocation getRenderOverlayTexture(Minecraft mc) } @Override - public int getColorTint() + public int getTintColor() { return 0xAF7FFFD4; } @@ -129,7 +128,7 @@ public int getColorTint() @Override public @NotNull Vector3f modifyFogColor(Camera camera, float partialTick, ClientLevel level, int renderDistance, float darkenWorldAmount, Vector3f fluidFogColor) { - int color = this.getColorTint(); + int color = this.getTintColor(); return new Vector3f((color >> 16 & 0xFF) / 255F, (color >> 8 & 0xFF) / 255F, (color & 0xFF) / 255F); } @@ -208,14 +207,14 @@ private void clientSetup(FMLClientSetupEvent event) .forEach(fluid -> ItemBlockRenderTypes.setRenderLayer(fluid, RenderType.translucent())); } - private void registerBlockColors(ColorHandlerEvent.Block event) + private void registerBlockColors(RegisterColorHandlersEvent.Block event) { event.getBlockColors().register((state, getter, pos, index) -> { if (getter != null && pos != null) { FluidState fluidState = getter.getFluidState(pos); - return RenderProperties.get(fluidState).getColorTint(fluidState, getter, pos); + return IClientFluidTypeExtensions.of(fluidState).getTintColor(fluidState, getter, pos); } else return 0xAF7FFFD4; }, TEST_FLUID_BLOCK.get()); } diff --git a/src/test/java/net/minecraftforge/debug/fluid/NewFluidTest.java b/src/test/java/net/minecraftforge/debug/fluid/NewFluidTest.java index c88ad78e148..1fadede73bf 100644 --- a/src/test/java/net/minecraftforge/debug/fluid/NewFluidTest.java +++ b/src/test/java/net/minecraftforge/debug/fluid/NewFluidTest.java @@ -12,7 +12,7 @@ import net.minecraft.core.BlockPos; import net.minecraft.world.level.BlockGetter; import net.minecraft.world.level.LevelAccessor; -import net.minecraftforge.client.IFluidTypeRenderProperties; +import net.minecraftforge.client.extensions.common.IClientFluidTypeExtensions; import net.minecraftforge.fluids.DispenseFluidContainer; import net.minecraftforge.fluids.FluidType; import org.apache.commons.lang3.Validate; @@ -73,9 +73,9 @@ private static ForgeFlowingFluid.Properties makeProperties() public static RegistryObject test_fluid_type = FLUID_TYPES.register("test_fluid", () -> new FluidType(FluidType.Properties.create()) { @Override - public void initializeClient(Consumer consumer) + public void initializeClient(Consumer consumer) { - consumer.accept(new IFluidTypeRenderProperties() + consumer.accept(new IClientFluidTypeExtensions() { @Override public ResourceLocation getStillTexture() @@ -97,7 +97,7 @@ public ResourceLocation getOverlayTexture() } @Override - public int getColorTint() + public int getTintColor() { return 0x3F1080FF; } diff --git a/src/test/java/net/minecraftforge/debug/recipe/recipebook/RecipeBookExtensionClientHelper.java b/src/test/java/net/minecraftforge/debug/recipe/recipebook/RecipeBookExtensionClientHelper.java index ca0fbe5875a..10d650d2182 100644 --- a/src/test/java/net/minecraftforge/debug/recipe/recipebook/RecipeBookExtensionClientHelper.java +++ b/src/test/java/net/minecraftforge/debug/recipe/recipebook/RecipeBookExtensionClientHelper.java @@ -8,10 +8,9 @@ import com.google.common.base.Suppliers; import com.google.common.collect.ImmutableList; import net.minecraft.client.RecipeBookCategories; -import net.minecraft.stats.RecipeBook; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; -import net.minecraftforge.client.RecipeBookRegistry; +import net.minecraftforge.client.event.RegisterRecipeBookCategoriesEvent; import java.util.function.Supplier; @@ -21,11 +20,11 @@ public class RecipeBookExtensionClientHelper public static final Supplier TESTING_CAT_1 = Suppliers.memoize(() -> RecipeBookCategories.create("TESTING_CAT_1", new ItemStack(Items.DIAMOND))); public static final Supplier TESTING_CAT_2 = Suppliers.memoize(() -> RecipeBookCategories.create("TESTING_CAT_2", new ItemStack(Items.NETHERITE_INGOT))); - public static void init() + public static void init(RegisterRecipeBookCategoriesEvent event) { - RecipeBookRegistry.addCategoriesToType(RecipeBookExtensionTest.TEST_TYPE, ImmutableList.of(TESTING_SEARCH.get(), TESTING_CAT_1.get(), TESTING_CAT_2.get())); - RecipeBookRegistry.addAggregateCategories(TESTING_SEARCH.get(), ImmutableList.of(TESTING_CAT_1.get(), TESTING_CAT_2.get())); - RecipeBookRegistry.addCategoriesFinder(RecipeBookExtensionTest.RECIPE_BOOK_TEST_RECIPE_TYPE.get(), r -> + event.registerBookCategories(RecipeBookExtensionTest.TEST_TYPE, ImmutableList.of(TESTING_SEARCH.get(), TESTING_CAT_1.get(), TESTING_CAT_2.get())); + event.registerAggregateCategory(TESTING_SEARCH.get(), ImmutableList.of(TESTING_CAT_1.get(), TESTING_CAT_2.get())); + event.registerRecipeCategoryFinder(RecipeBookExtensionTest.RECIPE_BOOK_TEST_RECIPE_TYPE.get(), r -> { if (r.getResultItem().getItem() == Items.DIAMOND_BLOCK) return TESTING_CAT_1.get(); diff --git a/src/test/java/net/minecraftforge/debug/recipe/recipebook/RecipeBookExtensionTest.java b/src/test/java/net/minecraftforge/debug/recipe/recipebook/RecipeBookExtensionTest.java index 5f656428073..8d72b44bf99 100644 --- a/src/test/java/net/minecraftforge/debug/recipe/recipebook/RecipeBookExtensionTest.java +++ b/src/test/java/net/minecraftforge/debug/recipe/recipebook/RecipeBookExtensionTest.java @@ -18,6 +18,7 @@ import net.minecraft.world.item.crafting.RecipeType; import net.minecraft.world.level.block.Blocks; import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.client.event.RegisterRecipeBookCategoriesEvent; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.common.extensions.IForgeMenuType; import net.minecraftforge.event.entity.player.PlayerInteractEvent; @@ -87,9 +88,15 @@ public static void clientSetup(FMLClientSetupEvent event) event.enqueueWork(() -> { MenuScreens.register(RECIPE_BOOK_TEST_MENU_TYPE.get(), RecipeBookTestScreen::new); - RecipeBookExtensionClientHelper.init(); }); } + @SubscribeEvent + public static void onRegisterRecipeBookCategories(RegisterRecipeBookCategoriesEvent event) + { + if (!ENABLED) + return; + RecipeBookExtensionClientHelper.init(event); + } } public static class RecipeBookTestContainer extends SimpleContainer diff --git a/src/test/java/net/minecraftforge/eventtest/internal/TestFramework.java b/src/test/java/net/minecraftforge/eventtest/internal/TestFramework.java index 8ee06d3a803..1e49e05bb15 100644 --- a/src/test/java/net/minecraftforge/eventtest/internal/TestFramework.java +++ b/src/test/java/net/minecraftforge/eventtest/internal/TestFramework.java @@ -6,7 +6,7 @@ package net.minecraftforge.eventtest.internal; import net.minecraft.client.gui.screens.TitleScreen; -import net.minecraftforge.client.event.ScreenOpenEvent; +import net.minecraftforge.client.event.ScreenEvent; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.event.GameShuttingDownEvent; import net.minecraftforge.fml.common.Mod; @@ -116,7 +116,7 @@ private List gatherEvents() { * the ScreenOpenEvent fired by TitleScreen is the last event fired without user interaction, so it is the * end of the "automatic" bootstrap time. */ - private void collectBootstrapTests(ScreenOpenEvent event) { + private void collectBootstrapTests(ScreenEvent.Opening event) { if(!(event.getScreen() instanceof TitleScreen) || bootstrapHandled) return; diff --git a/src/test/resources/META-INF/mods.toml b/src/test/resources/META-INF/mods.toml index cd0e02bbf98..a2751f88f21 100644 --- a/src/test/resources/META-INF/mods.toml +++ b/src/test/resources/META-INF/mods.toml @@ -240,6 +240,8 @@ modId="data_pack_registries_test" modId="mod_mismatch_test" [[mods]] modId="custom_transformtype_test" +[[mods]] +modId="mega_model_test" diff --git a/src/test/resources/assets/mega_model_test/blockstates/test_block.json b/src/test/resources/assets/mega_model_test/blockstates/test_block.json new file mode 100644 index 00000000000..2a4084d77d0 --- /dev/null +++ b/src/test/resources/assets/mega_model_test/blockstates/test_block.json @@ -0,0 +1,7 @@ +{ + "variants": { + "": { + "model": "mega_model_test:block/test_block" + } + } +} diff --git a/src/test/resources/assets/mega_model_test/models/block/test_block.json b/src/test/resources/assets/mega_model_test/models/block/test_block.json new file mode 100644 index 00000000000..efd7ad4cd37 --- /dev/null +++ b/src/test/resources/assets/mega_model_test/models/block/test_block.json @@ -0,0 +1,94 @@ +{ + "loader": "forge:separate_transforms", + "base": { + "parent": "block/block", + "loader": "forge:composite", + "__CHANGE_WHEN_UPDATING_TO_1.20": "REPLACE 'parts' WITH 'children' IN 1.20 OR THIS WILL NOT LOAD", + "parts": { + "first": { + "__CHANGE_WHEN_UPDATING_TO_1": "REPLACE 'minecraft:elements' WITH 'forge:elements' IN 1.20 OR THIS WILL NOT LOAD", + "loader": "minecraft:elements", + "textures": { + "tex": "minecraft:block/smooth_stone" + }, + "elements": [ + { + "from": [ 0, 0, 0 ], + "to": [ 16, 2, 16 ], + "faces": { + "down": { "texture": "#tex" }, + "up": { "texture": "#tex" }, + "north": { "texture": "#tex" }, + "south": { "texture": "#tex" }, + "west": { "texture": "#tex" }, + "east": { "texture": "#tex" } + } + } + ] + }, + "second": { + "loader": "forge:elements", + "render_type": "cutout", + "textures": { + "tex": "minecraft:block/oak_leaves" + }, + "elements": [ + { + "from": [ 2, 2, 2 ], + "to": [ 14, 6, 14 ], + "faces": { + "down": { "texture": "#tex" }, + "up": { "texture": "#tex" }, + "north": { "texture": "#tex" }, + "south": { "texture": "#tex" }, + "west": { "texture": "#tex" }, + "east": { "texture": "#tex" } + } + } + ] + }, + "third": { + "loader": "forge:elements", + "render_type": "translucent", + "textures": { + "tex": "minecraft:block/slime_block" + }, + "elements": [ + { + "from": [ 4, 6, 4 ], + "to": [ 12, 14, 12 ], + "faces": { + "down": { "texture": "#tex" }, + "up": { "texture": "#tex" }, + "north": { "texture": "#tex" }, + "south": { "texture": "#tex" }, + "west": { "texture": "#tex" }, + "east": { "texture": "#tex" } + } + } + ] + } + } + }, + "perspectives": { + "firstperson_lefthand": { + "parent": "forge:item/default", + "loader": "forge:item_layers", + "textures": { + "layer0": "minecraft:item/chainmail_chestplate", + "layer1": "minecraft:item/bow" + }, + "emissive_layers": [ 1 ] + }, + "firstperson_righthand": { + "parent": "forge:item/default", + "loader": "forge:fluid_container", + "fluid": "minecraft:lava", + "gui_light": "front", + "textures": { + "base": "minecraft:item/bucket", + "fluid": "forge:item/mask/bucket_fluid" + } + } + } +} diff --git a/src/test/resources/assets/mega_model_test/models/item/test_block.json b/src/test/resources/assets/mega_model_test/models/item/test_block.json new file mode 100644 index 00000000000..644508a99cd --- /dev/null +++ b/src/test/resources/assets/mega_model_test/models/item/test_block.json @@ -0,0 +1,3 @@ +{ + "parent": "mega_model_test:block/test_block" +} \ No newline at end of file