1
0
mirror of https://github.com/SquidDev-CC/CC-Tweaked synced 2025-10-18 07:27:39 +00:00

Compare commits

...

14 Commits

Author SHA1 Message Date
Jonathan Coates
c43d851e63 Register turtle upgrade models separately
ITurtleUpgrade.getModel has always been rather error-prone to use, due
to its client-only nature. As ModelResourceLocation is now client-only
again in Forge 1.19.1, no seems a good time to fix this.

The getter for models is now a separate interface inside a new
dan200.computercraft.api.client package. These are registered
per-TurtleUpgradeSerialiser (as those should correspond to class
anyway). It's a little ugly, and we may rename the XxxSerialiser classes
to something more general in a future update.

I'm not wild about the interface here either - happy to change it in
future versions too.

   * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

Also clean up the generic arguments to IUpgradeBase/UpgradeSerialiser a
little bit. It's not great (wish Java had HKTs), but it's better.
2022-07-28 19:02:38 +01:00
Jonathan Coates
50fe7935a3 Merge branch 'mc-1.18.x' into mc-1.19.x 2022-07-28 09:49:25 +01:00
Jonathan Coates
c3615d9c5b Update to 1.19.1 2022-07-28 08:52:03 +01:00
Jonathan Coates
25a44bea6e Correctly set VertexBuffer.format
Fixes #1137. Maybe.
2022-07-21 09:50:33 +01:00
Jonathan Coates
4a273ae8e5 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!
2022-07-16 19:08:11 +01:00
Jonathan Coates
e906f3ebc3 Remove IArguments.releaseImmediate
Was deprecated pre-1.19, just forgot to remove it as part of the update.
2022-07-02 17:00:14 +01:00
Jonathan Coates
92c613a7a2 Merge branch 'mc-1.18.x' into mc-1.19.x 2022-06-23 22:41:49 +01:00
Jonathan Coates
8fc7820a12 Sync each config type separately
Forge checks for early access now which is sensible, but given we
sidestep Forge's ConfigValue system anyway, not very useful for us :D:.

Fixes #1117
2022-06-20 19:58:10 +01:00
Jonathan Coates
a2e3d9d9bd Update JEI to 1.19
Fixes #1116
2022-06-19 11:17:31 +01:00
Jonathan Coates
755f8eff93 Mark 1.19 as alpha-quality
I knew I had an option for this, I just forgot to flip it!
2022-06-12 16:46:43 +01:00
Jonathan Coates
a879efc3d0 Don't shade all of Netty in the CC:T jar
Fixes #1108. Let this be a lesson to all of us: don't update mods at
midnight after a 20h day while half-delirious.
2022-06-12 16:39:57 +01:00
Jonathan Coates
a913232e62 Merge branch 'mc-1.18.x' into mc-1.19.x 2022-06-10 00:04:35 +01:00
Jonathan Coates
5382d34d29 Bump Forge version
Nothing major has changed, just at this point it's best to be on latest.
2022-06-09 23:34:46 +01:00
Jonathan Coates
8f7719a8dc Update to Minecraft 1.19
Oh my, a same day release! Well, if we use the AoE timezone.

Entirely untested (well, aside from automated tests), I haven't even
launched a client. In my defence, its just past midnight and I've been
up since 4am.
2022-06-08 00:10:55 +01:00
120 changed files with 1140 additions and 1016 deletions

View File

