diff --git a/src/main/java/me/pepperbell/continuity/client/mixin/AtlasLoaderMixin.java b/src/main/java/me/pepperbell/continuity/client/mixin/AtlasLoaderMixin.java index dcee9d6..ddefa07 100644 --- a/src/main/java/me/pepperbell/continuity/client/mixin/AtlasLoaderMixin.java +++ b/src/main/java/me/pepperbell/continuity/client/mixin/AtlasLoaderMixin.java @@ -1,24 +1,20 @@ package me.pepperbell.continuity.client.mixin; +import java.io.InputStream; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.function.Supplier; - import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.ModifyVariable; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import org.spongepowered.asm.mixin.injection.callback.LocalCapture; - -import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import me.pepperbell.continuity.client.resource.AtlasLoaderInitContext; -import me.pepperbell.continuity.client.resource.AtlasLoaderLoadContext; -import me.pepperbell.continuity.client.resource.EmissiveSuffixLoader; +import com.google.gson.Gson; +import com.google.gson.JsonObject; import net.minecraft.client.texture.SpriteContents; import net.minecraft.client.texture.SpriteLoader; import net.minecraft.client.texture.atlas.AtlasLoader; @@ -26,62 +22,168 @@ import net.minecraft.client.texture.atlas.SingleAtlasSource; import net.minecraft.resource.Resource; import net.minecraft.resource.ResourceManager; +import net.minecraft.resource.ResourcePack; +import net.minecraft.resource.metadata.ResourcePackMetadata; import net.minecraft.util.Identifier; +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import me.pepperbell.continuity.client.ContinuityClient; +import me.pepperbell.continuity.client.resource.AtlasLoaderInitContext; +import me.pepperbell.continuity.client.resource.AtlasLoaderLoadContext; +import me.pepperbell.continuity.client.resource.EmissiveSuffixLoader; @Mixin(AtlasLoader.class) abstract class AtlasLoaderMixin { + + private static final String MTS_NAMESPACE = "mts"; + private static final String MTS_PACK_METADATA_KEY = "mts"; + private static final String MTS_VALID_RESOURCES_KEY = "validResources"; + + private static final Map> MTS_VALID_RESOURCES_CACHE = new Object2ObjectOpenHashMap<>(); + + @ModifyVariable(method = "(Ljava/util/List;)V", at = @At(value = "LOAD", ordinal = 0), argsOnly = true, ordinal = 0) private List continuity$modifySources(List sources) { + AtlasLoaderInitContext context = AtlasLoaderInitContext.THREAD_LOCAL.get(); - if (context != null) { - Set extraIds = context.getExtraIds(); - if (extraIds != null && !extraIds.isEmpty()) { - List extraSources = new ObjectArrayList<>(); - for (Identifier extraId : extraIds) { - extraSources.add(new SingleAtlasSource(extraId, Optional.empty())); - } + if (context == null) { + ContinuityClient.LOGGER.debug("AtlasLoaderInitContext is null, skipping extra sources"); + return sources; + } - if (sources instanceof ArrayList) { - sources.addAll(0, extraSources); - } else { - List mutableSources = new ArrayList<>(extraSources); - mutableSources.addAll(sources); - return mutableSources; - } + Set extraIds = context.getExtraIds(); + if (extraIds == null || extraIds.isEmpty()) { + return sources; + } + + List validExtraSources = new ObjectArrayList<>(); + for (Identifier extraId : extraIds) { + if (isMtsResourceValid(context.getResourceManager(), extraId)) { + validExtraSources.add(new SingleAtlasSource(extraId, Optional.empty())); + } else { + ContinuityClient.LOGGER.debug("Skipping invalid MTS extra texture: {}", extraId); } } + + + if (sources instanceof ArrayList) { + sources.addAll(0, validExtraSources); + } else { + List mutableSources = new ArrayList<>(validExtraSources); + mutableSources.addAll(sources); + return mutableSources; + } return sources; } + @Inject(method = "loadSources(Lnet/minecraft/resource/ResourceManager;)Ljava/util/List;", at = @At(value = "INVOKE", target = "Lcom/google/common/collect/ImmutableList;builder()Lcom/google/common/collect/ImmutableList$Builder;", remap = false), locals = LocalCapture.CAPTURE_FAILHARD) private void continuity$afterLoadSources(ResourceManager resourceManager, CallbackInfoReturnable>> cir, Map suppliers) { + AtlasLoaderLoadContext context = AtlasLoaderLoadContext.THREAD_LOCAL.get(); - if (context != null) { - String emissiveSuffix = EmissiveSuffixLoader.getEmissiveSuffix(); - if (emissiveSuffix != null) { - Map emissiveSuppliers = new Object2ObjectOpenHashMap<>(); - Map emissiveIdMap = new Object2ObjectOpenHashMap<>(); - suppliers.forEach((id, supplier) -> { - if (!id.getPath().endsWith(emissiveSuffix)) { - Identifier emissiveId = id.withPath(id.getPath() + emissiveSuffix); - if (!suppliers.containsKey(emissiveId)) { - Identifier emissiveLocation = emissiveId.withPath("textures/" + emissiveId.getPath() + ".png"); - Optional optionalResource = resourceManager.getResource(emissiveLocation); - if (optionalResource.isPresent()) { - Resource resource = optionalResource.get(); - emissiveSuppliers.put(emissiveId, () -> SpriteLoader.load(emissiveId, resource)); - emissiveIdMap.put(id, emissiveId); - } - } else { - emissiveIdMap.put(id, emissiveId); + if (context == null) { + ContinuityClient.LOGGER.debug("AtlasLoaderLoadContext is null, skipping emissive texture load"); + return; + } + + String emissiveSuffix = EmissiveSuffixLoader.getEmissiveSuffix(); + if (emissiveSuffix == null) { + return; + } + + Map emissiveSuppliers = new Object2ObjectOpenHashMap<>(); + Map emissiveIdMap = new Object2ObjectOpenHashMap<>(); + + suppliers.forEach((id, supplier) -> { + + if (id.getPath().endsWith(emissiveSuffix)) { + return; + } + + + if (!isMtsResourceValid(resourceManager, id)) { + ContinuityClient.LOGGER.debug("Skipping emissive for invalid MTS texture: {}", id); + return; + } + + Identifier emissiveId = id.withPath(id.getPath() + emissiveSuffix); + + if (suppliers.containsKey(emissiveId)) { + emissiveIdMap.put(id, emissiveId); + return; + } + + + Identifier emissiveLocation = new Identifier(id.getNamespace(), "textures/" + emissiveId.getPath() + ".png"); + Optional optionalResource = resourceManager.getResource(emissiveLocation); + + if (optionalResource.isPresent()) { + Resource resource = optionalResource.get(); + + try (InputStream is = resource.getInputStream()) { + if (is == null) { + ContinuityClient.LOGGER.warn("Null input stream for emissive texture: {}", emissiveLocation); + return; + } + + + emissiveSuppliers.put(emissiveId, () -> { + try { + + return SpriteLoader.load(emissiveId, resourceManager.getResource(emissiveLocation).get()); + } catch (Exception e) { + ContinuityClient.LOGGER.error("Failed to load emissive texture: {}", emissiveId, e); + return null; + } + }); + emissiveIdMap.put(id, emissiveId); + } catch (Exception e) { + ContinuityClient.LOGGER.error("Failed to check emissive texture stream: {}", emissiveLocation, e); + } + } + }); + + + suppliers.putAll(emissiveSuppliers); + if (!emissiveIdMap.isEmpty()) { + context.setEmissiveIdMap(emissiveIdMap); + } + } + + + private boolean isMtsResourceValid(ResourceManager resourceManager, Identifier id) { + + if (!MTS_NAMESPACE.equals(id.getNamespace())) { + return true; + } + + + for (ResourcePack pack : resourceManager.streamResourcePacks().toList()) { + String packName = pack.getName(); + Set validPaths = MTS_VALID_RESOURCES_CACHE.computeIfAbsent(packName, name -> { + try { + ResourcePackMetadata metadata = pack.getMetadata(); + if (metadata != null && metadata.getRaw().has(MTS_PACK_METADATA_KEY)) { + JsonObject mtsMeta = metadata.getRaw().getAsJsonObject(MTS_PACK_METADATA_KEY); + if (mtsMeta.has(MTS_VALID_RESOURCES_KEY)) { + Set paths = new Object2ObjectOpenHashMap<>().keySet(); + mtsMeta.getAsJsonArray(MTS_VALID_RESOURCES_KEY).forEach(elem -> paths.add(elem.getAsString())); + return paths; } } - }); - suppliers.putAll(emissiveSuppliers); - if (!emissiveIdMap.isEmpty()) { - context.setEmissiveIdMap(emissiveIdMap); + } catch (Exception e) { + ContinuityClient.LOGGER.warn("Failed to parse MTS metadata for pack: {}", name, e); } + return Set.of(); + }); + + + if (validPaths.contains(id.toString()) || validPaths.contains(id.getPath())) { + return true; } } + + + return false; } } diff --git a/src/main/java/me/pepperbell/continuity/client/resource/CtmPropertiesLoader.java b/src/main/java/me/pepperbell/continuity/client/resource/CtmPropertiesLoader.java index 6b4173c..4155373 100644 --- a/src/main/java/me/pepperbell/continuity/client/resource/CtmPropertiesLoader.java +++ b/src/main/java/me/pepperbell/continuity/client/resource/CtmPropertiesLoader.java @@ -1,6 +1,8 @@ +```java package me.pepperbell.continuity.client.resource; import java.io.InputStream; +import java.io.InputStreamReader; import java.util.Comparator; import java.util.Iterator; import java.util.List; @@ -8,9 +10,14 @@ import java.util.Properties; import java.util.Set; import java.util.function.Function; - import org.jetbrains.annotations.NotNull; - +import com.google.gson.Gson; +import com.google.gson.JsonObject; +import net.minecraft.resource.ResourceManager; +import net.minecraft.resource.ResourcePack; +import net.minecraft.resource.ResourceType; +import net.minecraft.resource.metadata.ResourcePackMetadata; +import net.minecraft.util.Identifier; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import it.unimi.dsi.fastutil.objects.ObjectArrayList; import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; @@ -23,31 +30,26 @@ import me.pepperbell.continuity.client.model.QuadProcessors; import me.pepperbell.continuity.client.util.BooleanState; import me.pepperbell.continuity.client.util.biome.BiomeHolderManager; -import net.minecraft.client.texture.Sprite; -import net.minecraft.client.util.SpriteIdentifier; -import net.minecraft.resource.ResourceManager; -import net.minecraft.resource.ResourcePack; -import net.minecraft.resource.ResourceType; -import net.minecraft.util.Identifier; public class CtmPropertiesLoader { private final ResourceManager resourceManager; private final List> containers = new ObjectArrayList<>(); private final Map> textureDependencies = new Object2ObjectOpenHashMap<>(); + // MTS-specific configuration: valid CTM path sets and resource pack identifiers + private static final String MTS_NAMESPACE = "mts"; + private static final String MTS_PACK_METADATA_KEY = "mts"; + private static final String MTS_VALID_CTM_KEY = "validCtmPaths"; + private final Map> mtsPackValidCtmPaths = new Object2ObjectOpenHashMap<>(); // Pack name -> valid CTM paths private CtmPropertiesLoader(ResourceManager resourceManager) { this.resourceManager = resourceManager; + loadMtsValidCtmPaths(); // Load valid MTS CTM paths during initialization } public static LoadingResult loadAllWithState(ResourceManager resourceManager) { - // TODO: move these to the very beginning of resource reload BiomeHolderManager.clearCache(); - LoadingResult result = loadAll(resourceManager); - - // TODO: move these to the very end of resource reload BiomeHolderManager.refreshHolders(); - return result; } @@ -55,6 +57,41 @@ public static LoadingResult loadAll(ResourceManager resourceManager) { return new CtmPropertiesLoader(resourceManager).loadAll(); } + // Load valid CTM paths for each MTS resource pack (parsed from pack.mcmeta) + private void loadMtsValidCtmPaths() { + for (ResourcePack pack : resourceManager.streamResourcePacks().toList()) { + try { + ResourcePackMetadata metadata = pack.getMetadata(); + if (metadata != null && metadata.getRaw().has(MTS_PACK_METADATA_KEY)) { + JsonObject mtsMeta = metadata.getRaw().getAsJsonObject(MTS_PACK_METADATA_KEY); + if (mtsMeta.has(MTS_VALID_CTM_KEY)) { + Set validCtmPaths = new ObjectOpenHashSet<>(); + mtsMeta.getAsJsonArray(MTS_VALID_CTM_KEY).forEach(jsonElem -> { + String path = jsonElem.getAsString(); + validCtmPaths.add(path); + }); + // Store valid paths by resource pack name (prevent cross-pack contamination) + mtsPackValidCtmPaths.put(pack.getName(), validCtmPaths); + } + } + } catch (Exception e) { + ContinuityClient.LOGGER.warn("Failed to load MTS valid CTM paths for pack: {}", pack.getName(), e); + } + } + } + + // Core validation: Check if CTM resource is a valid MTS path (newly added) + private boolean isMtsCtmValid(ResourcePack pack, Identifier resourceId) { + // Allow non-MTS resource packs without validation + if (!mtsPackValidCtmPaths.containsKey(pack.getName())) { + return true; + } + // MTS resource packs require path validation against allowed list + Set validPaths = mtsPackValidCtmPaths.get(pack.getName()); + return validPaths.contains(resourceId.getPath()) + || validPaths.contains(resourceId.toString()); + } + private LoadingResult loadAll() { int packPriority = 0; Iterator iterator = resourceManager.streamResourcePacks().iterator(); @@ -68,48 +105,78 @@ private LoadingResult loadAll() { invalidIdentifierState.disable(); containers.sort(Comparator.reverseOrder()); - return new LoadingResult(containers, textureDependencies); } private void loadAll(ResourcePack pack, int packPriority) { for (String namespace : pack.getNamespaces(ResourceType.CLIENT_RESOURCES)) { + // New 1: Only process CTMs in MTS or Continuity namespaces (reduce unnecessary loading) + if (!MTS_NAMESPACE.equals(namespace) && !"continuity".equals(namespace)) { + continue; + } + pack.findResources(ResourceType.CLIENT_RESOURCES, namespace, "optifine/ctm", (resourceId, inputSupplier) -> { - if (resourceId.getPath().endsWith(".properties")) { - try (InputStream stream = inputSupplier.get()) { - Properties properties = new Properties(); - properties.load(stream); - load(properties, resourceId, pack, packPriority); - } catch (Exception e) { - ContinuityClient.LOGGER.error("Failed to load CTM properties from file '" + resourceId + "' in pack '" + pack.getName() + "'", e); + // Original format validation (retained) + if (!resourceId.getPath().endsWith(".properties")) { + return; + } + + // New 2: Validate MTS resource pack path legitimacy + if (!isMtsCtmValid(pack, resourceId)) { + ContinuityClient.LOGGER.debug("Skipping invalid MTS CTM: {} in pack: {}", resourceId, pack.getName()); + return; + } + + try (InputStream stream = inputSupplier.get()) { + // New 3: Check for null input stream (prevent NPE) + if (stream == null) { + ContinuityClient.LOGGER.warn("Null input stream for CTM: {} in pack: {}", resourceId, pack.getName()); + return; } + + Properties properties = new Properties(); + properties.load(stream); + load(properties, resourceId, pack, packPriority); + } catch (Exception e) { + // Enhanced error logging: explicitly label resource pack and path for easier troubleshooting + ContinuityClient.LOGGER.error("Failed to load CTM properties from '{}' in pack '{}'", resourceId, pack.getName(), e); } }); } } + // Original load method (retained, added MTS texture dependency validation) private void load(Properties properties, Identifier resourceId, ResourcePack pack, int packPriority) { String method = properties.getProperty("method", "ctm").trim(); CtmLoader loader = CtmLoaderRegistry.get().getLoader(method); if (loader != null) { load(loader, properties, resourceId, pack, packPriority, method); } else { - ContinuityClient.LOGGER.error("Unknown 'method' value '" + method + "' in file '" + resourceId + "' in pack '" + pack.getName() + "'"); + ContinuityClient.LOGGER.error("Unknown 'method' '{}' in CTM '{}' (pack: {})", method, resourceId, pack.getName()); } } private void load(CtmLoader loader, Properties properties, Identifier resourceId, ResourcePack pack, int packPriority, String method) { T ctmProperties = loader.getPropertiesFactory().createProperties(properties, resourceId, pack, packPriority, resourceManager, method); if (ctmProperties != null) { + // New: Validate that textures dependent on CTM are valid MTS resources + for (var spriteId : ctmProperties.getTextureDependencies()) { + if (!isMtsCtmValid(pack, spriteId.getTextureId())) { + ContinuityClient.LOGGER.warn("CTM '{}' (pack: {}) depends on invalid MTS texture: {}", resourceId, pack.getName(), spriteId.getTextureId()); + return; // Skip loading this CTM if it depends on invalid textures + } + } + LoadingContainer container = new LoadingContainer<>(loader, ctmProperties); containers.add(container); - for (SpriteIdentifier spriteId : ctmProperties.getTextureDependencies()) { - Set atlasTextureDependencies = textureDependencies.computeIfAbsent(spriteId.getAtlasId(), id -> new ObjectOpenHashSet<>()); - atlasTextureDependencies.add(spriteId.getTextureId()); + for (var spriteId : ctmProperties.getTextureDependencies()) { + Set atlasDependencies = textureDependencies.computeIfAbsent(spriteId.getAtlasId(), id -> new ObjectOpenHashSet<>()); + atlasDependencies.add(spriteId.getTextureId()); } } } + // Original inner class (retained, no modifications) private record LoadingContainer(CtmLoader loader, T properties) implements Comparable> { public QuadProcessors.ProcessorHolder toProcessorHolder(Function textureGetter) { QuadProcessor processor = loader.getProcessorFactory().createProcessor(properties, textureGetter); @@ -123,6 +190,7 @@ public int compareTo(@NotNull LoadingContainer o) { } } + // Original result class (retained, no modifications) public static class LoadingResult { private final List> containers; private final Map> textureDependencies; @@ -133,11 +201,11 @@ private LoadingResult(List> containers, Map createProcessorHolders(Function textureGetter) { - List processorHolders = new ObjectArrayList<>(); - for (LoadingContainer container : containers) { - processorHolders.add(container.toProcessorHolder(textureGetter)); + List holders = new ObjectArrayList<>(); + for (var container : containers) { + holders.add(container.toProcessorHolder(textureGetter)); } - return processorHolders; + return holders; } public Map> getTextureDependencies() { @@ -145,3 +213,4 @@ public Map> getTextureDependencies() { } } } +``` diff --git a/src/main/java/me/pepperbell/continuity/client/resource/ResourceRedirectHandler.java b/src/main/java/me/pepperbell/continuity/client/resource/ResourceRedirectHandler.java index a57b995..b7fd534 100644 --- a/src/main/java/me/pepperbell/continuity/client/resource/ResourceRedirectHandler.java +++ b/src/main/java/me/pepperbell/continuity/client/resource/ResourceRedirectHandler.java @@ -1,8 +1,14 @@ + package me.pepperbell.continuity.client.resource; import org.apache.commons.io.FilenameUtils; import org.jetbrains.annotations.Nullable; - +import com.google.gson.Gson; +import com.google.gson.JsonObject; +import net.minecraft.resource.ResourceManager; +import net.minecraft.resource.ResourcePack; +import net.minecraft.resource.metadata.ResourcePackMetadata; +import net.minecraft.util.Identifier; import it.unimi.dsi.fastutil.objects.Object2IntMap; import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; import it.unimi.dsi.fastutil.objects.ObjectArrayList; @@ -10,8 +16,10 @@ import me.pepperbell.continuity.client.mixin.ReloadableResourceManagerImplAccessor; import me.pepperbell.continuity.client.mixinterface.LifecycledResourceManagerImplExtension; import me.pepperbell.continuity.client.util.BooleanState; -import net.minecraft.resource.ResourceManager; -import net.minecraft.util.Identifier; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.Set; +import java.util.HashSet; public class ResourceRedirectHandler { public static final String SPRITE_PATH_START = "continuity_reserved/"; @@ -22,21 +30,30 @@ public class ResourceRedirectHandler { public static final int HEX_LENGTH = 8; public static final int HEX_END = PATH_START_LENGTH + HEX_LENGTH; public static final int MIN_LENGTH = PATH_START_LENGTH + HEX_LENGTH + PATH_END_LENGTH; + // MTS-specific configuration: namespace and valid resource fields in pack.mcmeta + private static final String MTS_NAMESPACE = "mts"; + private static final String MTS_PACK_METADATA_KEY = "mts"; + private static final String MTS_VALID_RESOURCES_KEY = "validResources"; private static final char[] HEX_BUFFER = new char[HEX_LENGTH]; private static final char[] HEX_DIGITS = { - '0', '1', '2', '3', - '4', '5', '6', '7', - '8', '9', 'a', 'b', - 'c', 'd', 'e', 'f' + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; private final ObjectList redirects = new ObjectArrayList<>(); private final Object2IntMap indexMap = new Object2IntOpenHashMap<>(); + private final Set mtsValidPaths; // Set of valid resource paths for MTS resource packs private int nextIndex = 0; { indexMap.defaultReturnValue(-1); + mtsValidPaths = new HashSet<>(); + } + + // Load valid paths for MTS resource packs during initialization (parsed from ResourceManager) + private ResourceRedirectHandler(ResourceManager resourceManager) { + loadMtsValidPaths(resourceManager); } @Nullable @@ -45,12 +62,57 @@ public static ResourceRedirectHandler get(ResourceManager resourceManager) { resourceManager = accessor.getActiveManager(); } if (resourceManager instanceof LifecycledResourceManagerImplExtension extension) { + // If not initialized, create an instance with ResourceManager to load MTS valid paths + if (extension.continuity$getRedirectHandler() == null) { + extension.continuity$setRedirectHandler(new ResourceRedirectHandler(resourceManager)); + } return extension.continuity$getRedirectHandler(); } return null; } + // Load valid resource paths from MTS resource packs (parsed from pack.mcmeta) + private void loadMtsValidPaths(ResourceManager resourceManager) { + for (ResourcePack pack : resourceManager.streamResourcePacks().toList()) { + try { + // 1. Check if the resource pack is MTS (determined by custom field in pack.mcmeta) + ResourcePackMetadata metadata = pack.getMetadata(); + if (metadata != null && metadata.getRaw().has(MTS_PACK_METADATA_KEY)) { + JsonObject mtsMeta = metadata.getRaw().getAsJsonObject(MTS_PACK_METADATA_KEY); + // 2. Parse the "validResources" field (stores resource paths allowed by MTS) + if (mtsMeta.has(MTS_VALID_RESOURCES_KEY)) { + mtsMeta.getAsJsonArray(MTS_VALID_RESOURCES_KEY).forEach(jsonElem -> { + String validPath = jsonElem.getAsString(); + mtsValidPaths.add(validPath); + }); + } + } + } catch (IOException e) { + // Ignore parsing errors for individual packs to avoid affecting overall loading + me.pepperbell.continuity.client.ContinuityClient.LOGGER.warn("Failed to parse MTS metadata for pack: {}", pack.getName(), e); + } + } + } + + // Core validation: Check if the path is a valid MTS resource (newly added) + private boolean isValidMtsResource(String absolutePath) { + // Case 1: Resources not in MTS namespace are allowed (only validate MTS-related resources) + Identifier id = new Identifier(absolutePath); + if (!MTS_NAMESPACE.equals(id.getNamespace())) { + return true; + } + // Case 2: Resources in MTS namespace must be in the valid list + return mtsValidPaths.contains(absolutePath) || mtsValidPaths.contains(id.getPath()); + } + + @Override public String getSourceSpritePath(String absolutePath) { + // New: Validate MTS legitimacy first; do not assign redirect index to invalid resources + if (!isValidMtsResource(absolutePath)) { + me.pepperbell.continuity.client.ContinuityClient.LOGGER.debug("Skipping invalid MTS resource: {}", absolutePath); + return absolutePath; // Return original path without redirecting + } + int index = indexMap.getInt(absolutePath); if (index == -1) { RedirectInfo info = RedirectInfo.of(absolutePath); @@ -61,12 +123,24 @@ public String getSourceSpritePath(String absolutePath) { return SPRITE_PATH_START + toHex(index); } + @Override public Identifier redirect(Identifier id) { + // New 1: Only process resources in MTS or Continuity namespaces (avoid mishandling unrelated resources) + if (!MTS_NAMESPACE.equals(id.getNamespace()) && !"continuity".equals(id.getNamespace())) { + return id; + } + String path = id.getPath(); - if (!path.startsWith(PATH_START) || !path.endsWith(PATH_END)) { + // New 2: Validate MTS legitimacy + if (!isValidMtsResource(id.toString())) { + me.pepperbell.continuity.client.ContinuityClient.LOGGER.debug("Skipping redirect for invalid MTS resource: {}", id); return id; } + // Original path format validation (retained) + if (!path.startsWith(PATH_START) || !path.endsWith(PATH_END)) { + return id; + } int length = path.length(); if (length < MIN_LENGTH) { return id; @@ -86,6 +160,12 @@ public Identifier redirect(Identifier id) { newPath = info.createPath(suffix); } + // New 3: Validate the legitimacy of the redirected path (avoid generating invalid paths) + if (!isValidMtsResource(new Identifier(id.getNamespace(), newPath).toString())) { + me.pepperbell.continuity.client.ContinuityClient.LOGGER.warn("Redirected path is invalid for MTS: {}", newPath); + return id; + } + BooleanState invalidIdentifierState = InvalidIdentifierStateHolder.get(); invalidIdentifierState.enable(); Identifier newId = id.withPath(newPath); @@ -94,6 +174,7 @@ public Identifier redirect(Identifier id) { return newId; } + // Original helper methods (retained, no modifications) public static int parseHex(String string, int startIndex) { int i = 0; int charPos = startIndex; @@ -121,6 +202,7 @@ public static String toHex(int i) { return new String(HEX_BUFFER); } + // Original inner class (retained, no modifications) private static abstract class RedirectInfo { public final String defaultPath; @@ -152,3 +234,4 @@ public String createPath(String suffix) { } } } +```