Respackopts/src/main/java/io/gitlab/jfronny/respackopts/mixin/ResourcePackManagerMixin.java

106 lines
5.1 KiB
Java

package io.gitlab.jfronny.respackopts.mixin;
import io.gitlab.jfronny.respackopts.Respackopts;
import io.gitlab.jfronny.respackopts.RespackoptsConfig;
import io.gitlab.jfronny.respackopts.integration.SaveHook;
import io.gitlab.jfronny.respackopts.model.PackMeta;
import io.gitlab.jfronny.respackopts.model.cache.CacheKey;
import io.gitlab.jfronny.respackopts.util.FallbackI18n;
import io.gitlab.jfronny.respackopts.util.MetaCache;
import net.minecraft.resource.*;
import net.minecraft.util.Identifier;
import org.spongepowered.asm.mixin.*;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.io.*;
import java.nio.file.Path;
import java.util.*;
@Mixin(ResourcePackManager.class)
public class ResourcePackManagerMixin {
@Shadow private Map<String, ResourcePackProfile> profiles;
@Unique private final Set<Path> dataLocations = new HashSet<>();
@Inject(at = @At("TAIL"), method = "scanPacks()V")
private void scanPacks(CallbackInfo info) {
FallbackI18n.clear();
Set<Path> newDataLocations = new HashSet<>();
Set<Path> toRemove = new HashSet<>(dataLocations);
profiles.forEach((s, v) -> {
try (ResourcePack rpi = v.createResourcePack()) {
String id = rpo$checkProfile(s, v.getDisplayName().getString(), rpi, newDataLocations, toRemove);
if (id != null) FallbackI18n.loadFrom(rpi, id);
}
});
dataLocations.clear();
dataLocations.addAll(newDataLocations);
for (Path s : toRemove) {
CacheKey k = MetaCache.getKeyByDataLocation(s);
if (k != null) MetaCache.remove(k);
}
MetaCache.save(SaveHook.Arguments.DO_NOTHING);
}
private static String rpo$checkProfile(String profileName, String displayName, ResourcePack rpi, Set<Path> dataLocations, Set<Path> toRemove) {
Path dataLocation = null;
if (rpi instanceof DirectoryResourcePack drp) {
Path pack = ((DirectoryResourcePackAccessor) drp).getRoot();
if (pack != null) dataLocation = pack.getParent().resolve(pack.getFileName() + Respackopts.FILE_EXTENSION);
else Respackopts.LOGGER.warn("Base path of directory resource pack " + rpi.getName() + " is null. This shouldn't happen!");
} else if (rpi instanceof ZipResourcePack zrp) {
File pack = ((ZipResourcePackAccessor) zrp).getBackingZipFile();
if (pack != null) dataLocation = pack.toPath().getParent().resolve(pack.getName() + Respackopts.FILE_EXTENSION);
else Respackopts.LOGGER.warn("Base path of zip resource pack " + rpi.getName() + " is null. This shouldn't happen!");
}
var conf = rpi.openRoot(Respackopts.ID + ".json5");
if (conf != null) {
try (InputStream is = conf.get()) {
return rpo$readConfiguration(is, dataLocation, rpi.getName(), displayName, dataLocations, toRemove);
} catch (Throwable e) {
String message = "Could not read respackopts config in root for " + profileName;
if (RespackoptsConfig.debugLogs) Respackopts.LOGGER.error(message, e);
else Respackopts.LOGGER.error(message);
}
}
Identifier confId = new Identifier(Respackopts.ID, "conf.json");
for (ResourceType type : ResourceType.values()) {
conf = rpi.open(type, confId);
if (conf != null) {
try (InputStream is = conf.get()) {
return rpo$readConfiguration(is, dataLocation, rpi.getName(), displayName, dataLocations, toRemove);
} catch (Throwable e) {
Respackopts.LOGGER.error("Could not initialize pack meta for " + profileName, e);
}
}
}
return null;
}
private static String rpo$readConfiguration(InputStream is, Path dataLocation, String packName, String displayName, Set<Path> dataLocations, Set<Path> toRemove) throws IOException {
try (InputStreamReader isr = new InputStreamReader(is)) {
PackMeta conf = Respackopts.GSON.fromJson(isr, PackMeta.class);
if (!Respackopts.isLegal(conf.id)) {
if (conf.version >= 10) {
Respackopts.LOGGER.error(displayName + " was not loaded as it uses an unsupported pack id: " + conf.id);
return null;
} else conf.id = Respackopts.sanitizeString(conf.id);
}
if (RespackoptsConfig.debugLogs) Respackopts.LOGGER.info("Discovered pack: " + conf.id);
if (Respackopts.META_VERSION < conf.version) {
Respackopts.LOGGER.error(displayName + " was not loaded as it specifies a newer respackopts version than is installed");
return null;
}
if (dataLocation == null) dataLocation = Respackopts.FALLBACK_CONF_DIR.resolve(conf.id + ".json");
MetaCache.addFromScan(displayName, packName, conf, dataLocation);
dataLocations.add(dataLocation);
toRemove.remove(dataLocation);
return conf.id;
}
}
}