@@ -110,6 +110,7 @@ minecraft {
} }
mappings channel: 'parchment', version: "${mapping_version}-${mc_version}" mappings channel: 'parchment', version: "${mapping_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')
@@ -148,10 +149,12 @@ 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.18.2:9.4.1.116:api") extraModsCompileOnly fg.deobf("mezz.jei:jei-1.19-forge-api:11.1.1.236")
extraModsRuntimeOnly fg.deobf("mezz.jei:jei-1.18.2:9.4.1.116") extraModsCompileOnly fg.deobf("mezz.jei:jei-1.19-common-api:11.1.1.236")
extraModsRuntimeOnly fg.deobf("mezz.jei:jei-1.19-forge:11.1.1.236")
shade 'org.squiddev:Cobalt:0.5.5' shade 'org.squiddev:Cobalt:0.5.5'
shade 'io.netty:netty-codec-http:4.1.76.Final'
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.7.0' testImplementation 'org.junit.jupiter:junit-jupiter-api:5.7.0'
testImplementation 'org.junit.jupiter:junit-jupiter-params:5.7.0' testImplementation 'org.junit.jupiter:junit-jupiter-params:5.7.0'
@@ -223,6 +226,7 @@ shadowJar {
archiveClassifier.set("") archiveClassifier.set("")
configurations = [project.configurations.shade] configurations = [project.configurations.shade]
relocate("org.squiddev.cobalt", "cc.tweaked.internal.cobalt") relocate("org.squiddev.cobalt", "cc.tweaked.internal.cobalt")
relocate("io.netty.handler.codec.http", "cc.tweaked.internal.netty")
minimize() minimize()
} }
@@ -491,7 +495,7 @@ def checkRelease = tasks.register("checkRelease") {
} }
check.dependsOn(checkRelease) check.dependsOn(checkRelease)
def isStable = true def isStable = false
curseforge { curseforge {
apiKey = project.hasProperty('curseForgeApiKey') ? project.curseForgeApiKey : '' apiKey = project.hasProperty('curseForgeApiKey') ? project.curseForgeApiKey : ''

View File

@@ -5,7 +5,7 @@ kotlin.stdlib.default.dependency=false
mod_version=1.100.9 mod_version=1.100.9
# Minecraft properties (update mods.toml when changing) # Minecraft properties (update mods.toml when changing)
mc_version=1.18.2 mc_version=1.19.1
mapping_version=2022.03.13 mapping_version=1.18.2-2022.07.03
forge_version=40.1.0 forge_version=42.0.0
# NO SERIOUSLY, UPDATE mods.toml WHEN CHANGING # NO SERIOUSLY, UPDATE mods.toml WHEN CHANGING

View File

@@ -61,9 +61,11 @@ public final class ComputerCraftAPIImpl implements IComputerCraftAPI
public static InputStream getResourceFile( String domain, String subPath ) public static InputStream getResourceFile( String domain, String subPath )
{ {
var manager = ServerLifecycleHooks.getCurrentServer().getResourceManager(); var manager = ServerLifecycleHooks.getCurrentServer().getResourceManager();
var resource = manager.getResource( new ResourceLocation( domain, subPath ) ).orElse( null );
if( resource == null ) return null;
try try
{ {
return manager.getResource( new ResourceLocation( domain, subPath ) ).getInputStream(); return resource.open();
} }
catch( IOException ignored ) catch( IOException ignored )
{ {

View File

@@ -0,0 +1,57 @@
/*
* This file is part of the public ComputerCraft API - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2022. This API may be redistributed unmodified and in full only.
* For help using the API, and posting your mods, visit the forums at computercraft.info.
*/
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 net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent;
import javax.annotation.Nonnull;
public final class ComputerCraftAPIClient
{
private ComputerCraftAPIClient()
{
}
/**
* Register a {@link TurtleUpgradeModeller} for a class of turtle upgrades.
*
* This may be called at any point after registry creation, though it is recommended to call it within {@link FMLClientSetupEvent}.
*
* @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( @Nonnull TurtleUpgradeSerialiser<T> serialiser, @Nonnull TurtleUpgradeModeller<T> modeller )
{
getInstance().registerTurtleUpgradeModeller( serialiser, modeller );
}
private static IComputerCraftAPIClient instance;
@Nonnull
private static IComputerCraftAPIClient getInstance()
{
if( instance != null ) return instance;
try
{
return instance = (IComputerCraftAPIClient) Class.forName( "dan200.computercraft.client.ComputerCraftAPIClientImpl" )
.getField( "INSTANCE" ).get( null );
}
catch( ReflectiveOperationException e )
{
throw new IllegalStateException( "Cannot find ComputerCraft API", e );
}
}
public interface IComputerCraftAPIClient
{
<T extends ITurtleUpgrade> void registerTurtleUpgradeModeller( @Nonnull TurtleUpgradeSerialiser<T> serialiser, @Nonnull TurtleUpgradeModeller<T> modeller );
}
}

View File

@@ -0,0 +1,68 @@
/*
* This file is part of the public ComputerCraft API - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2022. This API may be redistributed unmodified and in full only.
* For help using the API, and posting your mods, visit the forums at computercraft.info.
*/
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 javax.annotation.Nonnull;
import javax.annotation.Nullable;
/**
* Provides models for a {@link ITurtleUpgrade}.
*
* @param <T> The type of turtle upgrade this modeller applies to.
* @see ComputerCraftAPIClient#registerTurtleUpgradeModeller(TurtleUpgradeSerialiser, TurtleUpgradeModeller) To register a modeller.
*/
public interface TurtleUpgradeModeller<T extends ITurtleUpgrade>
{
/**
* Obtain the model to be used when rendering a turtle peripheral.
*
* When the current turtle is {@literal null}, this function should be constant for a given upgrade and side.
*
* @param upgrade The upgrade that you're getting the model for.
* @param turtle Access to the turtle that the upgrade resides on. This will be null when getting item models!
* @param side Which side of the turtle (left or right) the upgrade resides on.
* @return The model that you wish to be used to render your upgrade.
*/
@Nonnull
TransformedModel getModel( @Nonnull T upgrade, @Nullable ITurtleAccess turtle, @Nonnull TurtleSide side );
/**
* A basic {@link TurtleUpgradeModeller} which renders using the upgrade's {@linkplain ITurtleUpgrade#getCraftingItem()
* crafting item}.
*
* This uses appropriate transformations for "flat" items, namely those extending the {@literal minecraft:item/generated}
* model type. It will not appear correct for 3D models with additional depth, such as blocks.
*
* @param <T> The type of the turtle upgrade.
* @return The constructed modeller.
*/
@SuppressWarnings( "unchecked" )
static <T extends ITurtleUpgrade> TurtleUpgradeModeller<T> flatItem()
{
return (TurtleUpgradeModeller<T>) TurtleUpgradeModellers.FLAT_ITEM;
}
/**
* Construct a {@link TurtleUpgradeModeller} which has a single model for the left and right side.
*
* @param left The model to use on the left.
* @param right The model to use on the right.
* @param <T> The type of the turtle upgrade.
* @return The constructed modeller.
*/
static <T extends ITurtleUpgrade> TurtleUpgradeModeller<T> sided( ModelResourceLocation left, ModelResourceLocation right )
{
return ( upgrade, turtle, side ) -> TransformedModel.of( side == TurtleSide.LEFT ? left : right );
}
}

View File

@@ -0,0 +1,31 @@
/*
* This file is part of the public ComputerCraft API - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2022. This API may be redistributed unmodified and in full only.
* For help using the API, and posting your mods, visit the forums at computercraft.info.
*/
package dan200.computercraft.api.client.turtle;
import com.mojang.math.Matrix4f;
import com.mojang.math.Transformation;
import dan200.computercraft.api.client.TransformedModel;
import dan200.computercraft.api.turtle.ITurtleUpgrade;
import dan200.computercraft.api.turtle.TurtleSide;
class TurtleUpgradeModellers
{
private static final Transformation leftTransform = getMatrixFor( -0.40625f );
private static final Transformation rightTransform = getMatrixFor( 0.40625f );
private static Transformation getMatrixFor( float offset )
{
return new Transformation( new Matrix4f( new float[] {
0.0f, 0.0f, -1.0f, 1.0f + offset,
1.0f, 0.0f, 0.0f, 0.0f,
0.0f, -1.0f, 0.0f, 1.0f,
0.0f, 0.0f, 0.0f, 1.0f,
} ) );
}
static final TurtleUpgradeModeller<ITurtleUpgrade> FLAT_ITEM = ( upgrade, turtle, side ) ->
TransformedModel.of( upgrade.getCraftingItem(), side == TurtleSide.LEFT ? leftTransform : rightTransform );
}

View File

@@ -443,16 +443,4 @@ public interface IArguments
{ {
return optTable( index ).orElse( def ); return optTable( index ).orElse( def );
} }
/**
* This is called when the current function finishes, before any main thread tasks have run.
*
* Called when the current function returns, and so some values are no longer guaranteed to be safe to access.
*
* @deprecated This method was an internal implementation detail and is no longer used.
*/
@Deprecated
default void releaseImmediate()
{
}
} }

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;
@@ -25,6 +25,6 @@ public abstract class PocketUpgradeDataProvider extends UpgradeDataProvider<IPoc
{ {
public PocketUpgradeDataProvider( @Nonnull DataGenerator generator ) public PocketUpgradeDataProvider( @Nonnull DataGenerator generator )
{ {
super( generator, "Pocket Computer Upgrades", "computercraft/pocket_upgrades", PocketUpgradeSerialiser.REGISTRY_ID ); super( generator, "Pocket Computer Upgrades", "computercraft/pocket_upgrades", PocketUpgradeSerialiser.registry() );
} }
} }

View File

@@ -16,7 +16,7 @@ import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.crafting.SimpleRecipeSerializer; import net.minecraft.world.item.crafting.SimpleRecipeSerializer;
import net.minecraftforge.registries.DeferredRegister; import net.minecraftforge.registries.DeferredRegister;
import net.minecraftforge.registries.ForgeRegistryEntry; import net.minecraftforge.registries.IForgeRegistry;
import net.minecraftforge.registries.RegistryManager; import net.minecraftforge.registries.RegistryManager;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
@@ -33,23 +33,27 @@ import java.util.function.Function;
* @see IPocketUpgrade * @see IPocketUpgrade
* @see PocketUpgradeDataProvider * @see PocketUpgradeDataProvider
*/ */
public interface PocketUpgradeSerialiser<T extends IPocketUpgrade> extends UpgradeSerialiser<T, PocketUpgradeSerialiser<?>> public interface PocketUpgradeSerialiser<T extends IPocketUpgrade> extends UpgradeSerialiser<T>
{ {
/** /**
* The ID for the associated registry. * The ID for the associated registry.
* *
* 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()
*/ */
ResourceKey<Registry<PocketUpgradeSerialiser<?>>> REGISTRY_ID = ResourceKey.createRegistryKey( new ResourceLocation( ComputerCraft.MOD_ID, "pocket_upgrade_serialiser" ) ); ResourceKey<Registry<PocketUpgradeSerialiser<?>>> REGISTRY_ID = ResourceKey.createRegistryKey( new ResourceLocation( ComputerCraft.MOD_ID, "pocket_upgrade_serialiser" ) );
/** /**
* A convenient base class to inherit to implement {@link PocketUpgradeSerialiser}. * The associated registry.
* *
* @param <T> The type of the upgrade created by this serialiser. * @return The registry for pocket upgrade serialisers.
* @see #REGISTRY_ID
*/ */
abstract class Base<T extends IPocketUpgrade> extends ForgeRegistryEntry<PocketUpgradeSerialiser<?>> implements PocketUpgradeSerialiser<T> static IForgeRegistry<PocketUpgradeSerialiser<?>> registry()
{ {
return RegistryManager.ACTIVE.getRegistry( REGISTRY_ID );
} }
/** /**
@@ -65,7 +69,7 @@ public interface PocketUpgradeSerialiser<T extends IPocketUpgrade> extends Upgra
@Nonnull @Nonnull
static <T extends IPocketUpgrade> PocketUpgradeSerialiser<T> simple( @Nonnull Function<ResourceLocation, T> factory ) static <T extends IPocketUpgrade> PocketUpgradeSerialiser<T> simple( @Nonnull Function<ResourceLocation, T> factory )
{ {
class Impl extends SimpleSerialiser<T, PocketUpgradeSerialiser<?>> implements PocketUpgradeSerialiser<T> class Impl extends SimpleSerialiser<T> implements PocketUpgradeSerialiser<T>
{ {
private Impl( Function<ResourceLocation, T> constructor ) private Impl( Function<ResourceLocation, T> constructor )
{ {
@@ -88,7 +92,7 @@ public interface PocketUpgradeSerialiser<T extends IPocketUpgrade> extends Upgra
@Nonnull @Nonnull
static <T extends IPocketUpgrade> PocketUpgradeSerialiser<T> simpleWithCustomItem( @Nonnull BiFunction<ResourceLocation, ItemStack, T> factory ) static <T extends IPocketUpgrade> PocketUpgradeSerialiser<T> simpleWithCustomItem( @Nonnull BiFunction<ResourceLocation, ItemStack, T> factory )
{ {
class Impl extends SerialiserWithCraftingItem<T, PocketUpgradeSerialiser<?>> implements PocketUpgradeSerialiser<T> class Impl extends SerialiserWithCraftingItem<T> implements PocketUpgradeSerialiser<T>
{ {
private Impl( BiFunction<ResourceLocation, ItemStack, T> factory ) private Impl( BiFunction<ResourceLocation, ItemStack, T> factory )
{ {

View File

@@ -5,16 +5,11 @@
*/ */
package dan200.computercraft.api.turtle; package dan200.computercraft.api.turtle;
import dan200.computercraft.api.client.TransformedModel;
import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.api.peripheral.IPeripheral;
import dan200.computercraft.api.upgrades.IUpgradeBase; import dan200.computercraft.api.upgrades.IUpgradeBase;
import net.minecraft.client.resources.model.ModelResourceLocation;
import net.minecraft.core.Direction; import net.minecraft.core.Direction;
import net.minecraft.world.item.ItemStack;
import net.minecraftforge.api.distmarker.Dist;
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;
@@ -85,21 +80,6 @@ public interface ITurtleUpgrade extends IUpgradeBase
return TurtleCommandResult.failure(); return TurtleCommandResult.failure();
} }
/**
* Called to obtain the model to be used when rendering a turtle peripheral.
*
* This can be obtained from {@link net.minecraft.client.renderer.ItemModelShaper#getItemModel(ItemStack)},
* {@link net.minecraft.client.resources.model.ModelManager#getModel(ModelResourceLocation)} or any other
* source.
*
* @param turtle Access to the turtle that the upgrade resides on. This will be null when getting item models!
* @param side Which side of the turtle (left or right) the upgrade resides on.
* @return The model that you wish to be used to render your upgrade.
*/
@Nonnull
@OnlyIn( Dist.CLIENT )
TransformedModel getModel( @Nullable ITurtleAccess turtle, @Nonnull TurtleSide side );
/** /**
* Called once per tick for each turtle which has the upgrade equipped. * Called once per tick for each turtle which has the upgrade equipped.
* *

View File

@@ -14,7 +14,8 @@ 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 javax.annotation.Nonnull; import javax.annotation.Nonnull;
import java.util.function.Consumer; import java.util.function.Consumer;
@@ -34,7 +35,7 @@ public abstract class TurtleUpgradeDataProvider extends UpgradeDataProvider<ITur
public TurtleUpgradeDataProvider( DataGenerator generator ) public TurtleUpgradeDataProvider( DataGenerator generator )
{ {
super( generator, "Turtle Upgrades", "computercraft/turtle_upgrades", TurtleUpgradeSerialiser.REGISTRY_ID ); super( generator, "Turtle Upgrades", "computercraft/turtle_upgrades", TurtleUpgradeSerialiser.registry() );
} }
/** /**
@@ -137,9 +138,12 @@ public abstract class TurtleUpgradeDataProvider extends UpgradeDataProvider<ITur
public void add( @Nonnull Consumer<Upgrade<TurtleUpgradeSerialiser<?>>> add ) public void add( @Nonnull Consumer<Upgrade<TurtleUpgradeSerialiser<?>>> add )
{ {
add.accept( new Upgrade<>( id, serialiser, s -> { add.accept( new Upgrade<>( id, serialiser, s -> {
s.addProperty( "item", toolItem.getRegistryName().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", craftingItem.getRegistryName().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

@@ -6,6 +6,8 @@
package dan200.computercraft.api.turtle; package dan200.computercraft.api.turtle;
import dan200.computercraft.ComputerCraft; import dan200.computercraft.ComputerCraft;
import dan200.computercraft.api.client.ComputerCraftAPIClient;
import dan200.computercraft.api.client.turtle.TurtleUpgradeModeller;
import dan200.computercraft.api.upgrades.IUpgradeBase; import dan200.computercraft.api.upgrades.IUpgradeBase;
import dan200.computercraft.api.upgrades.UpgradeSerialiser; import dan200.computercraft.api.upgrades.UpgradeSerialiser;
import dan200.computercraft.internal.upgrades.SerialiserWithCraftingItem; import dan200.computercraft.internal.upgrades.SerialiserWithCraftingItem;
@@ -17,7 +19,6 @@ import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.crafting.RecipeSerializer; import net.minecraft.world.item.crafting.RecipeSerializer;
import net.minecraft.world.item.crafting.SimpleRecipeSerializer; import net.minecraft.world.item.crafting.SimpleRecipeSerializer;
import net.minecraftforge.registries.DeferredRegister; import net.minecraftforge.registries.DeferredRegister;
import net.minecraftforge.registries.ForgeRegistryEntry;
import net.minecraftforge.registries.IForgeRegistry; import net.minecraftforge.registries.IForgeRegistry;
import net.minecraftforge.registries.RegistryManager; import net.minecraftforge.registries.RegistryManager;
@@ -55,29 +56,42 @@ import java.util.function.Function;
* } * }
* }</pre> * }</pre>
* *
* Finally, we need to register a model for our upgrade. This is done with
* {@link ComputerCraftAPIClient#registerTurtleUpgradeModeller(TurtleUpgradeSerialiser, TurtleUpgradeModeller)}:
*
* <pre>{@code
* // Register our model inside FMLClientSetupEvent
* ComputerCraftAPIClient.registerTurtleUpgradeModeller(MY_UPGRADE.get(), TurtleUpgradeModeller.flatItem())
* }</pre>
*
* {@link TurtleUpgradeDataProvider} provides a data provider to aid with generating these JSON files. * {@link TurtleUpgradeDataProvider} provides a data provider to aid with generating these JSON files.
* *
* @param <T> The type of turtle upgrade this is responsible for serialising. * @param <T> The type of turtle upgrade this is responsible for serialising.
* @see ITurtleUpgrade * @see ITurtleUpgrade
* @see TurtleUpgradeDataProvider * @see TurtleUpgradeDataProvider
* @see TurtleUpgradeModeller
*/ */
public interface TurtleUpgradeSerialiser<T extends ITurtleUpgrade> extends UpgradeSerialiser<T, TurtleUpgradeSerialiser<?>> public interface TurtleUpgradeSerialiser<T extends ITurtleUpgrade> extends UpgradeSerialiser<T>
{ {
/** /**
* The ID for the associated registry. * The ID for the associated registry.
* *
* 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()
*/ */
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" ) );
/** /**
* A convenient base class to inherit to implement {@link TurtleUpgradeSerialiser}. * The associated registry.
* *
* @param <T> The type of the upgrade created by this serialiser. * @return The registry for pocket upgrade serialisers.
* @see #REGISTRY_ID
*/ */
abstract class Base<T extends ITurtleUpgrade> extends ForgeRegistryEntry<TurtleUpgradeSerialiser<?>> implements TurtleUpgradeSerialiser<T> static IForgeRegistry<TurtleUpgradeSerialiser<?>> registry()
{ {
return RegistryManager.ACTIVE.getRegistry( REGISTRY_ID );
} }
/** /**
@@ -93,7 +107,7 @@ public interface TurtleUpgradeSerialiser<T extends ITurtleUpgrade> extends Upgra
@Nonnull @Nonnull
static <T extends ITurtleUpgrade> TurtleUpgradeSerialiser<T> simple( @Nonnull Function<ResourceLocation, T> factory ) static <T extends ITurtleUpgrade> TurtleUpgradeSerialiser<T> simple( @Nonnull Function<ResourceLocation, T> factory )
{ {
class Impl extends SimpleSerialiser<T, TurtleUpgradeSerialiser<?>> implements TurtleUpgradeSerialiser<T> class Impl extends SimpleSerialiser<T> implements TurtleUpgradeSerialiser<T>
{ {
private Impl( Function<ResourceLocation, T> constructor ) private Impl( Function<ResourceLocation, T> constructor )
{ {
@@ -116,7 +130,7 @@ public interface TurtleUpgradeSerialiser<T extends ITurtleUpgrade> extends Upgra
@Nonnull @Nonnull
static <T extends ITurtleUpgrade> TurtleUpgradeSerialiser<T> simpleWithCustomItem( @Nonnull BiFunction<ResourceLocation, ItemStack, T> factory ) static <T extends ITurtleUpgrade> TurtleUpgradeSerialiser<T> simpleWithCustomItem( @Nonnull BiFunction<ResourceLocation, ItemStack, T> factory )
{ {
class Impl extends SerialiserWithCraftingItem<T, TurtleUpgradeSerialiser<?>> implements TurtleUpgradeSerialiser<T> class Impl extends SerialiserWithCraftingItem<T> implements TurtleUpgradeSerialiser<T>
{ {
private Impl( BiFunction<ResourceLocation, ItemStack, T> factory ) private Impl( BiFunction<ResourceLocation, ItemStack, T> factory )
{ {

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

@@ -5,21 +5,18 @@
*/ */
package dan200.computercraft.api.upgrades; package dan200.computercraft.api.upgrades;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import com.google.gson.JsonParseException; import com.google.gson.JsonParseException;
import dan200.computercraft.api.turtle.TurtleUpgradeSerialiser; import dan200.computercraft.api.turtle.TurtleUpgradeSerialiser;
import dan200.computercraft.internal.upgrades.SerialiserWithCraftingItem; import dan200.computercraft.internal.upgrades.SerialiserWithCraftingItem;
import dan200.computercraft.internal.upgrades.SimpleSerialiser; import dan200.computercraft.internal.upgrades.SimpleSerialiser;
import net.minecraft.core.Registry; import net.minecraft.data.CachedOutput;
import net.minecraft.data.DataGenerator; import net.minecraft.data.DataGenerator;
import net.minecraft.data.DataProvider; import net.minecraft.data.DataProvider;
import net.minecraft.data.HashCache;
import net.minecraft.resources.ResourceKey;
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.registries.RegistryManager; import net.minecraftforge.registries.ForgeRegistries;
import net.minecraftforge.registries.IForgeRegistry;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
@@ -37,19 +34,18 @@ import java.util.function.Function;
* @param <T> The base class of upgrades. * @param <T> The base class of upgrades.
* @param <R> The upgrade serialiser to register for. * @param <R> The upgrade serialiser to register for.
*/ */
public abstract class UpgradeDataProvider<T extends IUpgradeBase, R extends UpgradeSerialiser<?, R>> implements DataProvider public abstract class UpgradeDataProvider<T extends IUpgradeBase, R extends UpgradeSerialiser<? extends T>> implements DataProvider
{ {
private static final Logger LOGGER = LogManager.getLogger(); private static final Logger LOGGER = LogManager.getLogger();
private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create();
private final DataGenerator generator; private final DataGenerator generator;
private final String name; private final String name;
private final String folder; private final String folder;
private final ResourceKey<Registry<R>> registry; private final IForgeRegistry<R> registry;
private List<T> upgrades; private List<T> upgrades;
protected UpgradeDataProvider( @Nonnull DataGenerator generator, @Nonnull String name, @Nonnull String folder, @Nonnull ResourceKey<Registry<R>> registry ) protected UpgradeDataProvider( @Nonnull DataGenerator generator, @Nonnull String name, @Nonnull String folder, @Nonnull IForgeRegistry<R> registry )
{ {
this.generator = generator; this.generator = generator;
this.name = name; this.name = name;
@@ -92,7 +88,7 @@ public abstract class UpgradeDataProvider<T extends IUpgradeBase, R extends Upgr
} }
return new Upgrade<>( id, serialiser, s -> return new Upgrade<>( id, serialiser, s ->
s.addProperty( "item", Objects.requireNonNull( item.getRegistryName(), "Item is not registered" ).toString() ) s.addProperty( "item", Objects.requireNonNull( ForgeRegistries.ITEMS.getKey( item ), "Item is not registered" ).toString() )
); );
} }
@@ -111,7 +107,7 @@ public abstract class UpgradeDataProvider<T extends IUpgradeBase, R extends Upgr
protected abstract void addUpgrades( @Nonnull Consumer<Upgrade<R>> addUpgrade ); protected abstract void addUpgrades( @Nonnull Consumer<Upgrade<R>> addUpgrade );
@Override @Override
public final void run( @Nonnull HashCache cache ) throws IOException public final void run( @Nonnull CachedOutput cache ) throws IOException
{ {
Path base = generator.getOutputFolder().resolve( "data" ); Path base = generator.getOutputFolder().resolve( "data" );
@@ -121,12 +117,12 @@ public abstract class UpgradeDataProvider<T extends IUpgradeBase, R extends Upgr
if( !seen.add( upgrade.id() ) ) throw new IllegalStateException( "Duplicate upgrade " + upgrade.id() ); if( !seen.add( upgrade.id() ) ) throw new IllegalStateException( "Duplicate upgrade " + upgrade.id() );
var json = new JsonObject(); var json = new JsonObject();
json.addProperty( "type", Objects.requireNonNull( upgrade.serialiser().getRegistryName(), "Serialiser has not been registered" ).toString() ); json.addProperty( "type", Objects.requireNonNull( registry.getKey( upgrade.serialiser() ), "Serialiser has not been registered" ).toString() );
upgrade.serialise().accept( json ); upgrade.serialise().accept( json );
try try
{ {
DataProvider.save( GSON, cache, json, base.resolve( upgrade.id().getNamespace() + "/" + folder + "/" + upgrade.id().getPath() + ".json" ) ); DataProvider.saveStable( cache, json, base.resolve( upgrade.id().getNamespace() + "/" + folder + "/" + upgrade.id().getPath() + ".json" ) );
} }
catch( IOException e ) catch( IOException e )
{ {
@@ -135,7 +131,7 @@ public abstract class UpgradeDataProvider<T extends IUpgradeBase, R extends Upgr
try try
{ {
@SuppressWarnings( "unchecked" ) var result = (T) upgrade.serialiser().fromJson( upgrade.id(), json ); var result = upgrade.serialiser().fromJson( upgrade.id(), json );
upgrades.add( result ); upgrades.add( result );
} }
catch( IllegalArgumentException | JsonParseException e ) catch( IllegalArgumentException | JsonParseException e )
@@ -157,7 +153,7 @@ public abstract class UpgradeDataProvider<T extends IUpgradeBase, R extends Upgr
@Nonnull @Nonnull
public final R existingSerialiser( @Nonnull ResourceLocation id ) public final R existingSerialiser( @Nonnull ResourceLocation id )
{ {
var result = RegistryManager.ACTIVE.getRegistry( registry ).getValue( id ); var result = registry.getValue( id );
if( result == null ) throw new IllegalArgumentException( "No such serialiser " + registry ); if( result == null ) throw new IllegalArgumentException( "No such serialiser " + registry );
return result; return result;
} }
@@ -177,7 +173,7 @@ public abstract class UpgradeDataProvider<T extends IUpgradeBase, R extends Upgr
* @param serialise Augment the generated JSON with additional fields. * @param serialise Augment the generated JSON with additional fields.
* @param <R> The type of upgrade serialiser. * @param <R> The type of upgrade serialiser.
*/ */
public static record Upgrade<R extends UpgradeSerialiser<?, R>>( public record Upgrade<R extends UpgradeSerialiser<?>>(
ResourceLocation id, R serialiser, Consumer<JsonObject> serialise ResourceLocation id, R serialiser, Consumer<JsonObject> serialise
) )
{ {

View File

@@ -10,7 +10,6 @@ import dan200.computercraft.api.pocket.PocketUpgradeSerialiser;
import dan200.computercraft.api.turtle.TurtleUpgradeSerialiser; import dan200.computercraft.api.turtle.TurtleUpgradeSerialiser;
import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraftforge.registries.IForgeRegistryEntry;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
@@ -20,12 +19,11 @@ import javax.annotation.Nonnull;
* *
* However, it may sometimes be useful to implement this if you have some shared logic between upgrade types. * However, it may sometimes be useful to implement this if you have some shared logic between upgrade types.
* *
* @param <R> The serialiser for this upgrade category, either {@code TurtleUpgradeSerialiser<?>} or {@code PocketUpgradeSerialiser<?>}.
* @param <T> The upgrade that this class can serialise and deserialise. * @param <T> The upgrade that this class can serialise and deserialise.
* @see TurtleUpgradeSerialiser * @see TurtleUpgradeSerialiser
* @see PocketUpgradeSerialiser * @see PocketUpgradeSerialiser
*/ */
public interface UpgradeSerialiser<T extends IUpgradeBase, R extends UpgradeSerialiser<?, R>> extends IForgeRegistryEntry<R> public interface UpgradeSerialiser<T extends IUpgradeBase>
{ {
/** /**
* Read this upgrade from a JSON file in a datapack. * Read this upgrade from a JSON file in a datapack.

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

@@ -6,10 +6,13 @@
package dan200.computercraft.client; package dan200.computercraft.client;
import dan200.computercraft.ComputerCraft; import dan200.computercraft.ComputerCraft;
import dan200.computercraft.api.client.ComputerCraftAPIClient;
import dan200.computercraft.api.client.turtle.TurtleUpgradeModeller;
import dan200.computercraft.client.gui.*; import dan200.computercraft.client.gui.*;
import dan200.computercraft.client.render.TileEntityMonitorRenderer; import dan200.computercraft.client.render.TileEntityMonitorRenderer;
import dan200.computercraft.client.render.TileEntityTurtleRenderer; import dan200.computercraft.client.render.TileEntityTurtleRenderer;
import dan200.computercraft.client.render.TurtleModelLoader; import dan200.computercraft.client.render.TurtleModelLoader;
import dan200.computercraft.client.turtle.TurtleModemModeller;
import dan200.computercraft.shared.Registry; import dan200.computercraft.shared.Registry;
import dan200.computercraft.shared.common.IColouredItem; import dan200.computercraft.shared.common.IColouredItem;
import dan200.computercraft.shared.computer.inventory.ContainerComputerBase; import dan200.computercraft.shared.computer.inventory.ContainerComputerBase;
@@ -19,8 +22,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 +29,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 +68,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 +91,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:
@@ -114,7 +118,7 @@ public final class ClientRegistry
}, Registry.ModItems.POCKET_COMPUTER_NORMAL.get(), Registry.ModItems.POCKET_COMPUTER_ADVANCED.get() ); }, Registry.ModItems.POCKET_COMPUTER_NORMAL.get(), Registry.ModItems.POCKET_COMPUTER_ADVANCED.get() );
// Setup turtle colours // Setup turtle colours
event.getItemColors().register( event.register(
( stack, tintIndex ) -> tintIndex == 0 ? ((IColouredItem) stack.getItem()).getColour( stack ) : 0xFFFFFF, ( stack, tintIndex ) -> tintIndex == 0 ? ((IColouredItem) stack.getItem()).getColour( stack ) : 0xFFFFFF,
Registry.ModBlocks.TURTLE_NORMAL.get(), Registry.ModBlocks.TURTLE_ADVANCED.get() Registry.ModBlocks.TURTLE_NORMAL.get(), Registry.ModBlocks.TURTLE_ADVANCED.get()
); );
@@ -123,20 +127,24 @@ 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 );
BlockEntityRenderers.register( Registry.ModBlockEntities.TURTLE_NORMAL.get(), TileEntityTurtleRenderer::new ); BlockEntityRenderers.register( Registry.ModBlockEntities.TURTLE_NORMAL.get(), TileEntityTurtleRenderer::new );
BlockEntityRenderers.register( Registry.ModBlockEntities.TURTLE_ADVANCED.get(), TileEntityTurtleRenderer::new ); BlockEntityRenderers.register( Registry.ModBlockEntities.TURTLE_ADVANCED.get(), TileEntityTurtleRenderer::new );
ComputerCraftAPIClient.registerTurtleUpgradeModeller( Registry.ModTurtleSerialisers.SPEAKER.get(), TurtleUpgradeModeller.sided(
new ModelResourceLocation( "computercraft:turtle_speaker_upgrade_left", "inventory" ),
new ModelResourceLocation( "computercraft:turtle_speaker_upgrade_right", "inventory" )
) );
ComputerCraftAPIClient.registerTurtleUpgradeModeller( Registry.ModTurtleSerialisers.WORKBENCH.get(), TurtleUpgradeModeller.sided(
new ModelResourceLocation( "computercraft:turtle_crafting_table_left", "inventory" ),
new ModelResourceLocation( "computercraft:turtle_crafting_table_right", "inventory" )
) );
ComputerCraftAPIClient.registerTurtleUpgradeModeller( Registry.ModTurtleSerialisers.WIRELESS_MODEM_NORMAL.get(), new TurtleModemModeller( false ) );
ComputerCraftAPIClient.registerTurtleUpgradeModeller( Registry.ModTurtleSerialisers.WIRELESS_MODEM_ADVANCED.get(), new TurtleModemModeller( true ) );
ComputerCraftAPIClient.registerTurtleUpgradeModeller( Registry.ModTurtleSerialisers.TOOL.get(), TurtleUpgradeModeller.flatItem() );
event.enqueueWork( () -> { event.enqueueWork( () -> {
registerContainers(); registerContainers();

View File

@@ -8,8 +8,8 @@ package dan200.computercraft.client;
import dan200.computercraft.shared.command.text.ChatHelpers; import dan200.computercraft.shared.command.text.ChatHelpers;
import dan200.computercraft.shared.command.text.TableBuilder; import dan200.computercraft.shared.command.text.TableBuilder;
import dan200.computercraft.shared.command.text.TableFormatter; import dan200.computercraft.shared.command.text.TableFormatter;
import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
import net.minecraft.ChatFormatting; import net.minecraft.ChatFormatting;
import net.minecraft.client.GuiMessageTag;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.Font; import net.minecraft.client.gui.Font;
import net.minecraft.client.gui.components.ChatComponent; import net.minecraft.client.gui.components.ChatComponent;
@@ -18,13 +18,12 @@ import net.minecraft.util.Mth;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.util.Objects;
public class ClientTableFormatter implements TableFormatter public class ClientTableFormatter implements TableFormatter
{ {
public static final ClientTableFormatter INSTANCE = new ClientTableFormatter(); public static final ClientTableFormatter INSTANCE = new ClientTableFormatter();
private static final Int2IntOpenHashMap lastHeights = new Int2IntOpenHashMap();
private static Font renderer() private static Font renderer()
{ {
return Minecraft.getInstance().font; return Minecraft.getInstance().font;
@@ -59,7 +58,7 @@ public class ClientTableFormatter implements TableFormatter
} }
@Override @Override
public void writeLine( int id, Component component ) public void writeLine( String label, Component component )
{ {
Minecraft mc = Minecraft.getInstance(); Minecraft mc = Minecraft.getInstance();
ChatComponent chat = mc.gui.getChat(); ChatComponent chat = mc.gui.getChat();
@@ -68,20 +67,25 @@ public class ClientTableFormatter implements TableFormatter
// int maxWidth = MathHelper.floor( chat.getChatWidth() / chat.getScale() ); // int maxWidth = MathHelper.floor( chat.getChatWidth() / chat.getScale() );
// List<ITextProperties> list = RenderComponentsUtil.wrapComponents( component, maxWidth, mc.fontRenderer ); // List<ITextProperties> list = RenderComponentsUtil.wrapComponents( component, maxWidth, mc.fontRenderer );
// if( !list.isEmpty() ) chat.printChatMessageWithOptionalDeletion( list.get( 0 ), id ); // if( !list.isEmpty() ) chat.printChatMessageWithOptionalDeletion( list.get( 0 ), id );
chat.addMessage( component, id ); chat.addMessage( component, null, createTag( label ) );
} }
@Override @Override
public int display( TableBuilder table ) public void display( TableBuilder table )
{ {
ChatComponent chat = Minecraft.getInstance().gui.getChat(); ChatComponent chat = Minecraft.getInstance().gui.getChat();
int lastHeight = lastHeights.get( table.getId() ); var tag = createTag( table.getId() );
if( chat.allMessages.removeIf( guiMessage -> guiMessage.tag() != null && Objects.equals( guiMessage.tag().logTag(), tag.logTag() ) ) )
{
chat.refreshTrimmedMessage();
}
int height = TableFormatter.super.display( table ); TableFormatter.super.display( table );
lastHeights.put( table.getId(), height ); }
for( int i = height; i < lastHeight; i++ ) chat.removeById( i + table.getId() ); private static GuiMessageTag createTag( String id )
return height; {
return new GuiMessageTag( 0xa0a0a0, null, null, "ComputerCraft/" + id );
} }
} }

View File

@@ -0,0 +1,29 @@
/*
* 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;
import dan200.computercraft.api.client.ComputerCraftAPIClient;
import dan200.computercraft.api.client.turtle.TurtleUpgradeModeller;
import dan200.computercraft.api.turtle.ITurtleUpgrade;
import dan200.computercraft.api.turtle.TurtleUpgradeSerialiser;
import dan200.computercraft.client.turtle.TurtleUpgradeModellers;
import javax.annotation.Nonnull;
public final class ComputerCraftAPIClientImpl implements ComputerCraftAPIClient.IComputerCraftAPIClient
{
public static final ComputerCraftAPIClientImpl INSTANCE = new ComputerCraftAPIClientImpl();
private ComputerCraftAPIClientImpl()
{
}
@Override
public <T extends ITurtleUpgrade> void registerTurtleUpgradeModeller( @Nonnull TurtleUpgradeSerialiser<T> serialiser, @Nonnull TurtleUpgradeModeller<T> modeller )
{
TurtleUpgradeModellers.register( serialiser, modeller );
}
}

View File

@@ -20,7 +20,6 @@ import dan200.computercraft.shared.network.server.ContinueUploadMessage;
import dan200.computercraft.shared.network.server.UploadFileMessage; import dan200.computercraft.shared.network.server.UploadFileMessage;
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen; import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen;
import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.TranslatableComponent;
import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.entity.player.Inventory;
import org.lwjgl.glfw.GLFW; import org.lwjgl.glfw.GLFW;
@@ -37,9 +36,9 @@ import java.util.List;
public abstract class ComputerScreenBase<T extends ContainerComputerBase> extends AbstractContainerScreen<T> public abstract class ComputerScreenBase<T extends ContainerComputerBase> extends AbstractContainerScreen<T>
{ {
private static final Component OK = new TranslatableComponent( "gui.ok" ); private static final Component OK = Component.translatable( "gui.ok" );
private static final Component CANCEL = new TranslatableComponent( "gui.cancel" ); private static final Component CANCEL = Component.translatable( "gui.cancel" );
private static final Component OVERWRITE = new TranslatableComponent( "gui.computercraft.upload.overwrite_button" ); private static final Component OVERWRITE = Component.translatable( "gui.computercraft.upload.overwrite_button" );
protected WidgetTerminal terminal; protected WidgetTerminal terminal;
protected final ClientComputer computer; protected final ClientComputer computer;
@@ -158,7 +157,7 @@ public abstract class ComputerScreenBase<T extends ContainerComputerBase> extend
String name = file.getFileName().toString(); String name = file.getFileName().toString();
if( name.length() > UploadFileMessage.MAX_FILE_NAME ) if( name.length() > UploadFileMessage.MAX_FILE_NAME )
{ {
alert( UploadResult.FAILED_TITLE, new TranslatableComponent( "gui.computercraft.upload.failed.name_too_long" ) ); alert( UploadResult.FAILED_TITLE, Component.translatable( "gui.computercraft.upload.failed.name_too_long" ) );
return; return;
} }
@@ -169,7 +168,7 @@ public abstract class ComputerScreenBase<T extends ContainerComputerBase> extend
byte[] digest = FileUpload.getDigest( buffer ); byte[] digest = FileUpload.getDigest( buffer );
if( digest == null ) if( digest == null )
{ {
alert( UploadResult.FAILED_TITLE, new TranslatableComponent( "gui.computercraft.upload.failed.corrupted" ) ); alert( UploadResult.FAILED_TITLE, Component.translatable( "gui.computercraft.upload.failed.corrupted" ) );
return; return;
} }
@@ -178,13 +177,13 @@ public abstract class ComputerScreenBase<T extends ContainerComputerBase> extend
catch( IOException e ) catch( IOException e )
{ {
ComputerCraft.log.error( "Failed uploading files", e ); ComputerCraft.log.error( "Failed uploading files", e );
alert( UploadResult.FAILED_TITLE, new TranslatableComponent( "gui.computercraft.upload.failed.generic", "Cannot compute checksum" ) ); alert( UploadResult.FAILED_TITLE, Component.translatable( "gui.computercraft.upload.failed.generic", "Cannot compute checksum" ) );
} }
} }
if( toUpload.size() > UploadFileMessage.MAX_FILES ) if( toUpload.size() > UploadFileMessage.MAX_FILES )
{ {
alert( UploadResult.FAILED_TITLE, new TranslatableComponent( "gui.computercraft.upload.failed.too_many_files" ) ); alert( UploadResult.FAILED_TITLE, Component.translatable( "gui.computercraft.upload.failed.too_many_files" ) );
return; return;
} }

View File

@@ -15,7 +15,6 @@ import net.minecraft.client.gui.Font;
import net.minecraft.client.gui.screens.Screen; import net.minecraft.client.gui.screens.Screen;
import net.minecraft.client.gui.screens.inventory.MenuAccess; import net.minecraft.client.gui.screens.inventory.MenuAccess;
import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.TranslatableComponent;
import net.minecraft.util.FormattedCharSequence; import net.minecraft.util.FormattedCharSequence;
import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.entity.player.Inventory;
import org.lwjgl.glfw.GLFW; import org.lwjgl.glfw.GLFW;
@@ -112,7 +111,7 @@ public class NoTermComputerScreen<T extends ContainerComputerBase> extends Scree
super.render( transform, mouseX, mouseY, partialTicks ); super.render( transform, mouseX, mouseY, partialTicks );
Font font = minecraft.font; Font font = minecraft.font;
List<FormattedCharSequence> lines = font.split( new TranslatableComponent( "gui.computercraft.pocket_computer_overlay" ), (int) (width * 0.8) ); List<FormattedCharSequence> lines = font.split( Component.translatable( "gui.computercraft.pocket_computer_overlay" ), (int) (width * 0.8) );
float y = 10.0f; float y = 10.0f;
for( FormattedCharSequence line : lines ) for( FormattedCharSequence line : lines )
{ {

View File

@@ -12,7 +12,7 @@ import dan200.computercraft.shared.computer.core.ClientComputer;
import net.minecraft.ChatFormatting; import net.minecraft.ChatFormatting;
import net.minecraft.client.gui.components.AbstractWidget; import net.minecraft.client.gui.components.AbstractWidget;
import net.minecraft.client.gui.screens.Screen; import net.minecraft.client.gui.screens.Screen;
import net.minecraft.network.chat.TranslatableComponent; import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import java.util.Arrays; import java.util.Arrays;
@@ -53,11 +53,11 @@ public final class ComputerSidebar
screen, x, y, ICON_WIDTH, ICON_HEIGHT, () -> computer.isOn() ? 15 : 1, 1, ICON_TEX_Y_DIFF, screen, x, y, ICON_WIDTH, ICON_HEIGHT, () -> computer.isOn() ? 15 : 1, 1, ICON_TEX_Y_DIFF,
TEXTURE, TEX_SIZE, TEX_SIZE, b -> toggleComputer( computer ), TEXTURE, TEX_SIZE, TEX_SIZE, b -> toggleComputer( computer ),
() -> computer.isOn() ? Arrays.asList( () -> computer.isOn() ? Arrays.asList(
new TranslatableComponent( "gui.computercraft.tooltip.turn_off" ), Component.translatable( "gui.computercraft.tooltip.turn_off" ),
new TranslatableComponent( "gui.computercraft.tooltip.turn_off.key" ).withStyle( ChatFormatting.GRAY ) Component.translatable( "gui.computercraft.tooltip.turn_off.key" ).withStyle( ChatFormatting.GRAY )
) : Arrays.asList( ) : Arrays.asList(
new TranslatableComponent( "gui.computercraft.tooltip.turn_on" ), Component.translatable( "gui.computercraft.tooltip.turn_on" ),
new TranslatableComponent( "gui.computercraft.tooltip.turn_off.key" ).withStyle( ChatFormatting.GRAY ) Component.translatable( "gui.computercraft.tooltip.turn_off.key" ).withStyle( ChatFormatting.GRAY )
) )
) ); ) );
@@ -67,8 +67,8 @@ public final class ComputerSidebar
screen, x, y, ICON_WIDTH, ICON_HEIGHT, 29, 1, ICON_TEX_Y_DIFF, screen, x, y, ICON_WIDTH, ICON_HEIGHT, 29, 1, ICON_TEX_Y_DIFF,
TEXTURE, TEX_SIZE, TEX_SIZE, b -> computer.queueEvent( "terminate" ), TEXTURE, TEX_SIZE, TEX_SIZE, b -> computer.queueEvent( "terminate" ),
Arrays.asList( Arrays.asList(
new TranslatableComponent( "gui.computercraft.tooltip.terminate" ), Component.translatable( "gui.computercraft.tooltip.terminate" ),
new TranslatableComponent( "gui.computercraft.tooltip.terminate.key" ).withStyle( ChatFormatting.GRAY ) Component.translatable( "gui.computercraft.tooltip.terminate.key" ).withStyle( ChatFormatting.GRAY )
) )
) ); ) );
} }

View File

@@ -10,7 +10,6 @@ import com.mojang.blaze3d.vertex.PoseStack;
import net.minecraft.client.gui.components.Button; import net.minecraft.client.gui.components.Button;
import net.minecraft.client.gui.screens.Screen; import net.minecraft.client.gui.screens.Screen;
import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.TextComponent;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraftforge.common.util.NonNullSupplier; import net.minecraftforge.common.util.NonNullSupplier;
@@ -53,7 +52,7 @@ public class DynamicImageButton extends Button
OnPress onPress, NonNullSupplier<List<Component>> tooltip OnPress onPress, NonNullSupplier<List<Component>> tooltip
) )
{ {
super( x, y, width, height, TextComponent.EMPTY, onPress ); super( x, y, width, height, Component.empty(), onPress );
this.screen = screen; this.screen = screen;
this.textureWidth = textureWidth; this.textureWidth = textureWidth;
this.textureHeight = textureHeight; this.textureHeight = textureHeight;
@@ -84,7 +83,7 @@ public class DynamicImageButton extends Button
public Component getMessage() public Component getMessage()
{ {
List<Component> tooltip = this.tooltip.get(); List<Component> tooltip = this.tooltip.get();
return tooltip.isEmpty() ? TextComponent.EMPTY : tooltip.get( 0 ); return tooltip.isEmpty() ? Component.empty() : tooltip.get( 0 );
} }
@Override @Override

View File

@@ -17,7 +17,7 @@ import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.components.AbstractWidget; import net.minecraft.client.gui.components.AbstractWidget;
import net.minecraft.client.gui.narration.NarrationElementOutput; import net.minecraft.client.gui.narration.NarrationElementOutput;
import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.network.chat.TextComponent; import net.minecraft.network.chat.Component;
import org.lwjgl.glfw.GLFW; import org.lwjgl.glfw.GLFW;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
@@ -51,7 +51,7 @@ public class WidgetTerminal extends AbstractWidget
public WidgetTerminal( @Nonnull ClientComputer computer, int x, int y, int termWidth, int termHeight ) public WidgetTerminal( @Nonnull ClientComputer computer, int x, int y, int termWidth, int termHeight )
{ {
super( x, y, termWidth * FONT_WIDTH + MARGIN * 2, termHeight * FONT_HEIGHT + MARGIN * 2, TextComponent.EMPTY ); super( x, y, termWidth * FONT_WIDTH + MARGIN * 2, termHeight * FONT_HEIGHT + MARGIN * 2, Component.empty() );
this.computer = computer; this.computer = computer;

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

@@ -74,7 +74,7 @@ public abstract class ItemMapLikeRenderer
{ {
transform.pushPose(); transform.pushPose();
transform.mulPose( Vector3f.ZP.rotationDegrees( offset * 10f ) ); transform.mulPose( Vector3f.ZP.rotationDegrees( offset * 10f ) );
minecraft.getItemInHandRenderer().renderPlayerArm( transform, render, combinedLight, equipProgress, swingProgress, side ); minecraft.getEntityRenderDispatcher().getItemInHandRenderer().renderPlayerArm( transform, render, combinedLight, equipProgress, swingProgress, side );
transform.popPose(); transform.popPose();
} }
@@ -111,7 +111,7 @@ public abstract class ItemMapLikeRenderer
private void renderItemFirstPersonCenter( PoseStack transform, MultiBufferSource render, int combinedLight, float pitch, float equipProgress, float swingProgress, ItemStack stack ) private void renderItemFirstPersonCenter( PoseStack transform, MultiBufferSource render, int combinedLight, float pitch, float equipProgress, float swingProgress, ItemStack stack )
{ {
Minecraft minecraft = Minecraft.getInstance(); Minecraft minecraft = Minecraft.getInstance();
ItemInHandRenderer renderer = minecraft.getItemInHandRenderer(); ItemInHandRenderer renderer = minecraft.getEntityRenderDispatcher().getItemInHandRenderer();
// Setup the appropriate transformations. This is just copied from the // Setup the appropriate transformations. This is just copied from the
// corresponding method in ItemRenderer. // corresponding method in ItemRenderer.

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

@@ -12,6 +12,7 @@ import com.mojang.math.Vector3f;
import dan200.computercraft.api.client.TransformedModel; 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.client.turtle.TurtleUpgradeModellers;
import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.core.ComputerFamily;
import dan200.computercraft.shared.turtle.blocks.TileTurtle; import dan200.computercraft.shared.turtle.blocks.TileTurtle;
import dan200.computercraft.shared.util.DirectionUtil; import dan200.computercraft.shared.util.DirectionUtil;
@@ -30,14 +31,14 @@ 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.core.Direction;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
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;
import java.util.Random;
public class TileEntityTurtleRenderer implements BlockEntityRenderer<TileTurtle> public class TileEntityTurtleRenderer implements BlockEntityRenderer<TileTurtle>
{ {
@@ -46,7 +47,7 @@ public class TileEntityTurtleRenderer implements BlockEntityRenderer<TileTurtle>
private static final ModelResourceLocation COLOUR_TURTLE_MODEL = new ModelResourceLocation( "computercraft:turtle_colour", "inventory" ); private static final ModelResourceLocation COLOUR_TURTLE_MODEL = new ModelResourceLocation( "computercraft:turtle_colour", "inventory" );
private static final ModelResourceLocation ELF_OVERLAY_MODEL = new ModelResourceLocation( "computercraft:turtle_elf_overlay", "inventory" ); private static final ModelResourceLocation ELF_OVERLAY_MODEL = new ModelResourceLocation( "computercraft:turtle_elf_overlay", "inventory" );
private final Random random = new Random( 0 ); private final RandomSource random = RandomSource.create( 0 );
private final BlockEntityRenderDispatcher renderer; private final BlockEntityRenderDispatcher renderer;
@@ -148,7 +149,7 @@ public class TileEntityTurtleRenderer implements BlockEntityRenderer<TileTurtle>
transform.mulPose( Vector3f.XN.rotationDegrees( toolAngle ) ); transform.mulPose( Vector3f.XN.rotationDegrees( toolAngle ) );
transform.translate( 0.0f, -0.5f, -0.5f ); transform.translate( 0.0f, -0.5f, -0.5f );
TransformedModel model = upgrade.getModel( turtle.getAccess(), side ); TransformedModel model = TurtleUpgradeModellers.getModel( upgrade, turtle.getAccess(), side );
model.getMatrix().push( transform ); model.getMatrix().push( transform );
renderModel( transform, renderer, lightmapCoord, overlayLight, model.getModel(), null ); renderModel( transform, renderer, lightmapCoord, overlayLight, model.getModel(), null );
transform.popPose(); transform.popPose();
@@ -165,10 +166,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 +186,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.QuadTransformers;
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 : QuadTransformers.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,149 +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.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.*;
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 Random rand )
{
return getQuads( state, side, rand, EmptyModelData.INSTANCE );
}
@Nonnull
@Override
public List<BakedQuad> getQuads( BlockState state, Direction side, @Nonnull Random 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, Random 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,28 @@ 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.client.turtle.TurtleUpgradeModellers;
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.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.Random; 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 +42,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,112 +56,64 @@ 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
@Override
public BakedModel resolve( @Nonnull BakedModel originalModel, @Nonnull ItemStack stack, @Nullable ClientLevel world, @Nullable LivingEntity entity, int random )
{
ItemTurtle turtle = (ItemTurtle) stack.getItem();
int colour = turtle.getColour( stack );
ITurtleUpgrade leftUpgrade = turtle.getUpgrade( stack, TurtleSide.LEFT );
ITurtleUpgrade rightUpgrade = turtle.getUpgrade( stack, TurtleSide.RIGHT );
ResourceLocation overlay = turtle.getOverlay( stack );
boolean christmas = HolidayUtil.getCurrentHoliday() == Holiday.CHRISTMAS;
String label = turtle.getLabel( stack );
boolean flip = label != null && (label.equals( "Dinnerbone" ) || label.equals( "Grumm" ));
TurtleModelCombination combo = new TurtleModelCombination( colour != -1, leftUpgrade, rightUpgrade, overlay, christmas, flip );
BakedModel model = cachedModels.get( combo );
if( model == null ) cachedModels.put( combo, model = buildModel( combo ) );
return model;
}
};
} }
@Nonnull @Nonnull
@Override @Override
public ItemOverrides getOverrides() public BakedModel applyTransform( @Nonnull ItemTransforms.TransformType cameraTransformType, @Nonnull PoseStack poseStack, boolean applyLeftHandTransform )
{ {
return overrides; originalModel.applyTransform( cameraTransformType, poseStack, applyLeftHandTransform );
return this;
} }
private BakedModel buildModel( TurtleModelCombination combo ) @Nonnull
@Override
public List<BakedModel> getRenderPasses( ItemStack stack, boolean fabulous )
{
ItemTurtle turtle = (ItemTurtle) stack.getItem();
int colour = turtle.getColour( stack );
ITurtleUpgrade leftUpgrade = turtle.getUpgrade( stack, TurtleSide.LEFT );
ITurtleUpgrade rightUpgrade = turtle.getUpgrade( stack, TurtleSide.RIGHT );
ResourceLocation overlay = turtle.getOverlay( stack );
boolean christmas = HolidayUtil.getCurrentHoliday() == Holiday.CHRISTMAS;
String label = turtle.getLabel( stack );
boolean flip = label != null && (label.equals( "Dinnerbone" ) || label.equals( "Grumm" ));
TurtleModelCombination combo = new TurtleModelCombination( colour != -1, leftUpgrade, rightUpgrade, overlay, christmas, flip );
return cachedModels.computeIfAbsent( combo, this::buildModel );
}
private List<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; ModelResourceLocation overlayModelLocation = TileEntityTurtleRenderer.getTurtleOverlayModel( combo.overlay(), combo.christmas() );
return new TurtleMultiModel( baseModel, overlayModel, transform, leftModel, rightModel ); if( overlayModelLocation != null )
{
parts.add( new TransformedBakedModel( modelManager.getModel( overlayModelLocation ), transformation ) );
}
if( combo.leftUpgrade() != null )
{
parts.add( new TransformedBakedModel( TurtleUpgradeModellers.getModel( combo.leftUpgrade(), null, TurtleSide.LEFT ) ).composeWith( transformation ) );
}
if( combo.rightUpgrade() != null )
{
parts.add( new TransformedBakedModel( TurtleUpgradeModellers.getModel( combo.rightUpgrade(), null, TurtleSide.RIGHT ) ).composeWith( transformation ) );
}
return parts;
} }
@Nonnull
@Override
@Deprecated
public List<BakedQuad> getQuads( BlockState state, Direction facing, @Nonnull Random rand )
{
return familyModel.getQuads( state, facing, rand );
}
@Nonnull
@Override
@Deprecated
public List<BakedQuad> getQuads( BlockState state, Direction facing, @Nonnull Random rand, @Nonnull IModelData data )
{
return familyModel.getQuads( state, facing, rand, data );
}
@Override
public boolean useAmbientOcclusion()
{
return familyModel.useAmbientOcclusion();
}
@Override
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

@@ -9,6 +9,7 @@ import com.mojang.blaze3d.audio.Channel;
import dan200.computercraft.shared.peripheral.speaker.SpeakerPosition; import dan200.computercraft.shared.peripheral.speaker.SpeakerPosition;
import net.minecraft.client.resources.sounds.AbstractSoundInstance; import net.minecraft.client.resources.sounds.AbstractSoundInstance;
import net.minecraft.client.resources.sounds.Sound; import net.minecraft.client.resources.sounds.Sound;
import net.minecraft.client.resources.sounds.SoundInstance;
import net.minecraft.client.resources.sounds.TickableSoundInstance; import net.minecraft.client.resources.sounds.TickableSoundInstance;
import net.minecraft.client.sounds.AudioStream; import net.minecraft.client.sounds.AudioStream;
import net.minecraft.client.sounds.SoundBufferLibrary; import net.minecraft.client.sounds.SoundBufferLibrary;
@@ -32,7 +33,7 @@ public class SpeakerSound extends AbstractSoundInstance implements TickableSound
SpeakerSound( ResourceLocation sound, DfpwmStream stream, SpeakerPosition position, float volume, float pitch ) SpeakerSound( ResourceLocation sound, DfpwmStream stream, SpeakerPosition position, float volume, float pitch )
{ {
super( sound, SoundSource.RECORDS ); super( sound, SoundSource.RECORDS, SoundInstance.createUnseededRandom() );
setPosition( position ); setPosition( position );
this.stream = stream; this.stream = stream;
this.volume = volume; this.volume = volume;

View File

@@ -0,0 +1,59 @@
/*
* 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.turtle;
import dan200.computercraft.api.client.TransformedModel;
import dan200.computercraft.api.client.turtle.TurtleUpgradeModeller;
import dan200.computercraft.api.turtle.ITurtleAccess;
import dan200.computercraft.api.turtle.TurtleSide;
import dan200.computercraft.shared.turtle.upgrades.TurtleModem;
import net.minecraft.client.resources.model.ModelResourceLocation;
import net.minecraft.nbt.CompoundTag;
import org.jetbrains.annotations.Nullable;
import javax.annotation.Nonnull;
public class TurtleModemModeller implements TurtleUpgradeModeller<TurtleModem>
{
private final ModelResourceLocation leftOffModel;
private final ModelResourceLocation rightOffModel;
private final ModelResourceLocation leftOnModel;
private final ModelResourceLocation rightOnModel;
public TurtleModemModeller( boolean advanced )
{
if( advanced )
{
leftOffModel = new ModelResourceLocation( "computercraft:turtle_modem_advanced_off_left", "inventory" );
rightOffModel = new ModelResourceLocation( "computercraft:turtle_modem_advanced_off_right", "inventory" );
leftOnModel = new ModelResourceLocation( "computercraft:turtle_modem_advanced_on_left", "inventory" );
rightOnModel = new ModelResourceLocation( "computercraft:turtle_modem_advanced_on_right", "inventory" );
}
else
{
leftOffModel = new ModelResourceLocation( "computercraft:turtle_modem_normal_off_left", "inventory" );
rightOffModel = new ModelResourceLocation( "computercraft:turtle_modem_normal_off_right", "inventory" );
leftOnModel = new ModelResourceLocation( "computercraft:turtle_modem_normal_on_left", "inventory" );
rightOnModel = new ModelResourceLocation( "computercraft:turtle_modem_normal_on_right", "inventory" );
}
}
@Nonnull
@Override
public TransformedModel getModel( @Nonnull TurtleModem upgrade, @Nullable ITurtleAccess turtle, @Nonnull TurtleSide side )
{
boolean active = false;
if( turtle != null )
{
CompoundTag turtleNBT = turtle.getUpgradeNBTData( side );
active = turtleNBT.contains( "active" ) && turtleNBT.getBoolean( "active" );
}
return side == TurtleSide.LEFT
? TransformedModel.of( active ? leftOnModel : leftOffModel )
: TransformedModel.of( active ? rightOnModel : rightOffModel );
}
}

View File

@@ -0,0 +1,72 @@
/*
* 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.turtle;
import com.mojang.math.Transformation;
import dan200.computercraft.api.client.TransformedModel;
import dan200.computercraft.api.client.turtle.TurtleUpgradeModeller;
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.shared.TurtleUpgrades;
import dan200.computercraft.shared.UpgradeManager;
import net.minecraft.client.Minecraft;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.Map;
import java.util.WeakHashMap;
import java.util.concurrent.ConcurrentHashMap;
public final class TurtleUpgradeModellers
{
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<>();
/**
* In order to avoid a double lookup of {@link ITurtleUpgrade} to {@link UpgradeManager.UpgradeWrapper} to
* {@link TurtleUpgradeModeller}, we maintain a cache here.
* <p>
* Turtle upgrades may be removed as part of datapack reloads, so we use a weak map to avoid the memory leak.
*/
private static final WeakHashMap<ITurtleUpgrade, TurtleUpgradeModeller<?>> modelCache = new WeakHashMap<>();
private TurtleUpgradeModellers()
{
}
public static <T extends ITurtleUpgrade> void register( @Nonnull TurtleUpgradeSerialiser<T> serialiser, @Nonnull TurtleUpgradeModeller<T> modeller )
{
synchronized( turtleModels )
{
if( turtleModels.containsKey( serialiser ) )
{
throw new IllegalStateException( "Modeller already registered for serialiser" );
}
turtleModels.put( serialiser, modeller );
}
}
public static TransformedModel getModel( @Nonnull ITurtleUpgrade upgrade, @Nullable ITurtleAccess access, @Nonnull TurtleSide side )
{
@SuppressWarnings( "unchecked" )
var modeller = (TurtleUpgradeModeller<ITurtleUpgrade>) modelCache.computeIfAbsent( upgrade, TurtleUpgradeModellers::getModeller );
return modeller.getModel( upgrade, access, side );
}
private static TurtleUpgradeModeller<?> getModeller( ITurtleUpgrade upgradeA )
{
var wrapper = TurtleUpgrades.instance().getWrapper( upgradeA );
if( wrapper == null ) return NULL_TURTLE_MODELLER;
var modeller = turtleModels.get( wrapper.serialiser() );
return modeller == null ? NULL_TURTLE_MODELLER : modeller;
}
}

View File

@@ -12,6 +12,7 @@ import com.mojang.blaze3d.vertex.VertexFormat;
import com.mojang.math.Matrix4f; import com.mojang.math.Matrix4f;
import net.minecraft.client.renderer.ShaderInstance; import net.minecraft.client.renderer.ShaderInstance;
import org.lwjgl.opengl.GL15; import org.lwjgl.opengl.GL15;
import org.lwjgl.opengl.GL15C;
import org.lwjgl.opengl.GL45C; import org.lwjgl.opengl.GL45C;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
@@ -29,23 +30,39 @@ public class DirectVertexBuffer extends VertexBuffer
{ {
if( DirectBuffers.HAS_DSA ) if( DirectBuffers.HAS_DSA )
{ {
RenderSystem.glDeleteBuffers( vertextBufferId ); RenderSystem.glDeleteBuffers( vertexBufferId );
if( DirectBuffers.ON_LINUX ) BufferUploader.reset(); // See comment on DirectBuffers.deleteBuffer. if( DirectBuffers.ON_LINUX ) BufferUploader.reset(); // See comment on DirectBuffers.deleteBuffer.
vertextBufferId = GL45C.glCreateBuffers(); vertexBufferId = GL45C.glCreateBuffers();
} }
} }
public void upload( int vertexCount, VertexFormat.Mode mode, VertexFormat format, ByteBuffer buffer ) public void upload( int vertexCount, VertexFormat.Mode mode, VertexFormat format, ByteBuffer buffer )
{ {
RenderSystem.assertOnRenderThread(); bind();
DirectBuffers.setBufferData( GL15.GL_ARRAY_BUFFER, vertextBufferId, buffer, GL15.GL_STATIC_DRAW );
this.format = format;
this.mode = mode; this.mode = mode;
actualIndexCount = indexCount = mode.indexCount( vertexCount ); actualIndexCount = indexCount = mode.indexCount( vertexCount );
indexType = VertexFormat.IndexType.SHORT; indexType = VertexFormat.IndexType.SHORT;
sequentialIndices = true;
RenderSystem.assertOnRenderThread();
DirectBuffers.setBufferData( GL15.GL_ARRAY_BUFFER, vertexBufferId, buffer, GL15.GL_STATIC_DRAW );
if( format != this.format )
{
if( this.format != null ) this.format.clearBufferState();
this.format = format;
GL15C.glBindBuffer( GL15C.GL_ARRAY_BUFFER, vertexBufferId );
format.setupBufferState();
GL15C.glBindBuffer( GL15C.GL_ARRAY_BUFFER, 0 );
}
RenderSystem.AutoStorageIndexBuffer indexBuffer = RenderSystem.getSequentialBuffer( mode );
if( indexBuffer != sequentialIndices || !indexBuffer.hasStorage( indexCount ) )
{
indexBuffer.bind( indexCount );
sequentialIndices = indexBuffer;
}
} }
public void drawWithShader( Matrix4f modelView, Matrix4f projection, ShaderInstance shader, int indexCount ) public void drawWithShader( Matrix4f modelView, Matrix4f projection, ShaderInstance shader, int indexCount )

View File

@@ -14,7 +14,6 @@ import dan200.computercraft.core.apis.handles.ArrayByteChannel;
import dan200.computercraft.shared.util.IoUtil; import dan200.computercraft.shared.util.IoUtil;
import net.minecraft.ResourceLocationException; import net.minecraft.ResourceLocationException;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.packs.resources.PreparableReloadListener;
import net.minecraft.server.packs.resources.Resource; import net.minecraft.server.packs.resources.Resource;
import net.minecraft.server.packs.resources.ResourceManager; import net.minecraft.server.packs.resources.ResourceManager;
import net.minecraft.server.packs.resources.SimplePreparableReloadListener; import net.minecraft.server.packs.resources.SimplePreparableReloadListener;
@@ -22,7 +21,6 @@ import net.minecraft.util.profiling.ProfilerFiller;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.nio.channels.Channels; import java.nio.channels.Channels;
@@ -94,7 +92,7 @@ public final class ResourceMount implements IMount
String existingNamespace = null; String existingNamespace = null;
FileEntry newRoot = new FileEntry( new ResourceLocation( namespace, subPath ) ); FileEntry newRoot = new FileEntry( new ResourceLocation( namespace, subPath ) );
for( ResourceLocation file : manager.listResources( subPath, s -> true ) ) for( ResourceLocation file : manager.listResources( subPath, s -> true ).keySet() )
{ {
existingNamespace = file.getNamespace(); existingNamespace = file.getNamespace();
@@ -202,10 +200,11 @@ public final class ResourceMount implements IMount
byte[] contents = CONTENTS_CACHE.getIfPresent( file ); byte[] contents = CONTENTS_CACHE.getIfPresent( file );
if( contents != null ) return file.size = contents.length; if( contents != null ) return file.size = contents.length;
try Resource resource = manager.getResource( file.identifier ).orElse( null );
if( resource == null ) return file.size = 0;
try( InputStream s = resource.open() )
{ {
Resource resource = manager.getResource( file.identifier );
InputStream s = resource.getInputStream();
int total = 0, read = 0; int total = 0, read = 0;
do do
{ {
@@ -234,9 +233,10 @@ public final class ResourceMount implements IMount
byte[] contents = CONTENTS_CACHE.getIfPresent( file ); byte[] contents = CONTENTS_CACHE.getIfPresent( file );
if( contents != null ) return new ArrayByteChannel( contents ); if( contents != null ) return new ArrayByteChannel( contents );
try var resource = manager.getResource( file.identifier ).orElse( null );
if( resource != null )
{ {
InputStream stream = manager.getResource( file.identifier ).getInputStream(); InputStream stream = resource.open();
if( stream.available() > MAX_CACHED_SIZE ) return Channels.newChannel( stream ); if( stream.available() > MAX_CACHED_SIZE ) return Channels.newChannel( stream );
try try
@@ -251,9 +251,6 @@ public final class ResourceMount implements IMount
CONTENTS_CACHE.put( file, contents ); CONTENTS_CACHE.put( file, contents );
return new ArrayByteChannel( contents ); return new ArrayByteChannel( contents );
} }
catch( FileNotFoundException ignored )
{
}
} }
throw new IOException( "/" + path + ": No such file" ); throw new IOException( "/" + path + ": No such file" );

View File

@@ -17,10 +17,11 @@ import dan200.computercraft.shared.turtle.blocks.BlockTurtle;
import net.minecraft.core.Direction; import net.minecraft.core.Direction;
import net.minecraft.data.DataGenerator; import net.minecraft.data.DataGenerator;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.Item;
import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Block;
import net.minecraftforge.client.model.generators.*; import net.minecraftforge.client.model.generators.*;
import net.minecraftforge.common.data.ExistingFileHelper; import net.minecraftforge.common.data.ExistingFileHelper;
import net.minecraftforge.registries.IForgeRegistryEntry; import net.minecraftforge.registries.ForgeRegistries;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import java.util.Objects; import java.util.Objects;
@@ -206,7 +207,7 @@ class BlockModelProvider extends BlockStateProvider
for( MonitorEdgeState edge : BlockMonitor.STATE.getPossibleValues() ) for( MonitorEdgeState edge : BlockMonitor.STATE.getPossibleValues() )
{ {
String suffix = edge == MonitorEdgeState.NONE ? "" : "_" + edge.getSerializedName(); String suffix = edge == MonitorEdgeState.NONE ? "" : "_" + edge.getSerializedName();
ModelFile model = models().getBuilder( extend( block.getRegistryName(), suffix ) ); ModelFile model = models().getBuilder( extendedName( block, suffix ) );
for( Direction facing : BlockMonitor.FACING.getPossibleValues() ) for( Direction facing : BlockMonitor.FACING.getPossibleValues() )
{ {
@@ -260,20 +261,26 @@ class BlockModelProvider extends BlockStateProvider
private static ResourceLocation blockTexture( Block block, String suffix ) private static ResourceLocation blockTexture( Block block, String suffix )
{ {
ResourceLocation id = block.getRegistryName(); ResourceLocation id = ForgeRegistries.BLOCKS.getKey( block );
return new ResourceLocation( id.getNamespace(), "block/" + id.getPath() + suffix ); return new ResourceLocation( id.getNamespace(), "block/" + id.getPath() + suffix );
} }
@Nonnull @Nonnull
private String name( @Nonnull IForgeRegistryEntry<?> term ) private <T> String name( @Nonnull Block term )
{ {
return Objects.requireNonNull( term.getRegistryName() ).toString(); return Objects.requireNonNull( ForgeRegistries.BLOCKS.getKey( term ) ).toString();
} }
@Nonnull @Nonnull
private String extendedName( @Nonnull IForgeRegistryEntry<?> term, @Nonnull String suffix ) private <T> String name( @Nonnull Item term )
{ {
return extend( Objects.requireNonNull( term.getRegistryName() ), suffix ); return Objects.requireNonNull( ForgeRegistries.ITEMS.getKey( term ) ).toString();
}
@Nonnull
private String extendedName( @Nonnull Block term, @Nonnull String suffix )
{
return extend( Objects.requireNonNull( ForgeRegistries.BLOCKS.getKey( term ) ), suffix );
} }
@Nonnull @Nonnull

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
@@ -25,15 +25,15 @@ public class Generators
var turtleUpgrades = new TurtleUpgradeGenerator( generator ); var turtleUpgrades = new TurtleUpgradeGenerator( generator );
var pocketUpgrades = new PocketUpgradeGenerator( generator ); var pocketUpgrades = new PocketUpgradeGenerator( generator );
generator.addProvider( turtleUpgrades ); generator.addProvider( event.includeServer(), turtleUpgrades );
generator.addProvider( pocketUpgrades ); generator.addProvider( event.includeServer(), pocketUpgrades );
generator.addProvider( new RecipeGenerator( generator, turtleUpgrades, pocketUpgrades ) ); generator.addProvider( event.includeServer(), new RecipeGenerator( generator, turtleUpgrades, pocketUpgrades ) );
generator.addProvider( new LootTableGenerator( generator ) ); generator.addProvider( event.includeServer(), new LootTableGenerator( generator ) );
generator.addProvider( new BlockModelProvider( generator, existingFiles ) ); generator.addProvider( event.includeClient(), new BlockModelProvider( generator, existingFiles ) );
BlockTagsGenerator blockTags = new BlockTagsGenerator( generator, existingFiles ); BlockTagsGenerator blockTags = new BlockTagsGenerator( generator, existingFiles );
generator.addProvider( blockTags ); generator.addProvider( event.includeServer(), blockTags );
generator.addProvider( new ItemTagsGenerator( generator, blockTags, existingFiles ) ); generator.addProvider( event.includeServer(), new ItemTagsGenerator( generator, blockTags, existingFiles ) );
} }
} }

View File

@@ -9,9 +9,9 @@ import com.google.common.collect.Multimap;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.google.gson.GsonBuilder; import com.google.gson.GsonBuilder;
import dan200.computercraft.ComputerCraft; import dan200.computercraft.ComputerCraft;
import net.minecraft.data.CachedOutput;
import net.minecraft.data.DataGenerator; import net.minecraft.data.DataGenerator;
import net.minecraft.data.DataProvider; import net.minecraft.data.DataProvider;
import net.minecraft.data.HashCache;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.storage.loot.LootTable; import net.minecraft.world.level.storage.loot.LootTable;
import net.minecraft.world.level.storage.loot.LootTables; import net.minecraft.world.level.storage.loot.LootTables;
@@ -40,7 +40,7 @@ abstract class LootTableProvider implements DataProvider
} }
@Override @Override
public void run( @Nonnull HashCache cache ) public void run( @Nonnull CachedOutput cache )
{ {
Map<ResourceLocation, LootTable> tables = new HashMap<>(); Map<ResourceLocation, LootTable> tables = new HashMap<>();
ValidationContext validation = new ValidationContext( LootContextParamSets.ALL_PARAMS, x -> null, tables::get ); ValidationContext validation = new ValidationContext( LootContextParamSets.ALL_PARAMS, x -> null, tables::get );
@@ -64,7 +64,7 @@ abstract class LootTableProvider implements DataProvider
Path path = getPath( key ); Path path = getPath( key );
try try
{ {
DataProvider.save( GSON, cache, LootTables.serialize( value ), path ); DataProvider.saveStable( cache, LootTables.serialize( value ), path );
} }
catch( IOException e ) catch( IOException e )
{ {

View File

@@ -34,6 +34,7 @@ import net.minecraft.world.item.crafting.SimpleRecipeSerializer;
import net.minecraft.world.level.ItemLike; import net.minecraft.world.level.ItemLike;
import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.Blocks;
import net.minecraftforge.common.Tags; import net.minecraftforge.common.Tags;
import net.minecraftforge.registries.ForgeRegistries;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import java.util.Locale; import java.util.Locale;
@@ -393,6 +394,6 @@ class RecipeGenerator extends RecipeProvider
private static void addSpecial( Consumer<FinishedRecipe> add, SimpleRecipeSerializer<?> special ) private static void addSpecial( Consumer<FinishedRecipe> add, SimpleRecipeSerializer<?> special )
{ {
SpecialRecipeBuilder.special( special ).save( add, special.getRegistryName().toString() ); SpecialRecipeBuilder.special( special ).save( add, ForgeRegistries.RECIPE_SERIALIZERS.getKey( special ).toString() );
} }
} }

View File

@@ -12,7 +12,6 @@ import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraft.util.GsonHelper; import net.minecraft.util.GsonHelper;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
import net.minecraftforge.registries.ForgeRegistryEntry;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import java.util.function.BiFunction; import java.util.function.BiFunction;
@@ -22,10 +21,9 @@ import java.util.function.BiFunction;
* *
* Do <strong>NOT</strong> directly reference this class. It exists for internal use by the API. * Do <strong>NOT</strong> directly reference this class. It exists for internal use by the API.
* *
* @param <R> The serialiser for this upgrade category, either {@code TurtleUpgradeSerialiser<?>} or {@code PocketUpgradeSerialiser<?>}.
* @param <T> The upgrade that this class can serialise and deserialise. * @param <T> The upgrade that this class can serialise and deserialise.
*/ */
public abstract class SerialiserWithCraftingItem<T extends IUpgradeBase, R extends UpgradeSerialiser<?, R>> extends ForgeRegistryEntry<R> implements UpgradeSerialiser<T, R> public abstract class SerialiserWithCraftingItem<T extends IUpgradeBase> implements UpgradeSerialiser<T>
{ {
private final BiFunction<ResourceLocation, ItemStack, T> factory; private final BiFunction<ResourceLocation, ItemStack, T> factory;

View File

@@ -10,7 +10,6 @@ import dan200.computercraft.api.upgrades.IUpgradeBase;
import dan200.computercraft.api.upgrades.UpgradeSerialiser; import dan200.computercraft.api.upgrades.UpgradeSerialiser;
import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraftforge.registries.ForgeRegistryEntry;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import java.util.function.Function; import java.util.function.Function;
@@ -20,10 +19,9 @@ import java.util.function.Function;
* *
* Do <strong>NOT</strong> directly reference this class. It exists for internal use by the API. * Do <strong>NOT</strong> directly reference this class. It exists for internal use by the API.
* *
* @param <R> The serialiser for this upgrade category, either {@code TurtleUpgradeSerialiser<?>} or {@code PocketUpgradeSerialiser<?>}.
* @param <T> The upgrade that this class can serialise and deserialise. * @param <T> The upgrade that this class can serialise and deserialise.
*/ */
public abstract class SimpleSerialiser<T extends IUpgradeBase, R extends UpgradeSerialiser<?, R>> extends ForgeRegistryEntry<R> implements UpgradeSerialiser<T, R> public abstract class SimpleSerialiser<T extends IUpgradeBase> implements UpgradeSerialiser<T>
{ {
private final Function<ResourceLocation, T> constructor; private final Function<ResourceLocation, T> constructor;

View File

@@ -19,49 +19,47 @@ import net.minecraft.client.renderer.block.ModelBlockRenderer;
import net.minecraft.client.renderer.texture.OverlayTexture; import net.minecraft.client.renderer.texture.OverlayTexture;
import net.minecraft.client.resources.model.BakedModel; import net.minecraft.client.resources.model.BakedModel;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.util.RandomSource;
import net.minecraft.world.level.BlockAndTintGetter; 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.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.util.Random;
/** /**
* 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
{ {
@Shadow @Shadow
private final Random random; @Final
@Shadow private RandomSource random;
private final BlockModelShaper blockModelShaper;
@Shadow
private final ModelBlockRenderer modelRenderer;
public BlockRenderDispatcherMixin( Random random, BlockModelShaper blockModelShaper, ModelBlockRenderer modelRenderer ) @Shadow
{ @Final
this.random = random; private BlockModelShaper blockModelShaper;
this.blockModelShaper = blockModelShaper;
this.modelRenderer = modelRenderer; @Shadow
} @Final
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
) )
{ {
@@ -87,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

@@ -21,7 +21,6 @@ import dan200.computercraft.shared.peripheral.modem.wireless.WirelessNetwork;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.MinecraftServer; import net.minecraft.server.MinecraftServer;
import net.minecraft.server.dedicated.DedicatedServer; import net.minecraft.server.dedicated.DedicatedServer;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.inventory.AbstractContainerMenu; import net.minecraft.world.inventory.AbstractContainerMenu;
import net.minecraft.world.level.storage.loot.BuiltInLootTables; import net.minecraft.world.level.storage.loot.BuiltInLootTables;
import net.minecraft.world.level.storage.loot.LootPool; import net.minecraft.world.level.storage.loot.LootPool;
@@ -33,6 +32,8 @@ import net.minecraftforge.event.server.ServerStartingEvent;
import net.minecraftforge.event.server.ServerStoppedEvent; import net.minecraftforge.event.server.ServerStoppedEvent;
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.registries.ForgeRegistries;
import net.minecraftforge.registries.MissingMappingsEvent;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashSet; import java.util.HashSet;
@@ -72,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() );
} }
} }
} }
@@ -162,12 +163,12 @@ public final class CommonHooks
} }
@SubscribeEvent @SubscribeEvent
public static void onMissingEntityMappingsEvent( RegistryEvent.MissingMappings<EntityType<?>> event ) public static void onMissingEntityMappingsEvent( MissingMappingsEvent event )
{ {
ResourceLocation id = new ResourceLocation( ComputerCraft.MOD_ID, "turtle_player" ); ResourceLocation id = new ResourceLocation( ComputerCraft.MOD_ID, "turtle_player" );
for( RegistryEvent.MissingMappings.Mapping<EntityType<?>> mapping : event.getMappings( ComputerCraft.MOD_ID ) ) for( var mapping : event.getMappings( ForgeRegistries.BLOCKS.getRegistryKey(), ComputerCraft.MOD_ID ) )
{ {
if( mapping.key.equals( id ) ) mapping.ignore(); if( mapping.getKey().equals( id ) ) mapping.ignore();
} }
} }
} }

View File

@@ -5,11 +5,7 @@
*/ */
package dan200.computercraft.shared; package dan200.computercraft.shared;
import com.electronwill.nightconfig.core.CommentedConfig;
import com.electronwill.nightconfig.core.UnmodifiableConfig; import com.electronwill.nightconfig.core.UnmodifiableConfig;
import com.electronwill.nightconfig.core.file.CommentedFileConfig;
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;
@@ -291,7 +287,7 @@ public final class Config
ModLoadingContext.get().registerConfig( ModConfig.Type.CLIENT, clientSpec ); ModLoadingContext.get().registerConfig( ModConfig.Type.CLIENT, clientSpec );
} }
public static void sync() private static void syncServer()
{ {
// General // General
ComputerCraft.computerSpaceLimit = computerSpaceLimit.get(); ComputerCraft.computerSpaceLimit = computerSpaceLimit.get();
@@ -343,27 +339,30 @@ public final class Config
ComputerCraft.pocketTermHeight = pocketTermHeight.get(); ComputerCraft.pocketTermHeight = pocketTermHeight.get();
ComputerCraft.monitorWidth = monitorWidth.get(); ComputerCraft.monitorWidth = monitorWidth.get();
ComputerCraft.monitorHeight = monitorHeight.get(); ComputerCraft.monitorHeight = monitorHeight.get();
}
// Client private static void syncClient()
{
ComputerCraft.monitorRenderer = monitorRenderer.get(); ComputerCraft.monitorRenderer = monitorRenderer.get();
ComputerCraft.monitorDistance = monitorDistance.get(); ComputerCraft.monitorDistance = monitorDistance.get();
} }
private static void sync( ModConfig config )
{
if( !config.getModId().equals( ComputerCraft.MOD_ID ) ) return;
if( config.getType() == ModConfig.Type.SERVER ) syncServer();
if( config.getType() == ModConfig.Type.CLIENT ) syncClient();
}
@SubscribeEvent @SubscribeEvent
public static void sync( ModConfigEvent.Loading event ) public static void sync( ModConfigEvent.Loading event )
{ {
sync(); sync( event.getConfig() );
} }
@SubscribeEvent @SubscribeEvent
public static void sync( ModConfigEvent.Reloading event ) public static void sync( ModConfigEvent.Reloading event )
{ {
// Ensure file configs are reloaded. Forge should probably do this, so worth checking in the future. sync( event.getConfig() );
CommentedConfig config = event.getConfig().getConfigData();
if( config instanceof CommentedFileConfig loadable ) loadable.load();
sync();
} }
private static final Converter<String, String> converter = CaseFormat.LOWER_CAMEL.converterTo( CaseFormat.UPPER_UNDERSCORE );
} }

View File

@@ -5,6 +5,7 @@
*/ */
package dan200.computercraft.shared; package dan200.computercraft.shared;
import com.mojang.brigadier.arguments.ArgumentType;
import dan200.computercraft.ComputerCraft; import dan200.computercraft.ComputerCraft;
import dan200.computercraft.api.ComputerCraftAPI; import dan200.computercraft.api.ComputerCraftAPI;
import dan200.computercraft.api.media.IMedia; import dan200.computercraft.api.media.IMedia;
@@ -12,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.ArgumentSerializers; 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;
@@ -70,6 +74,9 @@ import dan200.computercraft.shared.util.CreativeTabMain;
import dan200.computercraft.shared.util.FixedPointTileEntityType; import dan200.computercraft.shared.util.FixedPointTileEntityType;
import dan200.computercraft.shared.util.ImpostorRecipe; import dan200.computercraft.shared.util.ImpostorRecipe;
import dan200.computercraft.shared.util.ImpostorShapelessRecipe; import dan200.computercraft.shared.util.ImpostorShapelessRecipe;
import net.minecraft.commands.synchronization.ArgumentTypeInfo;
import net.minecraft.commands.synchronization.ArgumentTypeInfos;
import net.minecraft.commands.synchronization.SingletonArgumentInfo;
import net.minecraft.core.cauldron.CauldronInteraction; import net.minecraft.core.cauldron.CauldronInteraction;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.inventory.MenuType; import net.minecraft.world.inventory.MenuType;
@@ -77,7 +84,6 @@ import net.minecraft.world.item.BlockItem;
import net.minecraft.world.item.CreativeModeTab; import net.minecraft.world.item.CreativeModeTab;
import net.minecraft.world.item.Item; import net.minecraft.world.item.Item;
import net.minecraft.world.item.RecordItem; import net.minecraft.world.item.RecordItem;
import net.minecraft.world.item.crafting.RecipeSerializer;
import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.entity.BlockEntityType;
@@ -86,7 +92,6 @@ import net.minecraft.world.level.material.Material;
import net.minecraft.world.level.storage.loot.predicates.LootItemConditionType; import net.minecraft.world.level.storage.loot.predicates.LootItemConditionType;
import net.minecraftforge.common.capabilities.RegisterCapabilitiesEvent; import net.minecraftforge.common.capabilities.RegisterCapabilitiesEvent;
import net.minecraftforge.energy.CapabilityEnergy; import net.minecraftforge.energy.CapabilityEnergy;
import net.minecraftforge.event.RegistryEvent;
import net.minecraftforge.eventbus.api.IEventBus; import net.minecraftforge.eventbus.api.IEventBus;
import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fluids.capability.CapabilityFluidHandler; import net.minecraftforge.fluids.capability.CapabilityFluidHandler;
@@ -162,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 )
{ {
@@ -281,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 ) );
@@ -308,38 +313,62 @@ public final class Registry
() -> ContainerData.toType( ViewComputerContainerData::new, ContainerViewComputer::new ) ); () -> ContainerData.toType( ViewComputerContainerData::new, ContainerViewComputer::new ) );
} }
static class ModArgumentTypes
{
static final DeferredRegister<ArgumentTypeInfo<?, ?>> ARGUMENT_TYPES = DeferredRegister.create( net.minecraft.core.Registry.COMMAND_ARGUMENT_TYPE_REGISTRY, ComputerCraft.MOD_ID );
@SuppressWarnings( "unchecked" )
private static <T extends ArgumentType<?>> void registerUnsafe( String name, Class<T> type, ArgumentTypeInfo<?, ?> 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 )
{
ARGUMENT_TYPES.register( name, () -> ArgumentTypeInfos.registerByClass( type, serializer ) );
}
private static <T extends ArgumentType<?>> void register( String name, Class<T> type, T instance )
{
register( name, type, SingletonArgumentInfo.contextFree( () -> instance ) );
}
static
{
register( "tracking_field", TrackingFieldArgumentType.class, TrackingFieldArgumentType.trackingField() );
register( "computer", ComputerArgumentType.class, ComputerArgumentType.oneComputer() );
register( "computers", ComputersArgumentType.class, new ComputersArgumentType.Info() );
registerUnsafe( "repeat", RepeatArgumentType.class, new RepeatArgumentType.Info() );
}
}
@SubscribeEvent @SubscribeEvent
public static void registerRegistries( NewRegistryEvent event ) public static void registerRegistries( NewRegistryEvent event )
{ {
@SuppressWarnings( "unchecked" )
Class<TurtleUpgradeSerialiser<?>> turtleType = (Class<TurtleUpgradeSerialiser<?>>) (Class<?>) TurtleUpgradeSerialiser.class;
event.create( new RegistryBuilder<TurtleUpgradeSerialiser<?>>() event.create( new RegistryBuilder<TurtleUpgradeSerialiser<?>>()
.setName( TurtleUpgradeSerialiser.REGISTRY_ID.location() ) .setName( TurtleUpgradeSerialiser.REGISTRY_ID.location() )
.setType( turtleType )
.disableSaving().disableSync() ); .disableSaving().disableSync() );
@SuppressWarnings( "unchecked" )
Class<PocketUpgradeSerialiser<?>> pocketType = (Class<PocketUpgradeSerialiser<?>>) (Class<?>) PocketUpgradeSerialiser.class;
event.create( new RegistryBuilder<PocketUpgradeSerialiser<?>>() event.create( new RegistryBuilder<PocketUpgradeSerialiser<?>>()
.setName( PocketUpgradeSerialiser.REGISTRY_ID.location() ) .setName( PocketUpgradeSerialiser.REGISTRY_ID.location() )
.setType( pocketType )
.disableSaving().disableSync() ); .disableSaving().disableSync() );
} }
@SubscribeEvent @SubscribeEvent
public static void registerRecipeSerializers( RegistryEvent.Register<RecipeSerializer<?>> event ) public static void registerRecipeSerializers( RegisterEvent event )
{ {
event.getRegistry().registerAll( event.register( ForgeRegistries.RECIPE_SERIALIZERS.getRegistryKey(), registry -> {
ColourableRecipe.SERIALIZER.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "colour" ) ), registry.register( new ResourceLocation( ComputerCraft.MOD_ID, "colour" ), ColourableRecipe.SERIALIZER );
ComputerUpgradeRecipe.SERIALIZER.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "computer_upgrade" ) ), registry.register( new ResourceLocation( ComputerCraft.MOD_ID, "computer_upgrade" ), ComputerUpgradeRecipe.SERIALIZER );
PocketComputerUpgradeRecipe.SERIALIZER.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "pocket_computer_upgrade" ) ), registry.register( new ResourceLocation( ComputerCraft.MOD_ID, "pocket_computer_upgrade" ), PocketComputerUpgradeRecipe.SERIALIZER );
DiskRecipe.SERIALIZER.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "disk" ) ), registry.register( new ResourceLocation( ComputerCraft.MOD_ID, "disk" ), DiskRecipe.SERIALIZER );
PrintoutRecipe.SERIALIZER.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "printout" ) ), registry.register( new ResourceLocation( ComputerCraft.MOD_ID, "printout" ), PrintoutRecipe.SERIALIZER );
TurtleRecipe.SERIALIZER.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "turtle" ) ), registry.register( new ResourceLocation( ComputerCraft.MOD_ID, "turtle" ), TurtleRecipe.SERIALIZER );
TurtleUpgradeRecipe.SERIALIZER.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "turtle_upgrade" ) ), registry.register( new ResourceLocation( ComputerCraft.MOD_ID, "turtle_upgrade" ), TurtleUpgradeRecipe.SERIALIZER );
ImpostorShapelessRecipe.SERIALIZER.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "impostor_shapeless" ) ), registry.register( new ResourceLocation( ComputerCraft.MOD_ID, "impostor_shapeless" ), ImpostorShapelessRecipe.SERIALIZER );
ImpostorRecipe.SERIALIZER.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "impostor_shaped" ) ) registry.register( new ResourceLocation( ComputerCraft.MOD_ID, "impostor_shaped" ), ImpostorRecipe.SERIALIZER );
); } );
} }
@SubscribeEvent @SubscribeEvent
@@ -356,7 +385,6 @@ public final class Registry
event.enqueueWork( () -> { event.enqueueWork( () -> {
registerProviders(); registerProviders();
ArgumentSerializers.register();
registerLoot(); registerLoot();
} ); } );
@@ -412,5 +440,6 @@ public final class Registry
ModTurtleSerialisers.SERIALISERS.register( bus ); ModTurtleSerialisers.SERIALISERS.register( bus );
ModPocketUpgradeSerialisers.SERIALISERS.register( bus ); ModPocketUpgradeSerialisers.SERIALISERS.register( bus );
ModContainers.CONTAINERS.register( bus ); ModContainers.CONTAINERS.register( bus );
ModArgumentTypes.ARGUMENT_TYPES.register( bus );
} }
} }

