mirror of
				https://github.com/SquidDev-CC/CC-Tweaked
				synced 2025-10-29 21:02:59 +00:00 
			
		
		
		
	Merge pull request #1684 from cc-tweaked/hotfix/turtle-modellers-redo
Rewrite turtle upgrade modeller registration API
This commit is contained in:
		| @@ -27,8 +27,13 @@ public final class ComputerCraftAPIClient { | ||||
|      * @param serialiser The turtle upgrade serialiser. | ||||
|      * @param modeller   The upgrade modeller. | ||||
|      * @param <T>        The type of the turtle upgrade. | ||||
|      * @deprecated This method can lead to confusing load behaviour on Forge. Use | ||||
|      * {@code dan200.computercraft.api.client.FabricComputerCraftAPIClient#registerTurtleUpgradeModeller} on Fabric, or | ||||
|      * {@code dan200.computercraft.api.client.turtle.RegisterTurtleModellersEvent} on Forge. | ||||
|      */ | ||||
|     @Deprecated(forRemoval = true) | ||||
|     public static <T extends ITurtleUpgrade> void registerTurtleUpgradeModeller(TurtleUpgradeSerialiser<T> serialiser, TurtleUpgradeModeller<T> modeller) { | ||||
|         // TODO(1.20.4): Remove this | ||||
|         getInstance().registerTurtleUpgradeModeller(serialiser, modeller); | ||||
|     } | ||||
| 
 | ||||
|   | ||||
| @@ -0,0 +1,26 @@ | ||||
| // SPDX-FileCopyrightText: 2023 The CC: Tweaked Developers | ||||
| // | ||||
| // SPDX-License-Identifier: MPL-2.0 | ||||
| 
 | ||||
| package dan200.computercraft.api.client.turtle; | ||||
| 
 | ||||
| import dan200.computercraft.api.turtle.ITurtleUpgrade; | ||||
| import dan200.computercraft.api.turtle.TurtleUpgradeSerialiser; | ||||
| 
 | ||||
| /** | ||||
|  * A functional interface to register a {@link TurtleUpgradeModeller} for a class of turtle upgrades. | ||||
|  * <p> | ||||
|  * This interface is largely intended to be used from multi-loader code, to allow sharing registration code between | ||||
|  * multiple loaders. | ||||
|  */ | ||||
| @FunctionalInterface | ||||
| public interface RegisterTurtleUpgradeModeller { | ||||
|     /** | ||||
|      * Register a {@link TurtleUpgradeModeller}. | ||||
|      * | ||||
|      * @param serialiser The turtle upgrade serialiser. | ||||
|      * @param modeller   The upgrade modeller. | ||||
|      * @param <T>        The type of the turtle upgrade. | ||||
|      */ | ||||
|     <T extends ITurtleUpgrade> void register(TurtleUpgradeSerialiser<T> serialiser, TurtleUpgradeModeller<T> modeller); | ||||
| } | ||||
| @@ -4,12 +4,10 @@ | ||||
| 
 | ||||
| package dan200.computercraft.api.client.turtle; | ||||
| 
 | ||||
| import dan200.computercraft.api.client.ComputerCraftAPIClient; | ||||
| import dan200.computercraft.api.client.TransformedModel; | ||||
| import dan200.computercraft.api.turtle.ITurtleAccess; | ||||
| import dan200.computercraft.api.turtle.ITurtleUpgrade; | ||||
| import dan200.computercraft.api.turtle.TurtleSide; | ||||
| import dan200.computercraft.api.turtle.TurtleUpgradeSerialiser; | ||||
| import net.minecraft.client.resources.model.ModelResourceLocation; | ||||
| import net.minecraft.client.resources.model.UnbakedModel; | ||||
| import net.minecraft.nbt.CompoundTag; | ||||
| @@ -21,9 +19,13 @@ import java.util.List; | ||||
| 
 | ||||
| /** | ||||
|  * Provides models for a {@link ITurtleUpgrade}. | ||||
|  * <p> | ||||
|  * Use {@code dan200.computercraft.api.client.FabricComputerCraftAPIClient#registerTurtleUpgradeModeller} to register a | ||||
|  * modeller on Fabric and {@code dan200.computercraft.api.client.turtle.RegisterTurtleModellersEvent} to register one | ||||
|  * on Forge | ||||
|  * | ||||
|  * @param <T> The type of turtle upgrade this modeller applies to. | ||||
|  * @see ComputerCraftAPIClient#registerTurtleUpgradeModeller(TurtleUpgradeSerialiser, TurtleUpgradeModeller) To register a modeller. | ||||
|  * @see RegisterTurtleUpgradeModeller For multi-loader registration support. | ||||
|  */ | ||||
| public interface TurtleUpgradeModeller<T extends ITurtleUpgrade> { | ||||
|     /** | ||||
|   | ||||
| @@ -48,13 +48,8 @@ import java.util.function.Function; | ||||
|  * } | ||||
|  * }</pre> | ||||
|  * <p> | ||||
|  * Finally, we need to register a model for our upgrade. This is done with | ||||
|  * {@link dan200.computercraft.api.client.ComputerCraftAPIClient#registerTurtleUpgradeModeller}: | ||||
|  * | ||||
|  * <pre>{@code | ||||
|  * // Register our model inside FMLClientSetupEvent | ||||
|  * ComputerCraftAPIClient.registerTurtleUpgradeModeller(MY_UPGRADE.get(), TurtleUpgradeModeller.flatItem()) | ||||
|  * }</pre> | ||||
|  * Finally, we need to register a model for our upgrade. The way to do this varies on mod loader, see | ||||
|  * {@link dan200.computercraft.api.client.turtle.TurtleUpgradeModeller} for more information. | ||||
|  * <p> | ||||
|  * {@link TurtleUpgradeDataProvider} provides a data provider to aid with generating these JSON files. | ||||
|  * | ||||
|   | ||||
| @@ -5,8 +5,8 @@ | ||||
| package dan200.computercraft.client; | ||||
| 
 | ||||
| import dan200.computercraft.api.ComputerCraftAPI; | ||||
| import dan200.computercraft.api.client.ComputerCraftAPIClient; | ||||
| import dan200.computercraft.api.client.turtle.TurtleUpgradeModeller; | ||||
| import dan200.computercraft.api.client.turtle.RegisterTurtleUpgradeModeller; | ||||
| import dan200.computercraft.client.gui.*; | ||||
| import dan200.computercraft.client.pocket.ClientPocketComputers; | ||||
| import dan200.computercraft.client.render.RenderTypes; | ||||
| @@ -60,18 +60,6 @@ public final class ClientRegistry { | ||||
|      * Register any client-side objects which don't have to be done on the main thread. | ||||
|      */ | ||||
|     public static void register() { | ||||
|         ComputerCraftAPIClient.registerTurtleUpgradeModeller(ModRegistry.TurtleSerialisers.SPEAKER.get(), TurtleUpgradeModeller.sided( | ||||
|             new ResourceLocation(ComputerCraftAPI.MOD_ID, "block/turtle_speaker_left"), | ||||
|             new ResourceLocation(ComputerCraftAPI.MOD_ID, "block/turtle_speaker_right") | ||||
|         )); | ||||
|         ComputerCraftAPIClient.registerTurtleUpgradeModeller(ModRegistry.TurtleSerialisers.WORKBENCH.get(), TurtleUpgradeModeller.sided( | ||||
|             new ResourceLocation(ComputerCraftAPI.MOD_ID, "block/turtle_crafting_table_left"), | ||||
|             new ResourceLocation(ComputerCraftAPI.MOD_ID, "block/turtle_crafting_table_right") | ||||
|         )); | ||||
|         ComputerCraftAPIClient.registerTurtleUpgradeModeller(ModRegistry.TurtleSerialisers.WIRELESS_MODEM_NORMAL.get(), new TurtleModemModeller(false)); | ||||
|         ComputerCraftAPIClient.registerTurtleUpgradeModeller(ModRegistry.TurtleSerialisers.WIRELESS_MODEM_ADVANCED.get(), new TurtleModemModeller(true)); | ||||
|         ComputerCraftAPIClient.registerTurtleUpgradeModeller(ModRegistry.TurtleSerialisers.TOOL.get(), TurtleUpgradeModeller.flatItem()); | ||||
| 
 | ||||
|         BlockEntityRenderers.register(ModRegistry.BlockEntities.MONITOR_NORMAL.get(), MonitorBlockEntityRenderer::new); | ||||
|         BlockEntityRenderers.register(ModRegistry.BlockEntities.MONITOR_ADVANCED.get(), MonitorBlockEntityRenderer::new); | ||||
|         BlockEntityRenderers.register(ModRegistry.BlockEntities.TURTLE_NORMAL.get(), TurtleBlockEntityRenderer::new); | ||||
| @@ -103,6 +91,20 @@ public final class ClientRegistry { | ||||
|         ); | ||||
|     } | ||||
| 
 | ||||
|     public static void registerTurtleModellers(RegisterTurtleUpgradeModeller register) { | ||||
|         register.register(ModRegistry.TurtleSerialisers.SPEAKER.get(), TurtleUpgradeModeller.sided( | ||||
|             new ResourceLocation(ComputerCraftAPI.MOD_ID, "block/turtle_speaker_left"), | ||||
|             new ResourceLocation(ComputerCraftAPI.MOD_ID, "block/turtle_speaker_right") | ||||
|         )); | ||||
|         register.register(ModRegistry.TurtleSerialisers.WORKBENCH.get(), TurtleUpgradeModeller.sided( | ||||
|             new ResourceLocation(ComputerCraftAPI.MOD_ID, "block/turtle_crafting_table_left"), | ||||
|             new ResourceLocation(ComputerCraftAPI.MOD_ID, "block/turtle_crafting_table_right") | ||||
|         )); | ||||
|         register.register(ModRegistry.TurtleSerialisers.WIRELESS_MODEM_NORMAL.get(), new TurtleModemModeller(false)); | ||||
|         register.register(ModRegistry.TurtleSerialisers.WIRELESS_MODEM_ADVANCED.get(), new TurtleModemModeller(true)); | ||||
|         register.register(ModRegistry.TurtleSerialisers.TOOL.get(), TurtleUpgradeModeller.flatItem()); | ||||
|     } | ||||
| 
 | ||||
|     @SafeVarargs | ||||
|     private static void registerItemProperty(String name, ClampedItemPropertyFunction getter, Supplier<? extends Item>... items) { | ||||
|         var id = new ResourceLocation(ComputerCraftAPI.MOD_ID, name); | ||||
|   | ||||
| @@ -11,11 +11,14 @@ import dan200.computercraft.api.turtle.ITurtleAccess; | ||||
| import dan200.computercraft.api.turtle.ITurtleUpgrade; | ||||
| import dan200.computercraft.api.turtle.TurtleSide; | ||||
| import dan200.computercraft.api.turtle.TurtleUpgradeSerialiser; | ||||
| import dan200.computercraft.impl.PlatformHelper; | ||||
| import dan200.computercraft.impl.TurtleUpgrades; | ||||
| import dan200.computercraft.impl.UpgradeManager; | ||||
| import net.minecraft.client.Minecraft; | ||||
| import net.minecraft.nbt.CompoundTag; | ||||
| import net.minecraft.resources.ResourceLocation; | ||||
| import org.slf4j.Logger; | ||||
| import org.slf4j.LoggerFactory; | ||||
| 
 | ||||
| import java.util.Map; | ||||
| import java.util.WeakHashMap; | ||||
| @@ -24,14 +27,15 @@ import java.util.stream.Stream; | ||||
| 
 | ||||
| /** | ||||
|  * A registry of {@link TurtleUpgradeModeller}s. | ||||
|  * | ||||
|  * @see dan200.computercraft.api.client.ComputerCraftAPIClient#registerTurtleUpgradeModeller(TurtleUpgradeSerialiser, TurtleUpgradeModeller) | ||||
|  */ | ||||
| public final class TurtleUpgradeModellers { | ||||
|     private static final Logger LOG = LoggerFactory.getLogger(TurtleUpgradeModellers.class); | ||||
| 
 | ||||
|     private static final TurtleUpgradeModeller<ITurtleUpgrade> NULL_TURTLE_MODELLER = (upgrade, turtle, side) -> | ||||
|         new TransformedModel(Minecraft.getInstance().getModelManager().getMissingModel(), Transformation.identity()); | ||||
| 
 | ||||
|     private static final Map<TurtleUpgradeSerialiser<?>, TurtleUpgradeModeller<?>> turtleModels = new ConcurrentHashMap<>(); | ||||
|     private static volatile boolean fetchedModels; | ||||
| 
 | ||||
|     /** | ||||
|      * In order to avoid a double lookup of {@link ITurtleUpgrade} to {@link UpgradeManager.UpgradeWrapper} to | ||||
| @@ -45,12 +49,18 @@ public final class TurtleUpgradeModellers { | ||||
|     } | ||||
| 
 | ||||
|     public static <T extends ITurtleUpgrade> void register(TurtleUpgradeSerialiser<T> serialiser, TurtleUpgradeModeller<T> modeller) { | ||||
|         synchronized (turtleModels) { | ||||
|             if (turtleModels.containsKey(serialiser)) { | ||||
|                 throw new IllegalStateException("Modeller already registered for serialiser"); | ||||
|             } | ||||
|         if (fetchedModels) { | ||||
|             // TODO(1.20.4): Replace with an error. | ||||
|             LOG.warn( | ||||
|                 "Turtle upgrade serialiser {} was registered too late, its models may not be loaded correctly. If you are " + | ||||
|                     "the mod author, you may be using a deprecated API - see https://github.com/cc-tweaked/CC-Tweaked/pull/1684 " + | ||||
|                     "for further information.", | ||||
|                 PlatformHelper.get().getRegistryKey(TurtleUpgradeSerialiser.registryId(), serialiser) | ||||
|             ); | ||||
|         } | ||||
| 
 | ||||
|             turtleModels.put(serialiser, modeller); | ||||
|         if (turtleModels.putIfAbsent(serialiser, modeller) != null) { | ||||
|             throw new IllegalStateException("Modeller already registered for serialiser"); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| @@ -75,6 +85,7 @@ public final class TurtleUpgradeModellers { | ||||
|     } | ||||
| 
 | ||||
|     public static Stream<ResourceLocation> getDependencies() { | ||||
|         fetchedModels = true; | ||||
|         return turtleModels.values().stream().flatMap(x -> x.getDependencies().stream()); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -0,0 +1,42 @@ | ||||
| // SPDX-FileCopyrightText: 2022 The CC: Tweaked Developers | ||||
| // | ||||
| // SPDX-License-Identifier: MPL-2.0 | ||||
| 
 | ||||
| package dan200.computercraft.api.client; | ||||
| 
 | ||||
| import dan200.computercraft.api.client.turtle.TurtleUpgradeModeller; | ||||
| import dan200.computercraft.api.turtle.ITurtleUpgrade; | ||||
| import dan200.computercraft.api.turtle.TurtleUpgradeSerialiser; | ||||
| import dan200.computercraft.impl.client.ComputerCraftAPIClientService; | ||||
| 
 | ||||
| /** | ||||
|  * The Fabric-specific entrypoint for ComputerCraft's API. | ||||
|  * | ||||
|  * @see dan200.computercraft.api.ComputerCraftAPI The main API | ||||
|  * @see dan200.computercraft.api.client.ComputerCraftAPIClient The main client-side API | ||||
|  */ | ||||
| public final class FabricComputerCraftAPIClient { | ||||
|     private FabricComputerCraftAPIClient() { | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Register a {@link TurtleUpgradeModeller} for a class of turtle upgrades. | ||||
|      * <p> | ||||
|      * This may be called at any point after registry creation, though it is recommended to call it within your client | ||||
|      * setup step. | ||||
|      * <p> | ||||
|      * This method may be used as a {@link dan200.computercraft.api.client.turtle.RegisterTurtleUpgradeModeller}, for | ||||
|      * convenient use in multi-loader code. | ||||
|      * | ||||
|      * @param serialiser The turtle upgrade serialiser. | ||||
|      * @param modeller   The upgrade modeller. | ||||
|      * @param <T>        The type of the turtle upgrade. | ||||
|      */ | ||||
|     public static <T extends ITurtleUpgrade> void registerTurtleUpgradeModeller(TurtleUpgradeSerialiser<T> serialiser, TurtleUpgradeModeller<T> modeller) { | ||||
|         getInstance().registerTurtleUpgradeModeller(serialiser, modeller); | ||||
|     } | ||||
| 
 | ||||
|     private static ComputerCraftAPIClientService getInstance() { | ||||
|         return ComputerCraftAPIClientService.get(); | ||||
|     } | ||||
| } | ||||
| @@ -5,6 +5,7 @@ | ||||
| package dan200.computercraft.client; | ||||
| 
 | ||||
| import dan200.computercraft.api.ComputerCraftAPI; | ||||
| import dan200.computercraft.api.client.FabricComputerCraftAPIClient; | ||||
| import dan200.computercraft.client.model.CustomModelLoader; | ||||
| import dan200.computercraft.impl.Services; | ||||
| import dan200.computercraft.shared.ModRegistry; | ||||
| @@ -40,6 +41,7 @@ public class ComputerCraftClient { | ||||
|         } | ||||
| 
 | ||||
|         ClientRegistry.register(); | ||||
|         ClientRegistry.registerTurtleModellers(FabricComputerCraftAPIClient::registerTurtleUpgradeModeller); | ||||
|         ClientRegistry.registerItemColours(ColorProviderRegistry.ITEM::register); | ||||
|         ClientRegistry.registerMainThread(); | ||||
| 
 | ||||
|   | ||||
| @@ -0,0 +1,32 @@ | ||||
| // SPDX-FileCopyrightText: 2023 The CC: Tweaked Developers | ||||
| // | ||||
| // SPDX-License-Identifier: MPL-2.0 | ||||
| 
 | ||||
| package dan200.computercraft.api.client.turtle; | ||||
| 
 | ||||
| import dan200.computercraft.api.turtle.ITurtleUpgrade; | ||||
| import dan200.computercraft.api.turtle.TurtleUpgradeSerialiser; | ||||
| import dan200.computercraft.api.turtle.TurtleUpgradeType; | ||||
| import dan200.computercraft.impl.client.ComputerCraftAPIClientService; | ||||
| import net.minecraftforge.eventbus.api.Event; | ||||
| import net.minecraftforge.fml.event.IModBusEvent; | ||||
| import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; | ||||
| import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent; | ||||
| 
 | ||||
| /** | ||||
|  * This event is fired to register {@link TurtleUpgradeModeller}s for a mod's {@linkplain TurtleUpgradeType turtle | ||||
|  * upgrades}. | ||||
|  * <p> | ||||
|  * This event is fired during the initial resource load. Registries will be frozen, but mods may not be fully | ||||
|  * initialised at this point (i.e. {@link FMLCommonSetupEvent} or {@link FMLClientSetupEvent} may not have been | ||||
|  * dispatched). Subscribers should be careful not to | ||||
|  */ | ||||
| public class RegisterTurtleModellersEvent extends Event implements IModBusEvent, RegisterTurtleUpgradeModeller { | ||||
|     /** | ||||
|      * {@inheritDoc} | ||||
|      */ | ||||
|     @Override | ||||
|     public <T extends ITurtleUpgrade> void register(TurtleUpgradeSerialiser<T> serialiser, TurtleUpgradeModeller<T> modeller) { | ||||
|         ComputerCraftAPIClientService.get().registerTurtleUpgradeModeller(serialiser, modeller); | ||||
|     } | ||||
| } | ||||
| @@ -5,6 +5,7 @@ | ||||
| package dan200.computercraft.client; | ||||
| 
 | ||||
| import dan200.computercraft.api.ComputerCraftAPI; | ||||
| import dan200.computercraft.api.client.turtle.RegisterTurtleModellersEvent; | ||||
| import dan200.computercraft.client.model.turtle.TurtleModelLoader; | ||||
| import net.minecraft.client.Minecraft; | ||||
| import net.minecraftforge.api.distmarker.Dist; | ||||
| @@ -13,6 +14,7 @@ import net.minecraftforge.client.event.RegisterClientReloadListenersEvent; | ||||
| import net.minecraftforge.client.event.RegisterColorHandlersEvent; | ||||
| import net.minecraftforge.client.event.RegisterShadersEvent; | ||||
| import net.minecraftforge.eventbus.api.SubscribeEvent; | ||||
| import net.minecraftforge.fml.ModLoader; | ||||
| import net.minecraftforge.fml.common.Mod; | ||||
| import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; | ||||
| 
 | ||||
| @@ -23,6 +25,9 @@ import java.io.IOException; | ||||
|  */ | ||||
| @Mod.EventBusSubscriber(modid = ComputerCraftAPI.MOD_ID, value = Dist.CLIENT, bus = Mod.EventBusSubscriber.Bus.MOD) | ||||
| public final class ForgeClientRegistry { | ||||
|     private static final Object lock = new Object(); | ||||
|     private static boolean gatheredModellers = false; | ||||
| 
 | ||||
|     private ForgeClientRegistry() { | ||||
|     } | ||||
| 
 | ||||
| @@ -31,8 +36,26 @@ public final class ForgeClientRegistry { | ||||
|         event.register("turtle", TurtleModelLoader.INSTANCE); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Turtle upgrade modellers must be loaded before we gather additional models. | ||||
|      * <p> | ||||
|      * Unfortunately, due to the nature of parallel mod loading (resource loading and mod setup events are fired in | ||||
|      * parallel), there's no way to guarantee this using existing events. Instead, we piggyback off | ||||
|      * {@link ModelEvent.RegisterAdditional}, registering models the first time the event is fired. | ||||
|      */ | ||||
|     private static void gatherModellers() { | ||||
|         if (gatheredModellers) return; | ||||
|         synchronized (lock) { | ||||
|             if (gatheredModellers) return; | ||||
| 
 | ||||
|             gatheredModellers = true; | ||||
|             ModLoader.get().postEvent(new RegisterTurtleModellersEvent()); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     @SubscribeEvent | ||||
|     public static void registerModels(ModelEvent.RegisterAdditional event) { | ||||
|         gatherModellers(); | ||||
|         ClientRegistry.registerExtraModels(event::register); | ||||
|     } | ||||
| 
 | ||||
| @@ -41,6 +64,11 @@ public final class ForgeClientRegistry { | ||||
|         ClientRegistry.registerShaders(event.getResourceProvider(), event::registerShader); | ||||
|     } | ||||
| 
 | ||||
|     @SubscribeEvent | ||||
|     public static void onTurtleModellers(RegisterTurtleModellersEvent event) { | ||||
|         ClientRegistry.registerTurtleModellers(event); | ||||
|     } | ||||
| 
 | ||||
|     @SubscribeEvent | ||||
|     public static void onItemColours(RegisterColorHandlersEvent.Item event) { | ||||
|         ClientRegistry.registerItemColours(event::register); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Jonathan Coates
					Jonathan Coates