async-pack-scan/src/client/java/io/gitlab/jfronny/aps/client/mixin/ResourcePackOrganizerMixin....

116 lines
4.0 KiB
Java

package io.gitlab.jfronny.aps.client.mixin;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import io.gitlab.jfronny.aps.client.impl.ResourcePackOrganizerLockState;
import io.gitlab.jfronny.libjf.LibJf;
import net.fabricmc.fabric.impl.resource.loader.FabricResourcePackProfile;
import net.minecraft.client.gui.screen.pack.ResourcePackOrganizer;
import net.minecraft.resource.ResourcePackManager;
import net.minecraft.resource.ResourcePackProfile;
import org.spongepowered.asm.mixin.*;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.stream.Stream;
@Mixin(ResourcePackOrganizer.class)
public abstract class ResourcePackOrganizerMixin {
@Shadow @Final private ResourcePackManager resourcePackManager;
@Shadow @Final List<ResourcePackProfile> enabledPacks;
@Shadow @Final List<ResourcePackProfile> disabledPacks;
@Unique private Future<Void> aps$packScan = null;
@Unique private final ResourcePackOrganizerLockState aps$lock = new ResourcePackOrganizerLockState();
/**
* @author JFronny
* @reason Make reloading asynchronous
*/
@Overwrite
public void refresh() {
if (aps$lock.requestScan().shouldStart()) aps$startScan();
}
@Unique
private void aps$startScan() {
Future<Void>[] tasks = new Future[1];
aps$packScan = tasks[0] = resourcePackManager.scanPacksAsync(() -> aps$afterScan(tasks[0]));
}
@Unique
private void aps$afterScan(Future<Void> task) {
try (var lock = aps$lock.lockResources()) {
if (task.isCancelled()) return;
enabledPacks.retainAll(resourcePackManager.getProfiles());
disabledPacks.clear();
disabledPacks.addAll(resourcePackManager.getProfiles());
disabledPacks.removeAll(enabledPacks);
filterFabricPacks(enabledPacks);
filterFabricPacks(disabledPacks);
if (aps$packScan == task) aps$packScan = null;
}
if (aps$lock.emitScanFinished().shouldContinue()) aps$startScan();
}
@Unique
private void filterFabricPacks(List<ResourcePackProfile> list) {
list.removeIf(profile -> profile instanceof FabricResourcePackProfile prpp && prpp.fabric_isHidden());
}
/**
* @author JFronny
* @reason Inject lock and resynchronize from pack scan
*/
@Overwrite
public void refreshEnabledProfiles() {
try {
if (aps$packScan != null) {
aps$packScan.get();
}
try (var lock = aps$lock.lockResources()) {
// Vanilla statement, copied into here
this.resourcePackManager.setEnabledProfiles(
Lists.reverse(this.enabledPacks)
.stream()
.map(ResourcePackProfile::getId)
.collect(ImmutableList.toImmutableList())
);
}
} catch (InterruptedException | ExecutionException e) {
LibJf.LOGGER.error("Pack scan was interrupted", e);
}
}
/**
* @author JFronny
* @reason Inject lock
*/
@Overwrite
public Stream<ResourcePackOrganizer.Pack> getDisabledPacks() {
try (var lock = aps$lock.lockResources()) {
return this.disabledPacks
.stream()
.<ResourcePackOrganizer.Pack>map(pack -> ((ResourcePackOrganizer) (Object) this).new DisabledPack(pack))
.toList()
.stream();
}
}
/**
* @author JFronny
* @reason Inject lock
*/
@Overwrite
public Stream<ResourcePackOrganizer.Pack> getEnabledPacks() {
try (var lock = aps$lock.lockResources()) {
return this.enabledPacks
.stream()
.<ResourcePackOrganizer.Pack>map(pack -> ((ResourcePackOrganizer) (Object) this).new EnabledPack(pack))
.toList()
.stream();
}
}
}