View File

@@ -37,12 +37,12 @@ import java.util.stream.Collectors;
* @see TurtleUpgrades * @see TurtleUpgrades
* @see PocketUpgrades * @see PocketUpgrades
*/ */
public class UpgradeManager<R extends UpgradeSerialiser<? extends T, R>, T extends IUpgradeBase> extends SimpleJsonResourceReloadListener public class UpgradeManager<R extends UpgradeSerialiser<? extends T>, T extends IUpgradeBase> extends SimpleJsonResourceReloadListener
{ {
private static final Logger LOGGER = LogManager.getLogger(); private static final Logger LOGGER = LogManager.getLogger();
private static final Gson GSON = (new GsonBuilder()).setPrettyPrinting().disableHtmlEscaping().create(); private static final Gson GSON = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create();
public static record UpgradeWrapper<R extends UpgradeSerialiser<? extends T, R>, T extends IUpgradeBase>( public record UpgradeWrapper<R extends UpgradeSerialiser<? extends T>, T extends IUpgradeBase>(
@Nonnull String id, @Nonnull T upgrade, @Nonnull R serialiser, @Nonnull String modId @Nonnull String id, @Nonnull T upgrade, @Nonnull R serialiser, @Nonnull String modId
) {} ) {}
@@ -66,6 +66,12 @@ public class UpgradeManager<R extends UpgradeSerialiser<? extends T, R>, T exten
return wrapper == null ? null : wrapper.upgrade(); return wrapper == null ? null : wrapper.upgrade();
} }
@Nullable
public UpgradeWrapper<R, T> getWrapper( @Nonnull T upgrade )
{
return currentWrappers.get( upgrade );
}
@Nullable @Nullable
public String getOwner( @Nonnull T upgrade ) public String getOwner( @Nonnull T upgrade )
{ {

View File

@@ -26,8 +26,6 @@ import net.minecraft.commands.CommandSourceStack;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.MutableComponent; import net.minecraft.network.chat.MutableComponent;
import net.minecraft.network.chat.TextComponent;
import net.minecraft.network.chat.TranslatableComponent;
import net.minecraft.network.protocol.game.ClientboundPlayerPositionPacket; import net.minecraft.network.protocol.game.ClientboundPlayerPositionPacket;
import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.level.ServerPlayer;
@@ -58,10 +56,6 @@ public final class CommandComputerCraft
{ {
public static final UUID SYSTEM_UUID = new UUID( 0, 0 ); public static final UUID SYSTEM_UUID = new UUID( 0, 0 );
private static final int DUMP_LIST_ID = 5373952;
private static final int DUMP_SINGLE_ID = 1844510720;
private static final int TRACK_ID = 373882880;
private CommandComputerCraft() private CommandComputerCraft()
{ {
} }
@@ -72,7 +66,7 @@ public final class CommandComputerCraft
.then( literal( "dump" ) .then( literal( "dump" )
.requires( UserLevel.OWNER_OP ) .requires( UserLevel.OWNER_OP )
.executes( context -> { .executes( context -> {
TableBuilder table = new TableBuilder( DUMP_LIST_ID, "Computer", "On", "Position" ); TableBuilder table = new TableBuilder( "DumpAll", "Computer", "On", "Position" );
CommandSourceStack source = context.getSource(); CommandSourceStack source = context.getSource();
List<ServerComputer> computers = new ArrayList<>( ComputerCraft.serverComputerRegistry.getComputers() ); List<ServerComputer> computers = new ArrayList<>( ComputerCraft.serverComputerRegistry.getComputers() );
@@ -117,7 +111,7 @@ public final class CommandComputerCraft
.executes( context -> { .executes( context -> {
ServerComputer computer = getComputerArgument( context, "computer" ); ServerComputer computer = getComputerArgument( context, "computer" );
TableBuilder table = new TableBuilder( DUMP_SINGLE_ID ); TableBuilder table = new TableBuilder( "Dump" );
table.row( header( "Instance" ), text( Integer.toString( computer.getInstanceID() ) ) ); table.row( header( "Instance" ), text( Integer.toString( computer.getInstanceID() ) ) );
table.row( header( "Id" ), text( Integer.toString( computer.getID() ) ) ); table.row( header( "Id" ), text( Integer.toString( computer.getID() ) ) );
table.row( header( "Label" ), text( computer.getLabel() ) ); table.row( header( "Label" ), text( computer.getLabel() ) );
@@ -231,7 +225,7 @@ public final class CommandComputerCraft
@Override @Override
public Component getDisplayName() public Component getDisplayName()
{ {
return new TranslatableComponent( "gui.computercraft.view_computer" ); return Component.translatable( "gui.computercraft.view_computer" );
} }
@Nonnull @Nonnull
@@ -287,7 +281,7 @@ public final class CommandComputerCraft
private static Component linkComputer( CommandSourceStack source, ServerComputer serverComputer, int computerId ) private static Component linkComputer( CommandSourceStack source, ServerComputer serverComputer, int computerId )
{ {
MutableComponent out = new TextComponent( "" ); MutableComponent out = Component.literal( "" );
// Append the computer instance // Append the computer instance
if( serverComputer == null ) if( serverComputer == null )
@@ -394,7 +388,7 @@ public final class CommandComputerCraft
Component[] headers = new Component[1 + fields.size()]; Component[] headers = new Component[1 + fields.size()];
headers[0] = translate( "commands.computercraft.track.dump.computer" ); headers[0] = translate( "commands.computercraft.track.dump.computer" );
for( int i = 0; i < fields.size(); i++ ) headers[i + 1] = translate( fields.get( i ).translationKey() ); for( int i = 0; i < fields.size(); i++ ) headers[i + 1] = translate( fields.get( i ).translationKey() );
TableBuilder table = new TableBuilder( TRACK_ID, headers ); TableBuilder table = new TableBuilder( "Metrics", headers );
for( ComputerTracker entry : timings ) for( ComputerTracker entry : timings )
{ {

View File

@@ -8,7 +8,7 @@ package dan200.computercraft.shared.command;
import com.mojang.brigadier.exceptions.Dynamic2CommandExceptionType; import com.mojang.brigadier.exceptions.Dynamic2CommandExceptionType;
import com.mojang.brigadier.exceptions.DynamicCommandExceptionType; import com.mojang.brigadier.exceptions.DynamicCommandExceptionType;
import com.mojang.brigadier.exceptions.SimpleCommandExceptionType; import com.mojang.brigadier.exceptions.SimpleCommandExceptionType;
import net.minecraft.network.chat.TranslatableComponent; import net.minecraft.network.chat.Component;
public final class Exceptions public final class Exceptions
{ {
@@ -27,16 +27,16 @@ public final class Exceptions
private static SimpleCommandExceptionType translated( String key ) private static SimpleCommandExceptionType translated( String key )
{ {
return new SimpleCommandExceptionType( new TranslatableComponent( key ) ); return new SimpleCommandExceptionType( Component.translatable( key ) );
} }
private static DynamicCommandExceptionType translated1( String key ) private static DynamicCommandExceptionType translated1( String key )
{ {
return new DynamicCommandExceptionType( x -> new TranslatableComponent( key, x ) ); return new DynamicCommandExceptionType( x -> Component.translatable( key, x ) );
} }
private static Dynamic2CommandExceptionType translated2( String key ) private static Dynamic2CommandExceptionType translated2( String key )
{ {
return new Dynamic2CommandExceptionType( ( x, y ) -> new TranslatableComponent( key, x, y ) ); return new Dynamic2CommandExceptionType( ( x, y ) -> Component.translatable( key, x, y ) );
} }
} }

View File

@@ -1,40 +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.shared.command.arguments;
import com.mojang.brigadier.arguments.ArgumentType;
import dan200.computercraft.ComputerCraft;
import net.minecraft.commands.synchronization.ArgumentSerializer;
import net.minecraft.commands.synchronization.ArgumentTypes;
import net.minecraft.commands.synchronization.EmptyArgumentSerializer;
import net.minecraft.resources.ResourceLocation;
public final class ArgumentSerializers
{
@SuppressWarnings( "unchecked" )
private static <T extends ArgumentType<?>> void registerUnsafe( ResourceLocation id, Class<T> type, ArgumentSerializer<?> serializer )
{
ArgumentTypes.register( id.toString(), type, (ArgumentSerializer<T>) serializer );
}
private static <T extends ArgumentType<?>> void register( ResourceLocation id, Class<T> type, ArgumentSerializer<T> serializer )
{
ArgumentTypes.register( id.toString(), type, serializer );
}
private static <T extends ArgumentType<?>> void register( ResourceLocation id, T instance )
{
registerUnsafe( id, instance.getClass(), new EmptyArgumentSerializer<>( () -> instance ) );
}
public static void register()
{
register( new ResourceLocation( ComputerCraft.MOD_ID, "tracking_field" ), TrackingFieldArgumentType.trackingField() );
register( new ResourceLocation( ComputerCraft.MOD_ID, "computer" ), ComputerArgumentType.oneComputer() );
register( new ResourceLocation( ComputerCraft.MOD_ID, "computers" ), ComputersArgumentType.class, new ComputersArgumentType.Serializer() );
registerUnsafe( new ResourceLocation( ComputerCraft.MOD_ID, "repeat" ), RepeatArgumentType.class, new RepeatArgumentType.Serializer() );
}
}

View File

@@ -0,0 +1,73 @@
/*
* 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.shared.command.arguments;
import com.google.gson.JsonObject;
import com.mojang.brigadier.Message;
import com.mojang.brigadier.arguments.ArgumentType;
import com.mojang.brigadier.exceptions.SimpleCommandExceptionType;
import net.minecraft.commands.synchronization.ArgumentTypeInfo;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.chat.Component;
import net.minecraftforge.registries.ForgeRegistries;
import java.util.Objects;
/**
* Utilities for working with arguments.
*
* @see net.minecraft.commands.synchronization.ArgumentUtils
*/
public class ArgumentUtils
{
public static <A extends ArgumentType<?>> JsonObject serializeToJson( ArgumentTypeInfo.Template<A> template )
{
JsonObject object = new JsonObject();
object.addProperty( "type", "argument" );
object.addProperty( "parser", ForgeRegistries.COMMAND_ARGUMENT_TYPES.getKey( template.type() ).toString() );
var properties = new JsonObject();
serializeToJson( properties, template.type(), template );
if( properties.size() > 0 ) object.add( "properties", properties );
return object;
}
@SuppressWarnings( "unchecked" )
private static <A extends ArgumentType<?>, T extends ArgumentTypeInfo.Template<A>> void serializeToJson( JsonObject jsonObject, ArgumentTypeInfo<A, T> argumentTypeInfo, ArgumentTypeInfo.Template<A> template )
{
argumentTypeInfo.serializeToJson( (T) template, jsonObject );
}
public static <A extends ArgumentType<?>> void serializeToNetwork( FriendlyByteBuf buffer, ArgumentTypeInfo.Template<A> template )
{
serializeToNetwork( buffer, template.type(), template );
}
@SuppressWarnings( "unchecked" )
private static <A extends ArgumentType<?>, T extends ArgumentTypeInfo.Template<A>> void serializeToNetwork( FriendlyByteBuf buffer, ArgumentTypeInfo<A, T> type, ArgumentTypeInfo.Template<A> template )
{
buffer.writeRegistryIdUnsafe( ForgeRegistries.COMMAND_ARGUMENT_TYPES, type );
type.serializeToNetwork( (T) template, buffer );
}
public static ArgumentTypeInfo.Template<?> deserialize( FriendlyByteBuf buffer )
{
var type = buffer.readRegistryIdUnsafe( ForgeRegistries.COMMAND_ARGUMENT_TYPES );
Objects.requireNonNull( type, "Unknown argument type" );
return type.deserializeFromNetwork( buffer );
}
public static Component getMessage( Message message )
{
return message instanceof Component component ? component : Component.literal( message.getString() );
}
public static Component getMessage( SimpleCommandExceptionType exception )
{
return getMessage( exception.create().getRawMessage() );
}
}

View File

@@ -15,9 +15,11 @@ import com.mojang.brigadier.suggestion.SuggestionsBuilder;
import dan200.computercraft.ComputerCraft; import dan200.computercraft.ComputerCraft;
import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.core.ComputerFamily;
import dan200.computercraft.shared.computer.core.ServerComputer; import dan200.computercraft.shared.computer.core.ServerComputer;
import net.minecraft.commands.CommandBuildContext;
import net.minecraft.commands.CommandSourceStack; import net.minecraft.commands.CommandSourceStack;
import net.minecraft.commands.synchronization.ArgumentSerializer; import net.minecraft.commands.synchronization.ArgumentTypeInfo;
import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.FriendlyByteBuf;
import org.jetbrains.annotations.NotNull;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import java.util.*; import java.util.*;
@@ -171,27 +173,48 @@ public final class ComputersArgumentType implements ArgumentType<ComputersArgume
); );
} }
public static class Serializer implements ArgumentSerializer<ComputersArgumentType> public static class Info implements ArgumentTypeInfo<ComputersArgumentType, Template>
{ {
@Override @Override
public void serializeToNetwork( @Nonnull ComputersArgumentType arg, @Nonnull FriendlyByteBuf buf ) public void serializeToNetwork( @Nonnull ComputersArgumentType.Template arg, @Nonnull FriendlyByteBuf buf )
{ {
buf.writeBoolean( arg.requireSome ); buf.writeBoolean( arg.requireSome() );
} }
@Nonnull @Nonnull
@Override @Override
public ComputersArgumentType deserializeFromNetwork( @Nonnull FriendlyByteBuf buf ) public ComputersArgumentType.Template deserializeFromNetwork( @Nonnull FriendlyByteBuf buf )
{ {
return buf.readBoolean() ? SOME : MANY; boolean requiresSome = buf.readBoolean();
return new ComputersArgumentType.Template( this, requiresSome );
} }
@Override @Override
public void serializeToJson( @Nonnull ComputersArgumentType arg, @Nonnull JsonObject json ) public void serializeToJson( @Nonnull ComputersArgumentType.Template arg, @Nonnull JsonObject json )
{ {
json.addProperty( "requireSome", arg.requireSome ); json.addProperty( "requireSome", arg.requireSome );
} }
@Override
public ComputersArgumentType.Template unpack( @NotNull ComputersArgumentType argumentType )
{
return new ComputersArgumentType.Template( this, argumentType.requireSome );
}
}
public record Template(Info info, boolean requireSome) implements ArgumentTypeInfo.Template<ComputersArgumentType>
{
@Override
public ComputersArgumentType instantiate( @NotNull CommandBuildContext context )
{
return requireSome ? SOME : MANY;
}
@Override
public Info type()
{
return info;
}
} }
@FunctionalInterface @FunctionalInterface

View File

@@ -6,7 +6,6 @@
package dan200.computercraft.shared.command.arguments; package dan200.computercraft.shared.command.arguments;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import com.mojang.brigadier.Message;
import com.mojang.brigadier.StringReader; import com.mojang.brigadier.StringReader;
import com.mojang.brigadier.arguments.ArgumentType; import com.mojang.brigadier.arguments.ArgumentType;
import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.context.CommandContext;
@@ -14,11 +13,12 @@ import com.mojang.brigadier.exceptions.CommandSyntaxException;
import com.mojang.brigadier.exceptions.SimpleCommandExceptionType; import com.mojang.brigadier.exceptions.SimpleCommandExceptionType;
import com.mojang.brigadier.suggestion.Suggestions; import com.mojang.brigadier.suggestion.Suggestions;
import com.mojang.brigadier.suggestion.SuggestionsBuilder; import com.mojang.brigadier.suggestion.SuggestionsBuilder;
import net.minecraft.commands.synchronization.ArgumentSerializer; import net.minecraft.commands.CommandBuildContext;
import net.minecraft.commands.synchronization.ArgumentTypes; import net.minecraft.commands.synchronization.ArgumentTypeInfo;
import net.minecraft.commands.synchronization.ArgumentTypeInfos;
import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.TextComponent; import org.jetbrains.annotations.NotNull;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import java.util.ArrayList; import java.util.ArrayList;
@@ -125,41 +125,60 @@ public final class RepeatArgumentType<T, U> implements ArgumentType<List<T>>
return child.getExamples(); return child.getExamples();
} }
public static class Serializer implements ArgumentSerializer<RepeatArgumentType<?, ?>> public static class Info implements ArgumentTypeInfo<RepeatArgumentType<?, ?>, Template>
{ {
@Override @Override
public void serializeToNetwork( @Nonnull RepeatArgumentType<?, ?> arg, @Nonnull FriendlyByteBuf buf ) public void serializeToNetwork( @Nonnull RepeatArgumentType.Template arg, @Nonnull FriendlyByteBuf buf )
{ {
buf.writeBoolean( arg.flatten ); buf.writeBoolean( arg.flatten );
ArgumentTypes.serialize( buf, arg.child ); ArgumentUtils.serializeToNetwork( buf, arg.child );
buf.writeComponent( getMessage( arg ) ); buf.writeComponent( ArgumentUtils.getMessage( arg.some ) );
} }
@Nonnull @Nonnull
@Override @Override
@SuppressWarnings( { "unchecked", "rawtypes" } ) public RepeatArgumentType.Template deserializeFromNetwork( @Nonnull FriendlyByteBuf buf )
public RepeatArgumentType<?, ?> deserializeFromNetwork( @Nonnull FriendlyByteBuf buf )
{ {
boolean isList = buf.readBoolean(); boolean isList = buf.readBoolean();
ArgumentType<?> child = ArgumentTypes.deserialize( buf ); var child = ArgumentUtils.deserialize( buf );
Component message = buf.readComponent(); Component message = buf.readComponent();
BiConsumer<List<Object>, ?> appender = isList ? ( list, x ) -> list.addAll( (Collection) x ) : List::add; return new RepeatArgumentType.Template( this, child, isList, new SimpleCommandExceptionType( message ) );
return new RepeatArgumentType( child, appender, isList, new SimpleCommandExceptionType( message ) ); }
@Nonnull
@Override
public RepeatArgumentType.Template unpack( RepeatArgumentType<?, ?> argumentType )
{
return new RepeatArgumentType.Template( this, ArgumentTypeInfos.unpack( argumentType.child ), argumentType.flatten, argumentType.some );
} }
@Override @Override
public void serializeToJson( @Nonnull RepeatArgumentType<?, ?> arg, @Nonnull JsonObject json ) public void serializeToJson( @Nonnull RepeatArgumentType.Template arg, @Nonnull JsonObject json )
{ {
json.addProperty( "flatten", arg.flatten ); json.addProperty( "flatten", arg.flatten );
json.addProperty( "child", "<<cannot serialize>>" ); // TODO: Potentially serialize this using reflection. json.add( "child", ArgumentUtils.serializeToJson( arg.child ) );
json.addProperty( "error", Component.Serializer.toJson( getMessage( arg ) ) ); json.addProperty( "error", Component.Serializer.toJson( ArgumentUtils.getMessage( arg.some ) ) );
}
}
public record Template(
Info info, ArgumentTypeInfo.Template<?> child, boolean flatten, SimpleCommandExceptionType some
) implements ArgumentTypeInfo.Template<RepeatArgumentType<?, ?>>
{
@Nonnull
@Override
@SuppressWarnings( { "unchecked", "rawtypes" } )
public RepeatArgumentType<?, ?> instantiate( @NotNull CommandBuildContext commandBuildContext )
{
var child = child().instantiate( commandBuildContext );
return flatten ? RepeatArgumentType.someFlat( (ArgumentType) child, some() ) : RepeatArgumentType.some( child, some() );
} }
private static Component getMessage( RepeatArgumentType<?, ?> arg ) @Nonnull
@Override
public ArgumentTypeInfo<RepeatArgumentType<?, ?>, ?> type()
{ {
Message message = arg.some.create().getRawMessage(); return info;
if( message instanceof Component ) return (Component) message;
return new TextComponent( message.getString() );
} }
} }
} }

View File

@@ -17,7 +17,6 @@ import net.minecraft.commands.CommandSourceStack;
import net.minecraft.network.chat.ClickEvent; import net.minecraft.network.chat.ClickEvent;
import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.MutableComponent; import net.minecraft.network.chat.MutableComponent;
import net.minecraft.network.chat.TextComponent;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import java.util.ArrayList; import java.util.ArrayList;
@@ -174,7 +173,7 @@ public final class HelpingArgumentBuilder extends LiteralArgumentBuilder<Command
temp.addChild( node ); temp.addChild( node );
String usage = dispatcher.getSmartUsage( temp, context.getSource() ).get( node ).substring( node.getName().length() ); String usage = dispatcher.getSmartUsage( temp, context.getSource() ).get( node ).substring( node.getName().length() );
MutableComponent output = new TextComponent( "" ) MutableComponent output = Component.literal( "" )
.append( coloured( "/" + command + usage, HEADER ) ) .append( coloured( "/" + command + usage, HEADER ) )
.append( " " ) .append( " " )
.append( coloured( translate( "commands." + id + ".synopsis" ), SYNOPSIS ) ) .append( coloured( translate( "commands." + id + ".synopsis" ), SYNOPSIS ) )

View File

@@ -20,7 +20,7 @@ public final class ChatHelpers
public static MutableComponent coloured( String text, ChatFormatting colour ) public static MutableComponent coloured( String text, ChatFormatting colour )
{ {
return new TextComponent( text == null ? "" : text ).withStyle( colour ); return Component.literal( text == null ? "" : text ).withStyle( colour );
} }
public static <T extends MutableComponent> T coloured( T component, ChatFormatting colour ) public static <T extends MutableComponent> T coloured( T component, ChatFormatting colour )
@@ -31,22 +31,22 @@ public final class ChatHelpers
public static MutableComponent text( String text ) public static MutableComponent text( String text )
{ {
return new TextComponent( text == null ? "" : text ); return Component.literal( text == null ? "" : text );
} }
public static MutableComponent translate( String text ) public static MutableComponent translate( String text )
{ {
return new TranslatableComponent( text == null ? "" : text ); return Component.translatable( text == null ? "" : text );
} }
public static MutableComponent translate( String text, Object... args ) public static MutableComponent translate( String text, Object... args )
{ {
return new TranslatableComponent( text == null ? "" : text, args ); return Component.translatable( text == null ? "" : text, args );
} }
public static MutableComponent list( Component... children ) public static MutableComponent list( Component... children )
{ {
MutableComponent component = new TextComponent( "" ); MutableComponent component = Component.literal( "" );
for( Component child : children ) for( Component child : children )
{ {
component.append( child ); component.append( child );
@@ -90,10 +90,10 @@ public final class ChatHelpers
public static MutableComponent copy( String text ) public static MutableComponent copy( String text )
{ {
TextComponent name = new TextComponent( text ); MutableComponent name = Component.literal( text );
Style style = name.getStyle() Style style = name.getStyle()
.withClickEvent( new ClickEvent( ClickEvent.Action.COPY_TO_CLIPBOARD, text ) ) .withClickEvent( new ClickEvent( ClickEvent.Action.COPY_TO_CLIPBOARD, text ) )
.withHoverEvent( new HoverEvent( HoverEvent.Action.SHOW_TEXT, new TranslatableComponent( "gui.computercraft.tooltip.copy" ) ) ); .withHoverEvent( new HoverEvent( HoverEvent.Action.SHOW_TEXT, Component.translatable( "gui.computercraft.tooltip.copy" ) ) );
return name.withStyle( style ); return name.withStyle( style );
} }
} }

View File

@@ -7,7 +7,6 @@ package dan200.computercraft.shared.command.text;
import net.minecraft.commands.CommandSourceStack; import net.minecraft.commands.CommandSourceStack;
import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.TextComponent;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@@ -27,7 +26,7 @@ public class ServerTableFormatter implements TableFormatter
{ {
int extraWidth = width - getWidth( component ); int extraWidth = width - getWidth( component );
if( extraWidth <= 0 ) return null; if( extraWidth <= 0 ) return null;
return new TextComponent( StringUtils.repeat( ' ', extraWidth ) ); return Component.literal( StringUtils.repeat( ' ', extraWidth ) );
} }
@Override @Override
@@ -43,7 +42,7 @@ public class ServerTableFormatter implements TableFormatter
} }
@Override @Override
public void writeLine( int id, Component component ) public void writeLine( String label, Component component )
{ {
source.sendSuccess( component, false ); source.sendSuccess( component, false );
} }

View File

@@ -19,30 +19,27 @@ import java.util.List;
public class TableBuilder public class TableBuilder
{ {
private final int id; private final String id;
private int columns = -1; private int columns = -1;
private final Component[] headers; private final Component[] headers;
private final ArrayList<Component[]> rows = new ArrayList<>(); private final ArrayList<Component[]> rows = new ArrayList<>();
private int additional; private int additional;
public TableBuilder( int id, @Nonnull Component... headers ) public TableBuilder( @Nonnull String id, @Nonnull Component... headers )
{ {
if( id < 0 ) throw new IllegalArgumentException( "ID must be positive" );
this.id = id; this.id = id;
this.headers = headers; this.headers = headers;
columns = headers.length; columns = headers.length;
} }
public TableBuilder( int id ) public TableBuilder( @Nonnull String id )
{ {
if( id < 0 ) throw new IllegalArgumentException( "ID must be positive" );
this.id = id; this.id = id;
headers = null; headers = null;
} }
public TableBuilder( int id, @Nonnull String... headers ) public TableBuilder( @Nonnull String id, @Nonnull String... headers )
{ {
if( id < 0 ) throw new IllegalArgumentException( "ID must be positive" );
this.id = id; this.id = id;
this.headers = new Component[headers.length]; this.headers = new Component[headers.length];
columns = headers.length; columns = headers.length;
@@ -65,7 +62,7 @@ public class TableBuilder
* *
* @return This table's type. * @return This table's type.
*/ */
public int getId() public String getId()
{ {
return id; return id;
} }

View File

@@ -7,7 +7,7 @@ package dan200.computercraft.shared.command.text;
import net.minecraft.ChatFormatting; import net.minecraft.ChatFormatting;
import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.TextComponent; import net.minecraft.network.chat.MutableComponent;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@@ -39,13 +39,13 @@ public interface TableFormatter
int getWidth( Component component ); int getWidth( Component component );
void writeLine( int id, Component component ); void writeLine( String label, Component component );
default int display( TableBuilder table ) default void display( TableBuilder table )
{ {
if( table.getColumns() <= 0 ) return 0; if( table.getColumns() <= 0 ) return;
int rowId = table.getId(); String id = table.getId();
int columns = table.getColumns(); int columns = table.getColumns();
int[] maxWidths = new int[columns]; int[] maxWidths = new int[columns];
@@ -76,7 +76,7 @@ public interface TableFormatter
if( headers != null ) if( headers != null )
{ {
TextComponent line = new TextComponent( "" ); MutableComponent line = Component.literal( "" );
for( int i = 0; i < columns - 1; i++ ) for( int i = 0; i < columns - 1; i++ )
{ {
line.append( headers[i] ); line.append( headers[i] );
@@ -86,18 +86,18 @@ public interface TableFormatter
} }
line.append( headers[columns - 1] ); line.append( headers[columns - 1] );
writeLine( rowId++, line ); writeLine( id, line );
// Write a separator line. We round the width up rather than down to make // Write a separator line. We round the width up rather than down to make
// it a tad prettier. // it a tad prettier.
int rowCharWidth = getWidth( HEADER ); int rowCharWidth = getWidth( HEADER );
int rowWidth = totalWidth / rowCharWidth + (totalWidth % rowCharWidth == 0 ? 0 : 1); int rowWidth = totalWidth / rowCharWidth + (totalWidth % rowCharWidth == 0 ? 0 : 1);
writeLine( rowId++, coloured( StringUtils.repeat( HEADER.getString(), rowWidth ), ChatFormatting.GRAY ) ); writeLine( id, coloured( StringUtils.repeat( HEADER.getString(), rowWidth ), ChatFormatting.GRAY ) );
} }
for( Component[] row : table.getRows() ) for( Component[] row : table.getRows() )
{ {
TextComponent line = new TextComponent( "" ); MutableComponent line = Component.literal( "" );
for( int i = 0; i < columns - 1; i++ ) for( int i = 0; i < columns - 1; i++ )
{ {
line.append( row[i] ); line.append( row[i] );
@@ -106,14 +106,12 @@ public interface TableFormatter
line.append( SEPARATOR ); line.append( SEPARATOR );
} }
line.append( row[columns - 1] ); line.append( row[columns - 1] );
writeLine( rowId++, line ); writeLine( id, line );
} }
if( table.getAdditional() > 0 ) if( table.getAdditional() > 0 )
{ {
writeLine( rowId++, coloured( translate( "commands.computercraft.generic.additional_rows", table.getAdditional() ), ChatFormatting.AQUA ) ); writeLine( id, coloured( translate( "commands.computercraft.generic.additional_rows", table.getAdditional() ), ChatFormatting.AQUA ) );
} }
return rowId - table.getId();
} }
} }

View File

@@ -7,6 +7,7 @@ package dan200.computercraft.shared.common;
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.util.RandomSource;
import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult; import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.player.Player;
@@ -23,7 +24,6 @@ import net.minecraftforge.registries.RegistryObject;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.util.Random;
public abstract class BlockGeneric extends BaseEntityBlock public abstract class BlockGeneric extends BaseEntityBlock
{ {
@@ -73,7 +73,7 @@ public abstract class BlockGeneric extends BaseEntityBlock
@Override @Override
@Deprecated @Deprecated
public void tick( @Nonnull BlockState state, ServerLevel world, @Nonnull BlockPos pos, @Nonnull Random rand ) public void tick( @Nonnull BlockState state, ServerLevel world, @Nonnull BlockPos pos, @Nonnull RandomSource rand )
{ {
BlockEntity te = world.getBlockEntity( pos ); BlockEntity te = world.getBlockEntity( pos );
if( te instanceof TileGeneric generic ) generic.blockTick(); if( te instanceof TileGeneric generic ) generic.blockTick();

View File

@@ -43,6 +43,13 @@ public class ContainerHeldItem extends AbstractContainerMenu
return stack; return stack;
} }
@Nonnull
@Override
public ItemStack quickMoveStack( @Nonnull Player player, int slot )
{
return ItemStack.EMPTY;
}
@Override @Override
public boolean stillValid( @Nonnull Player player ) public boolean stillValid( @Nonnull Player player )
{ {

View File

@@ -63,7 +63,7 @@ public class CommandAPI implements ILuaAPI
try try
{ {
receiver.clearOutput(); receiver.clearOutput();
int result = commandManager.performCommand( computer.getSource(), command ); int result = commandManager.performPrefixedCommand( computer.getSource(), command );
return new Object[] { result > 0, receiver.copyOutput(), result }; return new Object[] { result > 0, receiver.copyOutput(), result };
} }
catch( Throwable t ) catch( Throwable t )

View File

@@ -162,7 +162,7 @@ public abstract class BlockComputerBase<T extends TileComputerBase> extends Bloc
popResource( world, pos, item ); popResource( world, pos, item );
} }
state.spawnAfterBreak( serverWorld, pos, player.getMainHandItem() ); state.spawnAfterBreak( serverWorld, pos, player.getMainHandItem(), true );
} }
} }

View File

@@ -13,8 +13,6 @@ import net.minecraft.commands.CommandSource;
import net.minecraft.commands.CommandSourceStack; import net.minecraft.commands.CommandSourceStack;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.TextComponent;
import net.minecraft.network.chat.TranslatableComponent;
import net.minecraft.server.MinecraftServer; import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.player.Player;
@@ -27,7 +25,6 @@ import net.minecraft.world.phys.Vec3;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.UUID;
public class TileCommandComputer extends TileComputer public class TileCommandComputer extends TileComputer
{ {
@@ -51,7 +48,7 @@ public class TileCommandComputer extends TileComputer
} }
@Override @Override
public void sendMessage( @Nonnull Component textComponent, @Nonnull UUID id ) public void sendSystemMessage( @Nonnull Component textComponent )
{ {
output.put( output.size() + 1, textComponent.getString() ); output.put( output.size() + 1, textComponent.getString() );
} }
@@ -101,7 +98,7 @@ public class TileCommandComputer extends TileComputer
return new CommandSourceStack( receiver, return new CommandSourceStack( receiver,
Vec3.atCenterOf( worldPosition ), Vec2.ZERO, Vec3.atCenterOf( worldPosition ), Vec2.ZERO,
(ServerLevel) getLevel(), 2, (ServerLevel) getLevel(), 2,
name, new TextComponent( name ), name, Component.literal( name ),
getLevel().getServer(), null getLevel().getServer(), null
); );
} }
@@ -125,12 +122,12 @@ public class TileCommandComputer extends TileComputer
MinecraftServer server = player.getServer(); MinecraftServer server = player.getServer();
if( server == null || !server.isCommandBlockEnabled() ) if( server == null || !server.isCommandBlockEnabled() )
{ {
player.displayClientMessage( new TranslatableComponent( "advMode.notEnabled" ), true ); player.displayClientMessage( Component.translatable( "advMode.notEnabled" ), true );
return false; return false;
} }
else if( ComputerCraft.commandRequireCreative ? !player.canUseGameMasterBlocks() : !server.getPlayerList().isOp( player.getGameProfile() ) ) else if( ComputerCraft.commandRequireCreative ? !player.canUseGameMasterBlocks() : !server.getPlayerList().isOp( player.getGameProfile() ) )
{ {
player.displayClientMessage( new TranslatableComponent( "advMode.notAllowed" ), true ); player.displayClientMessage( Component.translatable( "advMode.notAllowed" ), true );
return false; return false;
} }

View File

@@ -22,8 +22,6 @@ import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction; import net.minecraft.core.Direction;
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.TextComponent;
import net.minecraft.network.chat.TranslatableComponent;
import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket; import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket;
import net.minecraft.world.*; import net.minecraft.world.*;
import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.player.Player;
@@ -439,8 +437,8 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT
public Component getName() public Component getName()
{ {
return hasCustomName() return hasCustomName()
? new TextComponent( label ) ? Component.literal( label )
: new TranslatableComponent( getBlockState().getBlock().getDescriptionId() ); : Component.translatable( getBlockState().getBlock().getDescriptionId() );
} }
@Override @Override
@@ -453,7 +451,7 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT
@Override @Override
public Component getCustomName() public Component getCustomName()
{ {
return hasCustomName() ? new TextComponent( label ) : null; return hasCustomName() ? Component.literal( label ) : null;
} }
@Nonnull @Nonnull

View File

@@ -12,7 +12,9 @@ import dan200.computercraft.shared.util.InvisibleSlot;
import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.player.Player;
import net.minecraft.world.inventory.MenuType; import net.minecraft.world.inventory.MenuType;
import net.minecraft.world.item.ItemStack;
import javax.annotation.Nonnull;
import java.util.function.Predicate; import java.util.function.Predicate;
/** /**
@@ -38,4 +40,11 @@ public class ComputerMenuWithoutInventory extends ContainerComputerBase
{ {
for( int i = 0; i < 9; i++ ) addSlot( new InvisibleSlot( player, i ) ); for( int i = 0; i < 9; i++ ) addSlot( new InvisibleSlot( player, i ) );
} }
@Nonnull
@Override
public ItemStack quickMoveStack( @Nonnull Player player, int slot )
{
return ItemStack.EMPTY;
}
} }

View File

@@ -16,7 +16,7 @@ import dan200.computercraft.shared.computer.upload.UploadResult;
import dan200.computercraft.shared.network.NetworkHandler; import dan200.computercraft.shared.network.NetworkHandler;
import dan200.computercraft.shared.network.client.UploadResultMessage; import dan200.computercraft.shared.network.client.UploadResultMessage;
import dan200.computercraft.shared.network.container.ComputerContainerData; import dan200.computercraft.shared.network.container.ComputerContainerData;
import net.minecraft.network.chat.TranslatableComponent; import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.player.Player;
@@ -154,7 +154,7 @@ public abstract class ContainerComputerBase extends AbstractContainerMenu implem
if( !upload.checksumMatches() ) if( !upload.checksumMatches() )
{ {
ComputerCraft.log.warn( "Checksum failed to match for {}.", upload.getName() ); ComputerCraft.log.warn( "Checksum failed to match for {}.", upload.getName() );
return new UploadResultMessage( UploadResult.ERROR, new TranslatableComponent( "gui.computercraft.upload.failed.corrupted" ) ); return new UploadResultMessage( UploadResult.ERROR, Component.translatable( "gui.computercraft.upload.failed.corrupted" ) );
} }
} }
@@ -170,7 +170,7 @@ public abstract class ContainerComputerBase extends AbstractContainerMenu implem
{ {
return new UploadResultMessage( return new UploadResultMessage(
UploadResult.ERROR, UploadResult.ERROR,
new TranslatableComponent( "gui.computercraft.upload.failed.overwrite_dir", upload.getName() ) Component.translatable( "gui.computercraft.upload.failed.overwrite_dir", upload.getName() )
); );
} }
@@ -184,7 +184,7 @@ public abstract class ContainerComputerBase extends AbstractContainerMenu implem
toUpload = files; toUpload = files;
return new UploadResultMessage( return new UploadResultMessage(
UploadResult.CONFIRM_OVERWRITE, UploadResult.CONFIRM_OVERWRITE,
new TranslatableComponent( "gui.computercraft.upload.overwrite.detail", joiner.toString() ) Component.translatable( "gui.computercraft.upload.overwrite.detail", joiner.toString() )
); );
} }
@@ -202,13 +202,13 @@ public abstract class ContainerComputerBase extends AbstractContainerMenu implem
} }
return new UploadResultMessage( return new UploadResultMessage(
UploadResult.SUCCESS, new TranslatableComponent( "gui.computercraft.upload.success.msg", files.size() ) UploadResult.SUCCESS, Component.translatable( "gui.computercraft.upload.success.msg", files.size() )
); );
} }
catch( FileSystemException | IOException e ) catch( FileSystemException | IOException e )
{ {
ComputerCraft.log.error( "Error uploading files", e ); ComputerCraft.log.error( "Error uploading files", e );
return new UploadResultMessage( UploadResult.ERROR, new TranslatableComponent( "gui.computercraft.upload.failed.generic", e.getMessage() ) ); return new UploadResultMessage( UploadResult.ERROR, Component.translatable( "gui.computercraft.upload.failed.generic", e.getMessage() ) );
} }
} }

View File

@@ -7,7 +7,7 @@ package dan200.computercraft.shared.computer.items;
import dan200.computercraft.shared.computer.blocks.BlockComputer; import dan200.computercraft.shared.computer.blocks.BlockComputer;
import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.core.ComputerFamily;
import net.minecraft.network.chat.TextComponent; import net.minecraft.network.chat.Component;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
@@ -23,7 +23,7 @@ public class ItemComputer extends ItemComputerBase
{ {
ItemStack result = new ItemStack( this ); ItemStack result = new ItemStack( this );
if( id >= 0 ) result.getOrCreateTag().putInt( NBT_ID, id ); if( id >= 0 ) result.getOrCreateTag().putInt( NBT_ID, id );
if( label != null ) result.setHoverName( new TextComponent( label ) ); if( label != null ) result.setHoverName( Component.literal( label ) );
return result; return result;
} }

View File

@@ -13,8 +13,6 @@ import dan200.computercraft.shared.computer.blocks.BlockComputerBase;
import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.core.ComputerFamily;
import net.minecraft.ChatFormatting; import net.minecraft.ChatFormatting;
import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.TextComponent;
import net.minecraft.network.chat.TranslatableComponent;
import net.minecraft.world.item.BlockItem; import net.minecraft.world.item.BlockItem;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.TooltipFlag; import net.minecraft.world.item.TooltipFlag;
@@ -42,7 +40,7 @@ public abstract class ItemComputerBase extends BlockItem implements IComputerIte
int id = getComputerID( stack ); int id = getComputerID( stack );
if( id >= 0 ) if( id >= 0 )
{ {
list.add( new TranslatableComponent( "gui.computercraft.tooltip.computer_id", id ) list.add( Component.translatable( "gui.computercraft.tooltip.computer_id", id )
.withStyle( ChatFormatting.GRAY ) ); .withStyle( ChatFormatting.GRAY ) );
} }
} }
@@ -67,7 +65,7 @@ public abstract class ItemComputerBase extends BlockItem implements IComputerIte
{ {
if( label != null ) if( label != null )
{ {
stack.setHoverName( new TextComponent( label ) ); stack.setHoverName( Component.literal( label ) );
} }
else else
{ {

View File

@@ -7,7 +7,6 @@ package dan200.computercraft.shared.computer.recipe;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.core.ComputerFamily;
import dan200.computercraft.shared.util.BasicRecipeSerializer;
import dan200.computercraft.shared.util.RecipeUtil; import dan200.computercraft.shared.util.RecipeUtil;
import net.minecraft.core.NonNullList; import net.minecraft.core.NonNullList;
import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.FriendlyByteBuf;
@@ -15,6 +14,7 @@ import net.minecraft.resources.ResourceLocation;
import net.minecraft.util.GsonHelper; import net.minecraft.util.GsonHelper;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.crafting.Ingredient; import net.minecraft.world.item.crafting.Ingredient;
import net.minecraft.world.item.crafting.RecipeSerializer;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
@@ -33,7 +33,7 @@ public abstract class ComputerFamilyRecipe extends ComputerConvertRecipe
return family; return family;
} }
public abstract static class Serializer<T extends ComputerFamilyRecipe> extends BasicRecipeSerializer<T> public abstract static class Serializer<T extends ComputerFamilyRecipe> implements RecipeSerializer<T>
{ {
protected abstract T create( ResourceLocation identifier, String group, int width, int height, NonNullList<Ingredient> ingredients, ItemStack result, ComputerFamily family ); protected abstract T create( ResourceLocation identifier, String group, int width, int height, NonNullList<Ingredient> ingredients, ItemStack result, ComputerFamily family );

View File

@@ -6,7 +6,6 @@
package dan200.computercraft.shared.computer.upload; package dan200.computercraft.shared.computer.upload;
import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.TranslatableComponent;
public enum UploadResult public enum UploadResult
{ {
@@ -14,12 +13,12 @@ public enum UploadResult
ERROR, ERROR,
CONFIRM_OVERWRITE; CONFIRM_OVERWRITE;
public static final Component SUCCESS_TITLE = new TranslatableComponent( "gui.computercraft.upload.success" ); public static final Component SUCCESS_TITLE = Component.translatable( "gui.computercraft.upload.success" );
public static final Component FAILED_TITLE = new TranslatableComponent( "gui.computercraft.upload.failed" ); public static final Component FAILED_TITLE = Component.translatable( "gui.computercraft.upload.failed" );
public static final Component COMPUTER_OFF_MSG = new TranslatableComponent( "gui.computercraft.upload.failed.computer_off" ); public static final Component COMPUTER_OFF_MSG = Component.translatable( "gui.computercraft.upload.failed.computer_off" );
public static final Component OUT_OF_SPACE_MSG = new TranslatableComponent( "gui.computercraft.upload.failed.out_of_space" ); public static final Component OUT_OF_SPACE_MSG = Component.translatable( "gui.computercraft.upload.failed.out_of_space" );
public static final Component TOO_MUCH_MSG = new TranslatableComponent( "gui.computercraft.upload.failed.too_much" ); public static final Component TOO_MUCH_MSG = Component.translatable( "gui.computercraft.upload.failed.too_much" );
public static final Component UPLOAD_OVERWRITE = new TranslatableComponent( "gui.computercraft.upload.overwrite" ); public static final Component UPLOAD_OVERWRITE = Component.translatable( "gui.computercraft.upload.overwrite" );
} }

View File

@@ -20,21 +20,22 @@ import dan200.computercraft.shared.turtle.items.ITurtleItem;
import dan200.computercraft.shared.turtle.items.TurtleItemFactory; import dan200.computercraft.shared.turtle.items.TurtleItemFactory;
import mezz.jei.api.IModPlugin; import mezz.jei.api.IModPlugin;
import mezz.jei.api.JeiPlugin; import mezz.jei.api.JeiPlugin;
import mezz.jei.api.constants.VanillaRecipeCategoryUid; import mezz.jei.api.constants.RecipeTypes;
import mezz.jei.api.constants.VanillaTypes; import mezz.jei.api.constants.VanillaTypes;
import mezz.jei.api.ingredients.subtypes.IIngredientSubtypeInterpreter; import mezz.jei.api.ingredients.subtypes.IIngredientSubtypeInterpreter;
import mezz.jei.api.recipe.IRecipeLookup;
import mezz.jei.api.recipe.IRecipeManager; import mezz.jei.api.recipe.IRecipeManager;
import mezz.jei.api.recipe.category.IRecipeCategory;
import mezz.jei.api.registration.IAdvancedRegistration; import mezz.jei.api.registration.IAdvancedRegistration;
import mezz.jei.api.registration.ISubtypeRegistration; import mezz.jei.api.registration.ISubtypeRegistration;
import mezz.jei.api.runtime.IJeiRuntime; import mezz.jei.api.runtime.IJeiRuntime;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.Item; import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.crafting.Recipe; import net.minecraft.world.item.crafting.CraftingRecipe;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
import static dan200.computercraft.shared.integration.jei.RecipeResolver.MAIN_FAMILIES; import static dan200.computercraft.shared.integration.jei.RecipeResolver.MAIN_FAMILIES;
@@ -52,13 +53,13 @@ public class JEIComputerCraft implements IModPlugin
@Override @Override
public void registerItemSubtypes( ISubtypeRegistration subtypeRegistry ) public void registerItemSubtypes( ISubtypeRegistration subtypeRegistry )
{ {
subtypeRegistry.registerSubtypeInterpreter( Registry.ModItems.TURTLE_NORMAL.get(), turtleSubtype ); subtypeRegistry.registerSubtypeInterpreter( VanillaTypes.ITEM_STACK, Registry.ModItems.TURTLE_NORMAL.get(), turtleSubtype );
subtypeRegistry.registerSubtypeInterpreter( Registry.ModItems.TURTLE_ADVANCED.get(), turtleSubtype ); subtypeRegistry.registerSubtypeInterpreter( VanillaTypes.ITEM_STACK, Registry.ModItems.TURTLE_ADVANCED.get(), turtleSubtype );
subtypeRegistry.registerSubtypeInterpreter( Registry.ModItems.POCKET_COMPUTER_NORMAL.get(), pocketSubtype ); subtypeRegistry.registerSubtypeInterpreter( VanillaTypes.ITEM_STACK, Registry.ModItems.POCKET_COMPUTER_NORMAL.get(), pocketSubtype );
subtypeRegistry.registerSubtypeInterpreter( Registry.ModItems.POCKET_COMPUTER_ADVANCED.get(), pocketSubtype ); subtypeRegistry.registerSubtypeInterpreter( VanillaTypes.ITEM_STACK, Registry.ModItems.POCKET_COMPUTER_ADVANCED.get(), pocketSubtype );
subtypeRegistry.registerSubtypeInterpreter( Registry.ModItems.DISK.get(), diskSubtype ); subtypeRegistry.registerSubtypeInterpreter( VanillaTypes.ITEM_STACK, Registry.ModItems.DISK.get(), diskSubtype );
} }
@Override @Override
@@ -89,27 +90,22 @@ public class JEIComputerCraft implements IModPlugin
if( !upgradeItems.isEmpty() ) if( !upgradeItems.isEmpty() )
{ {
runtime.getIngredientManager().addIngredientsAtRuntime( VanillaTypes.ITEM, upgradeItems ); runtime.getIngredientManager().addIngredientsAtRuntime( VanillaTypes.ITEM_STACK, upgradeItems );
} }
// Hide all upgrade recipes // Hide all upgrade recipes
IRecipeCategory<?> category = registry.getRecipeCategory( VanillaRecipeCategoryUid.CRAFTING, false ); IRecipeLookup<CraftingRecipe> category = registry.createRecipeLookup( RecipeTypes.CRAFTING );
if( category != null ) category.get().forEach( wrapper -> {
{ ResourceLocation id = wrapper.getId();
for( Object wrapper : registry.getRecipes( category, List.of(), false ) ) if( !id.getNamespace().equals( ComputerCraft.MOD_ID ) ) return;
{
if( !(wrapper instanceof Recipe) ) continue;
ResourceLocation id = ((Recipe<?>) wrapper).getId();
if( !id.getNamespace().equals( ComputerCraft.MOD_ID ) ) continue;
String path = id.getPath(); String path = id.getPath();
if( path.startsWith( "turtle_normal/" ) || path.startsWith( "turtle_advanced/" ) if( path.startsWith( "turtle_normal/" ) || path.startsWith( "turtle_advanced/" )
|| path.startsWith( "pocket_normal/" ) || path.startsWith( "pocket_advanced/" ) ) || path.startsWith( "pocket_normal/" ) || path.startsWith( "pocket_advanced/" ) )
{ {
registry.hideRecipe( wrapper, VanillaRecipeCategoryUid.CRAFTING ); registry.hideRecipes( RecipeTypes.CRAFTING, Collections.singleton( wrapper ) );
}
} }
} } );
} }
/** /**

View File

@@ -6,10 +6,10 @@
package dan200.computercraft.shared.integration.jei; package dan200.computercraft.shared.integration.jei;
import dan200.computercraft.ComputerCraft; import dan200.computercraft.ComputerCraft;
import dan200.computercraft.api.upgrades.IUpgradeBase;
import dan200.computercraft.api.pocket.IPocketUpgrade; import dan200.computercraft.api.pocket.IPocketUpgrade;
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.api.upgrades.IUpgradeBase;
import dan200.computercraft.shared.PocketUpgrades; import dan200.computercraft.shared.PocketUpgrades;
import dan200.computercraft.shared.TurtleUpgrades; import dan200.computercraft.shared.TurtleUpgrades;
import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.core.ComputerFamily;
@@ -17,8 +17,9 @@ import dan200.computercraft.shared.pocket.items.ItemPocketComputer;
import dan200.computercraft.shared.pocket.items.PocketComputerItemFactory; import dan200.computercraft.shared.pocket.items.PocketComputerItemFactory;
import dan200.computercraft.shared.turtle.items.ITurtleItem; import dan200.computercraft.shared.turtle.items.ITurtleItem;
import dan200.computercraft.shared.turtle.items.TurtleItemFactory; import dan200.computercraft.shared.turtle.items.TurtleItemFactory;
import mezz.jei.api.constants.VanillaRecipeCategoryUid; import mezz.jei.api.constants.RecipeTypes;
import mezz.jei.api.recipe.IFocus; import mezz.jei.api.recipe.IFocus;
import mezz.jei.api.recipe.RecipeType;
import mezz.jei.api.recipe.advanced.IRecipeManagerPlugin; import mezz.jei.api.recipe.advanced.IRecipeManagerPlugin;
import mezz.jei.api.recipe.category.IRecipeCategory; import mezz.jei.api.recipe.category.IRecipeCategory;
import net.minecraft.core.NonNullList; import net.minecraft.core.NonNullList;
@@ -95,7 +96,7 @@ class RecipeResolver implements IRecipeManagerPlugin
@Nonnull @Nonnull
@Override @Override
public <V> List<ResourceLocation> getRecipeCategoryUids( @Nonnull IFocus<V> focus ) public <V> List<RecipeType<?>> getRecipeTypes( @Nonnull IFocus<V> focus )
{ {
V value = focus.getTypedValue().getIngredient(); V value = focus.getTypedValue().getIngredient();
if( !(value instanceof ItemStack stack) ) return Collections.emptyList(); if( !(value instanceof ItemStack stack) ) return Collections.emptyList();
@@ -105,11 +106,11 @@ class RecipeResolver implements IRecipeManagerPlugin
case INPUT: case INPUT:
return stack.getItem() instanceof ITurtleItem || stack.getItem() instanceof ItemPocketComputer || return stack.getItem() instanceof ITurtleItem || stack.getItem() instanceof ItemPocketComputer ||
hasUpgrade( stack ) hasUpgrade( stack )
? Collections.singletonList( VanillaRecipeCategoryUid.CRAFTING ) ? Collections.singletonList( RecipeTypes.CRAFTING )
: Collections.emptyList(); : Collections.emptyList();
case OUTPUT: case OUTPUT:
return stack.getItem() instanceof ITurtleItem || stack.getItem() instanceof ItemPocketComputer return stack.getItem() instanceof ITurtleItem || stack.getItem() instanceof ItemPocketComputer
? Collections.singletonList( VanillaRecipeCategoryUid.CRAFTING ) ? Collections.singletonList( RecipeTypes.CRAFTING )
: Collections.emptyList(); : Collections.emptyList();
default: default:
return Collections.emptyList(); return Collections.emptyList();
@@ -120,7 +121,7 @@ class RecipeResolver implements IRecipeManagerPlugin
@Override @Override
public <T, V> List<T> getRecipes( @Nonnull IRecipeCategory<T> recipeCategory, @Nonnull IFocus<V> focus ) public <T, V> List<T> getRecipes( @Nonnull IRecipeCategory<T> recipeCategory, @Nonnull IFocus<V> focus )
{ {
if( !(focus.getTypedValue().getIngredient() instanceof ItemStack stack) || !recipeCategory.getUid().equals( VanillaRecipeCategoryUid.CRAFTING ) ) if( !(focus.getTypedValue().getIngredient() instanceof ItemStack stack) || recipeCategory.getRecipeType() != RecipeTypes.CRAFTING )
{ {
return Collections.emptyList(); return Collections.emptyList();
} }

View File

@@ -17,8 +17,6 @@ import net.minecraft.core.BlockPos;
import net.minecraft.core.NonNullList; import net.minecraft.core.NonNullList;
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.TextComponent;
import net.minecraft.network.chat.TranslatableComponent;
import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.CreativeModeTab; import net.minecraft.world.item.CreativeModeTab;
import net.minecraft.world.item.Item; import net.minecraft.world.item.Item;
@@ -53,7 +51,7 @@ public class ItemDisk extends Item implements IMedia, IColouredItem
@Override @Override
public void fillItemCategory( @Nonnull CreativeModeTab tabs, @Nonnull NonNullList<ItemStack> list ) public void fillItemCategory( @Nonnull CreativeModeTab tabs, @Nonnull NonNullList<ItemStack> list )
{ {
if( !allowdedIn( tabs ) ) return; if( !allowedIn( tabs ) ) return;
for( int colour = 0; colour < 16; colour++ ) for( int colour = 0; colour < 16; colour++ )
{ {
list.add( createFromIDAndColour( -1, null, Colour.VALUES[colour].getHex() ) ); list.add( createFromIDAndColour( -1, null, Colour.VALUES[colour].getHex() ) );
@@ -68,7 +66,7 @@ public class ItemDisk extends Item implements IMedia, IColouredItem
int id = getDiskID( stack ); int id = getDiskID( stack );
if( id >= 0 ) if( id >= 0 )
{ {
list.add( new TranslatableComponent( "gui.computercraft.tooltip.disk_id", id ) list.add( Component.translatable( "gui.computercraft.tooltip.disk_id", id )
.withStyle( ChatFormatting.GRAY ) ); .withStyle( ChatFormatting.GRAY ) );
} }
} }
@@ -91,7 +89,7 @@ public class ItemDisk extends Item implements IMedia, IColouredItem
{ {
if( label != null ) if( label != null )
{ {
stack.setHoverName( new TextComponent( label ) ); stack.setHoverName( Component.literal( label ) );
} }
else else
{ {

View File

@@ -10,7 +10,6 @@ import dan200.computercraft.shared.common.ContainerHeldItem;
import dan200.computercraft.shared.network.container.HeldItemContainerData; import dan200.computercraft.shared.network.container.HeldItemContainerData;
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.TextComponent;
import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult; import net.minecraft.world.InteractionResult;
import net.minecraft.world.InteractionResultHolder; import net.minecraft.world.InteractionResultHolder;
@@ -53,7 +52,7 @@ public class ItemPrintout extends Item
public void appendHoverText( @Nonnull ItemStack stack, Level world, @Nonnull List<Component> list, @Nonnull TooltipFlag options ) public void appendHoverText( @Nonnull ItemStack stack, Level world, @Nonnull List<Component> list, @Nonnull TooltipFlag options )
{ {
String title = getTitle( stack ); String title = getTitle( stack );
if( title != null && !title.isEmpty() ) list.add( new TextComponent( title ) ); if( title != null && !title.isEmpty() ) list.add( Component.literal( title ) );
} }
@Nonnull @Nonnull

View File

@@ -15,7 +15,6 @@ import net.minecraft.core.BlockPos;
import net.minecraft.core.NonNullList; import net.minecraft.core.NonNullList;
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.TextComponent;
import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.CreativeModeTab; import net.minecraft.world.item.CreativeModeTab;
import net.minecraft.world.item.Item; import net.minecraft.world.item.Item;
@@ -49,7 +48,7 @@ public class ItemTreasureDisk extends Item implements IMedia
public void appendHoverText( @Nonnull ItemStack stack, @Nullable Level world, @Nonnull List<Component> list, @Nonnull TooltipFlag tooltipOptions ) public void appendHoverText( @Nonnull ItemStack stack, @Nullable Level world, @Nonnull List<Component> list, @Nonnull TooltipFlag tooltipOptions )
{ {
String label = getTitle( stack ); String label = getTitle( stack );
if( !label.isEmpty() ) list.add( new TextComponent( label ) ); if( !label.isEmpty() ) list.add( Component.literal( label ) );
} }
@Override @Override

View File

@@ -6,7 +6,7 @@
package dan200.computercraft.shared.media.items; package dan200.computercraft.shared.media.items;
import dan200.computercraft.api.media.IMedia; import dan200.computercraft.api.media.IMedia;
import net.minecraft.network.chat.TranslatableComponent; import net.minecraft.network.chat.Component;
import net.minecraft.sounds.SoundEvent; import net.minecraft.sounds.SoundEvent;
import net.minecraft.world.item.Item; import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
@@ -37,7 +37,7 @@ public final class RecordMedia implements IMedia
Item item = stack.getItem(); Item item = stack.getItem();
if( !(item instanceof RecordItem) ) return null; if( !(item instanceof RecordItem) ) return null;
return new TranslatableComponent( item.getDescriptionId() + ".desc" ).getString(); return Component.translatable( item.getDescriptionId() + ".desc" ).getString();
} }
@Override @Override

View File

@@ -108,7 +108,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

@@ -16,6 +16,7 @@ import javax.annotation.Nonnull;
public class ChatTableClientMessage implements NetworkMessage public class ChatTableClientMessage implements NetworkMessage
{ {
private static final int MAX_LEN = 16;
private final TableBuilder table; private final TableBuilder table;
public ChatTableClientMessage( TableBuilder table ) public ChatTableClientMessage( TableBuilder table )
@@ -26,7 +27,7 @@ public class ChatTableClientMessage implements NetworkMessage
public ChatTableClientMessage( @Nonnull FriendlyByteBuf buf ) public ChatTableClientMessage( @Nonnull FriendlyByteBuf buf )
{ {
int id = buf.readVarInt(); String id = buf.readUtf( MAX_LEN );
int columns = buf.readVarInt(); int columns = buf.readVarInt();
TableBuilder table; TableBuilder table;
if( buf.readBoolean() ) if( buf.readBoolean() )
@@ -55,7 +56,7 @@ public class ChatTableClientMessage implements NetworkMessage
@Override @Override
public void toBytes( @Nonnull FriendlyByteBuf buf ) public void toBytes( @Nonnull FriendlyByteBuf buf )
{ {
buf.writeVarInt( table.getId() ); buf.writeUtf( table.getId(), MAX_LEN );
buf.writeVarInt( table.getColumns() ); buf.writeVarInt( table.getColumns() );
buf.writeBoolean( table.getHeaders() != null ); buf.writeBoolean( table.getHeaders() != null );
if( table.getHeaders() != null ) if( table.getHeaders() != null )

View File

@@ -9,11 +9,12 @@ import dan200.computercraft.shared.network.NetworkMessage;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.chat.TextComponent; import net.minecraft.network.chat.Component;
import net.minecraft.sounds.SoundEvent; import net.minecraft.sounds.SoundEvent;
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.network.NetworkEvent; import net.minecraftforge.network.NetworkEvent;
import net.minecraftforge.registries.ForgeRegistries;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
@@ -71,7 +72,7 @@ public class PlayRecordClientMessage implements NetworkMessage
{ {
buf.writeBoolean( true ); buf.writeBoolean( true );
buf.writeUtf( name ); buf.writeUtf( name );
buf.writeRegistryId( soundEvent ); buf.writeRegistryId( ForgeRegistries.SOUND_EVENTS, soundEvent );
} }
} }
@@ -81,6 +82,6 @@ public class PlayRecordClientMessage implements NetworkMessage
{ {
Minecraft mc = Minecraft.getInstance(); Minecraft mc = Minecraft.getInstance();
mc.levelRenderer.playStreamingMusic( soundEvent, pos, null ); mc.levelRenderer.playStreamingMusic( soundEvent, pos, null );
if( name != null ) mc.gui.setNowPlaying( new TextComponent( name ) ); if( name != null ) mc.gui.setNowPlaying( Component.literal( name ) );
} }
} }

View File

@@ -46,7 +46,7 @@ public class UpgradesLoadedMessage implements NetworkMessage
pocketUpgrades = fromBytes( buf, RegistryManager.ACTIVE.getRegistry( PocketUpgradeSerialiser.REGISTRY_ID ) ); pocketUpgrades = fromBytes( buf, RegistryManager.ACTIVE.getRegistry( PocketUpgradeSerialiser.REGISTRY_ID ) );
} }
private <R extends UpgradeSerialiser<? extends T, R>, T extends IUpgradeBase> Map<String, UpgradeManager.UpgradeWrapper<R, T>> fromBytes( private <R extends UpgradeSerialiser<? extends T>, T extends IUpgradeBase> Map<String, UpgradeManager.UpgradeWrapper<R, T>> fromBytes(
@Nonnull FriendlyByteBuf buf, @Nonnull IForgeRegistry<R> registry @Nonnull FriendlyByteBuf buf, @Nonnull IForgeRegistry<R> registry
) )
{ {
@@ -72,12 +72,12 @@ public class UpgradesLoadedMessage implements NetworkMessage
@Override @Override
public void toBytes( @Nonnull FriendlyByteBuf buf ) public void toBytes( @Nonnull FriendlyByteBuf buf )
{ {
toBytes( buf, turtleUpgrades ); toBytes( buf, TurtleUpgradeSerialiser.registry(), turtleUpgrades );
toBytes( buf, pocketUpgrades ); toBytes( buf, PocketUpgradeSerialiser.registry(), pocketUpgrades );
} }
private <R extends UpgradeSerialiser<? extends T, R>, T extends IUpgradeBase> void toBytes( private <R extends UpgradeSerialiser<? extends T>, T extends IUpgradeBase> void toBytes(
@Nonnull FriendlyByteBuf buf, Map<String, UpgradeManager.UpgradeWrapper<R, T>> upgrades @Nonnull FriendlyByteBuf buf, IForgeRegistry<R> registry, Map<String, UpgradeManager.UpgradeWrapper<R, T>> upgrades
) )
{ {
buf.writeVarInt( upgrades.size() ); buf.writeVarInt( upgrades.size() );
@@ -85,11 +85,12 @@ public class UpgradesLoadedMessage implements NetworkMessage
{ {
buf.writeUtf( entry.getKey() ); buf.writeUtf( entry.getKey() );
var serialiser = entry.getValue().serialiser();
@SuppressWarnings( "unchecked" ) @SuppressWarnings( "unchecked" )
var serialiser = (UpgradeSerialiser<T, R>) entry.getValue().serialiser(); var unwrapedSerialiser = (UpgradeSerialiser<T>) serialiser;
buf.writeResourceLocation( Objects.requireNonNull( serialiser.getRegistryName(), "Serialiser is not registered!" ) ); buf.writeResourceLocation( Objects.requireNonNull( registry.getKey( serialiser ), "Serialiser is not registered!" ) );
serialiser.toNetwork( buf, entry.getValue().upgrade() ); unwrapedSerialiser.toNetwork( buf, entry.getValue().upgrade() );
buf.writeUtf( entry.getValue().modId() ); buf.writeUtf( entry.getValue().modId() );
} }

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

@@ -20,7 +20,6 @@ import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction; import net.minecraft.core.Direction;
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.TranslatableComponent;
import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.level.ServerPlayer;
import net.minecraft.sounds.SoundEvent; import net.minecraft.sounds.SoundEvent;
import net.minecraft.world.*; import net.minecraft.world.*;
@@ -121,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;
} }
@@ -563,7 +562,7 @@ public final class TileDiskDrive extends TileGeneric implements DefaultInventory
@Override @Override
public Component getName() public Component getName()
{ {
return customName != null ? customName : new TranslatableComponent( getBlockState().getBlock().getDescriptionId() ); return customName != null ? customName : Component.translatable( getBlockState().getBlock().getDescriptionId() );
} }
@Nonnull @Nonnull

View File

@@ -14,6 +14,7 @@ import dan200.computercraft.api.peripheral.IDynamicPeripheral;
import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.api.peripheral.IPeripheral;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraftforge.registries.ForgeRegistries;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@@ -29,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 = tile.getType().getRegistryName(); 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

@@ -8,6 +8,7 @@ package dan200.computercraft.shared.peripheral.generic.data;
import dan200.computercraft.api.detail.BlockReference; import dan200.computercraft.api.detail.BlockReference;
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.properties.Property; import net.minecraft.world.level.block.state.properties.Property;
import net.minecraftforge.registries.ForgeRegistries;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import java.util.HashMap; import java.util.HashMap;
@@ -20,7 +21,7 @@ public class BlockData
{ {
BlockState state = block.state(); BlockState state = block.state();
data.put( "name", DataHelpers.getId( state.getBlock() ) ); data.put( "name", DataHelpers.getId( ForgeRegistries.BLOCKS, state.getBlock() ) );
Map<Object, Object> stateTable = new HashMap<>(); Map<Object, Object> stateTable = new HashMap<>();
for( Map.Entry<Property<?>, ? extends Comparable<?>> entry : state.getValues().entrySet() ) for( Map.Entry<Property<?>, ? extends Comparable<?>> entry : state.getValues().entrySet() )

View File

@@ -8,7 +8,7 @@ package dan200.computercraft.shared.peripheral.generic.data;
import net.minecraft.core.Holder; import net.minecraft.core.Holder;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraft.tags.TagKey; import net.minecraft.tags.TagKey;
import net.minecraftforge.registries.IForgeRegistryEntry; import net.minecraftforge.registries.IForgeRegistry;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@@ -33,9 +33,9 @@ public final class DataHelpers
} }
@Nullable @Nullable
public static String getId( @Nonnull IForgeRegistryEntry<?> entry ) public static <T> String getId( @Nonnull IForgeRegistry<T> registry, T entry )
{ {
ResourceLocation id = entry.getRegistryName(); ResourceLocation id = registry.getKey( entry );
return id == null ? null : id.toString(); return id == null ? null : id.toString();
} }
} }

View File

@@ -6,6 +6,7 @@
package dan200.computercraft.shared.peripheral.generic.data; package dan200.computercraft.shared.peripheral.generic.data;
import net.minecraftforge.fluids.FluidStack; import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.registries.ForgeRegistries;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import java.util.Map; import java.util.Map;
@@ -15,7 +16,7 @@ public class FluidData
@Nonnull @Nonnull
public static <T extends Map<? super String, Object>> T fillBasic( @Nonnull T data, @Nonnull FluidStack stack ) public static <T extends Map<? super String, Object>> T fillBasic( @Nonnull T data, @Nonnull FluidStack stack )
{ {
data.put( "name", DataHelpers.getId( stack.getFluid() ) ); data.put( "name", DataHelpers.getId( ForgeRegistries.FLUIDS, stack.getFluid() ) );
data.put( "amount", stack.getAmount() ); data.put( "amount", stack.getAmount() );
return data; return data;
} }

View File

@@ -15,6 +15,7 @@ import net.minecraft.world.item.EnchantedBookItem;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.enchantment.Enchantment; import net.minecraft.world.item.enchantment.Enchantment;
import net.minecraft.world.item.enchantment.EnchantmentHelper; import net.minecraft.world.item.enchantment.EnchantmentHelper;
import net.minecraftforge.registries.ForgeRegistries;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@@ -29,7 +30,7 @@ public class ItemData
@Nonnull @Nonnull
public static <T extends Map<? super String, Object>> T fillBasicSafe( @Nonnull T data, @Nonnull ItemStack stack ) public static <T extends Map<? super String, Object>> T fillBasicSafe( @Nonnull T data, @Nonnull ItemStack stack )
{ {
data.put( "name", DataHelpers.getId( stack.getItem() ) ); data.put( "name", DataHelpers.getId( ForgeRegistries.ITEMS, stack.getItem() ) );
data.put( "count", stack.getCount() ); data.put( "count", stack.getCount() );
return data; return data;
@@ -188,7 +189,7 @@ public class ItemData
Enchantment enchantment = entry.getKey(); Enchantment enchantment = entry.getKey();
Integer level = entry.getValue(); Integer level = entry.getValue();
HashMap<String, Object> enchant = new HashMap<>( 3 ); HashMap<String, Object> enchant = new HashMap<>( 3 );
enchant.put( "name", DataHelpers.getId( enchantment ) ); enchant.put( "name", DataHelpers.getId( ForgeRegistries.ENCHANTMENTS, enchantment ) );
enchant.put( "level", level ); enchant.put( "level", level );
enchant.put( "displayName", enchantment.getFullname( level ).getString() ); enchant.put( "displayName", enchantment.getFullname( level ).getString() );
enchants.add( enchant ); enchants.add( enchant );

View File

@@ -9,7 +9,6 @@ import dan200.computercraft.api.lua.LuaException;
import net.minecraft.ResourceLocationException; import net.minecraft.ResourceLocationException;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraftforge.registries.IForgeRegistry; import net.minecraftforge.registries.IForgeRegistry;
import net.minecraftforge.registries.IForgeRegistryEntry;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
@@ -42,7 +41,7 @@ final class ArgumentHelpers
} }
@Nonnull @Nonnull
public static <T extends IForgeRegistryEntry<T>> T getRegistryEntry( String name, String typeName, IForgeRegistry<T> registry ) throws LuaException public static <T> T getRegistryEntry( String name, String typeName, IForgeRegistry<T> registry ) throws LuaException
{ {
ResourceLocation id; ResourceLocation id;
try try

View File

@@ -63,7 +63,7 @@ public abstract class ItemBlockCable extends BlockItem
@Override @Override
public void fillItemCategory( @Nonnull CreativeModeTab group, @Nonnull NonNullList<ItemStack> list ) public void fillItemCategory( @Nonnull CreativeModeTab group, @Nonnull NonNullList<ItemStack> list )
{ {
if( allowdedIn( group ) ) list.add( new ItemStack( this ) ); if( allowedIn( group ) ) list.add( new ItemStack( this ) );
} }
@Nonnull @Nonnull

View File

@@ -20,7 +20,7 @@ import dan200.computercraft.shared.util.TickScheduler;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction; import net.minecraft.core.Direction;
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.chat.TranslatableComponent; import net.minecraft.network.chat.Component;
import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult; import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.player.Player;
@@ -269,12 +269,12 @@ public class TileCable extends TileGeneric
{ {
if( oldName != null ) if( oldName != null )
{ {
player.displayClientMessage( new TranslatableComponent( "chat.computercraft.wired_modem.peripheral_disconnected", player.displayClientMessage( Component.translatable( "chat.computercraft.wired_modem.peripheral_disconnected",
ChatHelpers.copy( oldName ) ), false ); ChatHelpers.copy( oldName ) ), false );
} }
if( newName != null ) if( newName != null )
{ {
player.displayClientMessage( new TranslatableComponent( "chat.computercraft.wired_modem.peripheral_connected", player.displayClientMessage( Component.translatable( "chat.computercraft.wired_modem.peripheral_connected",
ChatHelpers.copy( newName ) ), false ); ChatHelpers.copy( newName ) ), false );
} }
} }

View File

@@ -20,8 +20,8 @@ import dan200.computercraft.shared.util.TickScheduler;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction; import net.minecraft.core.Direction;
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.chat.TextComponent; import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.TranslatableComponent; import net.minecraft.network.chat.MutableComponent;
import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult; import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.player.Player;
@@ -223,14 +223,14 @@ public class TileWiredModemFull extends TileGeneric
List<String> names = new ArrayList<>( peripherals ); List<String> names = new ArrayList<>( peripherals );
names.sort( Comparator.naturalOrder() ); names.sort( Comparator.naturalOrder() );
TextComponent base = new TextComponent( "" ); MutableComponent base = Component.literal( "" );
for( int i = 0; i < names.size(); i++ ) for( int i = 0; i < names.size(); i++ )
{ {
if( i > 0 ) base.append( ", " ); if( i > 0 ) base.append( ", " );
base.append( ChatHelpers.copy( names.get( i ) ) ); base.append( ChatHelpers.copy( names.get( i ) ) );
} }
player.displayClientMessage( new TranslatableComponent( kind, base ), false ); player.displayClientMessage( Component.translatable( kind, base ), false );
} }
@Override @Override

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

@@ -15,7 +15,6 @@ import net.minecraft.core.Direction;
import net.minecraft.core.NonNullList; import net.minecraft.core.NonNullList;
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.TranslatableComponent;
import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.*; import net.minecraft.world.*;
import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.entity.player.Inventory;
@@ -100,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;
} }
@@ -492,7 +491,7 @@ public final class TilePrinter extends TileGeneric implements DefaultSidedInvent
@Override @Override
public Component getName() public Component getName()
{ {
return customName != null ? customName : new TranslatableComponent( getBlockState().getBlock().getDescriptionId() ); return customName != null ? customName : Component.translatable( getBlockState().getBlock().getDescriptionId() );
} }
@Nonnull @Nonnull

View File

@@ -27,6 +27,7 @@ import net.minecraft.sounds.SoundSource;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.state.properties.NoteBlockInstrument; import net.minecraft.world.level.block.state.properties.NoteBlockInstrument;
import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.Vec3;
import net.minecraftforge.registries.ForgeRegistries;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import java.util.*; import java.util.*;
@@ -89,7 +90,7 @@ public abstract class SpeakerPeripheral implements IPeripheral
lastPlayTime = clock; lastPlayTime = clock;
server.getPlayerList().broadcast( server.getPlayerList().broadcast(
null, pos.x, pos.y, pos.z, sound.volume * 16, level.dimension(), null, pos.x, pos.y, pos.z, sound.volume * 16, level.dimension(),
new ClientboundCustomSoundPacket( sound.location, SoundSource.RECORDS, pos, sound.volume, sound.pitch ) new ClientboundCustomSoundPacket( sound.location, SoundSource.RECORDS, pos, sound.volume, sound.pitch, level.getRandom().nextLong() )
); );
} }
pendingNotes.clear(); pendingNotes.clear();
@@ -241,7 +242,7 @@ public abstract class SpeakerPeripheral implements IPeripheral
synchronized( pendingNotes ) synchronized( pendingNotes )
{ {
if( pendingNotes.size() >= ComputerCraft.maxNotesPerTick ) return false; if( pendingNotes.size() >= ComputerCraft.maxNotesPerTick ) return false;
pendingNotes.add( new PendingSound( instrument.getSoundEvent().getRegistryName(), volume, (float) Math.pow( 2.0, (pitch - 12.0) / 12.0 ) ) ); pendingNotes.add( new PendingSound( ForgeRegistries.SOUND_EVENTS.getKey( instrument.getSoundEvent() ), volume, (float) Math.pow( 2.0, (pitch - 12.0) / 12.0 ) ) );
} }
return true; return true;
} }

View File

@@ -38,7 +38,7 @@ public record SpeakerPosition(@Nullable Level level, @Nonnull Vec3 position, @Nu
public Message asMessage() public Message asMessage()
{ {
if( level == null ) throw new NullPointerException( "Cannot send a position without a level" ); if( level == null ) throw new NullPointerException( "Cannot send a position without a level" );
return new Message( level.dimension().getRegistryName(), position, entity == null ? OptionalInt.empty() : OptionalInt.of( entity.getId() ) ); return new Message( level.dimension().location(), position, entity == null ? OptionalInt.empty() : OptionalInt.of( entity.getId() ) );
} }
public static final class Message public static final class Message
@@ -80,7 +80,7 @@ public record SpeakerPosition(@Nullable Level level, @Nonnull Vec3 position, @Nu
{ {
Minecraft minecraft = Minecraft.getInstance(); Minecraft minecraft = Minecraft.getInstance();
Level level = minecraft.level; Level level = minecraft.level;
if( level != null && !level.dimension().getRegistryName().equals( this.level ) ) level = null; if( level != null && !level.dimension().location().equals( this.level ) ) level = null;
return new SpeakerPosition( return new SpeakerPosition(
level, position, level, position,

View File

@@ -26,8 +26,6 @@ import net.minecraft.ChatFormatting;
import net.minecraft.core.NonNullList; import net.minecraft.core.NonNullList;
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.TextComponent;
import net.minecraft.network.chat.TranslatableComponent;
import net.minecraft.world.Container; import net.minecraft.world.Container;
import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult; import net.minecraft.world.InteractionResult;
@@ -67,7 +65,7 @@ public class ItemPocketComputer extends Item implements IComputerItem, IMedia, I
{ {
ItemStack result = new ItemStack( this ); ItemStack result = new ItemStack( this );
if( id >= 0 ) result.getOrCreateTag().putInt( NBT_ID, id ); if( id >= 0 ) result.getOrCreateTag().putInt( NBT_ID, id );
if( label != null ) result.setHoverName( new TextComponent( label ) ); if( label != null ) result.setHoverName( Component.literal( label ) );
if( upgrade != null ) result.getOrCreateTag().putString( NBT_UPGRADE, upgrade.getUpgradeID().toString() ); if( upgrade != null ) result.getOrCreateTag().putString( NBT_UPGRADE, upgrade.getUpgradeID().toString() );
if( colour != -1 ) result.getOrCreateTag().putInt( NBT_COLOUR, colour ); if( colour != -1 ) result.getOrCreateTag().putInt( NBT_COLOUR, colour );
return result; return result;
@@ -76,7 +74,7 @@ public class ItemPocketComputer extends Item implements IComputerItem, IMedia, I
@Override @Override
public void fillItemCategory( @Nonnull CreativeModeTab group, @Nonnull NonNullList<ItemStack> stacks ) public void fillItemCategory( @Nonnull CreativeModeTab group, @Nonnull NonNullList<ItemStack> stacks )
{ {
if( !allowdedIn( group ) ) return; if( !allowedIn( group ) ) return;
stacks.add( create( -1, null, -1, null ) ); stacks.add( create( -1, null, -1, null ) );
PocketUpgrades.getVanillaUpgrades().map( x -> create( -1, null, -1, x ) ).forEach( stacks::add ); PocketUpgrades.getVanillaUpgrades().map( x -> create( -1, null, -1, x ) ).forEach( stacks::add );
} }
@@ -182,8 +180,8 @@ public class ItemPocketComputer extends Item implements IComputerItem, IMedia, I
IPocketUpgrade upgrade = getUpgrade( stack ); IPocketUpgrade upgrade = getUpgrade( stack );
if( upgrade != null ) if( upgrade != null )
{ {
return new TranslatableComponent( baseString + ".upgraded", return Component.translatable( baseString + ".upgraded",
new TranslatableComponent( upgrade.getUnlocalisedAdjective() ) Component.translatable( upgrade.getUnlocalisedAdjective() )
); );
} }
else else
@@ -201,7 +199,7 @@ public class ItemPocketComputer extends Item implements IComputerItem, IMedia, I
int id = getComputerID( stack ); int id = getComputerID( stack );
if( id >= 0 ) if( id >= 0 )
{ {
list.add( new TranslatableComponent( "gui.computercraft.tooltip.computer_id", id ) list.add( Component.translatable( "gui.computercraft.tooltip.computer_id", id )
.withStyle( ChatFormatting.GRAY ) ); .withStyle( ChatFormatting.GRAY ) );
} }
} }
@@ -332,7 +330,7 @@ public class ItemPocketComputer extends Item implements IComputerItem, IMedia, I
{ {
if( label != null ) if( label != null )
{ {
stack.setHoverName( new TextComponent( label ) ); stack.setHoverName( Component.literal( label ) );
} }
else else
{ {

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

@@ -16,7 +16,7 @@ import dan200.computercraft.shared.util.InventoryUtil;
import dan200.computercraft.shared.util.WorldUtil; import dan200.computercraft.shared.util.WorldUtil;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction; import net.minecraft.core.Direction;
import net.minecraft.network.chat.TextComponent; import net.minecraft.network.chat.Component;
import net.minecraft.network.protocol.game.ServerboundInteractPacket; import net.minecraft.network.protocol.game.ServerboundInteractPacket;
import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult; import net.minecraft.world.InteractionResult;
@@ -284,7 +284,7 @@ public class TurtlePlaceCommand implements ITurtleCommand
} }
Item item = stack.getItem(); Item item = stack.getItem();
if( item instanceof BucketItem || item instanceof BoatItem || item instanceof WaterLilyBlockItem || item instanceof BottleItem ) if( item instanceof BucketItem || item instanceof BoatItem || item instanceof PlaceOnWaterBlockItem || item instanceof BottleItem )
{ {
InteractionResult actionResult = ForgeHooks.onItemRightClick( turtlePlayer, InteractionHand.MAIN_HAND ); InteractionResult actionResult = ForgeHooks.onItemRightClick( turtlePlayer, InteractionHand.MAIN_HAND );
if( actionResult != null && actionResult != InteractionResult.PASS ) return actionResult; if( actionResult != null && actionResult != InteractionResult.PASS ) return actionResult;
@@ -311,13 +311,13 @@ public class TurtlePlaceCommand implements ITurtleCommand
{ {
String line = split[i - firstLine]; String line = split[i - firstLine];
signTile.setMessage( i, line.length() > 15 signTile.setMessage( i, line.length() > 15
? new TextComponent( line.substring( 0, 15 ) ) ? Component.literal( line.substring( 0, 15 ) )
: new TextComponent( line ) : Component.literal( line )
); );
} }
else else
{ {
signTile.setMessage( i, new TextComponent( "" ) ); signTile.setMessage( i, Component.literal( "" ) );
} }
} }
signTile.setChanged(); signTile.setChanged();

Some files were not shown because too many files have changed in this diff Show More