mirror of
				https://github.com/SquidDev-CC/CC-Tweaked
				synced 2025-10-31 05:33:00 +00:00 
			
		
		
		
	Cleanup resource mount reloading
- Subscribe to the "on add reload listener" event, otherwise we don't get reloads beyond the first one! This means we no longer need to cast the resource manager to a reloadable one. - Change the mount cache so it's keyed on path, rather than "path ✕ manager". - Update the reload listener just to use the mount cache, rather than having its own separate list. I really don't understand what I was thinking before.
This commit is contained in:
		| @@ -28,6 +28,7 @@ import dan200.computercraft.shared.peripheral.modem.wireless.WirelessNetwork; | ||||
| import dan200.computercraft.shared.util.IDAssigner; | ||||
| import dan200.computercraft.shared.wired.WiredNode; | ||||
| import net.minecraft.resources.IReloadableResourceManager; | ||||
| import net.minecraft.resources.IResourceManager; | ||||
| import net.minecraft.tileentity.TileEntity; | ||||
| import net.minecraft.util.Direction; | ||||
| import net.minecraft.util.ResourceLocation; | ||||
| @@ -101,7 +102,7 @@ public final class ComputerCraftAPIImpl implements IComputerCraftAPI | ||||
|     @Override | ||||
|     public IMount createResourceMount( @Nonnull String domain, @Nonnull String subPath ) | ||||
|     { | ||||
|         IReloadableResourceManager manager = (IReloadableResourceManager) ServerLifecycleHooks.getCurrentServer().getDataPackRegistries().getResourceManager(); | ||||
|         IResourceManager manager = ServerLifecycleHooks.getCurrentServer().getDataPackRegistries().getResourceManager(); | ||||
|         ResourceMount mount = ResourceMount.get( domain, subPath, manager ); | ||||
|         return mount.exists( "" ) ? mount : null; | ||||
|     } | ||||
|   | ||||
| @@ -7,19 +7,17 @@ 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.resources.IReloadableResourceManager; | ||||
| import net.minecraft.client.resources.ReloadListener; | ||||
| import net.minecraft.profiler.IProfiler; | ||||
| import net.minecraft.resources.IResource; | ||||
| import net.minecraft.resources.IResourceManager; | ||||
| import net.minecraft.util.ResourceLocation; | ||||
| import net.minecraft.util.ResourceLocationException; | ||||
| import net.minecraftforge.resource.IResourceType; | ||||
| import net.minecraftforge.resource.ISelectiveResourceReloadListener; | ||||
| 
 | ||||
| import javax.annotation.Nonnull; | ||||
| import javax.annotation.Nullable; | ||||
| @@ -28,9 +26,10 @@ 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.TimeUnit; | ||||
| import java.util.function.Predicate; | ||||
| 
 | ||||
