package appeng.client; import appeng.api.parts.CableRenderMode; import appeng.block.crafting.AbstractCraftingUnitBlock; import appeng.block.paint.PaintSplotchesModel; import appeng.block.qnb.QnbFormedModel; import appeng.bootstrap.ModelsReloadCallback; import appeng.bootstrap.components.IClientSetupComponent; import appeng.bootstrap.components.IItemColorRegistrationComponent; import appeng.bootstrap.components.IModelBakeComponent; import appeng.client.gui.implementations.CellWorkbenchScreen; import appeng.client.gui.implementations.ChestScreen; import appeng.client.gui.implementations.CondenserScreen; import appeng.client.gui.implementations.CraftAmountScreen; import appeng.client.gui.implementations.CraftConfirmScreen; import appeng.client.gui.implementations.CraftingCPUScreen; import appeng.client.gui.implementations.CraftingStatusScreen; import appeng.client.gui.implementations.CraftingTermScreen; import appeng.client.gui.implementations.DriveScreen; import appeng.client.gui.implementations.FormationPlaneScreen; import appeng.client.gui.implementations.GrinderScreen; import appeng.client.gui.implementations.IOPortScreen; import appeng.client.gui.implementations.InscriberScreen; import appeng.client.gui.implementations.InterfaceScreen; import appeng.client.gui.implementations.InterfaceTerminalScreen; import appeng.client.gui.implementations.LevelEmitterScreen; import appeng.client.gui.implementations.MEMonitorableScreen; import appeng.client.gui.implementations.MEPortableCellScreen; import appeng.client.gui.implementations.MolecularAssemblerScreen; import appeng.client.gui.implementations.NetworkStatusScreen; import appeng.client.gui.implementations.NetworkToolScreen; import appeng.client.gui.implementations.PatternTermScreen; import appeng.client.gui.implementations.PriorityScreen; import appeng.client.gui.implementations.QNBScreen; import appeng.client.gui.implementations.QuartzKnifeScreen; import appeng.client.gui.implementations.SecurityStationScreen; import appeng.client.gui.implementations.SkyChestScreen; import appeng.client.gui.implementations.SpatialIOPortScreen; import appeng.client.gui.implementations.StorageBusScreen; import appeng.client.gui.implementations.UpgradeableScreen; import appeng.client.gui.implementations.VibrationChamberScreen; import appeng.client.gui.implementations.WirelessScreen; import appeng.client.gui.implementations.WirelessTermScreen; import appeng.client.render.FacadeItemModel; import appeng.client.render.SimpleModelLoader; import appeng.client.render.cablebus.CableBusModelLoader; import appeng.client.render.cablebus.P2PTunnelFrequencyModel; import appeng.client.render.crafting.CraftingCubeModel; import appeng.client.render.effects.ChargedOreFX; import appeng.client.render.effects.CraftingFx; import appeng.client.render.effects.EnergyFx; import appeng.client.render.effects.LightningArcFX; import appeng.client.render.effects.LightningFX; import appeng.client.render.effects.MatterCannonFX; import appeng.client.render.effects.ParticleTypes; import appeng.client.render.effects.VibrantFX; import appeng.client.render.model.BiometricCardModel; import appeng.client.render.model.ColorApplicatorModel; import appeng.client.render.model.DriveModel; import appeng.client.render.model.GlassModel; import appeng.client.render.model.MemoryCardModel; import appeng.client.render.model.SkyCompassModel; import appeng.client.render.spatial.SpatialPylonModel; import appeng.client.render.tesr.InscriberTESR; import appeng.client.render.tesr.SkyChestTESR; import appeng.container.implementations.CellWorkbenchContainer; import appeng.container.implementations.ChestContainer; import appeng.container.implementations.CondenserContainer; import appeng.container.implementations.CraftAmountContainer; import appeng.container.implementations.CraftConfirmContainer; import appeng.container.implementations.CraftingCPUContainer; import appeng.container.implementations.CraftingStatusContainer; import appeng.container.implementations.CraftingTermContainer; import appeng.container.implementations.DriveContainer; import appeng.container.implementations.FormationPlaneContainer; import appeng.container.implementations.GrinderContainer; import appeng.container.implementations.IOPortContainer; import appeng.container.implementations.InscriberContainer; import appeng.container.implementations.InterfaceContainer; import appeng.container.implementations.InterfaceTerminalContainer; import appeng.container.implementations.LevelEmitterContainer; import appeng.container.implementations.MEMonitorableContainer; import appeng.container.implementations.MEPortableCellContainer; import appeng.container.implementations.MolecularAssemblerContainer; import appeng.container.implementations.NetworkStatusContainer; import appeng.container.implementations.NetworkToolContainer; import appeng.container.implementations.PatternTermContainer; import appeng.container.implementations.PriorityContainer; import appeng.container.implementations.QNBContainer; import appeng.container.implementations.QuartzKnifeContainer; import appeng.container.implementations.SecurityStationContainer; import appeng.container.implementations.SkyChestContainer; import appeng.container.implementations.SpatialIOPortContainer; import appeng.container.implementations.StorageBusContainer; import appeng.container.implementations.UpgradeableContainer; import appeng.container.implementations.VibrationChamberContainer; import appeng.container.implementations.WirelessContainer; import appeng.container.implementations.WirelessTermContainer; import appeng.core.Api; import appeng.core.ApiDefinitions; import appeng.core.AppEng; import appeng.core.AppEngBase; import appeng.core.features.registries.PartModels; import appeng.core.sync.network.ClientNetworkHandler; import appeng.core.worlddata.WorldData; import appeng.entity.ChargedQuartzEntity; import appeng.entity.GrowingCrystalEntity; import appeng.entity.SingularityEntity; import appeng.entity.TinyTNTPrimedEntity; import appeng.entity.TinyTNTPrimedRenderer; import appeng.fluids.client.gui.FluidFormationPlaneScreen; import appeng.fluids.client.gui.FluidIOScreen; import appeng.fluids.client.gui.FluidInterfaceScreen; import appeng.fluids.client.gui.FluidLevelEmitterScreen; import appeng.fluids.client.gui.FluidStorageBusScreen; import appeng.fluids.client.gui.FluidTerminalScreen; import appeng.fluids.container.FluidFormationPlaneContainer; import appeng.fluids.container.FluidIOContainer; import appeng.fluids.container.FluidInterfaceContainer; import appeng.fluids.container.FluidLevelEmitterContainer; import appeng.fluids.container.FluidStorageBusContainer; import appeng.fluids.container.FluidTerminalContainer; import appeng.hooks.ClientTickHandler; import appeng.parts.automation.PlaneModel; import appeng.tile.crafting.MolecularAssemblerRenderer; import appeng.util.Platform; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper; import net.fabricmc.fabric.api.client.model.ModelLoadingRegistry; import net.fabricmc.fabric.api.client.particle.v1.ParticleFactoryRegistry; import net.fabricmc.fabric.api.client.rendereregistry.v1.EntityRendererRegistry; import net.fabricmc.fabric.api.client.screenhandler.v1.ScreenRegistry; import net.fabricmc.fabric.api.event.client.ClientSpriteRegistryCallback; import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents; import net.minecraft.client.MinecraftClient; import net.minecraft.client.options.KeyBinding; import net.minecraft.client.render.entity.ItemEntityRenderer; import net.minecraft.client.render.model.BakedModel; import net.minecraft.client.render.model.UnbakedModel; import net.minecraft.client.util.SpriteIdentifier; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.server.MinecraftServer; import net.minecraft.server.integrated.IntegratedServer; import net.minecraft.util.Identifier; import net.minecraft.util.hit.HitResult; import net.minecraft.world.World; import javax.annotation.Nonnull; import java.util.Collection; import java.util.EnumMap; import java.util.List; import java.util.Map; import java.util.Random; import java.util.function.Supplier; import java.util.stream.Collectors; import java.util.stream.Stream; @Environment(EnvType.CLIENT) public final class AppEngClient extends AppEngBase { private final static String KEY_CATEGORY = "key.appliedenergistics2.category"; private final MinecraftClient client; private final ClientNetworkHandler networkHandler; private final ClientTickHandler tickHandler; private final EnumMap bindings; public static AppEngClient instance() { return (AppEngClient) AppEng.instance(); } public AppEngClient() { super(); client = MinecraftClient.getInstance(); networkHandler = new ClientNetworkHandler(); tickHandler = new ClientTickHandler(); ModelsReloadCallback.EVENT.register(this::onModelsReloaded); callDeferredBootstrapComponents(IClientSetupComponent.class, IClientSetupComponent::setup); registerModelProviders(); registerParticleRenderers(); registerEntityRenderers(); registerItemColors(); registerTextures(); registerScreens(); // On the client, we'll register for server startup/shutdown to properly setup WorldData // each time the integrated server starts&stops ServerLifecycleEvents.SERVER_STARTED.register(WorldData::onServerStarting); ServerLifecycleEvents.SERVER_STOPPING.register(server -> WorldData.instance().onServerStopping()); ServerLifecycleEvents.SERVER_STOPPED.register(server -> WorldData.instance().onServerStoppped()); this.bindings = new EnumMap<>(ActionKey.class); for (ActionKey key : ActionKey.values()) { final KeyBinding binding = new KeyBinding(key.getTranslationKey(), key.getDefaultKey(), KEY_CATEGORY); KeyBindingHelper.registerKeyBinding(binding); this.bindings.put(key, binding); } } @Override public MinecraftServer getServer() { IntegratedServer server = client.getServer(); if (server != null) { return server; } throw new IllegalStateException("No server is currently running."); } @Override public Stream getPlayers() { return Stream.empty(); } @Override public void spawnEffect(EffectType effect, World world, double posX, double posY, double posZ, Object extra) { } @Override public boolean shouldAddParticles(Random r) { return false; } @Override public HitResult getRTR() { return client.crosshairTarget; } @Override public void postInit() { } @Override public CableRenderMode getRenderMode() { if (Platform.isServer()) { return super.getRenderMode(); } final MinecraftClient mc = MinecraftClient.getInstance(); final PlayerEntity player = mc.player; return this.renderModeForPlayer(player); } public void triggerUpdates() { if (client.player == null || client.world == null) { return; } final PlayerEntity player = client.player; final int x = (int) player.getX(); final int y = (int) player.getY(); final int z = (int) player.getZ(); final int range = 16 * 16; client.worldRenderer.scheduleBlockRenders(x - range, y - range, z - range, x + range, y + range, z + range); } @Override public void updateRenderMode(PlayerEntity player) { } @Override public boolean isActionKey(@Nonnull ActionKey key, int keyCode, int scanCode) { return this.bindings.get(key).matchesKey(keyCode, scanCode); } protected void registerParticleRenderers() { ParticleFactoryRegistry particles = ParticleFactoryRegistry.getInstance(); particles.register(ParticleTypes.CHARGED_ORE, ChargedOreFX.Factory::new); particles.register(ParticleTypes.CRAFTING, CraftingFx.Factory::new); particles.register(ParticleTypes.ENERGY, EnergyFx.Factory::new); particles.register(ParticleTypes.LIGHTNING_ARC, LightningArcFX.Factory::new); particles.register(ParticleTypes.LIGHTNING, LightningFX.Factory::new); particles.register(ParticleTypes.MATTER_CANNON, MatterCannonFX.Factory::new); particles.register(ParticleTypes.VIBRANT, VibrantFX.Factory::new); } protected void registerEntityRenderers() { EntityRendererRegistry registry = EntityRendererRegistry.INSTANCE; registry.register(TinyTNTPrimedEntity.TYPE, (dispatcher, context) -> new TinyTNTPrimedRenderer(dispatcher)); EntityRendererRegistry.Factory itemEntityFactory = (dispatcher, context) -> new ItemEntityRenderer(dispatcher, context.getItemRenderer()); registry.register(SingularityEntity.TYPE, itemEntityFactory); registry.register(GrowingCrystalEntity.TYPE, itemEntityFactory); registry.register(ChargedQuartzEntity.TYPE, itemEntityFactory); } protected void registerItemColors() { // TODO: Do not use the internal API final ApiDefinitions definitions = Api.INSTANCE.definitions(); definitions.getRegistry().getBootstrapComponents(IItemColorRegistrationComponent.class) .forEachRemaining(IItemColorRegistrationComponent::register); } protected void onModelsReloaded(Map loadedModels) { // TODO: Do not use the internal API final ApiDefinitions definitions = Api.INSTANCE.definitions(); definitions.getRegistry().getBootstrapComponents(IModelBakeComponent.class) .forEachRemaining(c -> c.onModelsReloaded(loadedModels)); } public void registerTextures() { Stream> sprites = Stream.of( SkyChestTESR.SPRITES, InscriberTESR.SPRITES ); // Group every needed sprite by atlas, since every atlas has their own event Map> groupedByAtlas = sprites.flatMap(Collection::stream) .collect(Collectors.groupingBy(SpriteIdentifier::getAtlasId)); // Register to the stitch event for each atlas for (Map.Entry> entry : groupedByAtlas.entrySet()) { ClientSpriteRegistryCallback.event(entry.getKey()) .register((spriteAtlasTexture, registry) -> { for (SpriteIdentifier spriteIdentifier : entry.getValue()) { registry.register(spriteIdentifier.getTextureId()); } }); } } private void registerModelProviders() { ModelLoadingRegistry.INSTANCE.registerAppender((resourceManager, consumer) -> { consumer.accept(MolecularAssemblerRenderer.LIGHTS_MODEL); }); ModelLoadingRegistry.INSTANCE.registerVariantProvider((resourceManager) -> { return (modelIdentifier, modelProviderContext) -> { if (MolecularAssemblerRenderer.LIGHTS_MODEL.equals(modelIdentifier)) { return modelProviderContext.loadModel(new Identifier(modelIdentifier.getNamespace(), modelIdentifier.getPath())); } return null; }; }); ModelLoadingRegistry.INSTANCE.registerResourceProvider(rm -> new CableBusModelLoader((PartModels) Api.INSTANCE.registries().partModels())); addBuiltInModel("block/quartz_glass", GlassModel::new); addBuiltInModel("block/sky_compass", SkyCompassModel::new); addBuiltInModel("item/sky_compass", SkyCompassModel::new); // FIXME FABRIC addBuiltInModel("item/dummy_fluid_item", DummyFluidItemModel::new); addBuiltInModel("item/memory_card", MemoryCardModel::new); addBuiltInModel("item/biometric_card", BiometricCardModel::new); addBuiltInModel("block/drive", DriveModel::new); addBuiltInModel("color_applicator", ColorApplicatorModel::new); // FIXME need to wire this up (this might just not be needed) addBuiltInModel("block/spatial_pylon", SpatialPylonModel::new); addBuiltInModel("block/paint", PaintSplotchesModel::new); addBuiltInModel("block/qnb/qnb_formed", QnbFormedModel::new); addBuiltInModel("part/p2p/p2p_tunnel_frequency", P2PTunnelFrequencyModel::new); addBuiltInModel("item/facade", FacadeItemModel::new); addPlaneModel("part/annihilation_plane", "part/annihilation_plane"); addPlaneModel("part/annihilation_plane_on", "part/annihilation_plane_on"); addPlaneModel("part/identity_annihilation_plane", "part/identity_annihilation_plane"); addPlaneModel("part/identity_annihilation_plane_on", "part/identity_annihilation_plane_on"); addPlaneModel("part/fluid_annihilation_plane", "part/fluid_annihilation_plane"); addPlaneModel("part/fluid_annihilation_plane_on", "part/fluid_annihilation_plane_on"); addPlaneModel("part/fluid_formation_plane", "part/fluid_formation_plane"); addPlaneModel("part/fluid_formation_plane_on", "part/fluid_formation_plane_on"); addPlaneModel("part/formation_plane", "part/formation_plane"); addPlaneModel("part/formation_plane_on", "part/formation_plane_on"); addBuiltInModel("block/crafting/1k_storage_formed", () -> new CraftingCubeModel(AbstractCraftingUnitBlock.CraftingUnitType.STORAGE_1K)); addBuiltInModel("block/crafting/4k_storage_formed", () -> new CraftingCubeModel(AbstractCraftingUnitBlock.CraftingUnitType.STORAGE_4K)); addBuiltInModel("block/crafting/16k_storage_formed", () -> new CraftingCubeModel(AbstractCraftingUnitBlock.CraftingUnitType.STORAGE_16K)); addBuiltInModel("block/crafting/64k_storage_formed", () -> new CraftingCubeModel(AbstractCraftingUnitBlock.CraftingUnitType.STORAGE_64K)); addBuiltInModel("block/crafting/accelerator_formed", () -> new CraftingCubeModel(AbstractCraftingUnitBlock.CraftingUnitType.ACCELERATOR)); addBuiltInModel("block/crafting/monitor_formed", () -> new CraftingCubeModel(AbstractCraftingUnitBlock.CraftingUnitType.MONITOR)); addBuiltInModel("block/crafting/unit_formed", () -> new CraftingCubeModel(AbstractCraftingUnitBlock.CraftingUnitType.UNIT)); // FIXME FABRIC ModelLoaderRegistry.registerLoader(new Identifier(AppEng.MOD_ID, "uvlightmap"), UVLModelLoader.INSTANCE); } private static void addPlaneModel(String planeName, String frontTexture) { Identifier frontTextureId = AppEng.makeId(frontTexture); Identifier sidesTextureId = AppEng.makeId("part/plane_sides"); Identifier backTextureId = AppEng.makeId("part/transition_plane_back"); addBuiltInModel(planeName, () -> new PlaneModel(frontTextureId, sidesTextureId, backTextureId)); } private static void addBuiltInModel(String id, Supplier modelFactory) { ModelLoadingRegistry.INSTANCE.registerResourceProvider( resourceManager -> new SimpleModelLoader<>(AppEng.makeId(id), modelFactory) ); } private void registerScreens() { ScreenRegistry.register(GrinderContainer.TYPE, GrinderScreen::new); ScreenRegistry.register(QNBContainer.TYPE, QNBScreen::new); ScreenRegistry.register(SkyChestContainer.TYPE, SkyChestScreen::new); ScreenRegistry.register(ChestContainer.TYPE, ChestScreen::new); ScreenRegistry.register(WirelessContainer.TYPE, WirelessScreen::new); ScreenRegistry.>register( MEMonitorableContainer.TYPE, MEMonitorableScreen::new); ScreenRegistry.register(MEPortableCellContainer.TYPE, MEPortableCellScreen::new); ScreenRegistry.register(WirelessTermContainer.TYPE, WirelessTermScreen::new); ScreenRegistry.register(NetworkStatusContainer.TYPE, NetworkStatusScreen::new); ScreenRegistry.>register( CraftingCPUContainer.TYPE, CraftingCPUScreen::new); ScreenRegistry.register(NetworkToolContainer.TYPE, NetworkToolScreen::new); ScreenRegistry.register(QuartzKnifeContainer.TYPE, QuartzKnifeScreen::new); ScreenRegistry.register(DriveContainer.TYPE, DriveScreen::new); ScreenRegistry.register(VibrationChamberContainer.TYPE, VibrationChamberScreen::new); ScreenRegistry.register(CondenserContainer.TYPE, CondenserScreen::new); ScreenRegistry.register(InterfaceContainer.TYPE, InterfaceScreen::new); ScreenRegistry.register(FluidInterfaceContainer.TYPE, FluidInterfaceScreen::new); ScreenRegistry.>register( UpgradeableContainer.TYPE, UpgradeableScreen::new); ScreenRegistry.register(FluidIOContainer.TYPE, FluidIOScreen::new); ScreenRegistry.register(IOPortContainer.TYPE, IOPortScreen::new); ScreenRegistry.register(StorageBusContainer.TYPE, StorageBusScreen::new); ScreenRegistry.register(FluidStorageBusContainer.TYPE, FluidStorageBusScreen::new); ScreenRegistry.register(FormationPlaneContainer.TYPE, FormationPlaneScreen::new); ScreenRegistry.register(FluidFormationPlaneContainer.TYPE, FluidFormationPlaneScreen::new); ScreenRegistry.register(PriorityContainer.TYPE, PriorityScreen::new); ScreenRegistry.register(SecurityStationContainer.TYPE, SecurityStationScreen::new); ScreenRegistry.register(CraftingTermContainer.TYPE, CraftingTermScreen::new); ScreenRegistry.register(PatternTermContainer.TYPE, PatternTermScreen::new); ScreenRegistry.register(FluidTerminalContainer.TYPE, FluidTerminalScreen::new); ScreenRegistry.register(LevelEmitterContainer.TYPE, LevelEmitterScreen::new); ScreenRegistry.register(FluidLevelEmitterContainer.TYPE, FluidLevelEmitterScreen::new); ScreenRegistry.register(SpatialIOPortContainer.TYPE, SpatialIOPortScreen::new); ScreenRegistry.register(InscriberContainer.TYPE, InscriberScreen::new); ScreenRegistry.register(CellWorkbenchContainer.TYPE, CellWorkbenchScreen::new); ScreenRegistry.register(MolecularAssemblerContainer.TYPE, MolecularAssemblerScreen::new); ScreenRegistry.register(CraftAmountContainer.TYPE, CraftAmountScreen::new); ScreenRegistry.register(CraftConfirmContainer.TYPE, CraftConfirmScreen::new); ScreenRegistry.register(InterfaceTerminalContainer.TYPE, InterfaceTerminalScreen::new); ScreenRegistry.register(CraftingStatusContainer.TYPE, CraftingStatusScreen::new); } }