191 lines
		
	
	
	
		
			6.6 KiB
		
	
	
	
		
			Java
		
	
	
	
	
	
			
		
		
	
	
			191 lines
		
	
	
	
		
			6.6 KiB
		
	
	
	
		
			Java
		
	
	
	
	
	
| package net.minecraft.client.renderer.texture;
 | |
| 
 | |
| import com.mojang.blaze3d.platform.NativeImage;
 | |
| import com.mojang.logging.LogUtils;
 | |
| import com.mojang.realmsclient.gui.screens.AddRealmPopupScreen;
 | |
| import java.io.FileNotFoundException;
 | |
| import java.io.IOException;
 | |
| import java.io.UncheckedIOException;
 | |
| import java.nio.file.Files;
 | |
| import java.nio.file.Path;
 | |
| import java.util.ArrayList;
 | |
| import java.util.HashMap;
 | |
| import java.util.HashSet;
 | |
| import java.util.List;
 | |
| import java.util.Map;
 | |
| import java.util.Set;
 | |
| import java.util.concurrent.CompletableFuture;
 | |
| import java.util.concurrent.Executor;
 | |
| import net.fabricmc.api.EnvType;
 | |
| import net.fabricmc.api.Environment;
 | |
| import net.minecraft.CrashReport;
 | |
| import net.minecraft.CrashReportCategory;
 | |
| import net.minecraft.ReportedException;
 | |
| import net.minecraft.resources.ResourceLocation;
 | |
| import net.minecraft.server.packs.resources.PreparableReloadListener;
 | |
| import net.minecraft.server.packs.resources.ResourceManager;
 | |
| import org.slf4j.Logger;
 | |
| 
 | |
| @Environment(EnvType.CLIENT)
 | |