| public final class ResourceMount implements IMount | ||||
| { | ||||
| @@ -58,50 +57,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<IReloadableResourceManager, Map<ResourceLocation, ResourceMount>> MOUNT_CACHE = new WeakHashMap<>( 2 ); | ||||
|     private static final Map<ResourceLocation, ResourceMount> MOUNT_CACHE = new HashMap<>( 2 ); | ||||
| 
 | ||||
|     private final String namespace; | ||||
|     private final String subPath; | ||||
|     private final IReloadableResourceManager manager; | ||||
|     private IResourceManager manager; | ||||
| 
 | ||||
|     @Nullable | ||||
|     private FileEntry root; | ||||
| 
 | ||||
|     public static ResourceMount get( String namespace, String subPath, IReloadableResourceManager manager ) | ||||
|     public static ResourceMount get( String namespace, String subPath, IResourceManager manager ) | ||||
|     { | ||||
|         Map<ResourceLocation, ResourceMount> cache; | ||||
| 
 | ||||
|         ResourceLocation path = new ResourceLocation( namespace, subPath ); | ||||
|         synchronized( MOUNT_CACHE ) | ||||
|         { | ||||
|             cache = MOUNT_CACHE.get( manager ); | ||||
|             if( cache == null ) MOUNT_CACHE.put( manager, cache = CACHE_TEMPLATE.makeMap() ); | ||||
|         } | ||||
| 
 | ||||
|         ResourceLocation path = new ResourceLocation( 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, IReloadableResourceManager manager ) | ||||
|     private ResourceMount( String namespace, String subPath, IResourceManager 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( IResourceManager manager ) | ||||
|     { | ||||
|         boolean hasAny = false; | ||||
|         String existingNamespace = null; | ||||
| @@ -118,6 +104,7 @@ public final class ResourceMount implements IMount | ||||
|             hasAny = true; | ||||
|         } | ||||
| 
 | ||||
|         this.manager = manager; | ||||
|         root = hasAny ? newRoot : null; | ||||
| 
 | ||||
|         if( !hasAny ) | ||||
| @@ -293,35 +280,30 @@ public final class ResourceMount implements IMount | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * A {@link ISelectiveResourceReloadListener} 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. | ||||
|      * A {@link ReloadListener} which reloads any associated mounts and correctly updates the resource manager they | ||||
|      * point to. | ||||
|      */ | ||||
|     static class Listener implements ISelectiveResourceReloadListener | ||||
|     public static final ReloadListener<Void> RELOAD_LISTENER = new ReloadListener<Void>() | ||||
|     { | ||||
|         private static final Listener INSTANCE = new Listener(); | ||||
| 
 | ||||
|         private final Set<ResourceMount> mounts = Collections.newSetFromMap( new WeakHashMap<>() ); | ||||
|         private final Set<IReloadableResourceManager> managers = Collections.newSetFromMap( new WeakHashMap<>() ); | ||||
| 
 | ||||
|         @Nonnull | ||||
|         @Override | ||||
|         public void onResourceManagerReload( @Nonnull IResourceManager manager ) | ||||
|         protected Void prepare( @Nonnull IResourceManager manager, @Nonnull IProfiler profiler ) | ||||
|         { | ||||
|             // FIXME: Remove this. We need this patch in order to prevent trying to load ReloadRequirements. | ||||
|             onResourceManagerReload( manager, x -> true ); | ||||
|             profiler.push( "Reloading ComputerCraft mounts" ); | ||||
|             try | ||||
|             { | ||||
|                 for( ResourceMount mount : MOUNT_CACHE.values() ) mount.load( manager ); | ||||
|             } | ||||
|             finally | ||||
|             { | ||||
|                 profiler.pop(); | ||||
|             } | ||||
|             return null; | ||||
|         } | ||||
| 
 | ||||
|         @Override | ||||
|         public synchronized void onResourceManagerReload( @Nonnull IResourceManager manager, @Nonnull Predicate<IResourceType> predicate ) | ||||
|         protected void apply( @Nonnull Void result, @Nonnull IResourceManager manager, @Nonnull IProfiler profiler ) | ||||
|         { | ||||
|             for( ResourceMount mount : mounts ) mount.load(); | ||||
|         } | ||||
| 
 | ||||
|         synchronized void add( IReloadableResourceManager manager, ResourceMount mount ) | ||||
|         { | ||||
|             if( managers.add( manager ) ) manager.registerReloadListener( this ); | ||||
|             mounts.add( mount ); | ||||
|         } | ||||
|         } | ||||
|     }; | ||||
| } | ||||
|   | ||||
| @@ -8,6 +8,7 @@ package dan200.computercraft.shared; | ||||
| import dan200.computercraft.ComputerCraft; | ||||
| import dan200.computercraft.core.apis.http.NetworkUtils; | ||||
| import dan200.computercraft.core.computer.MainThread; | ||||
| import dan200.computercraft.core.filesystem.ResourceMount; | ||||
| import dan200.computercraft.core.tracking.ComputerMBean; | ||||
| import dan200.computercraft.core.tracking.Tracking; | ||||
| import dan200.computercraft.shared.command.CommandComputerCraft; | ||||
| @@ -23,6 +24,7 @@ import net.minecraft.loot.TableLootEntry; | ||||
| import net.minecraft.server.MinecraftServer; | ||||
| import net.minecraft.server.dedicated.DedicatedServer; | ||||
| import net.minecraft.util.ResourceLocation; | ||||
| import net.minecraftforge.event.AddReloadListenerEvent; | ||||
| import net.minecraftforge.event.LootTableLoadEvent; | ||||
| import net.minecraftforge.event.RegisterCommandsEvent; | ||||
| import net.minecraftforge.event.TickEvent; | ||||
| @@ -138,4 +140,10 @@ public final class CommonHooks | ||||
|             .name( "computercraft_treasure" ) | ||||
|             .build() ); | ||||
|     } | ||||
| 
 | ||||
|     @SubscribeEvent | ||||
|     public static void onAddReloadListeners( AddReloadListenerEvent event ) | ||||
|     { | ||||
|         event.addListener( ResourceMount.RELOAD_LISTENER ); | ||||
|     } | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Jonathan Coates
					Jonathan Coates