All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.parzivail.util.client.texture.TextureProvider Maven / Gradle / Ivy

package com.parzivail.util.client.texture;

import com.mojang.authlib.minecraft.InsecurePublicKeyException;
import com.mojang.blaze3d.systems.RenderSystem;
import com.parzivail.util.ParziUtil;
import com.parzivail.util.data.FallbackIdentifier;
import org.jetbrains.annotations.NotNull;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Supplier;
import net.minecraft.class_1044;
import net.minecraft.class_1060;
import net.minecraft.class_156;
import net.minecraft.class_2960;
import net.minecraft.class_310;

public abstract class TextureProvider
{
	private static final ArrayList TEXTURE_CACHE = new ArrayList<>();
	private static final ArrayList FAILURE_CACHE = new ArrayList<>();
	private static final HashMap>> LOAD_CALLBACKS = new HashMap<>();

	public static final ArrayList> TEXTURE_PROVIDERS = new ArrayList<>();

	private final class_2960 root;
	private final class_1060 textureManager;

	protected TextureProvider(class_2960 cacheIdRoot, class_1060 textureManager)
	{
		this.root = cacheIdRoot;
		this.textureManager = textureManager;

		TEXTURE_PROVIDERS.add(this);
	}

	@NotNull
	protected class_2960 createCacheId(String requestName)
	{
		return new class_2960(root.method_12836(), root.method_12832() + "/" + requestName);
	}

	public boolean isProviderFor(class_2960 cacheId)
	{
		return cacheId.method_12836().equals(root.method_12836()) && cacheId.method_12832().startsWith(root.method_12832());
	}

	public class_2960 getProvidedId(class_2960 cacheId)
	{
		// If we provided this ID, return it
		if (isProviderFor(cacheId))
			return cacheId;

		// Also return if we provided the fallback ID in a FallbackIdentifier
		if (cacheId instanceof FallbackIdentifier fi && isProviderFor(fi.getSource()))
			return fi.getSource();

		return null;
	}

	public boolean isReady(class_2960 cacheId)
	{
		return TEXTURE_CACHE.contains(cacheId) && textureManager.method_34590(cacheId, null) != null;
	}

	protected void markTextureDirty(class_2960 cacheId)
	{
		TEXTURE_CACHE.removeIf(cacheId::equals);
	}

	protected void markTextureFailure(class_2960 cacheId)
	{
		FAILURE_CACHE.add(cacheId);
	}

	protected void registerDependencyCallbacks(class_2960 cacheId, class_2960 dependencyCacheId)
	{
		for (var provider : TEXTURE_PROVIDERS)
		{
			var providerCacheId = provider.getProvidedId(dependencyCacheId);

			if (providerCacheId != null && !provider.isReady(dependencyCacheId))
			{
				provider.addLoadCallback(providerCacheId, (success) -> {
					if (success)
						markTextureDirty(cacheId);
				});

				// There should only be one provider for each cache ID
				break;
			}
		}
	}

	public class_2960 getId(String requestName, Supplier fallback, Supplier requestFulfiller)
	{
		var cacheId = createCacheId(requestName);

		if (FAILURE_CACHE.contains(cacheId))
			return fallback == null ? cacheId : fallback.get();

		var texture = textureManager.method_34590(cacheId, null);

		// The texture is fully loaded and isn't marked as dirty (i.e. the cache contains it)
		if (texture != null && TEXTURE_CACHE.contains(cacheId))
			return cacheId;

		if (!TEXTURE_CACHE.contains(cacheId))
		{
			// The texture hasn't been stacked yet
			bakeTextureAsync(cacheId, requestFulfiller.get());
			TEXTURE_CACHE.add(cacheId);
		}

		// The texture has been stacked but hasn't been loaded yet

		// Don't use a fallback if none is supplied
		if (fallback == null)
			return cacheId;

		// Return the requested fallback
		var fallbackId = fallback.get();
		return new FallbackIdentifier(fallbackId.method_12836(), fallbackId.method_12832(), cacheId);
	}

	protected abstract CallbackTexture createTexture(class_2960 destId, TData requestData, Consumer callback);

	protected void bakeTextureAsync(class_2960 cacheId, TData request)
	{
		class_156.method_18349().execute(() -> {
			try
			{
				var minecraft = class_310.method_1551();
				minecraft.execute(() -> RenderSystem.recordRenderCall(() -> registerTexture(cacheId, request)));
			}
			catch (InsecurePublicKeyException insecureTextureException)
			{
				ParziUtil.LOG.warn("Attempt to load insecure texture blocked: %s ", cacheId, insecureTextureException);
			}
		});
	}

	protected void registerTexture(class_2960 cacheId, TData request)
	{
		ParziUtil.LOG.debug("Registering texture %s", cacheId);
		this.textureManager.method_4616(cacheId, createTexture(cacheId, request, success -> pollCallbacks(cacheId, success)));
	}

	public void addLoadCallback(class_2960 target, Consumer callback)
	{
		if (isReady(target))
		{
			callback.accept(true);
			return;
		}

		if (!LOAD_CALLBACKS.containsKey(target))
			LOAD_CALLBACKS.put(target, new ArrayList<>());

		LOAD_CALLBACKS.get(target).add(callback);
	}

	private void pollCallbacks(class_2960 identifier, boolean success)
	{
		var callbacks = LOAD_CALLBACKS.get(identifier);
		if (callbacks == null)
			return;

		callbacks.forEach(callback -> callback.accept(success));
		LOAD_CALLBACKS.remove(identifier);
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy