1
0
mirror of https://github.com/SquidDev-CC/CC-Tweaked synced 2024-11-13 05:19:59 +00:00

Update to latest Forge

- Lots of refactoring/cleanup to Forge's events and client APIs.
   - Render types/layers for blocks are now set on the model rather than
     in code.

   - Models now can work with multiple render types. As this would
     massively complicate the implementation of the turtle item model, we
     now implement a much simpler version, which makes use of Forge's
     BakedModel.getRenderPasses to return a separate model for the core
     turtle and each upgrade.

 - Send monitor contents to players immediately when they start watching
   the chunk. ChunkWatchEvent.Watch is now fired from a more sensible
   location, so this is much easier to implement!
This commit is contained in:
Jonathan Coates 2022-07-16 19:08:11 +01:00
parent e906f3ebc3
commit 4a273ae8e5
No known key found for this signature in database
GPG Key ID: B9E431FF07C98D06
37 changed files with 204 additions and 393 deletions

View File

@ -109,8 +109,8 @@ minecraft {
} }
} }
// mappings channel: 'parchment', version: "${mapping_version}-${mc_version}" mappings channel: 'parchment', version: "${mapping_version}-${mc_version}"
mappings channel: 'official', version: mc_version // mappings channel: 'official', version: mc_version
accessTransformer file('src/main/resources/META-INF/accesstransformer.cfg') accessTransformer file('src/main/resources/META-INF/accesstransformer.cfg')
accessTransformer file('src/testMod/resources/META-INF/accesstransformer.cfg') accessTransformer file('src/testMod/resources/META-INF/accesstransformer.cfg')
@ -149,9 +149,9 @@ dependencies {
minecraft "net.minecraftforge:forge:${mc_version}-${forge_version}" minecraft "net.minecraftforge:forge:${mc_version}-${forge_version}"
annotationProcessor 'org.spongepowered:mixin:0.8.4:processor' annotationProcessor 'org.spongepowered:mixin:0.8.4:processor'
extraModsCompileOnly fg.deobf("mezz.jei:jei-1.19-forge-api:11.0.0.206") extraModsCompileOnly fg.deobf("mezz.jei:jei-1.19-forge-api:11.0.0.211")
extraModsCompileOnly fg.deobf("mezz.jei:jei-1.19-common-api:11.0.0.206") extraModsCompileOnly fg.deobf("mezz.jei:jei-1.19-common-api:11.0.0.211")
extraModsRuntimeOnly fg.deobf("mezz.jei:jei-1.19-forge:11.0.0.206") extraModsRuntimeOnly fg.deobf("mezz.jei:jei-1.19-forge:11.0.0.211")
shade 'org.squiddev:Cobalt:0.5.5' shade 'org.squiddev:Cobalt:0.5.5'
shade 'io.netty:netty-codec-http:4.1.76.Final' shade 'io.netty:netty-codec-http:4.1.76.Final'

View File

@ -6,6 +6,6 @@ mod_version=1.100.8
# Minecraft properties (update mods.toml when changing) # Minecraft properties (update mods.toml when changing)
mc_version=1.19 mc_version=1.19
mapping_version=2022.03.13 mapping_version=1.18.2-2022.07.03
forge_version=41.0.38 forge_version=41.0.98
# NO SERIOUSLY, UPDATE mods.toml WHEN CHANGING # NO SERIOUSLY, UPDATE mods.toml WHEN CHANGING

View File

@ -7,7 +7,7 @@ package dan200.computercraft.api.pocket;
import dan200.computercraft.api.upgrades.UpgradeDataProvider; import dan200.computercraft.api.upgrades.UpgradeDataProvider;
import net.minecraft.data.DataGenerator; import net.minecraft.data.DataGenerator;
import net.minecraftforge.forge.event.lifecycle.GatherDataEvent; import net.minecraftforge.data.event.GatherDataEvent;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import java.util.function.Consumer; import java.util.function.Consumer;

View File

@ -47,6 +47,7 @@ public interface PocketUpgradeSerialiser<T extends IPocketUpgrade> extends Upgra
/** /**
* The associated registry. * The associated registry.
*
* @return The registry for pocket upgrade serialisers. * @return The registry for pocket upgrade serialisers.
* @see #REGISTRY_ID * @see #REGISTRY_ID
*/ */

View File

@ -14,7 +14,7 @@ import net.minecraft.world.item.ItemStack;
import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn; import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.event.entity.player.AttackEntityEvent; import net.minecraftforge.event.entity.player.AttackEntityEvent;
import net.minecraftforge.event.world.BlockEvent; import net.minecraftforge.event.level.BlockEvent;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;

View File

@ -14,7 +14,7 @@ import net.minecraft.tags.TagKey;
import net.minecraft.world.entity.ai.attributes.Attributes; import net.minecraft.world.entity.ai.attributes.Attributes;
import net.minecraft.world.item.Item; import net.minecraft.world.item.Item;
import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Block;
import net.minecraftforge.forge.event.lifecycle.GatherDataEvent; import net.minecraftforge.data.event.GatherDataEvent;
import net.minecraftforge.registries.ForgeRegistries; import net.minecraftforge.registries.ForgeRegistries;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
@ -140,7 +140,10 @@ public abstract class TurtleUpgradeDataProvider extends UpgradeDataProvider<ITur
add.accept( new Upgrade<>( id, serialiser, s -> { add.accept( new Upgrade<>( id, serialiser, s -> {
s.addProperty( "item", ForgeRegistries.ITEMS.getKey( toolItem ).toString() ); s.addProperty( "item", ForgeRegistries.ITEMS.getKey( toolItem ).toString() );
if( adjective != null ) s.addProperty( "adjective", adjective ); if( adjective != null ) s.addProperty( "adjective", adjective );
if( craftingItem != null ) s.addProperty( "craftItem", ForgeRegistries.ITEMS.getKey( craftingItem ).toString() ); if( craftingItem != null )
{
s.addProperty( "craftItem", ForgeRegistries.ITEMS.getKey( craftingItem ).toString() );
}
if( damageMultiplier != null ) s.addProperty( "damageMultiplier", damageMultiplier ); if( damageMultiplier != null ) s.addProperty( "damageMultiplier", damageMultiplier );
if( breakable != null ) s.addProperty( "breakable", breakable.location().toString() ); if( breakable != null ) s.addProperty( "breakable", breakable.location().toString() );
} ) ); } ) );

View File

@ -67,12 +67,14 @@ public interface TurtleUpgradeSerialiser<T extends ITurtleUpgrade> extends Upgra
* *
* This is largely intended for use with Forge Registry methods/classes, such as {@link DeferredRegister} and * This is largely intended for use with Forge Registry methods/classes, such as {@link DeferredRegister} and
* {@link RegistryManager#getRegistry(ResourceKey)}. * {@link RegistryManager#getRegistry(ResourceKey)}.
*
* @see #registry() * @see #registry()
*/ */
ResourceKey<Registry<TurtleUpgradeSerialiser<?>>> REGISTRY_ID = ResourceKey.createRegistryKey( new ResourceLocation( ComputerCraft.MOD_ID, "turtle_upgrade_serialiser" ) ); ResourceKey<Registry<TurtleUpgradeSerialiser<?>>> REGISTRY_ID = ResourceKey.createRegistryKey( new ResourceLocation( ComputerCraft.MOD_ID, "turtle_upgrade_serialiser" ) );
/** /**
* The associated registry. * The associated registry.
*
* @return The registry for pocket upgrade serialisers. * @return The registry for pocket upgrade serialisers.
* @see #REGISTRY_ID * @see #REGISTRY_ID
*/ */

View File

@ -68,7 +68,7 @@ public interface IUpgradeBase
* @param stack The stack to check. This is guaranteed to be non-empty and have the same item as * @param stack The stack to check. This is guaranteed to be non-empty and have the same item as
* {@link #getCraftingItem()}. * {@link #getCraftingItem()}.
* @return If this stack may be used to equip this upgrade. * @return If this stack may be used to equip this upgrade.
* @see net.minecraftforge.common.crafting.NBTIngredient#test(ItemStack) For the implementation of the default * @see net.minecraftforge.common.crafting.StrictNBTIngredient#test(ItemStack) For the implementation of the default
* check. * check.
*/ */
default boolean isItemSuitable( @Nonnull ItemStack stack ) default boolean isItemSuitable( @Nonnull ItemStack stack )

View File

@ -10,7 +10,7 @@ import dan200.computercraft.client.sound.SpeakerManager;
import dan200.computercraft.shared.peripheral.monitor.ClientMonitor; import dan200.computercraft.shared.peripheral.monitor.ClientMonitor;
import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.client.event.ClientPlayerNetworkEvent; import net.minecraftforge.client.event.ClientPlayerNetworkEvent;
import net.minecraftforge.event.world.WorldEvent; import net.minecraftforge.event.level.LevelEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.Mod;
@ -18,9 +18,9 @@ import net.minecraftforge.fml.common.Mod;
public class ClientHooks public class ClientHooks
{ {
@SubscribeEvent @SubscribeEvent
public static void onWorldUnload( WorldEvent.Unload event ) public static void onWorldUnload( LevelEvent.Unload event )
{ {
if( event.getWorld().isClientSide() ) if( event.getLevel().isClientSide() )
{ {
ClientMonitor.destroyAll(); ClientMonitor.destroyAll();
SpeakerManager.reset(); SpeakerManager.reset();
@ -28,13 +28,13 @@ public class ClientHooks
} }
@SubscribeEvent @SubscribeEvent
public static void onLogIn( ClientPlayerNetworkEvent.LoggedInEvent event ) public static void onLogIn( ClientPlayerNetworkEvent.LoggingIn event )
{ {
ComputerCraft.clientComputerRegistry.reset(); ComputerCraft.clientComputerRegistry.reset();
} }
@SubscribeEvent @SubscribeEvent
public static void onLogOut( ClientPlayerNetworkEvent.LoggedOutEvent event ) public static void onLogOut( ClientPlayerNetworkEvent.LoggingOut event )
{ {
ComputerCraft.clientComputerRegistry.reset(); ComputerCraft.clientComputerRegistry.reset();
} }

View File

@ -19,8 +19,6 @@ import dan200.computercraft.shared.media.items.ItemTreasureDisk;
import dan200.computercraft.shared.pocket.items.ItemPocketComputer; import dan200.computercraft.shared.pocket.items.ItemPocketComputer;
import dan200.computercraft.shared.util.Colour; import dan200.computercraft.shared.util.Colour;
import net.minecraft.client.gui.screens.MenuScreens; import net.minecraft.client.gui.screens.MenuScreens;
import net.minecraft.client.renderer.ItemBlockRenderTypes;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.blockentity.BlockEntityRenderers; import net.minecraft.client.renderer.blockentity.BlockEntityRenderers;
import net.minecraft.client.renderer.item.ItemProperties; import net.minecraft.client.renderer.item.ItemProperties;
import net.minecraft.client.renderer.item.ItemPropertyFunction; import net.minecraft.client.renderer.item.ItemPropertyFunction;
@ -28,10 +26,8 @@ import net.minecraft.client.resources.model.ModelResourceLocation;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.Item; import net.minecraft.world.item.Item;
import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.client.event.ColorHandlerEvent; import net.minecraftforge.client.event.ModelEvent;
import net.minecraftforge.client.event.ModelRegistryEvent; import net.minecraftforge.client.event.RegisterColorHandlersEvent;
import net.minecraftforge.client.model.ForgeModelBakery;
import net.minecraftforge.client.model.ModelLoaderRegistry;
import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent;
@ -69,17 +65,22 @@ public final class ClientRegistry
private ClientRegistry() {} private ClientRegistry() {}
@SubscribeEvent @SubscribeEvent
public static void registerModels( ModelRegistryEvent event ) public static void registerModelLoaders( ModelEvent.RegisterGeometryLoaders event )
{
event.register( "turtle", TurtleModelLoader.INSTANCE );
}
@SubscribeEvent
public static void registerModels( ModelEvent.RegisterAdditional event )
{ {
ModelLoaderRegistry.registerLoader( new ResourceLocation( ComputerCraft.MOD_ID, "turtle" ), TurtleModelLoader.INSTANCE );
for( String model : EXTRA_MODELS ) for( String model : EXTRA_MODELS )
{ {
ForgeModelBakery.addSpecialModel( new ModelResourceLocation( new ResourceLocation( ComputerCraft.MOD_ID, model ), "inventory" ) ); event.register( new ModelResourceLocation( new ResourceLocation( ComputerCraft.MOD_ID, model ), "inventory" ) );
} }
} }
@SubscribeEvent @SubscribeEvent
public static void onItemColours( ColorHandlerEvent.Item event ) public static void onItemColours( RegisterColorHandlersEvent.Item event )
{ {
if( Registry.ModItems.DISK == null || Registry.ModBlocks.TURTLE_NORMAL == null ) if( Registry.ModItems.DISK == null || Registry.ModBlocks.TURTLE_NORMAL == null )
{ {
@ -87,17 +88,17 @@ public final class ClientRegistry
return; return;
} }
event.getItemColors().register( event.register(
( stack, layer ) -> layer == 1 ? ((ItemDisk) stack.getItem()).getColour( stack ) : 0xFFFFFF, ( stack, layer ) -> layer == 1 ? ((ItemDisk) stack.getItem()).getColour( stack ) : 0xFFFFFF,
Registry.ModItems.DISK.get() Registry.ModItems.DISK.get()
); );
event.getItemColors().register( event.register(
( stack, layer ) -> layer == 1 ? ItemTreasureDisk.getColour( stack ) : 0xFFFFFF, ( stack, layer ) -> layer == 1 ? ItemTreasureDisk.getColour( stack ) : 0xFFFFFF,
Registry.ModItems.TREASURE_DISK.get() Registry.ModItems.TREASURE_DISK.get()
); );
event.getItemColors().register( ( stack, layer ) -> { event.register( ( stack, layer ) -> {
switch( layer ) switch( layer )
{ {
case 0: case 0:
@ -123,14 +124,6 @@ public final class ClientRegistry
@SubscribeEvent @SubscribeEvent
public static void setupClient( FMLClientSetupEvent event ) public static void setupClient( FMLClientSetupEvent event )
{ {
// While turtles themselves are not transparent, their upgrades may be.
ItemBlockRenderTypes.setRenderLayer( Registry.ModBlocks.TURTLE_NORMAL.get(), RenderType.translucent() );
ItemBlockRenderTypes.setRenderLayer( Registry.ModBlocks.TURTLE_ADVANCED.get(), RenderType.translucent() );
// Monitors' textures have transparent fronts and so count as cutouts.
ItemBlockRenderTypes.setRenderLayer( Registry.ModBlocks.MONITOR_NORMAL.get(), RenderType.cutout() );
ItemBlockRenderTypes.setRenderLayer( Registry.ModBlocks.MONITOR_ADVANCED.get(), RenderType.cutout() );
// Setup TESRs // Setup TESRs
BlockEntityRenderers.register( Registry.ModBlockEntities.MONITOR_NORMAL.get(), TileEntityMonitorRenderer::new ); BlockEntityRenderers.register( Registry.ModBlockEntities.MONITOR_NORMAL.get(), TileEntityMonitorRenderer::new );
BlockEntityRenderers.register( Registry.ModBlockEntities.MONITOR_ADVANCED.get(), TileEntityMonitorRenderer::new ); BlockEntityRenderers.register( Registry.ModBlockEntities.MONITOR_ADVANCED.get(), TileEntityMonitorRenderer::new );

View File

@ -23,7 +23,7 @@ import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.Vec3;
import net.minecraft.world.phys.shapes.VoxelShape; import net.minecraft.world.phys.shapes.VoxelShape;
import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.client.event.DrawSelectionEvent; import net.minecraftforge.client.event.RenderHighlightEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.Mod;
@ -41,7 +41,7 @@ public final class CableHighlightRenderer
* @see net.minecraft.client.renderer.LevelRenderer#renderHitOutline * @see net.minecraft.client.renderer.LevelRenderer#renderHitOutline
*/ */
@SubscribeEvent @SubscribeEvent
public static void drawHighlight( DrawSelectionEvent.HighlightBlock event ) public static void drawHighlight( RenderHighlightEvent.Block event )
{ {
BlockHitResult hit = event.getTarget(); BlockHitResult hit = event.getTarget();
BlockPos pos = hit.getBlockPos(); BlockPos pos = hit.getBlockPos();

View File

@ -15,7 +15,7 @@ import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.HitResult; import net.minecraft.world.phys.HitResult;
import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.client.event.RenderGameOverlayEvent; import net.minecraftforge.client.event.CustomizeGuiOverlayEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.Mod;
@ -25,7 +25,7 @@ import java.util.List;
public class DebugOverlay public class DebugOverlay
{ {
@SubscribeEvent @SubscribeEvent
public static void onRenderText( RenderGameOverlayEvent.Text event ) public static void onRenderText( CustomizeGuiOverlayEvent.DebugText event )
{ {
Minecraft minecraft = Minecraft.getInstance(); Minecraft minecraft = Minecraft.getInstance();
if( !minecraft.options.renderDebug || minecraft.level == null ) return; if( !minecraft.options.renderDebug || minecraft.level == null ) return;

View File

@ -18,7 +18,7 @@ import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.Vec3;
import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.client.event.DrawSelectionEvent; import net.minecraftforge.client.event.RenderHighlightEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.Mod;
@ -38,7 +38,7 @@ public final class MonitorHighlightRenderer
} }
@SubscribeEvent @SubscribeEvent
public static void drawHighlight( DrawSelectionEvent.HighlightBlock event ) public static void drawHighlight( RenderHighlightEvent.Block event )
{ {
// Preserve normal behaviour when crouching. // Preserve normal behaviour when crouching.
if( event.getCamera().getEntity().isCrouching() ) return; if( event.getCamera().getEntity().isCrouching() ) return;

View File

@ -34,7 +34,7 @@ import net.minecraft.util.RandomSource;
import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.HitResult; import net.minecraft.world.phys.HitResult;
import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.Vec3;
import net.minecraftforge.client.model.data.EmptyModelData; import net.minecraftforge.client.model.data.ModelData;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import java.util.List; import java.util.List;
@ -165,10 +165,10 @@ public class TileEntityTurtleRenderer implements BlockEntityRenderer<TileTurtle>
private void renderModel( @Nonnull PoseStack transform, @Nonnull VertexConsumer renderer, int lightmapCoord, int overlayLight, BakedModel model, int[] tints ) private void renderModel( @Nonnull PoseStack transform, @Nonnull VertexConsumer renderer, int lightmapCoord, int overlayLight, BakedModel model, int[] tints )
{ {
random.setSeed( 0 ); random.setSeed( 0 );
renderQuads( transform, renderer, lightmapCoord, overlayLight, model.getQuads( null, null, random, EmptyModelData.INSTANCE ), tints ); renderQuads( transform, renderer, lightmapCoord, overlayLight, model.getQuads( null, null, random, ModelData.EMPTY, null ), tints );
for( Direction facing : DirectionUtil.FACINGS ) for( Direction facing : DirectionUtil.FACINGS )
{ {
renderQuads( transform, renderer, lightmapCoord, overlayLight, model.getQuads( null, facing, random, EmptyModelData.INSTANCE ), tints ); renderQuads( transform, renderer, lightmapCoord, overlayLight, model.getQuads( null, facing, random, ModelData.EMPTY, null ), tints );
} }
} }
@ -185,10 +185,10 @@ public class TileEntityTurtleRenderer implements BlockEntityRenderer<TileTurtle>
if( idx >= 0 && idx < tints.length ) tint = tints[bakedquad.getTintIndex()]; if( idx >= 0 && idx < tints.length ) tint = tints[bakedquad.getTintIndex()];
} }
float f = (float) (tint >> 16 & 255) / 255.0F; float r = (float) (tint >> 16 & 255) / 255.0F;
float f1 = (float) (tint >> 8 & 255) / 255.0F; float g = (float) (tint >> 8 & 255) / 255.0F;
float f2 = (float) (tint & 255) / 255.0F; float b = (float) (tint & 255) / 255.0F;
buffer.putBulkData( matrix, bakedquad, f, f1, f2, lightmapCoord, overlayLight, true ); buffer.putBulkData( matrix, bakedquad, r, g, b, lightmapCoord, overlayLight );
} }
} }
} }

View File

@ -0,0 +1,60 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.client.render;
import com.mojang.math.Transformation;
import dan200.computercraft.api.client.TransformedModel;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.block.model.BakedQuad;
import net.minecraft.client.resources.model.BakedModel;
import net.minecraft.core.Direction;
import net.minecraft.util.RandomSource;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraftforge.client.model.BakedModelWrapper;
import net.minecraftforge.client.model.IQuadTransformer;
import net.minecraftforge.client.model.data.ModelData;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.annotation.Nonnull;
import java.util.List;
public class TransformedBakedModel extends BakedModelWrapper<BakedModel>
{
private final Transformation transformation;
private final boolean isIdentity;
public TransformedBakedModel( BakedModel model, Transformation transformation )
{
super( model );
this.transformation = transformation;
isIdentity = transformation.isIdentity();
}
public TransformedBakedModel( TransformedModel model )
{
this( model.getModel(), model.getMatrix() );
}
@Nonnull
@Override
public List<BakedQuad> getQuads( @Nullable BlockState state, @Nullable Direction side, @Nonnull RandomSource rand )
{
return getQuads( state, side, rand, ModelData.EMPTY, null );
}
@Override
public @NotNull List<BakedQuad> getQuads( @Nullable BlockState state, @Nullable Direction side, @NotNull RandomSource rand, @NotNull ModelData extraData, @Nullable RenderType renderType )
{
List<BakedQuad> quads = originalModel.getQuads( state, side, rand, extraData, renderType );
return isIdentity ? quads : IQuadTransformer.applying( transformation ).process( quads );
}
public TransformedBakedModel composeWith( Transformation other )
{
return new TransformedBakedModel( originalModel, other.compose( transformation ) );
}
}

View File

@ -13,11 +13,10 @@ import net.minecraft.client.renderer.block.model.ItemOverrides;
import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.resources.model.*; import net.minecraft.client.resources.model.*;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.packs.resources.ResourceManager;
import net.minecraft.util.GsonHelper; import net.minecraft.util.GsonHelper;
import net.minecraftforge.client.model.IModelConfiguration; import net.minecraftforge.client.model.geometry.IGeometryBakingContext;
import net.minecraftforge.client.model.IModelLoader; import net.minecraftforge.client.model.geometry.IGeometryLoader;
import net.minecraftforge.client.model.geometry.IModelGeometry; import net.minecraftforge.client.model.geometry.IUnbakedGeometry;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import java.util.Collection; import java.util.Collection;
@ -25,7 +24,7 @@ import java.util.HashSet;
import java.util.Set; import java.util.Set;
import java.util.function.Function; import java.util.function.Function;
public final class TurtleModelLoader implements IModelLoader<TurtleModelLoader.TurtleModel> public final class TurtleModelLoader implements IGeometryLoader<TurtleModelLoader.TurtleModel>
{ {
private static final ResourceLocation COLOUR_TURTLE_MODEL = new ResourceLocation( ComputerCraft.MOD_ID, "block/turtle_colour" ); private static final ResourceLocation COLOUR_TURTLE_MODEL = new ResourceLocation( ComputerCraft.MOD_ID, "block/turtle_colour" );
@ -35,20 +34,15 @@ public final class TurtleModelLoader implements IModelLoader<TurtleModelLoader.T
{ {
} }
@Override
public void onResourceManagerReload( @Nonnull ResourceManager manager )
{
}
@Nonnull @Nonnull
@Override @Override
public TurtleModel read( @Nonnull JsonDeserializationContext deserializationContext, @Nonnull JsonObject modelContents ) public TurtleModel read( @Nonnull JsonObject modelContents, @Nonnull JsonDeserializationContext deserializationContext )
{ {
ResourceLocation model = new ResourceLocation( GsonHelper.getAsString( modelContents, "model" ) ); ResourceLocation model = new ResourceLocation( GsonHelper.getAsString( modelContents, "model" ) );
return new TurtleModel( model ); return new TurtleModel( model );
} }
public static final class TurtleModel implements IModelGeometry<TurtleModel> public static final class TurtleModel implements IUnbakedGeometry<TurtleModel>
{ {
private final ResourceLocation family; private final ResourceLocation family;
@ -58,7 +52,7 @@ public final class TurtleModelLoader implements IModelLoader<TurtleModelLoader.T
} }
@Override @Override
public Collection<Material> getTextures( IModelConfiguration owner, Function<ResourceLocation, UnbakedModel> modelGetter, Set<Pair<String, String>> missingTextureErrors ) public Collection<Material> getMaterials( IGeometryBakingContext context, Function<ResourceLocation, UnbakedModel> modelGetter, Set<Pair<String, String>> missingTextureErrors )
{ {
Set<Material> materials = new HashSet<>(); Set<Material> materials = new HashSet<>();
materials.addAll( modelGetter.apply( family ).getMaterials( modelGetter, missingTextureErrors ) ); materials.addAll( modelGetter.apply( family ).getMaterials( modelGetter, missingTextureErrors ) );
@ -67,7 +61,7 @@ public final class TurtleModelLoader implements IModelLoader<TurtleModelLoader.T
} }
@Override @Override
public BakedModel bake( IModelConfiguration owner, ModelBakery bakery, Function<Material, TextureAtlasSprite> spriteGetter, ModelState transform, ItemOverrides overrides, ResourceLocation modelLocation ) public BakedModel bake( IGeometryBakingContext owner, ModelBakery bakery, Function<Material, TextureAtlasSprite> spriteGetter, ModelState transform, ItemOverrides overrides, ResourceLocation modelLocation )
{ {
return new TurtleSmartItemModel( return new TurtleSmartItemModel(
bakery.bake( family, transform, spriteGetter ), bakery.bake( family, transform, spriteGetter ),

View File

@ -1,153 +0,0 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.client.render;
import com.mojang.math.Transformation;
import dan200.computercraft.api.client.TransformedModel;
import net.minecraft.client.renderer.block.model.BakedQuad;
import net.minecraft.client.renderer.block.model.ItemOverrides;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.resources.model.BakedModel;
import net.minecraft.core.Direction;
import net.minecraft.util.RandomSource;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraftforge.client.model.data.EmptyModelData;
import net.minecraftforge.client.model.data.IModelData;
import net.minecraftforge.client.model.pipeline.BakedQuadBuilder;
import net.minecraftforge.client.model.pipeline.TRSRTransformer;
import javax.annotation.Nonnull;
import java.util.ArrayList;
import java.util.EnumMap;
import java.util.List;
import java.util.Map;
public class TurtleMultiModel implements BakedModel
{
private final BakedModel baseModel;
private final BakedModel overlayModel;
private final Transformation generalTransform;
private final TransformedModel leftUpgradeModel;
private final TransformedModel rightUpgradeModel;
private List<BakedQuad> generalQuads = null;
private final Map<Direction, List<BakedQuad>> faceQuads = new EnumMap<>( Direction.class );
public TurtleMultiModel( BakedModel baseModel, BakedModel overlayModel, Transformation generalTransform, TransformedModel leftUpgradeModel, TransformedModel rightUpgradeModel )
{
// Get the models
this.baseModel = baseModel;
this.overlayModel = overlayModel;
this.leftUpgradeModel = leftUpgradeModel;
this.rightUpgradeModel = rightUpgradeModel;
this.generalTransform = generalTransform;
}
@Nonnull
@Override
@Deprecated
public List<BakedQuad> getQuads( BlockState state, Direction side, @Nonnull RandomSource rand )
{
return getQuads( state, side, rand, EmptyModelData.INSTANCE );
}
@Nonnull
@Override
public List<BakedQuad> getQuads( BlockState state, Direction side, @Nonnull RandomSource rand, @Nonnull IModelData data )
{
if( side != null )
{
if( !faceQuads.containsKey( side ) ) faceQuads.put( side, buildQuads( state, side, rand ) );
return faceQuads.get( side );
}
else
{
if( generalQuads == null ) generalQuads = buildQuads( state, side, rand );
return generalQuads;
}
}
private List<BakedQuad> buildQuads( BlockState state, Direction side, RandomSource rand )
{
ArrayList<BakedQuad> quads = new ArrayList<>();
transformQuadsTo( quads, baseModel.getQuads( state, side, rand, EmptyModelData.INSTANCE ), generalTransform );
if( overlayModel != null )
{
transformQuadsTo( quads, overlayModel.getQuads( state, side, rand, EmptyModelData.INSTANCE ), generalTransform );
}
if( leftUpgradeModel != null )
{
Transformation upgradeTransform = generalTransform.compose( leftUpgradeModel.getMatrix() );
transformQuadsTo( quads, leftUpgradeModel.getModel().getQuads( state, side, rand, EmptyModelData.INSTANCE ), upgradeTransform );
}
if( rightUpgradeModel != null )
{
Transformation upgradeTransform = generalTransform.compose( rightUpgradeModel.getMatrix() );
transformQuadsTo( quads, rightUpgradeModel.getModel().getQuads( state, side, rand, EmptyModelData.INSTANCE ), upgradeTransform );
}
quads.trimToSize();
return quads;
}
@Override
public boolean useAmbientOcclusion()
{
return baseModel.useAmbientOcclusion();
}
@Override
public boolean isGui3d()
{
return baseModel.isGui3d();
}
@Override
public boolean isCustomRenderer()
{
return baseModel.isCustomRenderer();
}
@Override
public boolean usesBlockLight()
{
return baseModel.usesBlockLight();
}
@Nonnull
@Override
@Deprecated
public TextureAtlasSprite getParticleIcon()
{
return baseModel.getParticleIcon();
}
@Nonnull
@Override
@Deprecated
public net.minecraft.client.renderer.block.model.ItemTransforms getTransforms()
{
return baseModel.getTransforms();
}
@Nonnull
@Override
public ItemOverrides getOverrides()
{
return ItemOverrides.EMPTY;
}
private void transformQuadsTo( List<BakedQuad> output, List<BakedQuad> quads, Transformation transform )
{
for( BakedQuad quad : quads )
{
BakedQuadBuilder builder = new BakedQuadBuilder();
TRSRTransformer transformer = new TRSRTransformer( builder, transform );
quad.pipe( transformer );
output.add( builder.build() );
}
}
}

View File

@ -7,35 +7,27 @@ package dan200.computercraft.client.render;
import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.math.Transformation; import com.mojang.math.Transformation;
import dan200.computercraft.api.client.TransformedModel;
import dan200.computercraft.api.turtle.ITurtleUpgrade; import dan200.computercraft.api.turtle.ITurtleUpgrade;
import dan200.computercraft.api.turtle.TurtleSide; import dan200.computercraft.api.turtle.TurtleSide;
import dan200.computercraft.shared.turtle.items.ItemTurtle; import dan200.computercraft.shared.turtle.items.ItemTurtle;
import dan200.computercraft.shared.util.Holiday; import dan200.computercraft.shared.util.Holiday;
import dan200.computercraft.shared.util.HolidayUtil; import dan200.computercraft.shared.util.HolidayUtil;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.client.renderer.block.model.BakedQuad;
import net.minecraft.client.renderer.block.model.ItemOverrides;
import net.minecraft.client.renderer.block.model.ItemTransforms; import net.minecraft.client.renderer.block.model.ItemTransforms;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.resources.model.BakedModel; import net.minecraft.client.resources.model.BakedModel;
import net.minecraft.client.resources.model.ModelManager; import net.minecraft.client.resources.model.ModelManager;
import net.minecraft.client.resources.model.ModelResourceLocation; import net.minecraft.client.resources.model.ModelResourceLocation;
import net.minecraft.core.Direction;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraft.util.RandomSource;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.block.state.BlockState; import net.minecraftforge.client.model.BakedModelWrapper;
import net.minecraftforge.client.model.data.IModelData;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
public class TurtleSmartItemModel implements BakedModel public class TurtleSmartItemModel extends BakedModelWrapper<BakedModel>
{ {
private static final Transformation identity, flip; private static final Transformation identity, flip;
@ -49,7 +41,7 @@ public class TurtleSmartItemModel implements BakedModel
flip = new Transformation( stack.last().pose() ); flip = new Transformation( stack.last().pose() );
} }
private static record TurtleModelCombination( private record TurtleModelCombination(
boolean colour, boolean colour,
ITurtleUpgrade leftUpgrade, ITurtleUpgrade leftUpgrade,
ITurtleUpgrade rightUpgrade, ITurtleUpgrade rightUpgrade,
@ -63,21 +55,29 @@ public class TurtleSmartItemModel implements BakedModel
private final BakedModel familyModel; private final BakedModel familyModel;
private final BakedModel colourModel; private final BakedModel colourModel;
private final HashMap<TurtleModelCombination, BakedModel> cachedModels = new HashMap<>(); private final Map<TurtleModelCombination, List<BakedModel>> cachedModels = new HashMap<>();
private final ItemOverrides overrides;
public TurtleSmartItemModel( BakedModel familyModel, BakedModel colourModel ) public TurtleSmartItemModel( BakedModel familyModel, BakedModel colourModel )
{ {
super( familyModel );
this.familyModel = familyModel; this.familyModel = familyModel;
this.colourModel = colourModel; this.colourModel = colourModel;
}
overrides = new ItemOverrides()
{
@Nonnull @Nonnull
@Override @Override
public BakedModel resolve( @Nonnull BakedModel originalModel, @Nonnull ItemStack stack, @Nullable ClientLevel world, @Nullable LivingEntity entity, int random ) public BakedModel applyTransform( @Nonnull ItemTransforms.TransformType cameraTransformType, @Nonnull PoseStack poseStack, boolean applyLeftHandTransform )
{
originalModel.applyTransform( cameraTransformType, poseStack, applyLeftHandTransform );
return this;
}
@Nonnull
@Override
public List<BakedModel> getRenderPasses( ItemStack stack, boolean fabulous )
{ {
ItemTurtle turtle = (ItemTurtle) stack.getItem(); ItemTurtle turtle = (ItemTurtle) stack.getItem();
int colour = turtle.getColour( stack ); int colour = turtle.getColour( stack );
ITurtleUpgrade leftUpgrade = turtle.getUpgrade( stack, TurtleSide.LEFT ); ITurtleUpgrade leftUpgrade = turtle.getUpgrade( stack, TurtleSide.LEFT );
ITurtleUpgrade rightUpgrade = turtle.getUpgrade( stack, TurtleSide.RIGHT ); ITurtleUpgrade rightUpgrade = turtle.getUpgrade( stack, TurtleSide.RIGHT );
@ -85,90 +85,34 @@ public class TurtleSmartItemModel implements BakedModel
boolean christmas = HolidayUtil.getCurrentHoliday() == Holiday.CHRISTMAS; boolean christmas = HolidayUtil.getCurrentHoliday() == Holiday.CHRISTMAS;
String label = turtle.getLabel( stack ); String label = turtle.getLabel( stack );
boolean flip = label != null && (label.equals( "Dinnerbone" ) || label.equals( "Grumm" )); boolean flip = label != null && (label.equals( "Dinnerbone" ) || label.equals( "Grumm" ));
TurtleModelCombination combo = new TurtleModelCombination( colour != -1, leftUpgrade, rightUpgrade, overlay, christmas, flip ); TurtleModelCombination combo = new TurtleModelCombination( colour != -1, leftUpgrade, rightUpgrade, overlay, christmas, flip );
return cachedModels.computeIfAbsent( combo, this::buildModel );
BakedModel model = cachedModels.get( combo );
if( model == null ) cachedModels.put( combo, model = buildModel( combo ) );
return model;
}
};
} }
@Nonnull private List<BakedModel> buildModel( TurtleModelCombination combo )
@Override
public ItemOverrides getOverrides()
{
return overrides;
}
private BakedModel buildModel( TurtleModelCombination combo )
{ {
Minecraft mc = Minecraft.getInstance(); Minecraft mc = Minecraft.getInstance();
ModelManager modelManager = mc.getItemRenderer().getItemModelShaper().getModelManager(); ModelManager modelManager = mc.getItemRenderer().getItemModelShaper().getModelManager();
ModelResourceLocation overlayModelLocation = TileEntityTurtleRenderer.getTurtleOverlayModel( combo.overlay, combo.christmas );
BakedModel baseModel = combo.colour ? colourModel : familyModel; var transformation = combo.flip ? flip : identity;
BakedModel overlayModel = overlayModelLocation != null ? modelManager.getModel( overlayModelLocation ) : null; ArrayList<BakedModel> parts = new ArrayList<>( 4 );
Transformation transform = combo.flip ? flip : identity; parts.add( new TransformedBakedModel( combo.colour() ? colourModel : familyModel, transformation ) );
TransformedModel leftModel = combo.leftUpgrade != null ? combo.leftUpgrade.getModel( null, TurtleSide.LEFT ) : null;
TransformedModel rightModel = combo.rightUpgrade != null ? combo.rightUpgrade.getModel( null, TurtleSide.RIGHT ) : null;
return new TurtleMultiModel( baseModel, overlayModel, transform, leftModel, rightModel );
}
@Nonnull ModelResourceLocation overlayModelLocation = TileEntityTurtleRenderer.getTurtleOverlayModel( combo.overlay(), combo.christmas() );
@Override if( overlayModelLocation != null )
@Deprecated
public List<BakedQuad> getQuads( BlockState state, Direction facing, @Nonnull RandomSource rand )
{ {
return familyModel.getQuads( state, facing, rand ); parts.add( new TransformedBakedModel( modelManager.getModel( overlayModelLocation ), transformation ) );
} }
if( combo.leftUpgrade() != null )
@Nonnull
@Override
@Deprecated
public List<BakedQuad> getQuads( BlockState state, Direction facing, @Nonnull RandomSource rand, @Nonnull IModelData data )
{ {
return familyModel.getQuads( state, facing, rand, data ); parts.add( new TransformedBakedModel( combo.leftUpgrade().getModel( null, TurtleSide.LEFT ) ).composeWith( transformation ) );
} }
if( combo.rightUpgrade() != null )
@Override
public boolean useAmbientOcclusion()
{ {
return familyModel.useAmbientOcclusion(); parts.add( new TransformedBakedModel( combo.rightUpgrade().getModel( null, TurtleSide.RIGHT ) ).composeWith( transformation ) );
} }
@Override return parts;
public boolean isGui3d()
{
return familyModel.isGui3d();
} }
@Override
public boolean isCustomRenderer()
{
return familyModel.isCustomRenderer();
}
@Override
public boolean usesBlockLight()
{
return familyModel.usesBlockLight();
}
@Nonnull
@Override
@Deprecated
public TextureAtlasSprite getParticleIcon()
{
return familyModel.getParticleIcon();
}
@Nonnull
@Override
@Deprecated
public ItemTransforms getTransforms()
{
return familyModel.getTransforms();
}
} }

View File

@ -8,9 +8,9 @@ package dan200.computercraft.data;
import dan200.computercraft.shared.Registry; import dan200.computercraft.shared.Registry;
import net.minecraft.data.DataGenerator; import net.minecraft.data.DataGenerator;
import net.minecraftforge.common.data.ExistingFileHelper; import net.minecraftforge.common.data.ExistingFileHelper;
import net.minecraftforge.data.event.GatherDataEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.forge.event.lifecycle.GatherDataEvent;
@Mod.EventBusSubscriber( bus = Mod.EventBusSubscriber.Bus.MOD ) @Mod.EventBusSubscriber( bus = Mod.EventBusSubscriber.Bus.MOD )
public class Generators public class Generators

View File

@ -24,7 +24,7 @@ import net.minecraft.world.level.BlockAndTintGetter;
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.HitResult; import net.minecraft.world.phys.HitResult;
import net.minecraftforge.client.model.data.IModelData; import net.minecraftforge.client.model.data.ModelData;
import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Shadow;
@ -35,7 +35,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
/** /**
* Provides custom block breaking progress for modems, so it only applies to the current part. * Provides custom block breaking progress for modems, so it only applies to the current part.
* *
* @see BlockRenderDispatcher#renderBreakingTexture(BlockState, BlockPos, BlockAndTintGetter, PoseStack, VertexConsumer, IModelData) * @see BlockRenderDispatcher#renderBreakingTexture(BlockState, BlockPos, BlockAndTintGetter, PoseStack, VertexConsumer, ModelData)
*/ */
@Mixin( BlockRenderDispatcher.class ) @Mixin( BlockRenderDispatcher.class )
public class BlockRenderDispatcherMixin public class BlockRenderDispatcherMixin
@ -53,13 +53,13 @@ public class BlockRenderDispatcherMixin
private ModelBlockRenderer modelRenderer; private ModelBlockRenderer modelRenderer;
@Inject( @Inject(
method = "name=/^renderBreakingTexture/ desc=/IModelData;\\)V$/", method = "name=/^renderBreakingTexture/ desc=/ModelData;\\)V$/",
at = @At( "HEAD" ), at = @At( "HEAD" ),
cancellable = true, cancellable = true,
require = 0 // This isn't critical functionality, so don't worry if we can't apply it. require = 0 // This isn't critical functionality, so don't worry if we can't apply it.
) )
public void renderBlockDamage( public void renderBlockDamage(
BlockState state, BlockPos pos, BlockAndTintGetter world, PoseStack pose, VertexConsumer buffers, IModelData modelData, BlockState state, BlockPos pos, BlockAndTintGetter world, PoseStack pose, VertexConsumer buffers, ModelData modelData,
CallbackInfo info CallbackInfo info
) )
{ {
@ -85,6 +85,6 @@ public class BlockRenderDispatcherMixin
BakedModel model = blockModelShaper.getBlockModel( newState ); BakedModel model = blockModelShaper.getBlockModel( newState );
long seed = newState.getSeed( pos ); long seed = newState.getSeed( pos );
modelRenderer.tesselateBlock( world, model, newState, pos, pose, buffers, true, random, seed, OverlayTexture.NO_OVERLAY, modelData ); modelRenderer.tesselateBlock( world, model, newState, pos, pose, buffers, true, random, seed, OverlayTexture.NO_OVERLAY, modelData, null );
} }
} }

View File

@ -73,7 +73,7 @@ public final class CommonHooks
IComputer computer = ((IContainerComputer) container).getComputer(); IComputer computer = ((IContainerComputer) container).getComputer();
if( computer instanceof ServerComputer ) if( computer instanceof ServerComputer )
{ {
((ServerComputer) computer).sendTerminalState( event.getPlayer() ); ((ServerComputer) computer).sendTerminalState( event.getEntity() );
} }
} }
} }

View File

@ -6,8 +6,6 @@
package dan200.computercraft.shared; package dan200.computercraft.shared;
import com.electronwill.nightconfig.core.UnmodifiableConfig; import com.electronwill.nightconfig.core.UnmodifiableConfig;
import com.google.common.base.CaseFormat;
import com.google.common.base.Converter;
import dan200.computercraft.ComputerCraft; import dan200.computercraft.ComputerCraft;
import dan200.computercraft.core.apis.http.NetworkUtils; import dan200.computercraft.core.apis.http.NetworkUtils;
import dan200.computercraft.core.apis.http.options.Action; import dan200.computercraft.core.apis.http.options.Action;
@ -367,6 +365,4 @@ public final class Config
{ {
sync( event.getConfig() ); sync( event.getConfig() );
} }
private static final Converter<String, String> converter = CaseFormat.LOWER_CAMEL.converterTo( CaseFormat.UPPER_UNDERSCORE );
} }

View File

@ -13,7 +13,10 @@ import dan200.computercraft.api.network.wired.IWiredElement;
import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.api.peripheral.IPeripheral;
import dan200.computercraft.api.pocket.PocketUpgradeSerialiser; import dan200.computercraft.api.pocket.PocketUpgradeSerialiser;
import dan200.computercraft.api.turtle.TurtleUpgradeSerialiser; import dan200.computercraft.api.turtle.TurtleUpgradeSerialiser;
import dan200.computercraft.shared.command.arguments.*; import dan200.computercraft.shared.command.arguments.ComputerArgumentType;
import dan200.computercraft.shared.command.arguments.ComputersArgumentType;
import dan200.computercraft.shared.command.arguments.RepeatArgumentType;
import dan200.computercraft.shared.command.arguments.TrackingFieldArgumentType;
import dan200.computercraft.shared.common.ColourableRecipe; import dan200.computercraft.shared.common.ColourableRecipe;
import dan200.computercraft.shared.common.ContainerHeldItem; import dan200.computercraft.shared.common.ContainerHeldItem;
import dan200.computercraft.shared.common.DefaultBundledRedstoneProvider; import dan200.computercraft.shared.common.DefaultBundledRedstoneProvider;
@ -164,7 +167,7 @@ public final class Registry
public static class ModBlockEntities public static class ModBlockEntities
{ {
static final DeferredRegister<BlockEntityType<?>> TILES = DeferredRegister.create( ForgeRegistries.BLOCK_ENTITIES, ComputerCraft.MOD_ID ); static final DeferredRegister<BlockEntityType<?>> TILES = DeferredRegister.create( ForgeRegistries.BLOCK_ENTITY_TYPES, ComputerCraft.MOD_ID );
private static <T extends BlockEntity> RegistryObject<BlockEntityType<T>> ofBlock( RegistryObject<? extends Block> block, FixedPointTileEntityType.FixedPointBlockEntitySupplier<T> factory ) private static <T extends BlockEntity> RegistryObject<BlockEntityType<T>> ofBlock( RegistryObject<? extends Block> block, FixedPointTileEntityType.FixedPointBlockEntitySupplier<T> factory )
{ {
@ -283,7 +286,7 @@ public final class Registry
public static class ModContainers public static class ModContainers
{ {
static final DeferredRegister<MenuType<?>> CONTAINERS = DeferredRegister.create( ForgeRegistries.CONTAINERS, ComputerCraft.MOD_ID ); static final DeferredRegister<MenuType<?>> CONTAINERS = DeferredRegister.create( ForgeRegistries.MENU_TYPES, ComputerCraft.MOD_ID );
public static final RegistryObject<MenuType<ContainerComputerBase>> COMPUTER = CONTAINERS.register( "computer", public static final RegistryObject<MenuType<ContainerComputerBase>> COMPUTER = CONTAINERS.register( "computer",
() -> ContainerData.toType( ComputerContainerData::new, ComputerMenuWithoutInventory::new ) ); () -> ContainerData.toType( ComputerContainerData::new, ComputerMenuWithoutInventory::new ) );
@ -317,7 +320,7 @@ public final class Registry
@SuppressWarnings( "unchecked" ) @SuppressWarnings( "unchecked" )
private static <T extends ArgumentType<?>> void registerUnsafe( String name, Class<T> type, ArgumentTypeInfo<?, ?> serializer ) private static <T extends ArgumentType<?>> void registerUnsafe( String name, Class<T> type, ArgumentTypeInfo<?, ?> serializer )
{ {
ARGUMENT_TYPES.register( name, () -> ArgumentTypeInfos.registerByClass( type, (ArgumentTypeInfo<T, ?>)serializer ) ); ARGUMENT_TYPES.register( name, () -> ArgumentTypeInfos.registerByClass( type, (ArgumentTypeInfo<T, ?>) serializer ) );
} }
private static <T extends ArgumentType<?>> void register( String name, Class<T> type, ArgumentTypeInfo<T, ?> serializer ) private static <T extends ArgumentType<?>> void register( String name, Class<T> type, ArgumentTypeInfo<T, ?> serializer )

View File

@ -104,7 +104,7 @@ public final class NetworkHandler
network.messageBuilder( type, id, direction ) network.messageBuilder( type, id, direction )
.encoder( NetworkMessage::toBytes ) .encoder( NetworkMessage::toBytes )
.decoder( decoder ) .decoder( decoder )
.consumer( ( packet, contextSup ) -> { .consumerMainThread( ( packet, contextSup ) -> {
NetworkEvent.Context context = contextSup.get(); NetworkEvent.Context context = contextSup.get();
context.enqueueWork( () -> packet.handle( context ) ); context.enqueueWork( () -> packet.handle( context ) );
context.setPacketHandled( true ); context.setPacketHandled( true );

View File

@ -30,7 +30,7 @@ public interface ContainerData
default void open( Player player, MenuProvider owner ) default void open( Player player, MenuProvider owner )
{ {
NetworkHooks.openGui( (ServerPlayer) player, owner, this::toBytes ); NetworkHooks.openScreen( (ServerPlayer) player, owner, this::toBytes );
} }
static <C extends AbstractContainerMenu, T extends ContainerData> MenuType<C> toType( Function<FriendlyByteBuf, T> reader, Factory<C, T> factory ) static <C extends AbstractContainerMenu, T extends ContainerData> MenuType<C> toType( Function<FriendlyByteBuf, T> reader, Factory<C, T> factory )

View File

@ -120,7 +120,7 @@ public final class TileDiskDrive extends TileGeneric implements DefaultInventory
// Open the GUI // Open the GUI
if( !getLevel().isClientSide && isUsable( player ) ) if( !getLevel().isClientSide && isUsable( player ) )
{ {
NetworkHooks.openGui( (ServerPlayer) player, this ); NetworkHooks.openScreen( (ServerPlayer) player, this );
} }
return InteractionResult.SUCCESS; return InteractionResult.SUCCESS;
} }

View File

@ -30,7 +30,7 @@ class GenericPeripheral implements IDynamicPeripheral
GenericPeripheral( BlockEntity tile, String name, Set<String> additionalTypes, List<SaturatedMethod> methods ) GenericPeripheral( BlockEntity tile, String name, Set<String> additionalTypes, List<SaturatedMethod> methods )
{ {
ResourceLocation type = ForgeRegistries.BLOCK_ENTITIES.getKey( tile.getType() ); ResourceLocation type = ForgeRegistries.BLOCK_ENTITY_TYPES.getKey( tile.getType() );
this.tile = tile; this.tile = tile;
this.type = name != null ? name : (type != null ? type.toString() : "unknown"); this.type = name != null ? name : (type != null ? type.toString() : "unknown");
this.additionalTypes = additionalTypes; this.additionalTypes = additionalTypes;

View File

@ -11,13 +11,11 @@ import dan200.computercraft.shared.network.client.MonitorClientMessage;
import dan200.computercraft.shared.network.client.TerminalState; import dan200.computercraft.shared.network.client.TerminalState;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.LevelChunk;
import net.minecraftforge.event.TickEvent; import net.minecraftforge.event.TickEvent;
import net.minecraftforge.event.world.ChunkWatchEvent; import net.minecraftforge.event.level.ChunkWatchEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.Mod;
@ -28,7 +26,6 @@ import java.util.Queue;
public final class MonitorWatcher public final class MonitorWatcher
{ {
private static final Queue<TileMonitor> watching = new ArrayDeque<>(); private static final Queue<TileMonitor> watching = new ArrayDeque<>();
private static final Queue<PlayerUpdate> playerUpdates = new ArrayDeque<>();
private MonitorWatcher() private MonitorWatcher()
{ {
@ -46,47 +43,28 @@ public final class MonitorWatcher
@SubscribeEvent @SubscribeEvent
public static void onWatch( ChunkWatchEvent.Watch event ) public static void onWatch( ChunkWatchEvent.Watch event )
{ {
// Get the current chunk if it has been loaded. This is safe as, if the chunk hasn't been loaded yet, then the // Find all origin monitors who are not already on the queue and send the
// monitor will have no contents, and so we won't need to send an update anyway. // monitor data to the player.
ChunkPos chunkPos = event.getPos(); for( BlockEntity te : event.getChunk().getBlockEntities().values() )
LevelChunk chunk = event.getWorld().getChunkSource().getChunkNow( chunkPos.x, chunkPos.z );
if( chunk == null ) return;
for( BlockEntity te : chunk.getBlockEntities().values() )
{ {
// Find all origin monitors who are not already on the queue.
if( !(te instanceof TileMonitor monitor) ) continue; if( !(te instanceof TileMonitor monitor) ) continue;
ServerMonitor serverMonitor = getMonitor( monitor ); ServerMonitor serverMonitor = getMonitor( monitor );
if( serverMonitor == null || monitor.enqueued ) continue; if( serverMonitor == null || monitor.enqueued ) continue;
// The chunk hasn't been sent to the client yet, so we can't send an update. Do it on tick end. TerminalState state = monitor.cached;
playerUpdates.add( new PlayerUpdate( event.getPlayer(), monitor ) ); if( state == null ) state = monitor.cached = serverMonitor.write();
NetworkHandler.sendToPlayer( event.getPlayer(), new MonitorClientMessage( monitor.getBlockPos(), state ) );
} }
} }
@SubscribeEvent @SubscribeEvent
public static void onTick( TickEvent.ServerTickEvent event ) public static void onTick( TickEvent.ServerTickEvent event )
{ {
// Find all enqueued monitors and send their contents to all nearby players.
if( event.phase != TickEvent.Phase.END ) return; if( event.phase != TickEvent.Phase.END ) return;
PlayerUpdate playerUpdate;
while( (playerUpdate = playerUpdates.poll()) != null )
{
TileMonitor tile = playerUpdate.monitor;
if( tile.enqueued || tile.isRemoved() ) continue;
ServerMonitor monitor = getMonitor( tile );
if( monitor == null ) continue;
// Some basic sanity checks to the player. It's possible they're no longer within range, but that's harder
// to track efficiently.
ServerPlayer player = playerUpdate.player;
if( !player.isAlive() || player.getLevel() != tile.getLevel() ) continue;
NetworkHandler.sendToPlayer( playerUpdate.player, new MonitorClientMessage( tile.getBlockPos(), getState( tile, monitor ) ) );
}
long limit = ComputerCraft.monitorBandwidth; long limit = ComputerCraft.monitorBandwidth;
boolean obeyLimit = limit > 0; boolean obeyLimit = limit > 0;
@ -125,16 +103,4 @@ public final class MonitorWatcher
if( state == null ) state = tile.cached = monitor.write(); if( state == null ) state = tile.cached = monitor.write();
return state; return state;
} }
private static final class PlayerUpdate
{
final ServerPlayer player;
final TileMonitor monitor;
private PlayerUpdate( ServerPlayer player, TileMonitor monitor )
{
this.player = player;
this.monitor = monitor;
}
}
} }

View File

@ -99,7 +99,7 @@ public final class TilePrinter extends TileGeneric implements DefaultSidedInvent
if( !getLevel().isClientSide && isUsable( player ) ) if( !getLevel().isClientSide && isUsable( player ) )
{ {
NetworkHooks.openGui( (ServerPlayer) player, this ); NetworkHooks.openScreen( (ServerPlayer) player, this );
} }
return InteractionResult.SUCCESS; return InteractionResult.SUCCESS;
} }

View File

@ -37,7 +37,7 @@ public final class FurnaceRefuelHandler implements TurtleRefuelEvent.Handler
ItemStack stack = turtle.getItemHandler().extractItem( slot, limit, false ); ItemStack stack = turtle.getItemHandler().extractItem( slot, limit, false );
int fuelToGive = fuelPerItem * stack.getCount(); int fuelToGive = fuelPerItem * stack.getCount();
// Store the replacement item in the inventory // Store the replacement item in the inventory
ItemStack replacementStack = stack.getItem().getContainerItem( stack ); ItemStack replacementStack = ForgeHooks.getCraftingRemainingItem( stack );
if( !replacementStack.isEmpty() ) if( !replacementStack.isEmpty() )
{ {
ItemStack remainder = InventoryUtil.storeItems( replacementStack, turtle.getItemHandler(), turtle.getSelectedSlot() ); ItemStack remainder = InventoryUtil.storeItems( replacementStack, turtle.getItemHandler(), turtle.getSelectedSlot() );

View File

@ -42,7 +42,7 @@ import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.common.ToolActions; import net.minecraftforge.common.ToolActions;
import net.minecraftforge.event.entity.player.AttackEntityEvent; import net.minecraftforge.event.entity.player.AttackEntityEvent;
import net.minecraftforge.event.world.BlockEvent; import net.minecraftforge.event.level.BlockEvent;
import org.apache.commons.lang3.tuple.Pair; import org.apache.commons.lang3.tuple.Pair;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;

View File

@ -13,7 +13,7 @@ import net.minecraft.world.entity.item.ItemEntity;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
import net.minecraft.world.phys.AABB; import net.minecraft.world.phys.AABB;
import net.minecraftforge.event.entity.EntityJoinWorldEvent; import net.minecraftforge.event.entity.EntityJoinLevelEvent;
import net.minecraftforge.event.entity.living.LivingDropsEvent; import net.minecraftforge.event.entity.living.LivingDropsEvent;
import net.minecraftforge.eventbus.api.EventPriority; import net.minecraftforge.eventbus.api.EventPriority;
import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.eventbus.api.SubscribeEvent;
@ -80,10 +80,10 @@ public final class DropConsumer
} }
@SubscribeEvent( priority = EventPriority.HIGHEST ) @SubscribeEvent( priority = EventPriority.HIGHEST )
public static void onEntitySpawn( EntityJoinWorldEvent event ) public static void onEntitySpawn( EntityJoinLevelEvent event )
{ {
// Capture any nearby item spawns // Capture any nearby item spawns
if( dropWorld == event.getWorld() && event.getEntity() instanceof ItemEntity if( dropWorld == event.getLevel() && event.getEntity() instanceof ItemEntity
&& dropBounds.contains( event.getEntity().position() ) ) && dropBounds.contains( event.getEntity().position() ) )
{ {
handleDrops( ((ItemEntity) event.getEntity()).getItem() ); handleDrops( ((ItemEntity) event.getEntity()).getItem() );

View File

@ -21,6 +21,6 @@ CC: Tweaked is a fork of ComputerCraft, adding programmable computers, turtles a
[[dependencies.computercraft]] [[dependencies.computercraft]]
modId="forge" modId="forge"
mandatory=true mandatory=true
versionRange="[41.0.38,42)" versionRange="[41.0.98,42)"
ordering="NONE" ordering="NONE"
side="BOTH" side="BOTH"

View File

@ -1,5 +1,6 @@
{ {
"parent": "block/cube", "parent": "block/cube",
"render_type": "cutout",
"textures": { "textures": {
"particle": "#front", "particle": "#front",
"down": "#top", "down": "#top",

View File

@ -1,5 +1,6 @@
{ {
"parent": "block/block", "parent": "block/block",
"render_type": "translucent",
"textures": { "textures": {
"particle": "#texture" "particle": "#texture"
}, },

View File

@ -137,7 +137,7 @@ fun GameTestHelper.sequence(run: GameTestSequence.() -> GameTestSequence) {
run(startSequence()).thenSucceed() run(startSequence()).thenSucceed()
} }
private fun getName(type: BlockEntityType<*>): ResourceLocation = ForgeRegistries.BLOCK_ENTITIES.getKey(type)!! private fun getName(type: BlockEntityType<*>): ResourceLocation = ForgeRegistries.BLOCK_ENTITY_TYPES.getKey(type)!!
fun <T : BlockEntity> GameTestHelper.getBlockEntity(pos: BlockPos, type: BlockEntityType<T>): T { fun <T : BlockEntity> GameTestHelper.getBlockEntity(pos: BlockPos, type: BlockEntityType<T>): T {
val tile = getBlockEntity(pos) val tile = getBlockEntity(pos)

View File

@ -29,7 +29,7 @@ public final class ClientHooks
} }
@SubscribeEvent @SubscribeEvent
public static void onGuiInit( ScreenEvent.InitScreenEvent event ) public static void onGuiInit( ScreenEvent.Init event )
{ {
if( triggered || !(event.getScreen() instanceof TitleScreen) ) return; if( triggered || !(event.getScreen() instanceof TitleScreen) ) return;
triggered = true; triggered = true;