| public class TextureManager implements PreparableReloadListener, Tickable, AutoCloseable {
 | |
| 	private static final Logger LOGGER = LogUtils.getLogger();
 | |
| 	public static final ResourceLocation INTENTIONAL_MISSING_TEXTURE = ResourceLocation.withDefaultNamespace("");
 | |
| 	private final Map<ResourceLocation, AbstractTexture> byPath = new HashMap();
 | |
| 	private final Set<Tickable> tickableTextures = new HashSet();
 | |
| 	private final ResourceManager resourceManager;
 | |
| 
 | |
| 	public TextureManager(ResourceManager resourceManager) {
 | |
| 		this.resourceManager = resourceManager;
 | |
| 		NativeImage nativeImage = MissingTextureAtlasSprite.generateMissingImage();
 | |
| 		this.register(MissingTextureAtlasSprite.getLocation(), new DynamicTexture(() -> "(intentionally-)Missing Texture", nativeImage));
 | |
| 	}
 | |
| 
 | |
| 	public void registerAndLoad(ResourceLocation textureId, ReloadableTexture texture) {
 | |
| 		try {
 | |
| 			texture.apply(this.loadContentsSafe(textureId, texture));
 | |
| 		} catch (Throwable var6) {
 | |
| 			CrashReport crashReport = CrashReport.forThrowable(var6, "Uploading texture");
 | |
| 			CrashReportCategory crashReportCategory = crashReport.addCategory("Uploaded texture");
 | |
| 			crashReportCategory.setDetail("Resource location", texture.resourceId());
 | |
| 			crashReportCategory.setDetail("Texture id", textureId);
 | |
| 			throw new ReportedException(crashReport);
 | |
| 		}
 | |
| 
 | |
| 		this.register(textureId, texture);
 | |
| 	}
 | |
| 
 | |
| 	private TextureContents loadContentsSafe(ResourceLocation textureId, ReloadableTexture texture) {
 | |
| 		try {
 | |
| 			return loadContents(this.resourceManager, textureId, texture);
 | |
| 		} catch (Exception var4) {
 | |
| 			LOGGER.error("Failed to load texture {} into slot {}", texture.resourceId(), textureId, var4);
 | |
| 			return TextureContents.createMissing();
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	public void registerForNextReload(ResourceLocation textureId) {
 | |
| 		this.register(textureId, new SimpleTexture(textureId));
 | |
| 	}
 | |
| 
 | |
| 	public void register(ResourceLocation path, AbstractTexture texture) {
 | |
| 		AbstractTexture abstractTexture = (AbstractTexture)this.byPath.put(path, texture);
 | |
| 		if (abstractTexture != texture) {
 | |
| 			if (abstractTexture != null) {
 | |
| 				this.safeClose(path, abstractTexture);
 | |
| 			}
 | |
| 
 | |
| 			if (texture instanceof Tickable tickable) {
 | |
| 				this.tickableTextures.add(tickable);
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	private void safeClose(ResourceLocation path, AbstractTexture texture) {
 | |
| 		this.tickableTextures.remove(texture);
 | |
| 
 | |
| 		try {
 | |
| 			texture.close();
 | |
| 		} catch (Exception var4) {
 | |
| 			LOGGER.warn("Failed to close texture {}", path, var4);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	public AbstractTexture getTexture(ResourceLocation path) {
 | |
| 		AbstractTexture abstractTexture = (AbstractTexture)this.byPath.get(path);
 | |
| 		if (abstractTexture != null) {
 | |
| 			return abstractTexture;
 | |
| 		} else {
 | |
| 			SimpleTexture simpleTexture = new SimpleTexture(path);
 | |
| 			this.registerAndLoad(path, simpleTexture);
 | |
| 			return simpleTexture;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	@Override
 | |
| 	public void tick() {
 | |
| 		for (Tickable tickable : this.tickableTextures) {
 | |
| 			tickable.tick();
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	public void release(ResourceLocation path) {
 | |
| 		AbstractTexture abstractTexture = (AbstractTexture)this.byPath.remove(path);
 | |
| 		if (abstractTexture != null) {
 | |
| 			this.safeClose(path, abstractTexture);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	public void close() {
 | |
| 		this.byPath.forEach(this::safeClose);
 | |
| 		this.byPath.clear();
 | |
| 		this.tickableTextures.clear();
 | |
| 	}
 | |
| 
 | |
| 	@Override
 | |
| 	public CompletableFuture<Void> reload(
 | |
| 		PreparableReloadListener.PreparationBarrier preparationBarrier, ResourceManager resourceManager, Executor executor, Executor executor2
 | |
| 	) {
 | |
| 		List<TextureManager.PendingReload> list = new ArrayList();
 | |
| 		this.byPath.forEach((resourceLocation, abstractTexture) -> {
 | |
| 			if (abstractTexture instanceof ReloadableTexture reloadableTexture) {
 | |
| 				list.add(scheduleLoad(resourceManager, resourceLocation, reloadableTexture, executor));
 | |
| 			}
 | |
| 		});
 | |
| 		return CompletableFuture.allOf((CompletableFuture[])list.stream().map(TextureManager.PendingReload::newContents).toArray(CompletableFuture[]::new))
 | |
| 			.thenCompose(preparationBarrier::wait)
 | |
| 			.thenAcceptAsync(void_ -> {
 | |
| 				AddRealmPopupScreen.updateCarouselImages(this.resourceManager);
 | |
| 
 | |
| 				for (TextureManager.PendingReload pendingReload : list) {
 | |
| 					pendingReload.texture.apply((TextureContents)pendingReload.newContents.join());
 | |
| 				}
 | |
| 			}, executor2);
 | |
| 	}
 | |
| 
 | |
| 	public void dumpAllSheets(Path path) {
 | |
| 		try {
 | |
| 			Files.createDirectories(path);
 | |
| 		} catch (IOException var3) {
 | |
| 			LOGGER.error("Failed to create directory {}", path, var3);
 | |
| 			return;
 | |
| 		}
 | |
| 
 | |
| 		this.byPath.forEach((resourceLocation, abstractTexture) -> {
 | |
| 			if (abstractTexture instanceof Dumpable dumpable) {
 | |
| 				try {
 | |
| 					dumpable.dumpContents(resourceLocation, path);
 | |
| 				} catch (IOException var5) {
 | |
| 					LOGGER.error("Failed to dump texture {}", resourceLocation, var5);
 | |
| 				}
 | |
| 			}
 | |
| 		});
 | |
| 	}
 | |
| 
 | |
| 	private static TextureContents loadContents(ResourceManager resourceManager, ResourceLocation textureId, ReloadableTexture texture) throws IOException {
 | |
| 		try {
 | |
| 			return texture.loadContents(resourceManager);
 | |
| 		} catch (FileNotFoundException var4) {
 | |
| 			if (textureId != INTENTIONAL_MISSING_TEXTURE) {
 | |
| 				LOGGER.warn("Missing resource {} referenced from {}", texture.resourceId(), textureId);
 | |
| 			}
 | |
| 
 | |
| 			return TextureContents.createMissing();
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	private static TextureManager.PendingReload scheduleLoad(
 | |
| 		ResourceManager resourceManager, ResourceLocation textureId, ReloadableTexture texture, Executor executor
 | |
| 	) {
 | |
| 		return new TextureManager.PendingReload(texture, CompletableFuture.supplyAsync(() -> {
 | |
| 			try {
 | |
| 				return loadContents(resourceManager, textureId, texture);
 | |
| 			} catch (IOException var4) {
 | |
| 				throw new UncheckedIOException(var4);
 | |
| 			}
 | |
| 		}, executor));
 | |
| 	}
 | |
| 
 | |
| 	@Environment(EnvType.CLIENT)
 | |
| 	record PendingReload(ReloadableTexture texture, CompletableFuture<TextureContents> newContents) {
 | |
| 	}
 | |
| }
 |