1
0
mirror of https://github.com/SquidDev-CC/CC-Tweaked synced 2025-08-29 16:47:56 +00:00

Fix: register missing data pack reload listener.

Fixes "ComputerCraft may be installed incorrectly" and "File not found"
errors that sometimes happened after switching single player worlds or
running /reload.
This commit is contained in:
Toad-Dev
2022-01-04 21:25:00 -08:00
parent 1102ad6452
commit 3b4fcaa355
3 changed files with 39 additions and 45 deletions

View File

@@ -33,6 +33,7 @@ import me.shedaniel.cloth.api.utils.v1.GameInstanceUtils;
import net.fabricmc.loader.api.FabricLoader;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.resource.ReloadableResourceManager;
import net.minecraft.resource.ResourceManager;
import net.minecraft.server.MinecraftServer;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.BlockPos;
@@ -116,7 +117,7 @@ public final class ComputerCraftAPIImpl implements IComputerCraftAPI
MinecraftServer server = GameInstanceUtils.getServer();
if( server != null )
{
ReloadableResourceManager manager = (ReloadableResourceManager) ((MinecraftServerAccess) server).getServerResourceManager().getResourceManager();
ResourceManager manager = ((MinecraftServerAccess) server).getServerResourceManager().getResourceManager();
ResourceMount mount = ResourceMount.get( domain, subPath, manager );
return mount.exists( "" ) ? mount : null;
}

View File

@@ -7,16 +7,15 @@ package dan200.computercraft.core.filesystem;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.collect.MapMaker;
import com.google.common.io.ByteStreams;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.api.filesystem.IMount;
import dan200.computercraft.core.apis.handles.ArrayByteChannel;
import dan200.computercraft.shared.util.IoUtil;
import net.minecraft.resource.ReloadableResourceManager;
import net.fabricmc.fabric.api.resource.IdentifiableResourceReloadListener;
import net.fabricmc.fabric.api.resource.SimpleResourceReloadListener;
import net.minecraft.resource.Resource;
import net.minecraft.resource.ResourceManager;
import net.minecraft.resource.ResourceReloadListener;
import net.minecraft.util.Identifier;
import net.minecraft.util.InvalidIdentifierException;
import net.minecraft.util.profiler.Profiler;
@@ -28,7 +27,9 @@ import java.io.IOException;
import java.io.InputStream;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import java.util.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
@@ -59,50 +60,37 @@ public final class ResourceMount implements IMount
.<FileEntry, byte[]>weigher( ( k, v ) -> v.length )
.build();
private static final MapMaker CACHE_TEMPLATE = new MapMaker().weakValues().concurrencyLevel( 1 );
/**
* Maintain a cache of currently loaded resource mounts. This cache is invalidated when currentManager changes.
*/
private static final Map<ReloadableResourceManager, Map<Identifier, ResourceMount>> MOUNT_CACHE = new WeakHashMap<>( 2 );
private static final Map<Identifier, ResourceMount> MOUNT_CACHE = new HashMap<>( 2 );
private final String namespace;
private final String subPath;
private final ReloadableResourceManager manager;
private ResourceManager manager;
@Nullable
private FileEntry root;
public static ResourceMount get( String namespace, String subPath, ReloadableResourceManager manager )
public static ResourceMount get( String namespace, String subPath, ResourceManager manager )
{
Map<Identifier, ResourceMount> cache;
Identifier path = new Identifier( namespace, subPath );
synchronized( MOUNT_CACHE )
{
cache = MOUNT_CACHE.get( manager );
if( cache == null ) MOUNT_CACHE.put( manager, cache = CACHE_TEMPLATE.makeMap() );
}
Identifier path = new Identifier( namespace, subPath );
synchronized( cache )
{
ResourceMount mount = cache.get( path );
if( mount == null ) cache.put( path, mount = new ResourceMount( namespace, subPath, manager ) );
ResourceMount mount = MOUNT_CACHE.get( path );
if( mount == null ) MOUNT_CACHE.put( path, mount = new ResourceMount( namespace, subPath, manager ) );
return mount;
}
}
private ResourceMount( String namespace, String subPath, ReloadableResourceManager manager )
private ResourceMount( String namespace, String subPath, ResourceManager manager )
{
this.namespace = namespace;
this.subPath = subPath;
this.manager = manager;
Listener.INSTANCE.add( manager, this );
if( root == null ) load();
load( manager );
}
private void load()
private void load( ResourceManager manager )
{
boolean hasAny = false;
String existingNamespace = null;
@@ -119,6 +107,7 @@ public final class ResourceMount implements IMount
hasAny = true;
}
this.manager = manager;
root = hasAny ? newRoot : null;
if( !hasAny )
@@ -294,38 +283,37 @@ public final class ResourceMount implements IMount
}
/**
* A {@link ResourceReloadListener} which reloads any associated mounts.
*
* While people should really be keeping a permanent reference to this, some people construct it every
* method call, so let's make this as small as possible.
* An {@link IdentifiableResourceReloadListener} which reloads any associated mounts and correctly updates the resource manager they
* point to.
*/
static class Listener implements ResourceReloadListener
public static final IdentifiableResourceReloadListener RELOAD_LISTENER = new SimpleResourceReloadListener<Void>()
{
private static final Listener INSTANCE = new Listener();
private final Set<ResourceMount> mounts = Collections.newSetFromMap( new WeakHashMap<>() );
private final Set<ReloadableResourceManager> managers = Collections.newSetFromMap( new WeakHashMap<>() );
@Override
public Identifier getFabricId()
{
return new Identifier( ComputerCraft.MOD_ID, "resource_mount_reload_listener" );
}
@Override
public CompletableFuture<Void> reload( Synchronizer synchronizer, ResourceManager manager, Profiler prepareProfiler, Profiler applyProfiler, Executor prepareExecutor, Executor applyExecutor )
public CompletableFuture<Void> load( ResourceManager manager, Profiler profiler, Executor executor )
{
return CompletableFuture.runAsync( () -> {
prepareProfiler.push( "Mount reloading" );
profiler.push( "Reloading ComputerCraft mounts" );
try
{
for( ResourceMount mount : mounts ) mount.load();
for( ResourceMount mount : MOUNT_CACHE.values() ) mount.load( manager );
}
finally
{
prepareProfiler.pop();
profiler.pop();
}
}, prepareExecutor );
}, executor );
}
synchronized void add( ReloadableResourceManager manager, ResourceMount mount )
@Override
public CompletableFuture<Void> apply( Void data, ResourceManager manager, Profiler profiler, Executor executor )
{
if( managers.add( manager ) ) manager.registerListener( this );
mounts.add( mount );
return CompletableFuture.runAsync( () -> { }, executor );
}
}
};
}

View File

@@ -11,6 +11,7 @@ import dan200.computercraft.api.media.IMedia;
import dan200.computercraft.api.peripheral.IPeripheralTile;
import dan200.computercraft.api.turtle.event.TurtleEvent;
import dan200.computercraft.core.computer.MainThread;
import dan200.computercraft.core.filesystem.ResourceMount;
import dan200.computercraft.core.tracking.Tracking;
import dan200.computercraft.shared.TurtlePermissions;
import dan200.computercraft.shared.command.CommandComputerCraft;
@@ -33,11 +34,13 @@ import net.fabricmc.fabric.api.command.v1.CommandRegistrationCallback;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerBlockEntityEvents;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents;
import net.fabricmc.fabric.api.resource.ResourceManagerHelper;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.block.entity.CommandBlockBlockEntity;
import net.minecraft.item.Item;
import net.minecraft.item.MusicDiscItem;
import net.minecraft.loot.condition.LootConditionType;
import net.minecraft.resource.ResourceType;
import net.minecraft.server.MinecraftServer;
import net.minecraft.util.Identifier;
import net.minecraft.util.registry.Registry;
@@ -129,6 +132,8 @@ public final class ComputerCraftProxyCommon
TurtleEvent.EVENT_BUS.register( FurnaceRefuelHandler.INSTANCE );
TurtleEvent.EVENT_BUS.register( new TurtlePermissions() );
TurtleEvent.EVENT_BUS.register( new SignInspectHandler() );
ResourceManagerHelper.get( ResourceType.SERVER_DATA ).registerReloadListener( ResourceMount.RELOAD_LISTENER );
}
public static void registerLoot()