Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[1.21.1] Add event for registering atlases for use with Material #1581

Merged
merged 3 commits into from
Nov 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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)",
embeddedt marked this conversation as resolved.
Show resolved Hide resolved
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"
}
]
}