Skip to content

Commit

Permalink
[1.21.1] Add event for registering atlases for use with Material (#1581)
Browse files Browse the repository at this point in the history
  • Loading branch information
XFactHD authored Nov 9, 2024
1 parent e9d5fee commit 2ae3bb4
Show file tree
Hide file tree
Showing 5 changed files with 140 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
--- a/net/minecraft/client/resources/model/ModelManager.java
+++ b/net/minecraft/client/resources/model/ModelManager.java
@@ -63,13 +_,14 @@
@@ -63,18 +_,20 @@
TextureAtlas.LOCATION_BLOCKS,
ResourceLocation.withDefaultNamespace("blocks")
);
Expand All @@ -16,6 +16,12 @@

public ModelManager(TextureManager p_119406_, BlockColors p_119407_, int p_119408_) {
this.blockColors = p_119407_;
this.maxMipmapLevels = p_119408_;
this.blockModelShaper = new BlockModelShaper(this);
+ Map<ResourceLocation, ResourceLocation> VANILLA_ATLASES = net.neoforged.neoforge.client.ClientHooks.gatherMaterialAtlases(ModelManager.VANILLA_ATLASES);
this.atlases = new AtlasSet(VANILLA_ATLASES, p_119406_);
}

@@ -100,6 +_,7 @@
Executor p_249221_
) {
Expand Down
7 changes: 7 additions & 0 deletions src/main/java/net/neoforged/neoforge/client/ClientHooks.java
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@
import net.neoforged.neoforge.client.event.RegisterClientReloadListenersEvent;
import net.neoforged.neoforge.client.event.RegisterColorHandlersEvent;
import net.neoforged.neoforge.client.event.RegisterKeyMappingsEvent;
import net.neoforged.neoforge.client.event.RegisterMaterialAtlasesEvent;
import net.neoforged.neoforge.client.event.RegisterParticleProvidersEvent;
import net.neoforged.neoforge.client.event.RegisterShadersEvent;
import net.neoforged.neoforge.client.event.RegisterSpriteSourceTypesEvent;
Expand Down Expand Up @@ -1120,4 +1121,10 @@ public static RecipeBookType[] getFilteredRecipeBookTypeValues() {
}
return RECIPE_BOOK_TYPES;
}

public static Map<ResourceLocation, ResourceLocation> gatherMaterialAtlases(Map<ResourceLocation, ResourceLocation> vanillaAtlases) {
vanillaAtlases = new HashMap<>(vanillaAtlases);
ModLoader.postEvent(new RegisterMaterialAtlasesEvent(vanillaAtlases));
return Map.copyOf(vanillaAtlases);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*
* Copyright (c) NeoForged and contributors
* SPDX-License-Identifier: LGPL-2.1-only
*/

package net.neoforged.neoforge.client.event;

import java.util.Map;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.texture.TextureAtlas;
import net.minecraft.client.resources.TextureAtlasHolder;
import net.minecraft.client.resources.model.Material;
import net.minecraft.client.resources.model.ModelManager;
import net.minecraft.resources.ResourceLocation;
import net.neoforged.bus.api.Event;
import net.neoforged.bus.api.ICancellableEvent;
import net.neoforged.fml.LogicalSide;
import net.neoforged.fml.event.IModBusEvent;
import org.jetbrains.annotations.ApiStatus;

/**
* Fired for registering {@linkplain TextureAtlas texture atlases} that will be used with {@link Material} or
* other systems which retrieve the atlas via {@link Minecraft#getTextureAtlas(ResourceLocation)} or
* {@link ModelManager#getAtlas(ResourceLocation)}.
* <p>
* If an atlas is registered via this event, then it must <b>NOT</b> be used through a {@link TextureAtlasHolder}.
* <p>
* This event fires during startup when the {@link ModelManager} is constructed.
* <p>
* This event is not {@linkplain ICancellableEvent cancellable}.
* <p>
* This event is fired on the mod-specific event bus, only on the {@linkplain LogicalSide#CLIENT logical client}.
*/
public class RegisterMaterialAtlasesEvent extends Event implements IModBusEvent {
private final Map<ResourceLocation, ResourceLocation> atlases;

@ApiStatus.Internal
public RegisterMaterialAtlasesEvent(Map<ResourceLocation, ResourceLocation> atlases) {
this.atlases = atlases;
}

/**
* Register a texture atlas with the given name and info location
*
* @param atlasLocation The name of the texture atlas
* @param atlasInfoLocation The location of the atlas info JSON relative to the {@code atlases} directory
*/
public void register(ResourceLocation atlasLocation, ResourceLocation atlasInfoLocation) {
ResourceLocation oldAtlasInfoLoc = this.atlases.putIfAbsent(atlasLocation, atlasInfoLocation);
if (oldAtlasInfoLoc != null) {
throw new IllegalStateException(String.format(
"Duplicate registration of atlas: %s (old info: %s, new info: %s)",
atlasLocation,
oldAtlasInfoLoc,
atlasInfoLocation));
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
* Copyright (c) NeoForged and contributors
* SPDX-License-Identifier: LGPL-2.1-only
*/

package net.neoforged.neoforge.debug.client;

import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.texture.MissingTextureAtlasSprite;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.resources.model.Material;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.packs.resources.ResourceManagerReloadListener;
import net.neoforged.api.distmarker.Dist;
import net.neoforged.neoforge.client.event.RegisterClientReloadListenersEvent;
import net.neoforged.neoforge.client.event.RegisterMaterialAtlasesEvent;
import net.neoforged.testframework.DynamicTest;
import net.neoforged.testframework.annotation.ForEachTest;
import net.neoforged.testframework.annotation.TestHolder;

@ForEachTest(side = Dist.CLIENT, groups = { "client.texture_atlas", "texture_atlas" })
public class TextureAtlasTests {
@TestHolder(description = { "Tests that texture atlases intended for use with Material are correctly registered and loaded" }, enabledByDefault = true)
static void testMaterialAtlas(final DynamicTest test) {
String modId = test.createModId();
ResourceLocation atlasLoc = ResourceLocation.fromNamespaceAndPath(modId, "textures/atlas/material_test.png");

test.framework().modEventBus().addListener(RegisterMaterialAtlasesEvent.class, event -> {
ResourceLocation infoLoc = ResourceLocation.fromNamespaceAndPath(modId, "material_test");
event.register(atlasLoc, infoLoc);
});

test.framework().modEventBus().addListener(RegisterClientReloadListenersEvent.class, event -> {
event.registerReloadListener((ResourceManagerReloadListener) manager -> {
try {
Minecraft.getInstance().getModelManager().getAtlas(atlasLoc);
} catch (NullPointerException npe) {
test.fail("Atlas was not registered");
return;
} catch (Throwable t) {
test.fail("Atlas lookup failed: " + t.getMessage());
return;
}

try {
Material material = new Material(atlasLoc, ResourceLocation.withDefaultNamespace("block/stone"));
TextureAtlasSprite sprite = material.sprite();
if (sprite.contents().name().equals(MissingTextureAtlasSprite.getLocation())) {
test.fail("Expected sprite was not stitched");
return;
}
} catch (Throwable t) {
test.fail("Sprite lookup via material failed: " + t.getMessage());
}

test.pass();
});
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"sources": [
{
"type": "minecraft:single",
"resource": "minecraft:block/stone"
}
]
}

0 comments on commit 2ae3bb4

Please sign in to comment.