1
0
mirror of https://github.com/SquidDev-CC/CC-Tweaked synced 2025-08-29 08:42:17 +00:00

Merge branch 'fabric' into 1.17-alpha

This commit is contained in:
Nikita Savyolov
2021-10-09 21:02:41 +03:00
240 changed files with 5255 additions and 2663 deletions

View File

@@ -12,10 +12,10 @@ jobs:
- name: Checkout submodules - name: Checkout submodules
run: git submodule update --init --recursive run: git submodule update --init --recursive
- name: Set up Java 8 - name: Set up Java 16
uses: actions/setup-java@v1 uses: actions/setup-java@v1
with: with:
java-version: 8 java-version: 16
- name: Cache gradle dependencies - name: Cache gradle dependencies
uses: actions/cache@v2 uses: actions/cache@v2

1
.gitignore vendored
View File

@@ -21,3 +21,4 @@
.gradle .gradle
*.DS_Store *.DS_Store
.project .project
*.launch

View File

@@ -1,13 +1,13 @@
plugins { plugins {
id 'fabric-loom' version '0.8-SNAPSHOT' id 'fabric-loom' version '0.9-SNAPSHOT'
id 'maven-publish' id 'maven-publish'
id "checkstyle" id "checkstyle"
id "com.github.hierynomus.license" version "0.15.0" id "com.github.hierynomus.license" version "0.16.1"
} }
java { java {
toolchain { toolchain {
languageVersion = JavaLanguageVersion.of(8) languageVersion = JavaLanguageVersion.of(16)
vendor = JvmVendorSpec.ADOPTOPENJDK vendor = JvmVendorSpec.ADOPTOPENJDK
} }
} }
@@ -22,18 +22,23 @@ repositories {
maven { url 'https://jitpack.io' } maven { url 'https://jitpack.io' }
maven { url 'https://api.modrinth.com/maven'} maven { url 'https://api.modrinth.com/maven'}
maven { url "https://maven.shedaniel.me/" } maven { url "https://maven.shedaniel.me/" }
maven { url "https://maven.terraformersmc.com/" }
maven { maven {
name "SquidDev" name "SquidDev"
url "https://squiddev.cc/maven" url "https://squiddev.cc/maven"
} }
} }
loom {
accessWidenerPath = file("src/main/resources/cc.accesswidener")
}
configurations { configurations {
implementation.extendsFrom shade implementation.extendsFrom shade
} }
dependencies { dependencies {
checkstyle "com.puppycrawl.tools:checkstyle:8.25" checkstyle 'com.puppycrawl.tools:checkstyle:8.45.1'
minecraft "com.mojang:minecraft:${mc_version}" minecraft "com.mojang:minecraft:${mc_version}"
mappings "net.fabricmc:yarn:${mc_version}+build.${mappings_version}:v2" mappings "net.fabricmc:yarn:${mc_version}+build.${mappings_version}:v2"
@@ -43,7 +48,7 @@ dependencies {
modApi("me.shedaniel.cloth:cloth-config-fabric:${cloth_config_version}") { modApi("me.shedaniel.cloth:cloth-config-fabric:${cloth_config_version}") {
exclude(group: "net.fabricmc.fabric-api") exclude(group: "net.fabricmc.fabric-api")
} }
modImplementation "io.github.prospector:modmenu:${modmenu_version}" modImplementation "com.terraformersmc:modmenu:${modmenu_version}"
modImplementation "me.shedaniel.cloth.api:cloth-utils-v1:${cloth_api_version}" modImplementation "me.shedaniel.cloth.api:cloth-utils-v1:${cloth_api_version}"
implementation 'com.electronwill.night-config:toml:3.6.3' implementation 'com.electronwill.night-config:toml:3.6.3'
@@ -56,21 +61,16 @@ dependencies {
include 'com.electronwill.night-config:toml:3.6.3' include 'com.electronwill.night-config:toml:3.6.3'
include "me.shedaniel.cloth:cloth-config-fabric:${cloth_config_version}" include "me.shedaniel.cloth:cloth-config-fabric:${cloth_config_version}"
modRuntime "me.shedaniel:RoughlyEnoughItems-api:5.12.248" modRuntime "me.shedaniel:RoughlyEnoughItems-api-fabric:6.0.254-alpha"
modRuntime "me.shedaniel:RoughlyEnoughItems:5.12.248" modRuntime "me.shedaniel:RoughlyEnoughItems-fabric:6.0.254-alpha"
} }
processResources { processResources {
inputs.property "version", project.version inputs.property "version", project.version
from(sourceSets.main.resources.srcDirs) { filesMatching("fabric.mod.json") {
include "fabric.mod.json" expand "version": project.version
expand "version": project.version }
}
from(sourceSets.main.resources.srcDirs) {
exclude "fabric.mod.json"
}
} }
// ensure that the encoding is set to UTF-8, no matter what the system default is // ensure that the encoding is set to UTF-8, no matter what the system default is

View File

@@ -58,13 +58,13 @@
<module name="SimplifyBooleanExpression" /> <module name="SimplifyBooleanExpression" />
<module name="SimplifyBooleanReturn" /> <module name="SimplifyBooleanReturn" />
<module name="StringLiteralEquality" /> <module name="StringLiteralEquality" />
<module name="UnnecessaryParentheses" /> <!-- <module name="UnnecessaryParentheses" /> -->
<module name="UnnecessarySemicolonAfterTypeMemberDeclaration" /> <module name="UnnecessarySemicolonAfterTypeMemberDeclaration" />
<module name="UnnecessarySemicolonInTryWithResources" /> <module name="UnnecessarySemicolonInTryWithResources" />
<module name="UnnecessarySemicolonInEnumeration" /> <module name="UnnecessarySemicolonInEnumeration" />
<!-- Imports --> <!-- Imports -->
<module name="CustomImportOrder" /> <!--<module name="CustomImportOrder" />-->
<module name="IllegalImport" /> <module name="IllegalImport" />
<module name="RedundantImport" /> <module name="RedundantImport" />
<module name="UnusedImports" /> <module name="UnusedImports" />

View File

@@ -6,12 +6,12 @@ mod_version=1.96.1-rc1
# Minecraft properties # Minecraft properties
mc_version=1.17.1 mc_version=1.17.1
mappings_version=10 mappings_version=61
# Dependencies # Dependencies
cloth_config_version=5.0.34 cloth_config_version=5.0.34
fabric_loader_version=0.11.6 fabric_loader_version=0.11.7
fabric_api_version=0.36.1+1.17 fabric_api_version=0.40.1+1.17
jankson_version=1.2.0 jankson_version=1.2.0
modmenu_version=1.16.9 modmenu_version=2.0.2
cloth_api_version=2.0.54 cloth_api_version=2.0.54

View File

@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.1.1-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists

View File

@@ -73,6 +73,8 @@ public final class ComputerCraft implements ModInitializer
) ); ) );
public static int httpMaxRequests = 16; public static int httpMaxRequests = 16;
public static int httpMaxWebsockets = 4; public static int httpMaxWebsockets = 4;
public static int httpDownloadBandwidth = 32 * 1024 * 1024;
public static int httpUploadBandwidth = 32 * 1024 * 1024;
public static boolean enableCommandBlock = false; public static boolean enableCommandBlock = false;
public static int modemRange = 64; public static int modemRange = 64;
@@ -82,6 +84,7 @@ public final class ComputerCraft implements ModInitializer
public static int maxNotesPerTick = 8; public static int maxNotesPerTick = 8;
public static MonitorRenderer monitorRenderer = MonitorRenderer.BEST; public static MonitorRenderer monitorRenderer = MonitorRenderer.BEST;
public static double monitorDistanceSq = 4096; public static double monitorDistanceSq = 4096;
public static int monitorDistance = 65;
public static long monitorBandwidth = 1_000_000; public static long monitorBandwidth = 1_000_000;
public static boolean turtlesNeedFuel = true; public static boolean turtlesNeedFuel = true;

View File

@@ -6,16 +6,17 @@
package dan200.computercraft.api.client; package dan200.computercraft.api.client;
import dan200.computercraft.fabric.mixin.AffineTransformationAccess;
import net.fabricmc.api.EnvType; import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment; import net.fabricmc.api.Environment;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.client.render.model.BakedModel; import net.minecraft.client.render.model.BakedModel;
import net.minecraft.client.render.model.BakedModelManager; import net.minecraft.client.render.model.BakedModelManager;
import net.minecraft.client.util.ModelIdentifier; import net.minecraft.client.util.ModelIdentifier;
import net.minecraft.util.math.AffineTransformation;
import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.util.math.AffineTransformation; import net.minecraft.util.math.Vec3f;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import java.util.Objects; import java.util.Objects;
@@ -72,22 +73,14 @@ public final class TransformedModel
{ {
matrixStack.push(); matrixStack.push();
AffineTransformationAccess access = (AffineTransformationAccess) (Object) matrix; Vec3f translation = matrix.getTranslation();
if( access.getTranslation() != null ) matrixStack.translate( translation.getX(), translation.getY(), translation.getZ() );
{
matrixStack.translate( access.getTranslation().getX(), access.getTranslation().getY(), access.getTranslation().getZ() );
}
matrixStack.multiply( matrix.getRotation2() ); matrixStack.multiply( matrix.getRotation2() );
if( access.getScale() != null ) Vec3f scale = matrix.getScale();
{ matrixStack.scale( scale.getX(), scale.getY(), scale.getZ() );
matrixStack.scale( access.getScale().getX(), access.getScale().getY(), access.getScale().getZ() );
}
if( access.getRotation1() != null ) matrixStack.multiply( matrix.getRotation1() );
{
matrixStack.multiply( access.getRotation1() );
}
} }
} }

View File

@@ -9,17 +9,18 @@ package dan200.computercraft.api.lua;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
/** /**
* An interface passed to peripherals and {@link IDynamicLuaObject}s by computers or turtles, providing methods that allow the peripheral call to interface * An interface passed to peripherals and {@link IDynamicLuaObject}s by computers or turtles, providing methods
* with the computer. * that allow the peripheral call to interface with the computer.
*/ */
public interface ILuaContext public interface ILuaContext
{ {
/** /**
* Queue a task to be executed on the main server thread at the beginning of next tick, but do not wait for it to complete. This should be used when you * Queue a task to be executed on the main server thread at the beginning of next tick, but do not wait for it to
* need to interact with the world in a thread-safe manner but do not care about the result or you wish to run asynchronously. * complete. This should be used when you need to interact with the world in a thread-safe manner but do not care
* about the result or you wish to run asynchronously.
* *
* When the task has finished, it will enqueue a {@code task_completed} event, which takes the task id, a success value and the return values, or an * When the task has finished, it will enqueue a {@code task_completed} event, which takes the task id, a success
* error message if it failed. * value and the return values, or an error message if it failed.
* *
* @param task The task to execute on the main thread. * @param task The task to execute on the main thread.
* @return The "id" of the task. This will be the first argument to the {@code task_completed} event. * @return The "id" of the task. This will be the first argument to the {@code task_completed} event.
@@ -27,4 +28,18 @@ public interface ILuaContext
* @see LuaFunction#mainThread() To run functions on the main thread and return their results synchronously. * @see LuaFunction#mainThread() To run functions on the main thread and return their results synchronously.
*/ */
long issueMainThreadTask( @Nonnull ILuaTask task ) throws LuaException; long issueMainThreadTask( @Nonnull ILuaTask task ) throws LuaException;
/**
* Queue a task to be executed on the main server thread at the beginning of next tick, waiting for it to complete.
* This should be used when you need to interact with the world in a thread-safe manner.
*
* Note that the return values of your task are handled as events, meaning more complex objects such as maps or
* {@link IDynamicLuaObject} will not preserve their identities.
*
* @param task The task to execute on the main thread.
* @return The objects returned by {@code task}.
* @throws LuaException If the task could not be queued, or if the task threw an exception.
*/
@Nonnull
MethodResult executeMainThreadTask( @Nonnull ILuaTask task ) throws LuaException;
} }

View File

@@ -1,18 +0,0 @@
/*
* This file is part of the public ComputerCraft API - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2021. 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.lua;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public interface ILuaObject
{
@Nonnull
String[] getMethodNames();
@Nullable
Object[] callMethod( @Nonnull ILuaContext context, int method, @Nonnull Object[] arguments ) throws LuaException, InterruptedException;
}

View File

@@ -6,12 +6,15 @@
package dan200.computercraft.api.pocket; package dan200.computercraft.api.pocket;
import dan200.computercraft.shared.util.NonNullSupplier;
import net.minecraft.item.Item;
import net.minecraft.item.ItemConvertible; import net.minecraft.item.ItemConvertible;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import net.minecraft.util.Util; import net.minecraft.util.Util;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import java.util.function.Supplier;
/** /**
* A base class for {@link IPocketUpgrade}s. * A base class for {@link IPocketUpgrade}s.
@@ -22,27 +25,49 @@ public abstract class AbstractPocketUpgrade implements IPocketUpgrade
{ {
private final Identifier id; private final Identifier id;
private final String adjective; private final String adjective;
private final ItemStack stack; private final NonNullSupplier<ItemStack> stack;
protected AbstractPocketUpgrade( Identifier id, ItemConvertible item ) protected AbstractPocketUpgrade( Identifier id, String adjective, NonNullSupplier<ItemStack> stack )
{
this( id, Util.createTranslationKey( "upgrade", id ) + ".adjective", item );
}
protected AbstractPocketUpgrade( Identifier id, String adjective, ItemConvertible item )
{
this.id = id;
this.adjective = adjective;
stack = new ItemStack( item );
}
protected AbstractPocketUpgrade( Identifier id, String adjective, ItemStack stack )
{ {
this.id = id; this.id = id;
this.adjective = adjective; this.adjective = adjective;
this.stack = stack; this.stack = stack;
} }
protected AbstractPocketUpgrade( Identifier id, NonNullSupplier<ItemStack> item )
{
this( id, Util.createTranslationKey( "upgrade", id ) + ".adjective", item );
}
protected AbstractPocketUpgrade( Identifier id, String adjective, ItemStack stack )
{
this( id, adjective, () -> stack );
}
protected AbstractPocketUpgrade( Identifier id, ItemStack stack )
{
this( id, () -> stack );
}
protected AbstractPocketUpgrade( Identifier id, String adjective, ItemConvertible item )
{
this( id, adjective, new CachedStack( () -> item ) );
}
protected AbstractPocketUpgrade( Identifier id, ItemConvertible item )
{
this( id, new CachedStack( () -> item ) );
}
protected AbstractPocketUpgrade( Identifier id, String adjective, Supplier<? extends ItemConvertible> item )
{
this( id, adjective, new CachedStack( item ) );
}
protected AbstractPocketUpgrade( Identifier id, Supplier<? extends ItemConvertible> item )
{
this( id, new CachedStack( item ) );
}
@Nonnull @Nonnull
@Override @Override
@@ -62,6 +87,32 @@ public abstract class AbstractPocketUpgrade implements IPocketUpgrade
@Override @Override
public final ItemStack getCraftingItem() public final ItemStack getCraftingItem()
{ {
return stack; return stack.get();
}
/**
* Caches the construction of an item stack.
*
* @see dan200.computercraft.api.turtle.AbstractTurtleUpgrade For explanation of this class.
*/
private static final class CachedStack implements NonNullSupplier<ItemStack>
{
private final Supplier<? extends ItemConvertible> provider;
private Item item;
private ItemStack stack;
CachedStack( Supplier<? extends ItemConvertible> provider )
{
this.provider = provider;
}
@Nonnull
@Override
public ItemStack get()
{
Item item = provider.get().asItem();
if( item == this.item && stack != null ) return stack;
return stack = new ItemStack( this.item = item );
}
} }
} }

View File

@@ -6,12 +6,15 @@
package dan200.computercraft.api.turtle; package dan200.computercraft.api.turtle;
import dan200.computercraft.shared.util.NonNullSupplier;
import net.minecraft.item.Item;
import net.minecraft.item.ItemConvertible; import net.minecraft.item.ItemConvertible;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import net.minecraft.util.Util; import net.minecraft.util.Util;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import java.util.function.Supplier;
/** /**
* A base class for {@link ITurtleUpgrade}s. * A base class for {@link ITurtleUpgrade}s.
@@ -23,14 +26,9 @@ public abstract class AbstractTurtleUpgrade implements ITurtleUpgrade
private final Identifier id; private final Identifier id;
private final TurtleUpgradeType type; private final TurtleUpgradeType type;
private final String adjective; private final String adjective;
private final ItemStack stack; private final NonNullSupplier<ItemStack> stack;
protected AbstractTurtleUpgrade( Identifier id, TurtleUpgradeType type, String adjective, ItemConvertible item ) protected AbstractTurtleUpgrade( Identifier id, TurtleUpgradeType type, String adjective, NonNullSupplier<ItemStack> stack )
{
this( id, type, adjective, new ItemStack( item ) );
}
protected AbstractTurtleUpgrade( Identifier id, TurtleUpgradeType type, String adjective, ItemStack stack )
{ {
this.id = id; this.id = id;
this.type = type; this.type = type;
@@ -38,16 +36,40 @@ public abstract class AbstractTurtleUpgrade implements ITurtleUpgrade
this.stack = stack; this.stack = stack;
} }
protected AbstractTurtleUpgrade( Identifier id, TurtleUpgradeType type, ItemConvertible item ) protected AbstractTurtleUpgrade( Identifier id, TurtleUpgradeType type, NonNullSupplier<ItemStack> stack )
{
this( id, type, new ItemStack( item ) );
}
protected AbstractTurtleUpgrade( Identifier id, TurtleUpgradeType type, ItemStack stack )
{ {
this( id, type, Util.createTranslationKey( "upgrade", id ) + ".adjective", stack ); this( id, type, Util.createTranslationKey( "upgrade", id ) + ".adjective", stack );
} }
protected AbstractTurtleUpgrade( Identifier id, TurtleUpgradeType type, String adjective, ItemStack stack )
{
this( id, type, adjective, () -> stack );
}
protected AbstractTurtleUpgrade( Identifier id, TurtleUpgradeType type, ItemStack stack )
{
this( id, type, () -> stack );
}
protected AbstractTurtleUpgrade( Identifier id, TurtleUpgradeType type, String adjective, ItemConvertible item )
{
this( id, type, adjective, new CachedStack( () -> item ) );
}
protected AbstractTurtleUpgrade( Identifier id, TurtleUpgradeType type, ItemConvertible item )
{
this( id, type, new CachedStack( () -> item ) );
}
protected AbstractTurtleUpgrade( Identifier id, TurtleUpgradeType type, String adjective, Supplier<? extends ItemConvertible> item )
{
this( id, type, adjective, new CachedStack( item ) );
}
protected AbstractTurtleUpgrade( Identifier id, TurtleUpgradeType type, Supplier<? extends ItemConvertible> item )
{
this( id, type, new CachedStack( item ) );
}
@Nonnull @Nonnull
@Override @Override
@@ -74,6 +96,32 @@ public abstract class AbstractTurtleUpgrade implements ITurtleUpgrade
@Override @Override
public final ItemStack getCraftingItem() public final ItemStack getCraftingItem()
{ {
return stack; return stack.get();
}
/**
* A supplier which converts an item into an item stack.
*
* Constructing item stacks is somewhat expensive due to attaching capabilities. We cache it if given a consistent item.
*/
private static final class CachedStack implements NonNullSupplier<ItemStack>
{
private final Supplier<? extends ItemConvertible> provider;
private Item item;
private ItemStack stack;
CachedStack( Supplier<? extends ItemConvertible> provider )
{
this.provider = provider;
}
@Nonnull
@Override
public ItemStack get()
{
Item item = provider.get().asItem();
if( item == this.item && stack != null ) return stack;
return stack = new ItemStack( this.item = item );
}
} }
} }

View File

@@ -23,20 +23,16 @@ import net.minecraft.network.packet.c2s.play.RequestCommandCompletionsC2SPacket;
import net.minecraft.network.packet.c2s.play.VehicleMoveC2SPacket; import net.minecraft.network.packet.c2s.play.VehicleMoveC2SPacket;
import net.minecraft.recipe.Recipe; import net.minecraft.recipe.Recipe;
import net.minecraft.screen.NamedScreenHandlerFactory; import net.minecraft.screen.NamedScreenHandlerFactory;
import net.minecraft.screen.ScreenHandler;
import net.minecraft.server.network.ServerPlayNetworkHandler; import net.minecraft.server.network.ServerPlayNetworkHandler;
import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.server.network.ServerPlayerInteractionManager;
import net.minecraft.server.world.ServerWorld; import net.minecraft.server.world.ServerWorld;
import net.minecraft.sound.SoundCategory; import net.minecraft.sound.SoundCategory;
import net.minecraft.sound.SoundEvent; import net.minecraft.sound.SoundEvent;
import net.minecraft.text.Text; import net.minecraft.text.Text;
import net.minecraft.util.Hand; import net.minecraft.util.Hand;
import net.minecraft.util.collection.DefaultedList;
import net.minecraft.util.math.ChunkPos; import net.minecraft.util.math.ChunkPos;
import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3d;
import net.minecraft.village.TradeOfferList; import net.minecraft.village.TradeOfferList;
import net.minecraft.world.GameMode;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import javax.crypto.Cipher; import javax.crypto.Cipher;
@@ -53,7 +49,7 @@ public class FakePlayer extends ServerPlayerEntity
{ {
public FakePlayer( ServerWorld world, GameProfile gameProfile ) public FakePlayer( ServerWorld world, GameProfile gameProfile )
{ {
super( world.getServer(), world, gameProfile, new ServerPlayerInteractionManager( world ) ); super( world.getServer(), world, gameProfile );
networkHandler = new FakeNetHandler( this ); networkHandler = new FakeNetHandler( this );
} }
@@ -137,30 +133,30 @@ public class FakePlayer extends ServerPlayerEntity
{ {
} }
@Override // @Override
public void onSlotUpdate( ScreenHandler container, int slot, ItemStack stack ) // public void onSlotUpdate( ScreenHandler container, int slot, ItemStack stack )
{ // {
} // }
//
@Override // @Override
public void onHandlerRegistered( ScreenHandler container, DefaultedList<ItemStack> defaultedList ) // public void onHandlerRegistered( ScreenHandler container, DefaultedList<ItemStack> defaultedList )
{ // {
} // }
//
@Override // @Override
public void onPropertyUpdate( ScreenHandler container, int key, int value ) // public void onPropertyUpdate( ScreenHandler container, int key, int value )
{ // {
} // }
@Override @Override
public void closeHandledScreen() public void closeHandledScreen()
{ {
} }
@Override // @Override
public void updateCursorStack() // public void updateCursorStack()
{ // {
} // }
@Override @Override
public int unlockRecipes( Collection<Recipe<?>> recipes ) public int unlockRecipes( Collection<Recipe<?>> recipes )
@@ -196,12 +192,12 @@ public class FakePlayer extends ServerPlayerEntity
} }
@Override @Override
protected void onStatusEffectApplied( StatusEffectInstance statusEffectInstance ) protected void onStatusEffectApplied( StatusEffectInstance statusEffectInstance, @Nullable Entity source )
{ {
} }
@Override @Override
protected void onStatusEffectUpgraded( StatusEffectInstance statusEffectInstance, boolean particles ) protected void onStatusEffectUpgraded( StatusEffectInstance statusEffectInstance, boolean particles, @Nullable Entity source )
{ {
} }
@@ -215,10 +211,10 @@ public class FakePlayer extends ServerPlayerEntity
{ {
} }
@Override // @Override
public void changeGameMode( GameMode gameMode ) // public void setGameMode( GameMode gameMode )
{ // {
} // }
@Override @Override
public void sendMessage( Text message, MessageType type, UUID senderUuid ) public void sendMessage( Text message, MessageType type, UUID senderUuid )
@@ -232,15 +228,15 @@ public class FakePlayer extends ServerPlayerEntity
return "[Fake Player]"; return "[Fake Player]";
} }
@Override // @Override
public void sendResourcePackUrl( String url, String hash ) // public void sendResourcePackUrl( String url, String hash )
{ // {
} // }
@Override // @Override
public void onStoppedTracking( Entity entity ) // public void onStoppedTracking( Entity entity )
{ // {
} // }
@Override @Override
public void setCameraEntity( Entity entity ) public void setCameraEntity( Entity entity )
@@ -347,10 +343,5 @@ public class FakePlayer extends ServerPlayerEntity
public void disableAutoRead() public void disableAutoRead()
{ {
} }
@Override
public void setCompressionThreshold( int size )
{
}
} }
} }

View File

@@ -77,7 +77,7 @@ public final class ClientRegistry
} }
@SuppressWarnings( "NewExpressionSideOnly" ) @SuppressWarnings( "NewExpressionSideOnly" )
public static void onModelBakeEvent( ResourceManager manager, Consumer<ModelIdentifier> out ) public static void onModelBakeEvent( ResourceManager manager, Consumer<Identifier> out )
{ {
for( String model : EXTRA_MODELS ) for( String model : EXTRA_MODELS )
{ {

View File

@@ -21,10 +21,6 @@ import org.apache.commons.lang3.StringUtils;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@SuppressWarnings( {
"MethodCallSideOnly",
"LocalVariableDeclarationSideOnly"
} )
public class ClientTableFormatter implements TableFormatter public class ClientTableFormatter implements TableFormatter
{ {
public static final ClientTableFormatter INSTANCE = new ClientTableFormatter(); public static final ClientTableFormatter INSTANCE = new ClientTableFormatter();

View File

@@ -0,0 +1,84 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.client;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.sound.AbstractSoundInstance;
import net.minecraft.client.sound.SoundInstance;
import net.minecraft.client.sound.TickableSoundInstance;
import net.minecraft.sound.SoundCategory;
import net.minecraft.sound.SoundEvent;
import net.minecraft.util.math.Vec3d;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
public class SoundManager
{
private static final Map<UUID, MoveableSound> sounds = new HashMap<>();
public static void playSound( UUID source, Vec3d position, SoundEvent event, float volume, float pitch )
{
var soundManager = MinecraftClient.getInstance().getSoundManager();
MoveableSound oldSound = sounds.get( source );
if( oldSound != null ) soundManager.stop( oldSound );
MoveableSound newSound = new MoveableSound( event, position, volume, pitch );
sounds.put( source, newSound );
soundManager.play( newSound );
}
public static void stopSound( UUID source )
{
SoundInstance sound = sounds.remove( source );
if( sound == null ) return;
MinecraftClient.getInstance().getSoundManager().stop( sound );
}
public static void moveSound( UUID source, Vec3d position )
{
MoveableSound sound = sounds.get( source );
if( sound != null ) sound.setPosition( position );
}
public static void reset()
{
sounds.clear();
}
private static class MoveableSound extends AbstractSoundInstance implements TickableSoundInstance
{
protected MoveableSound( SoundEvent sound, Vec3d position, float volume, float pitch )
{
super( sound, SoundCategory.RECORDS );
setPosition( position );
this.volume = volume;
this.pitch = pitch;
attenuationType = SoundInstance.AttenuationType.LINEAR;
}
void setPosition( Vec3d position )
{
x = (float) position.getX();
y = (float) position.getY();
z = (float) position.getZ();
}
@Override
public boolean isDone()
{
return false;
}
@Override
public void tick()
{
}
}
}

View File

@@ -0,0 +1,230 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.client.gui;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.client.gui.widgets.ComputerSidebar;
import dan200.computercraft.client.gui.widgets.WidgetTerminal;
import dan200.computercraft.shared.computer.core.ClientComputer;
import dan200.computercraft.shared.computer.core.ComputerFamily;
import dan200.computercraft.shared.computer.inventory.ContainerComputerBase;
import dan200.computercraft.shared.computer.upload.FileUpload;
import dan200.computercraft.shared.computer.upload.UploadResult;
import dan200.computercraft.shared.network.NetworkHandler;
import dan200.computercraft.shared.network.server.ContinueUploadMessage;
import dan200.computercraft.shared.network.server.UploadFileMessage;
import net.minecraft.client.gui.screen.ingame.HandledScreen;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.text.Text;
import net.minecraft.text.TranslatableText;
import org.lwjgl.glfw.GLFW;
import javax.annotation.Nonnull;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SeekableByteChannel;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public abstract class ComputerScreenBase<T extends ContainerComputerBase> extends HandledScreen<T>
{
private static final Text OK = new TranslatableText( "gui.ok" );
private static final Text CANCEL = new TranslatableText( "gui.cancel" );
private static final Text OVERWRITE = new TranslatableText( "gui.computercraft.upload.overwrite_button" );
protected WidgetTerminal terminal;
protected final ClientComputer computer;
protected final ComputerFamily family;
protected final int sidebarYOffset;
public ComputerScreenBase( T container, PlayerInventory player, Text title, int sidebarYOffset )
{
super( container, player, title );
computer = (ClientComputer) container.getComputer();
family = container.getFamily();
this.sidebarYOffset = sidebarYOffset;
}
protected abstract WidgetTerminal createTerminal();
@Override
protected final void init()
{
super.init();
client.keyboard.setRepeatEvents( true );
terminal = addDrawableChild( createTerminal() );
ComputerSidebar.addButtons( this, computer, this::addDrawableChild, x, y + sidebarYOffset );
setFocused( terminal );
}
@Override
public final void removed()
{
super.removed();
client.keyboard.setRepeatEvents( false );
}
@Override
public final void handledScreenTick()
{
super.handledScreenTick();
terminal.update();
}
@Override
public final boolean keyPressed( int key, int scancode, int modifiers )
{
// Forward the tab key to the terminal, rather than moving between controls.
if( key == GLFW.GLFW_KEY_TAB && getFocused() != null && getFocused() == terminal )
{
return getFocused().keyPressed( key, scancode, modifiers );
}
return super.keyPressed( key, scancode, modifiers );
}
@Override
public final void render( @Nonnull MatrixStack stack, int mouseX, int mouseY, float partialTicks )
{
renderBackground( stack );
super.render( stack, mouseX, mouseY, partialTicks );
drawMouseoverTooltip( stack, mouseX, mouseY );
}
@Override
public final boolean mouseDragged( double x, double y, int button, double deltaX, double deltaY )
{
return getFocused() != null && getFocused().mouseDragged( x, y, button, deltaX, deltaY ) || super.mouseDragged( x, y, button, deltaX, deltaY );
}
@Override
protected void drawForeground( @Nonnull MatrixStack transform, int mouseX, int mouseY )
{
// Skip rendering labels.
}
@Override
public void filesDragged( @Nonnull List<Path> files )
{
// TODO: this thing doesn't work in Tweaked at this moment
if ( true ) return;
if( files.isEmpty() ) return;
if( computer == null || !computer.isOn() )
{
alert( UploadResult.FAILED_TITLE, UploadResult.COMPUTER_OFF_MSG );
return;
}
long size = 0;
List<FileUpload> toUpload = new ArrayList<>();
for( Path file : files )
{
// TODO: Recurse directories? If so, we probably want to shunt this off-thread.
if( !Files.isRegularFile( file ) ) continue;
try( SeekableByteChannel sbc = Files.newByteChannel( file ) )
{
long fileSize = sbc.size();
if( fileSize > UploadFileMessage.MAX_SIZE || (size += fileSize) >= UploadFileMessage.MAX_SIZE )
{
alert( UploadResult.FAILED_TITLE, UploadResult.TOO_MUCH_MSG );
return;
}
String name = file.getFileName().toString();
if( name.length() > UploadFileMessage.MAX_FILE_NAME )
{
alert( UploadResult.FAILED_TITLE, new TranslatableText( "gui.computercraft.upload.failed.name_too_long" ) );
return;
}
ByteBuffer buffer = ByteBuffer.allocateDirect( (int) fileSize );
sbc.read( buffer );
buffer.flip();
byte[] digest = FileUpload.getDigest( buffer );
if( digest == null )
{
alert( UploadResult.FAILED_TITLE, new TranslatableText( "gui.computercraft.upload.failed.corrupted" ) );
return;
}
buffer.rewind();
toUpload.add( new FileUpload( name, buffer, digest ) );
}
catch( IOException e )
{
ComputerCraft.log.error( "Failed uploading files", e );
alert( UploadResult.FAILED_TITLE, new TranslatableText( "gui.computercraft.upload.failed.generic", "Cannot compute checksum" ) );
}
}
if( toUpload.size() > UploadFileMessage.MAX_FILES )
{
alert( UploadResult.FAILED_TITLE, new TranslatableText( "gui.computercraft.upload.failed.too_many_files" ) );
return;
}
if( toUpload.size() > 0 )
{
UploadFileMessage.send( computer.getInstanceID(), toUpload );
}
}
public void uploadResult( UploadResult result, Text message )
{
switch( result )
{
case SUCCESS:
alert( UploadResult.SUCCESS_TITLE, message );
break;
case ERROR:
alert( UploadResult.FAILED_TITLE, message );
break;
case CONFIRM_OVERWRITE:
OptionScreen.show(
client, UploadResult.UPLOAD_OVERWRITE, message,
Arrays.asList(
OptionScreen.newButton( CANCEL, b -> cancelUpload() ),
OptionScreen.newButton( OVERWRITE, b -> continueUpload() )
),
this::cancelUpload
);
break;
}
}
private void continueUpload()
{
if( client.currentScreen instanceof OptionScreen ) ((OptionScreen) client.currentScreen).disable();
NetworkHandler.sendToServer( new ContinueUploadMessage( computer.getInstanceID(), true ) );
}
private void cancelUpload()
{
client.setScreen( this );
NetworkHandler.sendToServer( new ContinueUploadMessage( computer.getInstanceID(), false ) );
}
private void alert( Text title, Text message )
{
OptionScreen.show( client, title, message,
Collections.singletonList( OptionScreen.newButton( OK, b -> client.setScreen( this ) ) ),
() -> client.setScreen( this )
);
}
}

View File

@@ -6,22 +6,24 @@
package dan200.computercraft.client.gui; package dan200.computercraft.client.gui;
import com.mojang.blaze3d.systems.RenderSystem;
import dan200.computercraft.client.FrameInfo; import dan200.computercraft.client.FrameInfo;
import dan200.computercraft.client.render.RenderTypes;
import dan200.computercraft.core.terminal.Terminal; import dan200.computercraft.core.terminal.Terminal;
import dan200.computercraft.core.terminal.TextBuffer; import dan200.computercraft.core.terminal.TextBuffer;
import dan200.computercraft.shared.util.Colour; import dan200.computercraft.shared.util.Colour;
import dan200.computercraft.shared.util.Palette; import dan200.computercraft.shared.util.Palette;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.client.render.*; import net.minecraft.client.render.VertexConsumer;
import net.minecraft.client.render.VertexConsumerProvider;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import net.minecraft.util.math.AffineTransformation; import net.minecraft.util.math.AffineTransformation;
import net.minecraft.util.math.Matrix4f; import net.minecraft.util.math.Matrix4f;
import org.lwjgl.opengl.GL11;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import static dan200.computercraft.client.render.RenderTypes.FULL_BRIGHT_LIGHTMAP;
public final class FixedWidthFontRenderer public final class FixedWidthFontRenderer
{ {
public static final int FONT_HEIGHT = 9; public static final int FONT_HEIGHT = 9;
@@ -31,47 +33,16 @@ public final class FixedWidthFontRenderer
public static final float BACKGROUND_END = (WIDTH - 4.0f) / WIDTH; public static final float BACKGROUND_END = (WIDTH - 4.0f) / WIDTH;
private static final Matrix4f IDENTITY = AffineTransformation.identity() private static final Matrix4f IDENTITY = AffineTransformation.identity()
.getMatrix(); .getMatrix();
private static final Identifier FONT = new Identifier( "computercraft", "textures/gui/term_font.png" ); public static final Identifier FONT = new Identifier( "computercraft", "textures/gui/term_font.png" );
public static final RenderLayer TYPE = Type.MAIN;
private FixedWidthFontRenderer() private FixedWidthFontRenderer()
{ {
} }
public static void drawString( float x, float y, @Nonnull TextBuffer text, @Nonnull TextBuffer textColour, @Nullable TextBuffer backgroundColour,
@Nonnull Palette palette, boolean greyscale, float leftMarginSize, float rightMarginSize )
{
bindFont();
VertexConsumerProvider.Immediate renderer = MinecraftClient.getInstance()
.getBufferBuilders()
.getEntityVertexConsumers();
drawString( IDENTITY,
((VertexConsumerProvider) renderer).getBuffer( TYPE ),
x,
y,
text,
textColour,
backgroundColour,
palette,
greyscale,
leftMarginSize,
rightMarginSize );
renderer.draw();
}
private static void bindFont()
{
MinecraftClient.getInstance()
.getTextureManager()
.bindTexture( FONT );
RenderSystem.texParameter( GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_CLAMP );
}
public static void drawString( @Nonnull Matrix4f transform, @Nonnull VertexConsumer renderer, float x, float y, @Nonnull TextBuffer text, public static void drawString( @Nonnull Matrix4f transform, @Nonnull VertexConsumer renderer, float x, float y, @Nonnull TextBuffer text,
@Nonnull TextBuffer textColour, @Nullable TextBuffer backgroundColour, @Nonnull Palette palette, boolean greyscale, @Nonnull TextBuffer textColour, @Nullable TextBuffer backgroundColour, @Nonnull Palette palette, boolean greyscale,
float leftMarginSize, float rightMarginSize ) float leftMarginSize, float rightMarginSize, int light )
{ {
if( backgroundColour != null ) if( backgroundColour != null )
{ {
@@ -99,7 +70,7 @@ public final class FixedWidthFontRenderer
{ {
index = '?'; index = '?';
} }
drawChar( transform, renderer, x + i * FONT_WIDTH, y, index, r, g, b ); drawChar( transform, renderer, x + i * FONT_WIDTH, y, index, r, g, b, light );
} }
} }
@@ -170,7 +141,7 @@ public final class FixedWidthFontRenderer
return (float) ((rgb[0] + rgb[1] + rgb[2]) / 3); return (float) ((rgb[0] + rgb[1] + rgb[2]) / 3);
} }
private static void drawChar( Matrix4f transform, VertexConsumer buffer, float x, float y, int index, float r, float g, float b ) private static void drawChar( Matrix4f transform, VertexConsumer buffer, float x, float y, int index, float r, float g, float b, int light )
{ {
// Short circuit to avoid the common case - the texture should be blank here after all. // Short circuit to avoid the common case - the texture should be blank here after all.
if( index == '\0' || index == ' ' ) if( index == '\0' || index == ' ' )
@@ -187,26 +158,32 @@ public final class FixedWidthFontRenderer
buffer.vertex( transform, x, y, 0f ) buffer.vertex( transform, x, y, 0f )
.color( r, g, b, 1.0f ) .color( r, g, b, 1.0f )
.texture( xStart / WIDTH, yStart / WIDTH ) .texture( xStart / WIDTH, yStart / WIDTH )
.light( light )
.next(); .next();
buffer.vertex( transform, x, y + FONT_HEIGHT, 0f ) buffer.vertex( transform, x, y + FONT_HEIGHT, 0f )
.color( r, g, b, 1.0f ) .color( r, g, b, 1.0f )
.texture( xStart / WIDTH, (yStart + FONT_HEIGHT) / WIDTH ) .texture( xStart / WIDTH, (yStart + FONT_HEIGHT) / WIDTH )
.light( light )
.next(); .next();
buffer.vertex( transform, x + FONT_WIDTH, y, 0f ) buffer.vertex( transform, x + FONT_WIDTH, y, 0f )
.color( r, g, b, 1.0f ) .color( r, g, b, 1.0f )
.texture( (xStart + FONT_WIDTH) / WIDTH, yStart / WIDTH ) .texture( (xStart + FONT_WIDTH) / WIDTH, yStart / WIDTH )
.light( light )
.next(); .next();
buffer.vertex( transform, x + FONT_WIDTH, y, 0f ) buffer.vertex( transform, x + FONT_WIDTH, y, 0f )
.color( r, g, b, 1.0f ) .color( r, g, b, 1.0f )
.texture( (xStart + FONT_WIDTH) / WIDTH, yStart / WIDTH ) .texture( (xStart + FONT_WIDTH) / WIDTH, yStart / WIDTH )
.light( light )
.next(); .next();
buffer.vertex( transform, x, y + FONT_HEIGHT, 0f ) buffer.vertex( transform, x, y + FONT_HEIGHT, 0f )
.color( r, g, b, 1.0f ) .color( r, g, b, 1.0f )
.texture( xStart / WIDTH, (yStart + FONT_HEIGHT) / WIDTH ) .texture( xStart / WIDTH, (yStart + FONT_HEIGHT) / WIDTH )
.light( light )
.next(); .next();
buffer.vertex( transform, x + FONT_WIDTH, y + FONT_HEIGHT, 0f ) buffer.vertex( transform, x + FONT_WIDTH, y + FONT_HEIGHT, 0f )
.color( r, g, b, 1.0f ) .color( r, g, b, 1.0f )
.texture( (xStart + FONT_WIDTH) / WIDTH, (yStart + FONT_HEIGHT) / WIDTH ) .texture( (xStart + FONT_WIDTH) / WIDTH, (yStart + FONT_HEIGHT) / WIDTH )
.light( light )
.next(); .next();
} }
@@ -300,7 +277,7 @@ public final class FixedWidthFontRenderer
palette, palette,
greyscale, greyscale,
leftMarginSize, leftMarginSize,
rightMarginSize ); rightMarginSize, FULL_BRIGHT_LIGHTMAP );
} }
} }
@@ -328,7 +305,7 @@ public final class FixedWidthFontRenderer
b = (float) colour[2]; b = (float) colour[2];
} }
drawChar( transform, buffer, x + cursorX * FONT_WIDTH, y + cursorY * FONT_HEIGHT, '_', r, g, b ); drawChar( transform, buffer, x + cursorX * FONT_WIDTH, y + cursorY * FONT_HEIGHT, '_', r, g, b, FULL_BRIGHT_LIGHTMAP );
} }
} }
@@ -342,14 +319,12 @@ public final class FixedWidthFontRenderer
public static void drawTerminal( @Nonnull Matrix4f transform, float x, float y, @Nonnull Terminal terminal, boolean greyscale, float topMarginSize, public static void drawTerminal( @Nonnull Matrix4f transform, float x, float y, @Nonnull Terminal terminal, boolean greyscale, float topMarginSize,
float bottomMarginSize, float leftMarginSize, float rightMarginSize ) float bottomMarginSize, float leftMarginSize, float rightMarginSize )
{ {
bindFont();
VertexConsumerProvider.Immediate renderer = MinecraftClient.getInstance() VertexConsumerProvider.Immediate renderer = MinecraftClient.getInstance()
.getBufferBuilders() .getBufferBuilders()
.getEntityVertexConsumers(); .getEntityVertexConsumers();
VertexConsumer buffer = renderer.getBuffer( TYPE ); VertexConsumer buffer = renderer.getBuffer( RenderTypes.TERMINAL_WITH_DEPTH );
drawTerminal( transform, buffer, x, y, terminal, greyscale, topMarginSize, bottomMarginSize, leftMarginSize, rightMarginSize ); drawTerminal( transform, buffer, x, y, terminal, greyscale, topMarginSize, bottomMarginSize, leftMarginSize, rightMarginSize );
renderer.draw( TYPE ); renderer.draw();
} }
public static void drawTerminal( float x, float y, @Nonnull Terminal terminal, boolean greyscale, float topMarginSize, float bottomMarginSize, public static void drawTerminal( float x, float y, @Nonnull Terminal terminal, boolean greyscale, float topMarginSize, float bottomMarginSize,
@@ -360,13 +335,12 @@ public final class FixedWidthFontRenderer
public static void drawEmptyTerminal( float x, float y, float width, float height ) public static void drawEmptyTerminal( float x, float y, float width, float height )
{ {
Colour colour = Colour.BLACK;
drawEmptyTerminal( IDENTITY, x, y, width, height ); drawEmptyTerminal( IDENTITY, x, y, width, height );
} }
public static void drawEmptyTerminal( @Nonnull Matrix4f transform, float x, float y, float width, float height ) public static void drawEmptyTerminal( @Nonnull Matrix4f transform, float x, float y, float width, float height )
{ {
bindFont();
VertexConsumerProvider.Immediate renderer = MinecraftClient.getInstance() VertexConsumerProvider.Immediate renderer = MinecraftClient.getInstance()
.getBufferBuilders() .getBufferBuilders()
.getEntityVertexConsumers(); .getEntityVertexConsumers();
@@ -378,44 +352,12 @@ public final class FixedWidthFontRenderer
float height ) float height )
{ {
Colour colour = Colour.BLACK; Colour colour = Colour.BLACK;
drawQuad( transform, renderer.getBuffer( TYPE ), x, y, width, height, colour.getR(), colour.getG(), colour.getB() ); drawQuad( transform, renderer.getBuffer( RenderTypes.TERMINAL_WITH_DEPTH ), x, y, width, height, colour.getR(), colour.getG(), colour.getB() );
} }
public static void drawBlocker( @Nonnull Matrix4f transform, @Nonnull VertexConsumerProvider renderer, float x, float y, float width, float height ) public static void drawBlocker( @Nonnull Matrix4f transform, @Nonnull VertexConsumerProvider renderer, float x, float y, float width, float height )
{ {
Colour colour = Colour.BLACK; Colour colour = Colour.BLACK;
drawQuad( transform, renderer.getBuffer( Type.BLOCKER ), x, y, width, height, colour.getR(), colour.getG(), colour.getB() ); drawQuad( transform, renderer.getBuffer( RenderTypes.TERMINAL_BLOCKER ), x, y, width, height, colour.getR(), colour.getG(), colour.getB() );
}
private static final class Type extends RenderPhase
{
private static final int GL_MODE = GL11.GL_TRIANGLES;
private static final VertexFormat FORMAT = VertexFormats.POSITION_COLOR_TEXTURE;
static final RenderLayer MAIN = RenderLayer.of( "terminal_font", FORMAT, GL_MODE, 1024, false, false, // useDelegate, needsSorting
RenderLayer.MultiPhaseParameters.builder()
.texture( new RenderPhase.Texture( FONT,
false,
false ) ) // blur, minimap
.alpha( ONE_TENTH_ALPHA )
.lightmap( DISABLE_LIGHTMAP )
.writeMaskState( COLOR_MASK )
.build( false ) );
static final RenderLayer BLOCKER = RenderLayer.of( "terminal_blocker", FORMAT, GL_MODE, 256, false, false, // useDelegate, needsSorting
RenderLayer.MultiPhaseParameters.builder()
.texture( new RenderPhase.Texture( FONT,
false,
false ) ) // blur, minimap
.alpha( ONE_TENTH_ALPHA )
.writeMaskState( ALL_MASK )
.lightmap( DISABLE_LIGHTMAP )
.build( false ) );
private Type( String name, Runnable setup, Runnable destroy )
{
super( name, setup, destroy );
}
} }
} }

View File

@@ -6,54 +6,45 @@
package dan200.computercraft.client.gui; package dan200.computercraft.client.gui;
import com.mojang.blaze3d.systems.RenderSystem;
import dan200.computercraft.ComputerCraft; import dan200.computercraft.ComputerCraft;
import dan200.computercraft.client.gui.widgets.ComputerSidebar;
import dan200.computercraft.client.gui.widgets.WidgetTerminal; import dan200.computercraft.client.gui.widgets.WidgetTerminal;
import dan200.computercraft.client.gui.widgets.WidgetWrapper;
import dan200.computercraft.client.render.ComputerBorderRenderer; import dan200.computercraft.client.render.ComputerBorderRenderer;
import dan200.computercraft.shared.computer.core.ClientComputer; import dan200.computercraft.client.render.RenderTypes;
import dan200.computercraft.shared.computer.core.ComputerFamily; //import dan200.computercraft.shared.computer.inventory.ContainerComputer;
import dan200.computercraft.shared.computer.inventory.ContainerComputer;
import dan200.computercraft.shared.computer.inventory.ContainerComputerBase; import dan200.computercraft.shared.computer.inventory.ContainerComputerBase;
import dan200.computercraft.shared.computer.inventory.ContainerViewComputer; import dan200.computercraft.shared.computer.inventory.ContainerViewComputer;
import dan200.computercraft.shared.pocket.inventory.ContainerPocketComputer; //import dan200.computercraft.shared.pocket.inventory.ContainerPocketComputer;
import net.minecraft.client.gui.screen.ingame.HandledScreen;
import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.player.PlayerInventory; import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.text.Text; import net.minecraft.text.Text;
import org.lwjgl.glfw.GLFW;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import static dan200.computercraft.client.render.ComputerBorderRenderer.BORDER; import static dan200.computercraft.client.render.ComputerBorderRenderer.BORDER;
import static dan200.computercraft.client.render.ComputerBorderRenderer.MARGIN; import static dan200.computercraft.client.render.ComputerBorderRenderer.getTexture;
public class GuiComputer<T extends ContainerComputerBase> extends HandledScreen<T> public final class GuiComputer<T extends ContainerComputerBase> extends ComputerScreenBase<T>
{ {
protected final ComputerFamily family;
protected final ClientComputer computer;
private final int termWidth; private final int termWidth;
private final int termHeight; private final int termHeight;
protected WidgetTerminal terminal; private GuiComputer( T container, PlayerInventory player, Text title, int termWidth, int termHeight )
protected WidgetWrapper terminalWrapper;
protected GuiComputer( T container, PlayerInventory player, Text title, int termWidth, int termHeight )
{ {
super( container, player, title ); super( container, player, title, BORDER );
this.family = container.getFamily();
this.computer = (ClientComputer) container.getComputer();
this.termWidth = termWidth; this.termWidth = termWidth;
this.termHeight = termHeight; this.termHeight = termHeight;
this.terminal = null;
backgroundWidth = WidgetTerminal.getWidth( termWidth ) + BORDER * 2 + ComputerSidebar.WIDTH;
backgroundHeight = WidgetTerminal.getHeight( termHeight ) + BORDER * 2;
} }
public static GuiComputer<ContainerComputer> create( ContainerComputer container, PlayerInventory inventory, Text component ) public static GuiComputer<ContainerComputerBase> create( ContainerComputerBase container, PlayerInventory inventory, Text component )
{ {
return new GuiComputer<>( container, inventory, component, ComputerCraft.computerTermWidth, ComputerCraft.computerTermHeight ); return new GuiComputer<>( container, inventory, component, ComputerCraft.computerTermWidth, ComputerCraft.computerTermHeight );
} }
public static GuiComputer<ContainerPocketComputer> createPocket( ContainerPocketComputer container, PlayerInventory inventory, Text component ) public static GuiComputer<ContainerComputerBase> createPocket( ContainerComputerBase container, PlayerInventory inventory, Text component )
{ {
return new GuiComputer<>( container, inventory, component, ComputerCraft.pocketTermWidth, ComputerCraft.pocketTermHeight ); return new GuiComputer<>( container, inventory, component, ComputerCraft.pocketTermWidth, ComputerCraft.pocketTermHeight );
} }
@@ -63,96 +54,19 @@ public class GuiComputer<T extends ContainerComputerBase> extends HandledScreen<
return new GuiComputer<>( container, inventory, component, container.getWidth(), container.getHeight() ); return new GuiComputer<>( container, inventory, component, container.getWidth(), container.getHeight() );
} }
protected void initTerminal( int border, int widthExtra, int heightExtra )
{
client.keyboard.setRepeatEvents( true );
int termPxWidth = termWidth * FixedWidthFontRenderer.FONT_WIDTH;
int termPxHeight = termHeight * FixedWidthFontRenderer.FONT_HEIGHT;
backgroundWidth = termPxWidth + MARGIN * 2 + border * 2 + widthExtra;
backgroundHeight = termPxHeight + MARGIN * 2 + border * 2 + heightExtra;
super.init();
terminal = new WidgetTerminal( client, () -> computer, termWidth, termHeight, MARGIN, MARGIN, MARGIN, MARGIN );
terminalWrapper = new WidgetWrapper( terminal, MARGIN + border + x, MARGIN + border + y, termPxWidth, termPxHeight );
children.add( terminalWrapper );
setFocused( terminalWrapper );
}
@Override @Override
protected void init() protected WidgetTerminal createTerminal()
{ {
initTerminal( BORDER, 0, 0 ); return new WidgetTerminal( computer,
x + ComputerSidebar.WIDTH + BORDER, y + BORDER, termWidth, termHeight
);
} }
@Override
public void render( @Nonnull MatrixStack stack, int mouseX, int mouseY, float partialTicks )
{
this.renderBackground( stack );
super.render( stack, mouseX, mouseY, partialTicks );
drawMouseoverTooltip( stack, mouseX, mouseY );
}
@Override
protected void drawForeground( @Nonnull MatrixStack transform, int mouseX, int mouseY )
{
// Skip rendering labels.
}
@Override @Override
public void drawBackground( @Nonnull MatrixStack stack, float partialTicks, int mouseX, int mouseY ) public void drawBackground( @Nonnull MatrixStack stack, float partialTicks, int mouseX, int mouseY )
{ {
// Draw terminal ComputerBorderRenderer.render(
terminal.draw( terminalWrapper.getX(), terminalWrapper.getY() ); getTexture( family ), terminal.x, terminal.y, getZOffset(),
RenderTypes.FULL_BRIGHT_LIGHTMAP, terminal.getWidth(), terminal.getHeight() );
// Draw a border around the terminal ComputerSidebar.renderBackground( stack, x, y + sidebarYOffset );
RenderSystem.color4f( 1, 1, 1, 1 );
client.getTextureManager()
.bindTexture( ComputerBorderRenderer.getTexture( family ) );
ComputerBorderRenderer.render( terminalWrapper.getX() - MARGIN, terminalWrapper.getY() - MARGIN,
getZOffset(), terminalWrapper.getWidth() + MARGIN * 2, terminalWrapper.getHeight() + MARGIN * 2 );
}
@Override
public boolean mouseDragged( double x, double y, int button, double deltaX, double deltaY )
{
return (getFocused() != null && getFocused().mouseDragged( x, y, button, deltaX, deltaY )) || super.mouseDragged( x, y, button, deltaX, deltaY );
}
@Override
public boolean mouseReleased( double mouseX, double mouseY, int button )
{
return (getFocused() != null && getFocused().mouseReleased( mouseX, mouseY, button )) || super.mouseReleased( x, y, button );
}
@Override
public boolean keyPressed( int key, int scancode, int modifiers )
{
// Forward the tab key to the terminal, rather than moving between controls.
if( key == GLFW.GLFW_KEY_TAB && getFocused() != null && getFocused() == terminalWrapper )
{
return getFocused().keyPressed( key, scancode, modifiers );
}
return super.keyPressed( key, scancode, modifiers );
}
@Override
public void removed()
{
super.removed();
children.remove( terminal );
terminal = null;
client.keyboard.setRepeatEvents( false );
}
@Override
public void tick()
{
super.tick();
terminal.update();
} }
} }

View File

@@ -9,6 +9,7 @@ package dan200.computercraft.client.gui;
import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.systems.RenderSystem;
import dan200.computercraft.shared.peripheral.diskdrive.ContainerDiskDrive; import dan200.computercraft.shared.peripheral.diskdrive.ContainerDiskDrive;
import net.minecraft.client.gui.screen.ingame.HandledScreen; import net.minecraft.client.gui.screen.ingame.HandledScreen;
import net.minecraft.client.render.GameRenderer;
import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.player.PlayerInventory; import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.text.Text; import net.minecraft.text.Text;
@@ -36,9 +37,9 @@ public class GuiDiskDrive extends HandledScreen<ContainerDiskDrive>
@Override @Override
protected void drawBackground( @Nonnull MatrixStack transform, float partialTicks, int mouseX, int mouseY ) protected void drawBackground( @Nonnull MatrixStack transform, float partialTicks, int mouseX, int mouseY )
{ {
RenderSystem.color4f( 1.0F, 1.0F, 1.0F, 1.0F ); RenderSystem.setShader( GameRenderer::getPositionTexShader );
client.getTextureManager() RenderSystem.setShaderColor( 1.0F, 1.0F, 1.0F, 1.0F );
.bindTexture( BACKGROUND ); RenderSystem.setShaderTexture( 0, BACKGROUND );
drawTexture( transform, x, y, 0, 0, backgroundWidth, backgroundHeight ); drawTexture( transform, x, y, 0, 0, backgroundWidth, backgroundHeight );
} }
} }

View File

@@ -25,14 +25,6 @@ public class GuiPrinter extends HandledScreen<ContainerPrinter>
super( container, player, title ); super( container, player, title );
} }
/*@Override
protected void drawGuiContainerForegroundLayer( int mouseX, int mouseY )
{
String title = getTitle().getFormattedText();
font.drawString( title, (xSize - font.getStringWidth( title )) / 2.0f, 6, 0x404040 );
font.drawString( I18n.format( "container.inventory" ), 8, ySize - 96 + 2, 0x404040 );
}*/
@Override @Override
public void render( @Nonnull MatrixStack stack, int mouseX, int mouseY, float partialTicks ) public void render( @Nonnull MatrixStack stack, int mouseX, int mouseY, float partialTicks )
{ {
@@ -44,9 +36,8 @@ public class GuiPrinter extends HandledScreen<ContainerPrinter>
@Override @Override
protected void drawBackground( @Nonnull MatrixStack transform, float partialTicks, int mouseX, int mouseY ) protected void drawBackground( @Nonnull MatrixStack transform, float partialTicks, int mouseX, int mouseY )
{ {
RenderSystem.color4f( 1.0F, 1.0F, 1.0F, 1.0F ); RenderSystem.setShaderColor( 1.0F, 1.0F, 1.0F, 1.0F );
client.getTextureManager() RenderSystem.setShaderTexture( 0, BACKGROUND );
.bindTexture( BACKGROUND );
drawTexture( transform, x, y, 0, 0, backgroundWidth, backgroundHeight ); drawTexture( transform, x, y, 0, 0, backgroundWidth, backgroundHeight );
if( getScreenHandler().isPrinting() ) if( getScreenHandler().isPrinting() )

View File

@@ -22,6 +22,7 @@ import org.lwjgl.glfw.GLFW;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import static dan200.computercraft.client.render.PrintoutRenderer.*; import static dan200.computercraft.client.render.PrintoutRenderer.*;
import static dan200.computercraft.client.render.RenderTypes.FULL_BRIGHT_LIGHTMAP;
public class GuiPrintout extends HandledScreen<ContainerHeldItem> public class GuiPrintout extends HandledScreen<ContainerHeldItem>
{ {
@@ -108,7 +109,7 @@ public class GuiPrintout extends HandledScreen<ContainerHeldItem>
protected void drawBackground( @Nonnull MatrixStack transform, float partialTicks, int mouseX, int mouseY ) protected void drawBackground( @Nonnull MatrixStack transform, float partialTicks, int mouseX, int mouseY )
{ {
// Draw the printout // Draw the printout
RenderSystem.color4f( 1.0f, 1.0f, 1.0f, 1.0f ); RenderSystem.setShaderColor( 1.0f, 1.0f, 1.0f, 1.0f );
RenderSystem.enableDepthTest(); RenderSystem.enableDepthTest();
VertexConsumerProvider.Immediate renderer = MinecraftClient.getInstance() VertexConsumerProvider.Immediate renderer = MinecraftClient.getInstance()
@@ -116,8 +117,8 @@ public class GuiPrintout extends HandledScreen<ContainerHeldItem>
.getEntityVertexConsumers(); .getEntityVertexConsumers();
Matrix4f matrix = transform.peek() Matrix4f matrix = transform.peek()
.getModel(); .getModel();
drawBorder( matrix, renderer, x, y, getZOffset(), page, pages, book ); drawBorder( matrix, renderer, x, y, getZOffset(), page, pages, book, FULL_BRIGHT_LIGHTMAP );
drawText( matrix, renderer, x + X_TEXT_MARGIN, y + Y_TEXT_MARGIN, ItemPrintout.LINES_PER_PAGE * page, text, colours ); drawText( matrix, renderer, x + X_TEXT_MARGIN, y + Y_TEXT_MARGIN, ItemPrintout.LINES_PER_PAGE * page, FULL_BRIGHT_LIGHTMAP, text, colours );
renderer.draw(); renderer.draw();
} }

View File

@@ -8,6 +8,9 @@ package dan200.computercraft.client.gui;
import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.systems.RenderSystem;
import dan200.computercraft.ComputerCraft; import dan200.computercraft.ComputerCraft;
import dan200.computercraft.client.gui.widgets.ComputerSidebar;
import dan200.computercraft.client.gui.widgets.WidgetTerminal;
import dan200.computercraft.client.render.ComputerBorderRenderer;
import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.core.ComputerFamily;
import dan200.computercraft.shared.turtle.inventory.ContainerTurtle; import dan200.computercraft.shared.turtle.inventory.ContainerTurtle;
import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.MatrixStack;
@@ -17,40 +20,46 @@ import net.minecraft.util.Identifier;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
public class GuiTurtle extends GuiComputer<ContainerTurtle> import static dan200.computercraft.shared.turtle.inventory.ContainerTurtle.BORDER;
public class GuiTurtle extends ComputerScreenBase<ContainerTurtle>
{ {
private static final Identifier BACKGROUND_NORMAL = new Identifier( "computercraft", "textures/gui/turtle_normal.png" ); private static final Identifier BACKGROUND_NORMAL = new Identifier( "computercraft", "textures/gui/turtle_normal.png" );
private static final Identifier BACKGROUND_ADVANCED = new Identifier( "computercraft", "textures/gui/turtle_advanced.png" ); private static final Identifier BACKGROUND_ADVANCED = new Identifier( "computercraft", "textures/gui/turtle_advanced.png" );
private final ContainerTurtle container;
private static final int TEX_WIDTH = 254;
private static final int TEX_HEIGHT = 217;
private final ComputerFamily family;
public GuiTurtle( ContainerTurtle container, PlayerInventory player, Text title ) public GuiTurtle( ContainerTurtle container, PlayerInventory player, Text title )
{ {
super( container, player, title, ComputerCraft.turtleTermWidth, ComputerCraft.turtleTermHeight ); super( container, player, title, BORDER );
family = container.getFamily();
backgroundWidth = TEX_WIDTH + ComputerSidebar.WIDTH;
backgroundHeight = TEX_HEIGHT;
this.container = container;
} }
@Override @Override
protected void init() protected WidgetTerminal createTerminal()
{ {
initTerminal( 8, 0, 80 ); return new WidgetTerminal(
computer, x + BORDER + ComputerSidebar.WIDTH, y + BORDER,
ComputerCraft.turtleTermWidth, ComputerCraft.turtleTermHeight
);
} }
@Override @Override
public void drawBackground( @Nonnull MatrixStack transform, float partialTicks, int mouseX, int mouseY ) public void drawBackground( @Nonnull MatrixStack transform, float partialTicks, int mouseX, int mouseY )
{ {
// Draw term boolean advanced = family == ComputerFamily.ADVANCED;
Identifier texture = family == ComputerFamily.ADVANCED ? BACKGROUND_ADVANCED : BACKGROUND_NORMAL; RenderSystem.setShaderTexture( 0, advanced ? BACKGROUND_ADVANCED : BACKGROUND_NORMAL );
terminal.draw( terminalWrapper.getX(), terminalWrapper.getY() ); drawTexture( transform, x + ComputerSidebar.WIDTH, y, 0, 0, TEX_WIDTH, TEX_HEIGHT );
// Draw border/inventory
RenderSystem.color4f( 1.0F, 1.0F, 1.0F, 1.0F );
client.getTextureManager()
.bindTexture( texture );
drawTexture( transform, x, y, 0, 0, backgroundWidth, backgroundHeight );
// Draw selection slot // Draw selection slot
int slot = container.getSelectedSlot(); int slot = getScreenHandler().getSelectedSlot();
if( slot >= 0 ) if( slot >= 0 )
{ {
int slotX = slot % 4; int slotX = slot % 4;
@@ -61,5 +70,8 @@ public class GuiTurtle extends GuiComputer<ContainerTurtle>
24, 24,
24 ); 24 );
} }
RenderSystem.setShaderTexture( 0, advanced ? ComputerBorderRenderer.BACKGROUND_ADVANCED : ComputerBorderRenderer.BACKGROUND_NORMAL );
ComputerSidebar.renderBackground( transform, x, y + sidebarYOffset );
} }
} }

View File

@@ -0,0 +1,118 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.client.gui;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.client.gui.widgets.WidgetTerminal;
import dan200.computercraft.shared.computer.core.ClientComputer;
import dan200.computercraft.shared.computer.inventory.ContainerComputerBase;
import net.minecraft.client.font.TextRenderer;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.gui.screen.ingame.ScreenHandlerProvider;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.text.OrderedText;
import net.minecraft.text.Text;
import net.minecraft.text.TranslatableText;
import org.lwjgl.glfw.GLFW;
import javax.annotation.Nonnull;
import java.util.List;
public class NoTermComputerScreen<T extends ContainerComputerBase> extends Screen implements ScreenHandlerProvider<T>
{
private final T menu;
private WidgetTerminal terminal;
public NoTermComputerScreen( T menu, PlayerInventory player, Text title )
{
super( title );
this.menu = menu;
}
@Nonnull
@Override
public T getScreenHandler()
{
return menu;
}
@Override
protected void init()
{
this.passEvents = true;
client.mouse.lockCursor();
client.currentScreen = this;
super.init();
client.keyboard.setRepeatEvents( true );
terminal = addDrawableChild( new WidgetTerminal( (ClientComputer) menu.getComputer(), 0, 0, ComputerCraft.pocketTermWidth, ComputerCraft.pocketTermHeight ) );
terminal.visible = false;
terminal.active = false;
setFocused( terminal );
}
@Override
public final void removed()
{
super.removed();
client.keyboard.setRepeatEvents( false );
}
@Override
public final void tick()
{
super.tick();
terminal.update();
}
@Override
public boolean mouseScrolled( double pMouseX, double pMouseY, double pDelta )
{
client.player.getInventory().scrollInHotbar( pDelta );
return super.mouseScrolled( pMouseX, pMouseY, pDelta );
}
@Override
public void onClose()
{
client.player.closeHandledScreen();
super.onClose();
}
@Override
public boolean isPauseScreen()
{
return false;
}
@Override
public final boolean keyPressed( int key, int scancode, int modifiers )
{
// Forward the tab key to the terminal, rather than moving between controls.
if( key == GLFW.GLFW_KEY_TAB && getFocused() != null && getFocused() == terminal )
{
return getFocused().keyPressed( key, scancode, modifiers );
}
return super.keyPressed( key, scancode, modifiers );
}
@Override
public void render( MatrixStack transform, int mouseX, int mouseY, float partialTicks )
{
super.render( transform, mouseX, mouseY, partialTicks );
TextRenderer font = client.textRenderer;
List<OrderedText> lines = font.wrapLines( new TranslatableText( "gui.computercraft.pocket_computer_overlay" ), (int) (width * 0.8) );
float y = 10.0f;
for( OrderedText line : lines )
{
font.drawWithShadow( transform, line, (float) ((width / 2) - (client.textRenderer.getWidth( line ) / 2)), y, 0xFFFFFF );
y += 9.0f;
}
}
}

View File

@@ -0,0 +1,128 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.client.gui;
import com.mojang.blaze3d.systems.RenderSystem;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.font.MultilineText;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.gui.widget.ButtonWidget;
import net.minecraft.client.gui.widget.ClickableWidget;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.text.Text;
import net.minecraft.util.Identifier;
import javax.annotation.Nonnull;
import java.util.List;
public final class OptionScreen extends Screen
{
private static final Identifier BACKGROUND = new Identifier( "computercraft", "textures/gui/blank_screen.png" );
public static final int BUTTON_WIDTH = 100;
public static final int BUTTON_HEIGHT = 20;
private static final int PADDING = 16;
private static final int FONT_HEIGHT = 9;
private int x;
private int y;
private int innerWidth;
private int innerHeight;
private MultilineText messageRenderer;
private final Text message;
private final List<ClickableWidget> buttons;
private final Runnable exit;
private final Screen originalScreen;
private OptionScreen( Text title, Text message, List<ClickableWidget> buttons, Runnable exit, Screen originalScreen )
{
super( title );
this.message = message;
this.buttons = buttons;
this.exit = exit;
this.originalScreen = originalScreen;
}
public static void show( MinecraftClient client, Text title, Text message, List<ClickableWidget> buttons, Runnable exit )
{
client.setScreen( new OptionScreen( title, message, buttons, exit, unwrap( client.currentScreen ) ) );
}
public static Screen unwrap( Screen screen )
{
return screen instanceof OptionScreen ? ((OptionScreen) screen).getOriginalScreen() : screen;
}
@Override
public void init()
{
super.init();
int buttonWidth = BUTTON_WIDTH * buttons.size() + PADDING * (buttons.size() - 1);
int innerWidth = this.innerWidth = Math.max( 256, buttonWidth + PADDING * 2 );
messageRenderer = MultilineText.create( textRenderer, message, innerWidth - PADDING * 2 );
int textHeight = messageRenderer.count() * FONT_HEIGHT + PADDING * 2;
innerHeight = textHeight + (buttons.isEmpty() ? 0 : buttons.get( 0 ).getHeight()) + PADDING;
x = (width - innerWidth) / 2;
y = (height - innerHeight) / 2;
int x = (width - buttonWidth) / 2;
for( ClickableWidget button : buttons )
{
button.x = x;
button.y = y + textHeight;
addDrawableChild( button );
x += BUTTON_WIDTH + PADDING;
}
}
@Override
public void render( @Nonnull MatrixStack transform, int mouseX, int mouseY, float partialTicks )
{
renderBackground( transform );
// Render the actual texture.
RenderSystem.setShaderTexture( 0, BACKGROUND );
drawTexture( transform, x, y, 0, 0, innerWidth, PADDING );
drawTexture( transform,
x, y + PADDING, 0, PADDING, innerWidth, innerHeight - PADDING * 2,
innerWidth, PADDING
);
drawTexture( transform, x, y + innerHeight - PADDING, 0, 256 - PADDING, innerWidth, PADDING );
messageRenderer.draw( transform, x + PADDING, y + PADDING, FONT_HEIGHT, 0x404040 );
super.render( transform, mouseX, mouseY, partialTicks );
}
@Override
public void onClose()
{
exit.run();
}
public static ClickableWidget newButton( Text component, ButtonWidget.PressAction clicked )
{
return new ButtonWidget( 0, 0, BUTTON_WIDTH, BUTTON_HEIGHT, component, clicked );
}
public void disable()
{
for( ClickableWidget widget : buttons ) widget.active = false;
}
@Nonnull
public Screen getOriginalScreen()
{
return originalScreen;
}
}

View File

@@ -0,0 +1,107 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.client.gui.widgets;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.client.render.ComputerBorderRenderer;
import dan200.computercraft.shared.command.text.ChatHelpers;
import dan200.computercraft.shared.computer.core.ClientComputer;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.gui.widget.ClickableWidget;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.text.TranslatableText;
import net.minecraft.util.Formatting;
import net.minecraft.util.Identifier;
import java.util.Arrays;
import java.util.function.Consumer;
/**
* Registers buttons to interact with a computer.
*/
public final class ComputerSidebar
{
private static final Identifier TEXTURE = new Identifier( ComputerCraft.MOD_ID, "textures/gui/buttons.png" );
private static final int TEX_SIZE = 64;
private static final int ICON_WIDTH = 12;
private static final int ICON_HEIGHT = 12;
private static final int ICON_MARGIN = 2;
private static final int ICON_TEX_Y_DIFF = 14;
private static final int CORNERS_BORDER = 3;
private static final int FULL_BORDER = CORNERS_BORDER + ICON_MARGIN;
private static final int BUTTONS = 2;
private static final int HEIGHT = (ICON_HEIGHT + ICON_MARGIN * 2) * BUTTONS + CORNERS_BORDER * 2;
public static final int WIDTH = 17;
private ComputerSidebar()
{
}
public static void addButtons( Screen screen, ClientComputer computer, Consumer<ClickableWidget> add, int x, int y )
{
x += CORNERS_BORDER + 1;
y += CORNERS_BORDER + ICON_MARGIN;
add.accept( new DynamicImageButton(
screen, x, y, ICON_WIDTH, ICON_HEIGHT, () -> computer.isOn() ? 15 : 1, 1, ICON_TEX_Y_DIFF,
TEXTURE, TEX_SIZE, TEX_SIZE, b -> toggleComputer( computer ),
() -> computer.isOn() ? Arrays.asList(
new TranslatableText( "gui.computercraft.tooltip.turn_off" ),
ChatHelpers.coloured( new TranslatableText( "gui.computercraft.tooltip.turn_off.key" ), Formatting.GRAY )
) : Arrays.asList(
new TranslatableText( "gui.computercraft.tooltip.turn_on" ),
ChatHelpers.coloured( new TranslatableText( "gui.computercraft.tooltip.turn_off.key" ), Formatting.GRAY )
)
) );
y += ICON_HEIGHT + ICON_MARGIN * 2;
add.accept( new DynamicImageButton(
screen, x, y, ICON_WIDTH, ICON_HEIGHT, 29, 1, ICON_TEX_Y_DIFF,
TEXTURE, TEX_SIZE, TEX_SIZE, b -> computer.queueEvent( "terminate" ),
Arrays.asList(
new TranslatableText( "gui.computercraft.tooltip.terminate" ),
ChatHelpers.coloured( new TranslatableText( "gui.computercraft.tooltip.terminate.key" ), Formatting.GRAY )
)
) );
}
public static void renderBackground( MatrixStack transform, int x, int y )
{
Screen.drawTexture( transform,
x, y, 0, 102, WIDTH, FULL_BORDER,
ComputerBorderRenderer.TEX_SIZE, ComputerBorderRenderer.TEX_SIZE
);
Screen.drawTexture( transform,
x, y + FULL_BORDER, WIDTH, HEIGHT - FULL_BORDER * 2,
0, 107, WIDTH, 4,
ComputerBorderRenderer.TEX_SIZE, ComputerBorderRenderer.TEX_SIZE
);
Screen.drawTexture( transform,
x, y + HEIGHT - FULL_BORDER, 0, 111, WIDTH, FULL_BORDER,
ComputerBorderRenderer.TEX_SIZE, ComputerBorderRenderer.TEX_SIZE
);
}
private static void toggleComputer( ClientComputer computer )
{
if( computer.isOn() )
{
computer.shutdown();
}
else
{
computer.turnOn();
}
}
}

View File

@@ -0,0 +1,100 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.client.gui.widgets;
import com.mojang.blaze3d.systems.RenderSystem;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.gui.widget.ButtonWidget;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.text.LiteralText;
import net.minecraft.text.Text;
import net.minecraft.util.Identifier;
import javax.annotation.Nonnull;
import java.util.List;
import java.util.function.IntSupplier;
import java.util.function.Supplier;
/**
* Version of {@link net.minecraft.client.gui.widget.TexturedButtonWidget} which allows changing some properties
* dynamically.
*/
public class DynamicImageButton extends ButtonWidget
{
private final Screen screen;
private final Identifier texture;
private final IntSupplier xTexStart;
private final int yTexStart;
private final int yDiffTex;
private final int textureWidth;
private final int textureHeight;
private final Supplier<List<Text>> tooltip;
public DynamicImageButton(
Screen screen, int x, int y, int width, int height, int xTexStart, int yTexStart, int yDiffTex,
Identifier texture, int textureWidth, int textureHeight,
PressAction onPress, List<Text> tooltip
)
{
this(
screen, x, y, width, height, () -> xTexStart, yTexStart, yDiffTex,
texture, textureWidth, textureHeight,
onPress, () -> tooltip
);
}
public DynamicImageButton(
Screen screen, int x, int y, int width, int height, IntSupplier xTexStart, int yTexStart, int yDiffTex,
Identifier texture, int textureWidth, int textureHeight,
PressAction onPress, Supplier<List<Text>> tooltip
)
{
super( x, y, width, height, LiteralText.EMPTY, onPress );
this.screen = screen;
this.textureWidth = textureWidth;
this.textureHeight = textureHeight;
this.xTexStart = xTexStart;
this.yTexStart = yTexStart;
this.yDiffTex = yDiffTex;
this.texture = texture;
this.tooltip = tooltip;
}
@Override
public void renderButton( @Nonnull MatrixStack stack, int mouseX, int mouseY, float partialTicks )
{
RenderSystem.setShaderTexture( 0, texture );
RenderSystem.disableDepthTest();
int yTex = yTexStart;
if( isHovered() ) yTex += yDiffTex;
drawTexture( stack, x, y, xTexStart.getAsInt(), yTex, width, height, textureWidth, textureHeight );
RenderSystem.enableDepthTest();
if( isHovered() ) renderToolTip( stack, mouseX, mouseY );
}
@Nonnull
@Override
public Text getMessage()
{
List<Text> tooltip = this.tooltip.get();
return tooltip.isEmpty() ? LiteralText.EMPTY : tooltip.get( 0 );
}
// @Override
public void renderToolTip( @Nonnull MatrixStack stack, int mouseX, int mouseY )
{
List<Text> tooltip = this.tooltip.get();
if( !tooltip.isEmpty() )
{
screen.renderTooltip( stack, tooltip, mouseX, mouseY );
}
}
}

View File

@@ -9,66 +9,84 @@ package dan200.computercraft.client.gui.widgets;
import dan200.computercraft.client.gui.FixedWidthFontRenderer; import dan200.computercraft.client.gui.FixedWidthFontRenderer;
import dan200.computercraft.core.terminal.Terminal; import dan200.computercraft.core.terminal.Terminal;
import dan200.computercraft.shared.computer.core.ClientComputer; import dan200.computercraft.shared.computer.core.ClientComputer;
import dan200.computercraft.shared.computer.core.IComputer;
import net.minecraft.SharedConstants; import net.minecraft.SharedConstants;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.Element; import net.minecraft.client.gui.screen.narration.NarrationMessageBuilder;
import net.minecraft.client.gui.widget.ClickableWidget;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.text.LiteralText;
import net.minecraft.util.math.Matrix4f;
import org.lwjgl.glfw.GLFW; import org.lwjgl.glfw.GLFW;
import javax.annotation.Nonnull;
import java.util.BitSet; import java.util.BitSet;
import java.util.function.Supplier;
import static dan200.computercraft.client.gui.FixedWidthFontRenderer.FONT_HEIGHT; import static dan200.computercraft.client.gui.FixedWidthFontRenderer.FONT_HEIGHT;
import static dan200.computercraft.client.gui.FixedWidthFontRenderer.FONT_WIDTH; import static dan200.computercraft.client.gui.FixedWidthFontRenderer.FONT_WIDTH;
import static dan200.computercraft.client.render.ComputerBorderRenderer.MARGIN;
public class WidgetTerminal implements Element public class WidgetTerminal extends ClickableWidget
{ {
private static final float TERMINATE_TIME = 0.5f; private static final float TERMINATE_TIME = 0.5f;
private final MinecraftClient client; private final ClientComputer computer;
private final Supplier<ClientComputer> computer;
private final int termWidth; // The positions of the actual terminal
private final int termHeight; private final int innerX;
private final int leftMargin; private final int innerY;
private final int rightMargin; private final int innerWidth;
private final int topMargin; private final int innerHeight;
private final int bottomMargin;
private final BitSet keysDown = new BitSet( 256 );
private boolean focused;
private float terminateTimer = -1; private float terminateTimer = -1;
private float rebootTimer = -1; private float rebootTimer = -1;
private float shutdownTimer = -1; private float shutdownTimer = -1;
private int lastMouseButton = -1; private int lastMouseButton = -1;
private int lastMouseX = -1; private int lastMouseX = -1;
private int lastMouseY = -1; private int lastMouseY = -1;
public WidgetTerminal( MinecraftClient client, Supplier<ClientComputer> computer, int termWidth, int termHeight, int leftMargin, int rightMargin, private final BitSet keysDown = new BitSet( 256 );
int topMargin, int bottomMargin )
public WidgetTerminal( @Nonnull ClientComputer computer, int x, int y, int termWidth, int termHeight )
{ {
this.client = client; super( x, y, termWidth * FONT_WIDTH + MARGIN * 2, termHeight * FONT_HEIGHT + MARGIN * 2, LiteralText.EMPTY );
this.computer = computer; this.computer = computer;
this.termWidth = termWidth;
this.termHeight = termHeight; innerX = x + MARGIN;
this.leftMargin = leftMargin; innerY = y + MARGIN;
this.rightMargin = rightMargin; innerWidth = termWidth * FONT_WIDTH;
this.topMargin = topMargin; innerHeight = termHeight * FONT_HEIGHT;
this.bottomMargin = bottomMargin; }
@Override
public boolean charTyped( char ch, int modifiers )
{
if( ch >= 32 && ch <= 126 || ch >= 160 && ch <= 255 ) // printable chars in byte range
{
// Queue the "char" event
queueEvent( "char", Character.toString( ch ) );
}
return true;
}
private boolean inTermRegion( double mouseX, double mouseY )
{
return active && visible && mouseX >= innerX && mouseY >= innerY && mouseX < innerX + innerWidth && mouseY < innerY + innerHeight;
} }
@Override @Override
public boolean mouseClicked( double mouseX, double mouseY, int button ) public boolean mouseClicked( double mouseX, double mouseY, int button )
{ {
ClientComputer computer = this.computer.get(); if( !inTermRegion( mouseX, mouseY ) ) return false;
if( computer == null || !computer.isColour() || button < 0 || button > 2 ) if( !computer.isColour() || button < 0 || button > 2 ) return false;
{
return false;
}
Terminal term = computer.getTerminal(); Terminal term = computer.getTerminal();
if( term != null ) if( term != null )
{ {
int charX = (int) (mouseX / FONT_WIDTH); int charX = (int) ((mouseX - innerX) / FONT_WIDTH);
int charY = (int) (mouseY / FONT_HEIGHT); int charY = (int) ((mouseY - innerY) / FONT_HEIGHT);
charX = Math.min( Math.max( charX, 0 ), term.getWidth() - 1 ); charX = Math.min( Math.max( charX, 0 ), term.getWidth() - 1 );
charY = Math.min( Math.max( charY, 0 ), term.getHeight() - 1 ); charY = Math.min( Math.max( charY, 0 ), term.getHeight() - 1 );
@@ -85,17 +103,14 @@ public class WidgetTerminal implements Element
@Override @Override
public boolean mouseReleased( double mouseX, double mouseY, int button ) public boolean mouseReleased( double mouseX, double mouseY, int button )
{ {
ClientComputer computer = this.computer.get(); if( !inTermRegion( mouseX, mouseY ) ) return false;
if( computer == null || !computer.isColour() || button < 0 || button > 2 ) if( !computer.isColour() || button < 0 || button > 2 ) return false;
{
return false;
}
Terminal term = computer.getTerminal(); Terminal term = computer.getTerminal();
if( term != null ) if( term != null )
{ {
int charX = (int) (mouseX / FONT_WIDTH); int charX = (int) ((mouseX - innerX) / FONT_WIDTH);
int charY = (int) (mouseY / FONT_HEIGHT); int charY = (int) ((mouseY - innerY) / FONT_HEIGHT);
charX = Math.min( Math.max( charX, 0 ), term.getWidth() - 1 ); charX = Math.min( Math.max( charX, 0 ), term.getWidth() - 1 );
charY = Math.min( Math.max( charY, 0 ), term.getHeight() - 1 ); charY = Math.min( Math.max( charY, 0 ), term.getHeight() - 1 );
@@ -115,17 +130,14 @@ public class WidgetTerminal implements Element
@Override @Override
public boolean mouseDragged( double mouseX, double mouseY, int button, double v2, double v3 ) public boolean mouseDragged( double mouseX, double mouseY, int button, double v2, double v3 )
{ {
ClientComputer computer = this.computer.get(); if( !inTermRegion( mouseX, mouseY ) ) return false;
if( computer == null || !computer.isColour() || button < 0 || button > 2 ) if( !computer.isColour() || button < 0 || button > 2 ) return false;
{
return false;
}
Terminal term = computer.getTerminal(); Terminal term = computer.getTerminal();
if( term != null ) if( term != null )
{ {
int charX = (int) (mouseX / FONT_WIDTH); int charX = (int) ((mouseX - innerX) / FONT_WIDTH);
int charY = (int) (mouseY / FONT_HEIGHT); int charY = (int) ((mouseY - innerY) / FONT_HEIGHT);
charX = Math.min( Math.max( charX, 0 ), term.getWidth() - 1 ); charX = Math.min( Math.max( charX, 0 ), term.getWidth() - 1 );
charY = Math.min( Math.max( charY, 0 ), term.getHeight() - 1 ); charY = Math.min( Math.max( charY, 0 ), term.getHeight() - 1 );
@@ -143,17 +155,14 @@ public class WidgetTerminal implements Element
@Override @Override
public boolean mouseScrolled( double mouseX, double mouseY, double delta ) public boolean mouseScrolled( double mouseX, double mouseY, double delta )
{ {
ClientComputer computer = this.computer.get(); if( !inTermRegion( mouseX, mouseY ) ) return false;
if( computer == null || !computer.isColour() || delta == 0 ) if( !computer.isColour() || delta == 0 ) return false;
{
return false;
}
Terminal term = computer.getTerminal(); Terminal term = computer.getTerminal();
if( term != null ) if( term != null )
{ {
int charX = (int) (mouseX / FONT_WIDTH); int charX = (int) ((mouseX - innerX) / FONT_WIDTH);
int charY = (int) (mouseY / FONT_HEIGHT); int charY = (int) ((mouseY - innerY) / FONT_HEIGHT);
charX = Math.min( Math.max( charX, 0 ), term.getWidth() - 1 ); charX = Math.min( Math.max( charX, 0 ), term.getWidth() - 1 );
charY = Math.min( Math.max( charY, 0 ), term.getHeight() - 1 ); charY = Math.min( Math.max( charY, 0 ), term.getHeight() - 1 );
@@ -198,7 +207,7 @@ public class WidgetTerminal implements Element
case GLFW.GLFW_KEY_V: case GLFW.GLFW_KEY_V:
// Ctrl+V for paste // Ctrl+V for paste
String clipboard = client.keyboard.getClipboard(); String clipboard = MinecraftClient.getInstance().keyboard.getClipboard();
if( clipboard != null ) if( clipboard != null )
{ {
// Clip to the first occurrence of \r or \n // Clip to the first occurrence of \r or \n
@@ -239,11 +248,7 @@ public class WidgetTerminal implements Element
// Queue the "key" event and add to the down set // Queue the "key" event and add to the down set
boolean repeat = keysDown.get( key ); boolean repeat = keysDown.get( key );
keysDown.set( key ); keysDown.set( key );
IComputer computer = this.computer.get(); computer.keyDown( key, repeat );
if( computer != null )
{
computer.keyDown( key, repeat );
}
} }
return true; return true;
@@ -256,11 +261,7 @@ public class WidgetTerminal implements Element
if( key >= 0 && keysDown.get( key ) ) if( key >= 0 && keysDown.get( key ) )
{ {
keysDown.set( key, false ); keysDown.set( key, false );
IComputer computer = this.computer.get(); computer.keyUp( key );
if( computer != null )
{
computer.keyUp( key );
}
} }
switch( key ) switch( key )
@@ -284,47 +285,26 @@ public class WidgetTerminal implements Element
} }
@Override @Override
public boolean charTyped( char ch, int modifiers ) public void onFocusedChanged( boolean focused )
{ {
if( ch >= 32 && ch <= 126 || ch >= 160 && ch <= 255 ) // printable chars in byte range if( !focused )
{
// Queue the "char" event
queueEvent( "char", Character.toString( ch ) );
}
return true;
}
@Override
public boolean changeFocus( boolean reversed )
{
if( focused )
{ {
// When blurring, we should make all keys go up // When blurring, we should make all keys go up
for( int key = 0; key < keysDown.size(); key++ ) for( int key = 0; key < keysDown.size(); key++ )
{ {
if( keysDown.get( key ) ) if( keysDown.get( key ) ) computer.keyUp( key );
{
queueEvent( "key_up", key );
}
} }
keysDown.clear(); keysDown.clear();
// When blurring, we should make the last mouse button go up // When blurring, we should make the last mouse button go up
if( lastMouseButton > 0 ) if( lastMouseButton > 0 )
{ {
IComputer computer = this.computer.get(); computer.mouseUp( lastMouseButton + 1, lastMouseX + 1, lastMouseY + 1 );
if( computer != null )
{
computer.mouseUp( lastMouseButton + 1, lastMouseX + 1, lastMouseY + 1 );
}
lastMouseButton = -1; lastMouseButton = -1;
} }
shutdownTimer = terminateTimer = rebootTimer = -1; shutdownTimer = terminateTimer = rebootTimer = -1;
} }
focused = !focused;
return true;
} }
@Override @Override
@@ -335,11 +315,7 @@ public class WidgetTerminal implements Element
private void queueEvent( String event, Object... args ) private void queueEvent( String event, Object... args )
{ {
ClientComputer computer = this.computer.get(); computer.queueEvent( event, args );
if( computer != null )
{
computer.queueEvent( event, args );
}
} }
public void update() public void update()
@@ -351,50 +327,53 @@ public class WidgetTerminal implements Element
if( shutdownTimer >= 0 && shutdownTimer < TERMINATE_TIME && (shutdownTimer += 0.05f) > TERMINATE_TIME ) if( shutdownTimer >= 0 && shutdownTimer < TERMINATE_TIME && (shutdownTimer += 0.05f) > TERMINATE_TIME )
{ {
ClientComputer computer = this.computer.get(); computer.shutdown();
if( computer != null )
{
computer.shutdown();
}
} }
if( rebootTimer >= 0 && rebootTimer < TERMINATE_TIME && (rebootTimer += 0.05f) > TERMINATE_TIME ) if( rebootTimer >= 0 && rebootTimer < TERMINATE_TIME && (rebootTimer += 0.05f) > TERMINATE_TIME )
{ {
ClientComputer computer = this.computer.get(); computer.reboot();
if( computer != null )
{
computer.reboot();
}
} }
} }
private void queueEvent( String event ) private void queueEvent( String event )
{ {
ClientComputer computer = this.computer.get(); ClientComputer computer = this.computer;
if( computer != null ) if( computer != null )
{ {
computer.queueEvent( event ); computer.queueEvent( event );
} }
} }
public void draw( int originX, int originY ) @Override
public void render( @Nonnull MatrixStack transform, int mouseX, int mouseY, float partialTicks )
{ {
synchronized( computer ) if( !visible ) return;
Matrix4f matrix = transform.peek().getModel();
Terminal terminal = computer.getTerminal();
if( terminal != null )
{ {
// Draw the screen contents FixedWidthFontRenderer.drawTerminal( matrix, innerX, innerY, terminal, !computer.isColour(), MARGIN, MARGIN, MARGIN, MARGIN );
ClientComputer computer = this.computer.get(); }
Terminal terminal = computer != null ? computer.getTerminal() : null; else
if( terminal != null ) {
{ FixedWidthFontRenderer.drawEmptyTerminal( matrix, x, y, width, height );
FixedWidthFontRenderer.drawTerminal( originX, originY, terminal, !computer.isColour(), topMargin, bottomMargin, leftMargin,
rightMargin );
}
else
{
FixedWidthFontRenderer.drawEmptyTerminal( originX - leftMargin,
originY - rightMargin, termWidth * FONT_WIDTH + leftMargin + rightMargin,
termHeight * FONT_HEIGHT + topMargin + bottomMargin );
}
} }
} }
@Override
public void appendNarrations( NarrationMessageBuilder builder )
{
}
public static int getWidth( int termWidth )
{
return termWidth * FONT_WIDTH + MARGIN * 2;
}
public static int getHeight( int termHeight )
{
return termHeight * FONT_HEIGHT + MARGIN * 2;
}
} }

View File

@@ -1,106 +0,0 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.client.gui.widgets;
import net.minecraft.client.gui.Element;
public class WidgetWrapper implements Element
{
private final Element listener;
private final int x;
private final int y;
private final int width;
private final int height;
public WidgetWrapper( Element listener, int x, int y, int width, int height )
{
this.listener = listener;
this.x = x;
this.y = y;
this.width = width;
this.height = height;
}
@Override
public boolean mouseClicked( double x, double y, int button )
{
double dx = x - this.x, dy = y - this.y;
return dx >= 0 && dx < width && dy >= 0 && dy < height && listener.mouseClicked( dx, dy, button );
}
@Override
public boolean mouseReleased( double x, double y, int button )
{
double dx = x - this.x, dy = y - this.y;
return dx >= 0 && dx < width && dy >= 0 && dy < height && listener.mouseReleased( dx, dy, button );
}
@Override
public boolean mouseDragged( double x, double y, int button, double deltaX, double deltaY )
{
double dx = x - this.x, dy = y - this.y;
return dx >= 0 && dx < width && dy >= 0 && dy < height && listener.mouseDragged( dx, dy, button, deltaX, deltaY );
}
@Override
public boolean mouseScrolled( double x, double y, double delta )
{
double dx = x - this.x, dy = y - this.y;
return dx >= 0 && dx < width && dy >= 0 && dy < height && listener.mouseScrolled( dx, dy, delta );
}
@Override
public boolean keyPressed( int key, int scancode, int modifiers )
{
return listener.keyPressed( key, scancode, modifiers );
}
@Override
public boolean keyReleased( int key, int scancode, int modifiers )
{
return listener.keyReleased( key, scancode, modifiers );
}
@Override
public boolean charTyped( char character, int modifiers )
{
return listener.charTyped( character, modifiers );
}
@Override
public boolean changeFocus( boolean b )
{
return listener.changeFocus( b );
}
@Override
public boolean isMouseOver( double x, double y )
{
double dx = x - this.x, dy = y - this.y;
return dx >= 0 && dx < width && dy >= 0 && dy < height;
}
public int getX()
{
return x;
}
public int getY()
{
return y;
}
public int getWidth()
{
return width;
}
public int getHeight()
{
return height;
}
}

View File

@@ -19,12 +19,11 @@ import dan200.computercraft.shared.ComputerCraftRegistry;
import dan200.computercraft.shared.common.ContainerHeldItem; import dan200.computercraft.shared.common.ContainerHeldItem;
import dan200.computercraft.shared.common.IColouredItem; import dan200.computercraft.shared.common.IColouredItem;
import dan200.computercraft.shared.common.TileGeneric; import dan200.computercraft.shared.common.TileGeneric;
import dan200.computercraft.shared.computer.inventory.ContainerComputer; import dan200.computercraft.shared.computer.inventory.ContainerComputerBase;
import dan200.computercraft.shared.computer.inventory.ContainerViewComputer; import dan200.computercraft.shared.computer.inventory.ContainerViewComputer;
import dan200.computercraft.shared.peripheral.diskdrive.ContainerDiskDrive; import dan200.computercraft.shared.peripheral.diskdrive.ContainerDiskDrive;
import dan200.computercraft.shared.peripheral.monitor.ClientMonitor; import dan200.computercraft.shared.peripheral.monitor.ClientMonitor;
import dan200.computercraft.shared.peripheral.printer.ContainerPrinter; import dan200.computercraft.shared.peripheral.printer.ContainerPrinter;
import dan200.computercraft.shared.pocket.inventory.ContainerPocketComputer;
import dan200.computercraft.shared.pocket.items.ItemPocketComputer; import dan200.computercraft.shared.pocket.items.ItemPocketComputer;
import dan200.computercraft.shared.turtle.inventory.ContainerTurtle; import dan200.computercraft.shared.turtle.inventory.ContainerTurtle;
import dan200.computercraft.shared.util.Config; import dan200.computercraft.shared.util.Config;
@@ -35,12 +34,12 @@ import net.fabricmc.fabric.api.blockrenderlayer.v1.BlockRenderLayerMap;
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientBlockEntityEvents; import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientBlockEntityEvents;
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents; import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents;
import net.fabricmc.fabric.api.client.model.ModelLoadingRegistry; import net.fabricmc.fabric.api.client.model.ModelLoadingRegistry;
import net.fabricmc.fabric.api.client.rendereregistry.v1.BlockEntityRendererRegistry; import net.fabricmc.fabric.api.client.rendering.v1.BlockEntityRendererRegistry;
import net.fabricmc.fabric.api.client.rendereregistry.v1.EntityRendererRegistry; import net.fabricmc.fabric.api.client.rendering.v1.EntityRendererRegistry;
import net.fabricmc.fabric.api.client.screenhandler.v1.ScreenRegistry; import net.fabricmc.fabric.api.client.screenhandler.v1.ScreenRegistry;
import net.fabricmc.fabric.api.event.client.ClientSpriteRegistryCallback; import net.fabricmc.fabric.api.event.client.ClientSpriteRegistryCallback;
import net.fabricmc.fabric.mixin.object.builder.ModelPredicateProviderRegistrySpecificAccessor; import net.fabricmc.fabric.api.object.builder.v1.client.model.FabricModelPredicateProviderRegistry;
import net.minecraft.client.item.ModelPredicateProvider; import net.minecraft.client.item.UnclampedModelPredicateProvider;
import net.minecraft.client.render.RenderLayer; import net.minecraft.client.render.RenderLayer;
import net.minecraft.item.Item; import net.minecraft.item.Item;
import net.minecraft.screen.PlayerScreenHandler; import net.minecraft.screen.PlayerScreenHandler;
@@ -76,33 +75,32 @@ public final class ComputerCraftProxyClient implements ClientModInitializer
// While turtles themselves are not transparent, their upgrades may be. // While turtles themselves are not transparent, their upgrades may be.
BlockRenderLayerMap.INSTANCE.putBlock( ComputerCraftRegistry.ModBlocks.TURTLE_NORMAL, RenderLayer.getTranslucent() ); BlockRenderLayerMap.INSTANCE.putBlock( ComputerCraftRegistry.ModBlocks.TURTLE_NORMAL, RenderLayer.getTranslucent() );
BlockRenderLayerMap.INSTANCE.putBlock( ComputerCraftRegistry.ModBlocks.TURTLE_ADVANCED, RenderLayer.getTranslucent() ); BlockRenderLayerMap.INSTANCE.putBlock( ComputerCraftRegistry.ModBlocks.TURTLE_ADVANCED, RenderLayer.getTranslucent() );
// Monitors' textures have transparent fronts and so count as cutouts. // Monitors' textures have transparent fronts and so count as cutouts.
BlockRenderLayerMap.INSTANCE.putBlock( ComputerCraftRegistry.ModBlocks.MONITOR_NORMAL, RenderLayer.getCutout() ); BlockRenderLayerMap.INSTANCE.putBlock( ComputerCraftRegistry.ModBlocks.MONITOR_NORMAL, RenderLayer.getCutout() );
BlockRenderLayerMap.INSTANCE.putBlock( ComputerCraftRegistry.ModBlocks.MONITOR_ADVANCED, RenderLayer.getCutout() ); BlockRenderLayerMap.INSTANCE.putBlock( ComputerCraftRegistry.ModBlocks.MONITOR_ADVANCED, RenderLayer.getCutout() );
// Setup TESRs // Setup TESRs
BlockEntityRendererRegistry.INSTANCE.register( ComputerCraftRegistry.ModTiles.MONITOR_NORMAL, TileEntityMonitorRenderer::new ); BlockEntityRendererRegistry.register( ComputerCraftRegistry.ModTiles.MONITOR_NORMAL, TileEntityMonitorRenderer::new );
BlockEntityRendererRegistry.INSTANCE.register( ComputerCraftRegistry.ModTiles.MONITOR_ADVANCED, TileEntityMonitorRenderer::new ); BlockEntityRendererRegistry.register( ComputerCraftRegistry.ModTiles.MONITOR_ADVANCED, TileEntityMonitorRenderer::new );
BlockEntityRendererRegistry.INSTANCE.register( ComputerCraftRegistry.ModTiles.TURTLE_NORMAL, TileEntityTurtleRenderer::new ); BlockEntityRendererRegistry.register( ComputerCraftRegistry.ModTiles.TURTLE_NORMAL, TileEntityTurtleRenderer::new );
BlockEntityRendererRegistry.INSTANCE.register( ComputerCraftRegistry.ModTiles.TURTLE_ADVANCED, TileEntityTurtleRenderer::new ); BlockEntityRendererRegistry.register( ComputerCraftRegistry.ModTiles.TURTLE_ADVANCED, TileEntityTurtleRenderer::new );
ClientSpriteRegistryCallback.event( PlayerScreenHandler.BLOCK_ATLAS_TEXTURE ) ClientSpriteRegistryCallback.event( PlayerScreenHandler.BLOCK_ATLAS_TEXTURE )
.register( ClientRegistry::onTextureStitchEvent ); .register( ClientRegistry::onTextureStitchEvent );
ModelLoadingRegistry.INSTANCE.registerAppender( ClientRegistry::onModelBakeEvent ); ModelLoadingRegistry.INSTANCE.registerModelProvider( ClientRegistry::onModelBakeEvent );
ModelLoadingRegistry.INSTANCE.registerResourceProvider( loader -> ( name, context ) -> TurtleModelLoader.INSTANCE.accepts( name ) ? ModelLoadingRegistry.INSTANCE.registerResourceProvider( loader -> ( name, context ) -> TurtleModelLoader.INSTANCE.accepts( name ) ?
TurtleModelLoader.INSTANCE.loadModel( TurtleModelLoader.INSTANCE.loadModel(
name ) : null ); name ) : null );
EntityRendererRegistry.INSTANCE.register( ComputerCraftRegistry.ModEntities.TURTLE_PLAYER, TurtlePlayerRenderer::new ); EntityRendererRegistry.register( ComputerCraftRegistry.ModEntities.TURTLE_PLAYER, TurtlePlayerRenderer::new );
registerItemProperty( "state", registerItemProperty( "state",
( stack, world, player ) -> ItemPocketComputer.getState( stack ) ( stack, world, player, integer ) -> ItemPocketComputer.getState( stack )
.ordinal(), .ordinal(),
() -> ComputerCraftRegistry.ModItems.POCKET_COMPUTER_NORMAL, () -> ComputerCraftRegistry.ModItems.POCKET_COMPUTER_NORMAL,
() -> ComputerCraftRegistry.ModItems.POCKET_COMPUTER_ADVANCED ); () -> ComputerCraftRegistry.ModItems.POCKET_COMPUTER_ADVANCED );
registerItemProperty( "state", registerItemProperty( "state",
( stack, world, player ) -> IColouredItem.getColourBasic( stack ) != -1 ? 1 : 0, ( stack, world, player, integer ) -> IColouredItem.getColourBasic( stack ) != -1 ? 1 : 0,
() -> ComputerCraftRegistry.ModItems.POCKET_COMPUTER_NORMAL, () -> ComputerCraftRegistry.ModItems.POCKET_COMPUTER_NORMAL,
() -> ComputerCraftRegistry.ModItems.POCKET_COMPUTER_ADVANCED ); () -> ComputerCraftRegistry.ModItems.POCKET_COMPUTER_ADVANCED );
ClientRegistry.onItemColours(); ClientRegistry.onItemColours();
@@ -113,9 +111,11 @@ public final class ComputerCraftProxyClient implements ClientModInitializer
// My IDE doesn't think so, but we do actually need these generics. // My IDE doesn't think so, but we do actually need these generics.
private static void registerContainers() private static void registerContainers()
{ {
ScreenRegistry.<ContainerComputer, GuiComputer<ContainerComputer>>register( ComputerCraftRegistry.ModContainers.COMPUTER, GuiComputer::create ); ScreenRegistry.<ContainerComputerBase, GuiComputer<ContainerComputerBase>>register( ComputerCraftRegistry.ModContainers.COMPUTER, GuiComputer::create );
ScreenRegistry.<ContainerPocketComputer, GuiComputer<ContainerPocketComputer>>register( ComputerCraftRegistry.ModContainers.POCKET_COMPUTER, ScreenRegistry.<ContainerComputerBase, GuiComputer<ContainerComputerBase>>register( ComputerCraftRegistry.ModContainers.POCKET_COMPUTER,
GuiComputer::createPocket ); GuiComputer::createPocket );
ScreenRegistry.<ContainerComputerBase, NoTermComputerScreen<ContainerComputerBase>>register( ComputerCraftRegistry.ModContainers.POCKET_COMPUTER_NO_TERM,
NoTermComputerScreen::new );
ScreenRegistry.<ContainerTurtle, GuiTurtle>register( ComputerCraftRegistry.ModContainers.TURTLE, GuiTurtle::new ); ScreenRegistry.<ContainerTurtle, GuiTurtle>register( ComputerCraftRegistry.ModContainers.TURTLE, GuiTurtle::new );
ScreenRegistry.<ContainerPrinter, GuiPrinter>register( ComputerCraftRegistry.ModContainers.PRINTER, GuiPrinter::new ); ScreenRegistry.<ContainerPrinter, GuiPrinter>register( ComputerCraftRegistry.ModContainers.PRINTER, GuiPrinter::new );
@@ -127,12 +127,12 @@ public final class ComputerCraftProxyClient implements ClientModInitializer
} }
@SafeVarargs @SafeVarargs
private static void registerItemProperty( String name, ModelPredicateProvider getter, Supplier<? extends Item>... items ) private static void registerItemProperty( String name, UnclampedModelPredicateProvider getter, Supplier<? extends Item>... items )
{ {
Identifier id = new Identifier( ComputerCraft.MOD_ID, name ); Identifier id = new Identifier( ComputerCraft.MOD_ID, name );
for( Supplier<? extends Item> item : items ) for( Supplier<? extends Item> item : items )
{ {
ModelPredicateProviderRegistrySpecificAccessor.callRegister( item.get(), id, getter ); FabricModelPredicateProviderRegistry.register( item.get(), id, getter );
} }
} }
} }

View File

@@ -18,9 +18,7 @@ import net.minecraft.client.render.Camera;
import net.minecraft.client.render.VertexConsumer; import net.minecraft.client.render.VertexConsumer;
import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.*;
import net.minecraft.util.math.Matrix4f;
import net.minecraft.util.math.Vec3d;
import net.minecraft.util.shape.VoxelShape; import net.minecraft.util.shape.VoxelShape;
@Environment( EnvType.CLIENT ) @Environment( EnvType.CLIENT )
@@ -49,17 +47,29 @@ public final class CableHighlightRenderer
state ); state );
Vec3d cameraPos = info.getPos(); Vec3d cameraPos = info.getPos();
double xOffset = pos.getX() - cameraPos.getX(); double xOffset = pos.getX() - cameraPos.getX();
double yOffset = pos.getY() - cameraPos.getY(); double yOffset = pos.getY() - cameraPos.getY();
double zOffset = pos.getZ() - cameraPos.getZ(); double zOffset = pos.getZ() - cameraPos.getZ();
Matrix4f matrix4f = stack.peek() Matrix4f matrix4f = stack.peek()
.getModel(); .getModel();
Matrix3f normal = stack.peek().getNormal();
shape.forEachEdge( ( x1, y1, z1, x2, y2, z2 ) -> { shape.forEachEdge( ( x1, y1, z1, x2, y2, z2 ) -> {
float xDelta = (float) (x2 - x1);
float yDelta = (float) (y2 - y1);
float zDelta = (float) (z2 - z1);
float len = MathHelper.sqrt( xDelta * xDelta + yDelta * yDelta + zDelta * zDelta );
xDelta = xDelta / len;
yDelta = yDelta / len;
zDelta = zDelta / len;
consumer.vertex( matrix4f, (float) (x1 + xOffset), (float) (y1 + yOffset), (float) (z1 + zOffset) ) consumer.vertex( matrix4f, (float) (x1 + xOffset), (float) (y1 + yOffset), (float) (z1 + zOffset) )
.color( 0, 0, 0, 0.4f ) .color( 0, 0, 0, 0.4f )
.normal( normal, xDelta, yDelta, zDelta )
.next(); .next();
consumer.vertex( matrix4f, (float) (x2 + xOffset), (float) (y2 + yOffset), (float) (z2 + zOffset) ) consumer.vertex( matrix4f, (float) (x2 + xOffset), (float) (y2 + yOffset), (float) (z2 + zOffset) )
.color( 0, 0, 0, 0.4f ) .color( 0, 0, 0, 0.4f )
.normal( normal, xDelta, yDelta, zDelta )
.next(); .next();
} ); } );

View File

@@ -5,16 +5,14 @@
*/ */
package dan200.computercraft.client.render; package dan200.computercraft.client.render;
import com.mojang.blaze3d.systems.RenderSystem;
import dan200.computercraft.ComputerCraft; import dan200.computercraft.ComputerCraft;
import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.core.ComputerFamily;
import net.minecraft.client.render.BufferBuilder; import net.minecraft.client.render.RenderLayer;
import net.minecraft.client.render.Tessellator; import net.minecraft.client.render.Tessellator;
import net.minecraft.client.render.VertexConsumer; import net.minecraft.client.render.VertexConsumer;
import net.minecraft.client.render.VertexFormats; import net.minecraft.client.render.VertexConsumerProvider;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import net.minecraft.util.math.Matrix4f; import net.minecraft.util.math.Matrix4f;
import org.lwjgl.opengl.GL11;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
@@ -42,7 +40,8 @@ public class ComputerBorderRenderer
private static final int LIGHT_CORNER_Y = 80; private static final int LIGHT_CORNER_Y = 80;
public static final int LIGHT_HEIGHT = 8; public static final int LIGHT_HEIGHT = 8;
private static final float TEX_SCALE = 1 / 256.0f; public static final int TEX_SIZE = 256;
private static final float TEX_SCALE = 1 / (float) TEX_SIZE;
static static
{ {
@@ -54,11 +53,14 @@ public class ComputerBorderRenderer
private final int z; private final int z;
private final float r, g, b; private final float r, g, b;
public ComputerBorderRenderer( Matrix4f transform, VertexConsumer builder, int z, float r, float g, float b ) private final int light;
public ComputerBorderRenderer( Matrix4f transform, VertexConsumer builder, int z, int light, float r, float g, float b )
{ {
this.transform = transform; this.transform = transform;
this.builder = builder; this.builder = builder;
this.z = z; this.z = z;
this.light = light;
this.r = r; this.r = r;
this.g = g; this.g = g;
this.b = b; this.b = b;
@@ -80,31 +82,17 @@ public class ComputerBorderRenderer
} }
} }
public static void render( int x, int y, int z, int width, int height ) public static void render( Identifier location, int x, int y, int z, int light, int width, int height )
{ {
Tessellator tessellator = Tessellator.getInstance(); VertexConsumerProvider.Immediate source = VertexConsumerProvider.immediate( Tessellator.getInstance().getBuffer() );
BufferBuilder buffer = tessellator.getBuffer(); render( IDENTITY, source.getBuffer( RenderLayer.getText( location ) ), x, y, z, light, width, height, false, 1, 1, 1 );
buffer.begin( GL11.GL_QUADS, VertexFormats.POSITION_COLOR_TEXTURE ); source.draw();
render( IDENTITY, buffer, x, y, z, width, height );
RenderSystem.enableAlphaTest();
tessellator.draw();
} }
public static void render( Matrix4f transform, VertexConsumer buffer, int x, int y, int z, int width, int height )
{
render( transform, buffer, x, y, z, width, height, 1, 1, 1 );
}
public static void render( Matrix4f transform, VertexConsumer buffer, int x, int y, int z, int width, int height, float r, float g, float b ) public static void render( Matrix4f transform, VertexConsumer buffer, int x, int y, int z, int light, int width, int height, boolean withLight, float r, float g, float b )
{ {
render( transform, buffer, x, y, z, width, height, false, r, g, b ); new ComputerBorderRenderer( transform, buffer, z, light, r, g, b ).doRender( x, y, width, height, withLight );
}
public static void render( Matrix4f transform, VertexConsumer buffer, int x, int y, int z, int width, int height, boolean withLight, float r, float g, float b )
{
new ComputerBorderRenderer( transform, buffer, z, r, g, b ).doRender( x, y, width, height, withLight );
} }
public void doRender( int x, int y, int width, int height, boolean withLight ) public void doRender( int x, int y, int width, int height, boolean withLight )
@@ -157,18 +145,22 @@ public class ComputerBorderRenderer
builder.vertex( transform, x, y + height, z ) builder.vertex( transform, x, y + height, z )
.color( r, g, b, 1.0f ) .color( r, g, b, 1.0f )
.texture( u * TEX_SCALE, (v + textureHeight) * TEX_SCALE ) .texture( u * TEX_SCALE, (v + textureHeight) * TEX_SCALE )
.light( light )
.next(); .next();
builder.vertex( transform, x + width, y + height, z ) builder.vertex( transform, x + width, y + height, z )
.color( r, g, b, 1.0f ) .color( r, g, b, 1.0f )
.texture( (u + textureWidth) * TEX_SCALE, (v + textureHeight) * TEX_SCALE ) .texture( (u + textureWidth) * TEX_SCALE, (v + textureHeight) * TEX_SCALE )
.light( light )
.next(); .next();
builder.vertex( transform, x + width, y, z ) builder.vertex( transform, x + width, y, z )
.color( r, g, b, 1.0f ) .color( r, g, b, 1.0f )
.texture( (u + textureWidth) * TEX_SCALE, v * TEX_SCALE ) .texture( (u + textureWidth) * TEX_SCALE, v * TEX_SCALE )
.light( light )
.next(); .next();
builder.vertex( transform, x, y, z ) builder.vertex( transform, x, y, z )
.color( r, g, b, 1.0f ) .color( r, g, b, 1.0f )
.texture( u * TEX_SCALE, v * TEX_SCALE ) .texture( u * TEX_SCALE, v * TEX_SCALE )
.light( light )
.next(); .next();
} }
} }

View File

@@ -89,7 +89,7 @@ public abstract class ItemMapLikeRenderer
transform.multiply( Vec3f.POSITIVE_X.getDegreesQuaternion( rX * 20.0F ) ); transform.multiply( Vec3f.POSITIVE_X.getDegreesQuaternion( rX * 20.0F ) );
transform.scale( 2.0F, 2.0F, 2.0F ); transform.scale( 2.0F, 2.0F, 2.0F );
renderItem( transform, render, stack ); renderItem( transform, render, stack, combinedLight );
} }
/** /**
@@ -133,7 +133,7 @@ public abstract class ItemMapLikeRenderer
transform.multiply( Vec3f.POSITIVE_X.getDegreesQuaternion( f2 * -45f ) ); transform.multiply( Vec3f.POSITIVE_X.getDegreesQuaternion( f2 * -45f ) );
transform.multiply( Vec3f.POSITIVE_Y.getDegreesQuaternion( offset * f2 * -30f ) ); transform.multiply( Vec3f.POSITIVE_Y.getDegreesQuaternion( offset * f2 * -30f ) );
renderItem( transform, render, stack ); renderItem( transform, render, stack, combinedLight );
transform.pop(); transform.pop();
} }
@@ -144,6 +144,7 @@ public abstract class ItemMapLikeRenderer
* @param transform The matrix transformation stack * @param transform The matrix transformation stack
* @param render The buffer to render to * @param render The buffer to render to
* @param stack The stack to render * @param stack The stack to render
* @param light TODO rebase
*/ */
protected abstract void renderItem( MatrixStack transform, VertexConsumerProvider render, ItemStack stack ); protected abstract void renderItem( MatrixStack transform, VertexConsumerProvider render, ItemStack stack, int light );
} }

View File

@@ -15,15 +15,12 @@ import dan200.computercraft.shared.computer.core.ComputerFamily;
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.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.client.render.BufferBuilder; import net.minecraft.client.render.*;
import net.minecraft.client.render.Tessellator;
import net.minecraft.client.render.VertexConsumerProvider;
import net.minecraft.client.render.VertexFormats;
import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.Matrix4f; import net.minecraft.util.math.Matrix4f;
import net.minecraft.util.math.Vec3f; import net.minecraft.util.math.Vec3f;
import org.lwjgl.opengl.GL11;
import static dan200.computercraft.client.gui.FixedWidthFontRenderer.FONT_HEIGHT; import static dan200.computercraft.client.gui.FixedWidthFontRenderer.FONT_HEIGHT;
import static dan200.computercraft.client.gui.FixedWidthFontRenderer.FONT_WIDTH; import static dan200.computercraft.client.gui.FixedWidthFontRenderer.FONT_WIDTH;
@@ -41,7 +38,7 @@ public final class ItemPocketRenderer extends ItemMapLikeRenderer
} }
@Override @Override
protected void renderItem( MatrixStack transform, VertexConsumerProvider render, ItemStack stack ) protected void renderItem( MatrixStack transform, VertexConsumerProvider render, ItemStack stack, int light )
{ {
ClientComputer computer = ItemPocketComputer.createClientComputer( stack ); ClientComputer computer = ItemPocketComputer.createClientComputer( stack );
Terminal terminal = computer == null ? null : computer.getTerminal(); Terminal terminal = computer == null ? null : computer.getTerminal();
@@ -79,7 +76,7 @@ public final class ItemPocketRenderer extends ItemMapLikeRenderer
Matrix4f matrix = transform.peek() Matrix4f matrix = transform.peek()
.getModel(); .getModel();
renderFrame( matrix, family, frameColour, width, height ); renderFrame( matrix, render, family, frameColour, light, width, height );
// Render the light // Render the light
int lightColour = ItemPocketComputer.getLightState( stack ); int lightColour = ItemPocketComputer.getLightState( stack );
@@ -91,7 +88,12 @@ public final class ItemPocketRenderer extends ItemMapLikeRenderer
if( computer != null && terminal != null ) if( computer != null && terminal != null )
{ {
FixedWidthFontRenderer.drawTerminal( matrix, MARGIN, MARGIN, terminal, !computer.isColour(), MARGIN, MARGIN, MARGIN, MARGIN ); FixedWidthFontRenderer.drawTerminal(
matrix, render.getBuffer( RenderTypes.TERMINAL_WITHOUT_DEPTH ),
MARGIN, MARGIN, terminal, !computer.isColour(), MARGIN, MARGIN, MARGIN, MARGIN
);
FixedWidthFontRenderer.drawBlocker( transform.peek().getModel(), render, 0, 0, width, height );
} }
else else
{ {
@@ -101,24 +103,20 @@ public final class ItemPocketRenderer extends ItemMapLikeRenderer
transform.pop(); transform.pop();
} }
private static void renderFrame( Matrix4f transform, ComputerFamily family, int colour, int width, int height ) private static void renderFrame( Matrix4f transform, VertexConsumerProvider render, ComputerFamily family, int colour, int light, int width, int height )
{ {
RenderSystem.enableBlend(); RenderSystem.enableBlend();
MinecraftClient.getInstance() MinecraftClient.getInstance()
.getTextureManager() .getTextureManager()
.bindTexture( colour != -1 ? ComputerBorderRenderer.BACKGROUND_COLOUR : ComputerBorderRenderer.getTexture( family ) ); .bindTexture( colour != -1 ? ComputerBorderRenderer.BACKGROUND_COLOUR : ComputerBorderRenderer.getTexture( family ) );
Identifier texture = colour != -1 ? ComputerBorderRenderer.BACKGROUND_COLOUR : ComputerBorderRenderer.getTexture( family );
float r = ((colour >>> 16) & 0xFF) / 255.0f; float r = ((colour >>> 16) & 0xFF) / 255.0f;
float g = ((colour >>> 8) & 0xFF) / 255.0f; float g = ((colour >>> 8) & 0xFF) / 255.0f;
float b = (colour & 0xFF) / 255.0f; float b = (colour & 0xFF) / 255.0f;
Tessellator tessellator = Tessellator.getInstance(); ComputerBorderRenderer.render( transform, render.getBuffer( RenderLayer.getText( texture ) ), 0, 0, 0, light, width, height, true, r, g, b );
BufferBuilder buffer = tessellator.getBuffer();
buffer.begin( GL11.GL_QUADS, VertexFormats.POSITION_COLOR_TEXTURE );
ComputerBorderRenderer.render( transform, buffer, 0, 0, 0, width, height, true, r, g, b );
tessellator.draw();
} }
private static void renderLight( Matrix4f transform, int colour, int width, int height ) private static void renderLight( Matrix4f transform, int colour, int width, int height )
@@ -131,7 +129,7 @@ public final class ItemPocketRenderer extends ItemMapLikeRenderer
Tessellator tessellator = Tessellator.getInstance(); Tessellator tessellator = Tessellator.getInstance();
BufferBuilder buffer = tessellator.getBuffer(); BufferBuilder buffer = tessellator.getBuffer();
buffer.begin( GL11.GL_QUADS, VertexFormats.POSITION_COLOR ); buffer.begin( VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_COLOR );
buffer.vertex( transform, width - LIGHT_HEIGHT * 2, height + LIGHT_HEIGHT + BORDER / 2.0f, 0 ) buffer.vertex( transform, width - LIGHT_HEIGHT * 2, height + LIGHT_HEIGHT + BORDER / 2.0f, 0 )
.color( r, g, b, 1.0f ) .color( r, g, b, 1.0f )
.next(); .next();

View File

@@ -9,6 +9,7 @@ package dan200.computercraft.client.render;
import dan200.computercraft.shared.media.items.ItemPrintout; import dan200.computercraft.shared.media.items.ItemPrintout;
import net.minecraft.client.render.VertexConsumerProvider; import net.minecraft.client.render.VertexConsumerProvider;
import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.util.math.Vec3f;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.util.math.Matrix4f; import net.minecraft.util.math.Matrix4f;
import net.minecraft.util.math.Vec3f; import net.minecraft.util.math.Vec3f;
@@ -31,16 +32,16 @@ public final class ItemPrintoutRenderer extends ItemMapLikeRenderer
} }
@Override @Override
protected void renderItem( MatrixStack transform, VertexConsumerProvider render, ItemStack stack ) protected void renderItem( MatrixStack transform, VertexConsumerProvider render, ItemStack stack, int light )
{ {
transform.multiply( Vec3f.POSITIVE_X.getDegreesQuaternion( 180f ) ); transform.multiply( Vec3f.POSITIVE_X.getDegreesQuaternion( 180f ) );
transform.scale( 0.42f, 0.42f, -0.42f ); transform.scale( 0.42f, 0.42f, -0.42f );
transform.translate( -0.5f, -0.48f, 0.0f ); transform.translate( -0.5f, -0.48f, 0.0f );
drawPrintout( transform, render, stack ); drawPrintout( transform, render, stack, light );
} }
private static void drawPrintout( MatrixStack transform, VertexConsumerProvider render, ItemStack stack ) private static void drawPrintout( MatrixStack transform, VertexConsumerProvider render, ItemStack stack, int light )
{ {
int pages = ItemPrintout.getPageCount( stack ); int pages = ItemPrintout.getPageCount( stack );
boolean book = ((ItemPrintout) stack.getItem()).getType() == ItemPrintout.Type.BOOK; boolean book = ((ItemPrintout) stack.getItem()).getType() == ItemPrintout.Type.BOOK;
@@ -72,11 +73,11 @@ public final class ItemPrintoutRenderer extends ItemMapLikeRenderer
Matrix4f matrix = transform.peek() Matrix4f matrix = transform.peek()
.getModel(); .getModel();
drawBorder( matrix, render, 0, 0, -0.01f, 0, pages, book ); drawBorder( matrix, render, 0, 0, -0.01f, 0, pages, book, light );
drawText( matrix, render, X_TEXT_MARGIN, Y_TEXT_MARGIN, 0, ItemPrintout.getText( stack ), ItemPrintout.getColours( stack ) ); drawText( matrix, render, X_TEXT_MARGIN, Y_TEXT_MARGIN, 0, light, ItemPrintout.getText( stack ), ItemPrintout.getColours( stack ) );
} }
public boolean renderInFrame( MatrixStack matrixStack, VertexConsumerProvider consumerProvider, ItemStack stack ) public boolean renderInFrame( MatrixStack matrixStack, VertexConsumerProvider consumerProvider, ItemStack stack, int light )
{ {
if( !(stack.getItem() instanceof ItemPrintout) ) if( !(stack.getItem() instanceof ItemPrintout) )
{ {
@@ -89,7 +90,7 @@ public final class ItemPrintoutRenderer extends ItemMapLikeRenderer
matrixStack.scale( 0.95f, 0.95f, -0.95f ); matrixStack.scale( 0.95f, 0.95f, -0.95f );
matrixStack.translate( -0.5f, -0.5f, 0.0f ); matrixStack.translate( -0.5f, -0.5f, 0.0f );
drawPrintout( matrixStack, consumerProvider, stack ); drawPrintout( matrixStack, consumerProvider, stack, light );
return true; return true;
} }

View File

@@ -5,7 +5,6 @@
*/ */
package dan200.computercraft.client.render; package dan200.computercraft.client.render;
import dan200.computercraft.fabric.mixin.BakedQuadAccess;
import net.fabricmc.api.EnvType; import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment; import net.fabricmc.api.Environment;
import net.minecraft.client.render.VertexFormat; import net.minecraft.client.render.VertexFormat;
@@ -14,6 +13,7 @@ import net.minecraft.client.render.VertexFormats;
import net.minecraft.client.render.model.BakedQuad; import net.minecraft.client.render.model.BakedQuad;
import net.minecraft.util.math.Matrix4f; import net.minecraft.util.math.Matrix4f;
import net.minecraft.util.math.Vector4f; import net.minecraft.util.math.Vector4f;
import java.util.List; import java.util.List;
/** /**
@@ -57,30 +57,43 @@ public final class ModelTransformer
private static BakedQuad doTransformQuad( VertexFormat format, BakedQuad quad, Matrix4f transform ) private static BakedQuad doTransformQuad( VertexFormat format, BakedQuad quad, Matrix4f transform )
{ {
int[] vertexData = quad.getVertexData().clone(); int[] vertexData = quad.getVertexData().clone();
BakedQuad copy = new BakedQuad( vertexData, -1, quad.getFace(), ((BakedQuadAccess) quad).getSprite(), true ); BakedQuad copy = new BakedQuad( vertexData, -1, quad.getFace(), quad.getSprite(), true );
int offsetBytes = 0; int offsetBytes = 0;
for( int v = 0; v < 4; ++v ) for( int v = 0; v < 4; ++v )
{ {
for( VertexFormatElement element : format.getElements() ) // For each vertex element for( VertexFormatElement element : format.getElements() ) // For each vertex element
{ {
int start = offsetBytes / Integer.BYTES; if( element.isPosition() &&
if( element.getType() == VertexFormatElement.Type.POSITION && element.getDataType() == VertexFormatElement.DataType.FLOAT ) // When we find a position element element.getDataType() == VertexFormatElement.DataType.FLOAT &&
element.getLength() == 3 ) // When we find a position element
{ {
Vector4f pos = new Vector4f( Float.intBitsToFloat( vertexData[start] ), for ( int j = 0; j < 4; ++j ) // For each corner of the quad
Float.intBitsToFloat( vertexData[start + 1] ), {
Float.intBitsToFloat( vertexData[start + 2] ), int start = offsetBytes + j * format.getVertexSize();
1 ); if ( (start % 4) == 0 )
{
start = start / 4;
// Transform the position // Extract the position
pos.transform( transform ); Vector4f pos = new Vector4f(
Float.intBitsToFloat( vertexData[start] ),
Float.intBitsToFloat( vertexData[start + 1] ),
Float.intBitsToFloat( vertexData[start + 2] ),
1
);
// Insert the position // Transform the position
vertexData[start] = Float.floatToRawIntBits( pos.getX() ); pos.transform( transform );
vertexData[start + 1] = Float.floatToRawIntBits( pos.getY() );
vertexData[start + 2] = Float.floatToRawIntBits( pos.getZ() ); // Insert the position
vertexData[start] = Float.floatToRawIntBits( pos.getX() );
vertexData[start + 1] = Float.floatToRawIntBits( pos.getY() );
vertexData[start + 2] = Float.floatToRawIntBits( pos.getZ() );
}
}
} }
offsetBytes += element.getByteLength(); offsetBytes += element.getLength();
} }
} }
return copy; return copy;

View File

@@ -15,14 +15,10 @@ import net.minecraft.client.MinecraftClient;
import net.minecraft.client.render.VertexConsumer; import net.minecraft.client.render.VertexConsumer;
import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.*;
import net.minecraft.util.math.Direction;
import net.minecraft.util.math.Matrix4f;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World; import net.minecraft.world.World;
import java.util.EnumSet; import java.util.EnumSet;
import static net.minecraft.util.math.Direction.*; import static net.minecraft.util.math.Direction.*;
/** /**
@@ -36,9 +32,7 @@ public final class MonitorHighlightRenderer
{ {
} }
public static boolean drawHighlight( public static boolean drawHighlight( MatrixStack matrixStack, VertexConsumer vertexConsumer, Entity entity, double d, double e, double f, BlockPos pos, BlockState blockState )
MatrixStack matrixStack, VertexConsumer vertexConsumer, Entity entity, double d, double e, double f, BlockPos pos, BlockState blockState
)
{ {
// Preserve normal behaviour when crouching. // Preserve normal behaviour when crouching.
if( entity.isInSneakingPose() ) if( entity.isInSneakingPose() )
@@ -49,13 +43,11 @@ public final class MonitorHighlightRenderer
World world = entity.getEntityWorld(); World world = entity.getEntityWorld();
BlockEntity tile = world.getBlockEntity( pos ); BlockEntity tile = world.getBlockEntity( pos );
if( !(tile instanceof TileMonitor) ) if( !(tile instanceof TileMonitor monitor) )
{ {
return false; return false;
} }
TileMonitor monitor = (TileMonitor) tile;
// Determine which sides are part of the external faces of the monitor, and so which need to be rendered. // Determine which sides are part of the external faces of the monitor, and so which need to be rendered.
EnumSet<Direction> faces = EnumSet.allOf( Direction.class ); EnumSet<Direction> faces = EnumSet.allOf( Direction.class );
Direction front = monitor.getFront(); Direction front = monitor.getFront();
@@ -87,53 +79,54 @@ public final class MonitorHighlightRenderer
// I wish I could think of a better way to do this // I wish I could think of a better way to do this
Matrix4f transform = matrixStack.peek() Matrix4f transform = matrixStack.peek()
.getModel(); .getModel();
Matrix3f normal = matrixStack.peek().getNormal();
if( faces.contains( NORTH ) || faces.contains( WEST ) ) if( faces.contains( NORTH ) || faces.contains( WEST ) )
{ {
line( vertexConsumer, transform, 0, 0, 0, UP ); line( vertexConsumer, transform, normal, 0, 0, 0, UP );
} }
if( faces.contains( SOUTH ) || faces.contains( WEST ) ) if( faces.contains( SOUTH ) || faces.contains( WEST ) )
{ {
line( vertexConsumer, transform, 0, 0, 1, UP ); line( vertexConsumer, transform, normal, 0, 0, 1, UP );
} }
if( faces.contains( NORTH ) || faces.contains( EAST ) ) if( faces.contains( NORTH ) || faces.contains( EAST ) )
{ {
line( vertexConsumer, transform, 1, 0, 0, UP ); line( vertexConsumer, transform, normal, 1, 0, 0, UP );
} }
if( faces.contains( SOUTH ) || faces.contains( EAST ) ) if( faces.contains( SOUTH ) || faces.contains( EAST ) )
{ {
line( vertexConsumer, transform, 1, 0, 1, UP ); line( vertexConsumer, transform, normal, 1, 0, 1, UP );
} }
if( faces.contains( NORTH ) || faces.contains( DOWN ) ) if( faces.contains( NORTH ) || faces.contains( DOWN ) )
{ {
line( vertexConsumer, transform, 0, 0, 0, EAST ); line( vertexConsumer, transform, normal, 0, 0, 0, EAST );
} }
if( faces.contains( SOUTH ) || faces.contains( DOWN ) ) if( faces.contains( SOUTH ) || faces.contains( DOWN ) )
{ {
line( vertexConsumer, transform, 0, 0, 1, EAST ); line( vertexConsumer, transform, normal, 0, 0, 1, EAST );
} }
if( faces.contains( NORTH ) || faces.contains( UP ) ) if( faces.contains( NORTH ) || faces.contains( UP ) )
{ {
line( vertexConsumer, transform, 0, 1, 0, EAST ); line( vertexConsumer, transform, normal, 0, 1, 0, EAST );
} }
if( faces.contains( SOUTH ) || faces.contains( UP ) ) if( faces.contains( SOUTH ) || faces.contains( UP ) )
{ {
line( vertexConsumer, transform, 0, 1, 1, EAST ); line( vertexConsumer, transform, normal, 0, 1, 1, EAST );
} }
if( faces.contains( WEST ) || faces.contains( DOWN ) ) if( faces.contains( WEST ) || faces.contains( DOWN ) )
{ {
line( vertexConsumer, transform, 0, 0, 0, SOUTH ); line( vertexConsumer, transform, normal, 0, 0, 0, SOUTH );
} }
if( faces.contains( EAST ) || faces.contains( DOWN ) ) if( faces.contains( EAST ) || faces.contains( DOWN ) )
{ {
line( vertexConsumer, transform, 1, 0, 0, SOUTH ); line( vertexConsumer, transform, normal, 1, 0, 0, SOUTH );
} }
if( faces.contains( WEST ) || faces.contains( UP ) ) if( faces.contains( WEST ) || faces.contains( UP ) )
{ {
line( vertexConsumer, transform, 0, 1, 0, SOUTH ); line( vertexConsumer, transform, normal, 0, 1, 0, SOUTH );
} }
if( faces.contains( EAST ) || faces.contains( UP ) ) if( faces.contains( EAST ) || faces.contains( UP ) )
{ {
line( vertexConsumer, transform, 1, 1, 0, SOUTH ); line( vertexConsumer, transform, normal, 1, 1, 0, SOUTH );
} }
matrixStack.pop(); matrixStack.pop();
@@ -141,13 +134,15 @@ public final class MonitorHighlightRenderer
return true; return true;
} }
private static void line( VertexConsumer buffer, Matrix4f transform, float x, float y, float z, Direction direction ) private static void line( VertexConsumer buffer, Matrix4f transform, Matrix3f normal, float x, float y, float z, Direction direction )
{ {
buffer.vertex( transform, x, y, z ) buffer.vertex( transform, x, y, z )
.color( 0, 0, 0, 0.4f ) .color( 0, 0, 0, 0.4f )
.normal( normal, direction.getOffsetX(), direction.getOffsetY(), direction.getOffsetZ() )
.next(); .next();
buffer.vertex( transform, x + direction.getOffsetX(), y + direction.getOffsetY(), z + direction.getOffsetZ() ) buffer.vertex( transform, x + direction.getOffsetX(), y + direction.getOffsetY(), z + direction.getOffsetZ() )
.color( 0, 0, 0, 0.4f ) .color( 0, 0, 0, 0.4f )
.normal( normal, direction.getOffsetX(), direction.getOffsetY(), direction.getOffsetZ() )
.next(); .next();
} }
} }

View File

@@ -5,180 +5,107 @@
*/ */
package dan200.computercraft.client.render; package dan200.computercraft.client.render;
import com.google.common.base.Strings;
import com.mojang.blaze3d.platform.GlStateManager;
import com.mojang.blaze3d.systems.RenderSystem;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.client.gui.FixedWidthFontRenderer; import dan200.computercraft.client.gui.FixedWidthFontRenderer;
import dan200.computercraft.shared.util.Palette; import dan200.computercraft.shared.util.Palette;
import net.minecraft.client.texture.TextureUtil; import net.minecraft.client.gl.GlUniform;
import net.minecraft.util.math.Matrix4f; import net.minecraft.client.render.Shader;
import org.lwjgl.BufferUtils; import net.minecraft.client.render.VertexFormat;
import net.minecraft.resource.ResourceFactory;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.lwjgl.opengl.GL13; import org.lwjgl.opengl.GL13;
import org.lwjgl.opengl.GL20;
import java.io.InputStream; import javax.annotation.Nullable;
import java.io.IOException;
import java.nio.FloatBuffer; import java.nio.FloatBuffer;
class MonitorTextureBufferShader public class MonitorTextureBufferShader extends Shader
{ {
static final int TEXTURE_INDEX = GL13.GL_TEXTURE3; static final int TEXTURE_INDEX = GL13.GL_TEXTURE3;
private static final FloatBuffer MATRIX_BUFFER = BufferUtils.createFloatBuffer( 16 ); private static final Logger LOGGER = LogManager.getLogger();
private static final FloatBuffer PALETTE_BUFFER = BufferUtils.createFloatBuffer( 16 * 3 );
private static int uniformMv; private final GlUniform palette;
private final GlUniform width;
private final GlUniform height;
private static int uniformFont; public MonitorTextureBufferShader( ResourceFactory factory, String name, VertexFormat format ) throws IOException
private static int uniformWidth;
private static int uniformHeight;
private static int uniformTbo;
private static int uniformPalette;
private static boolean initialised;
private static boolean ok;
private static int program;
static void setupUniform( Matrix4f transform, int width, int height, Palette palette, boolean greyscale )
{ {
MATRIX_BUFFER.rewind(); super( factory, name, format );
transform.writeColumnMajor( MATRIX_BUFFER );
MATRIX_BUFFER.rewind();
RenderSystem.glUniformMatrix4( uniformMv, false, MATRIX_BUFFER );
RenderSystem.glUniform1i( uniformWidth, width ); width = getUniformChecked( "Width" );
RenderSystem.glUniform1i( uniformHeight, height ); height = getUniformChecked( "Height" );
palette = new GlUniform( "Palette", GlUniform.field_32044 /* UT_FLOAT3 */, 16 * 3, this );
updateUniformLocation( palette );
PALETTE_BUFFER.rewind(); GlUniform tbo = getUniformChecked( "Tbo" );
if( tbo != null ) tbo.set( TEXTURE_INDEX - GL13.GL_TEXTURE0 );
}
void setupUniform( int width, int height, Palette palette, boolean greyscale )
{
if( this.width != null ) this.width.set( width );
if( this.height != null ) this.height.set( height );
setupPalette( palette, greyscale );
}
private void setupPalette( Palette palette, boolean greyscale )
{
if( this.palette == null ) return;
FloatBuffer paletteBuffer = this.palette.getFloatData();
paletteBuffer.rewind();
for( int i = 0; i < 16; i++ ) for( int i = 0; i < 16; i++ )
{ {
double[] colour = palette.getColour( i ); double[] colour = palette.getColour( i );
if( greyscale ) if( greyscale )
{ {
float f = FixedWidthFontRenderer.toGreyscale( colour ); float f = FixedWidthFontRenderer.toGreyscale( colour );
PALETTE_BUFFER.put( f ) paletteBuffer.put( f ).put( f ).put( f );
.put( f )
.put( f );
} }
else else
{ {
PALETTE_BUFFER.put( (float) colour[0] ) paletteBuffer.put( (float) colour[0] ).put( (float) colour[1] ).put( (float) colour[2] );
.put( (float) colour[1] )
.put( (float) colour[2] );
} }
} }
PALETTE_BUFFER.flip();
RenderSystem.glUniform3( uniformPalette, PALETTE_BUFFER );
}
static boolean use()
{
if( initialised )
{
if( ok )
{
GlStateManager.useProgram( program );
}
return ok;
}
if( ok = load() )
{
GL20.glUseProgram( program );
RenderSystem.glUniform1i( uniformFont, 0 );
RenderSystem.glUniform1i( uniformTbo, TEXTURE_INDEX - GL13.GL_TEXTURE0 );
}
return ok;
}
private static boolean load()
{
initialised = true;
try
{
int vertexShader = loadShader( GL20.GL_VERTEX_SHADER, "assets/computercraft/shaders/monitor.vert" );
int fragmentShader = loadShader( GL20.GL_FRAGMENT_SHADER, "assets/computercraft/shaders/monitor.frag" );
program = GlStateManager.createProgram();
GlStateManager.attachShader( program, vertexShader );
GlStateManager.attachShader( program, fragmentShader );
GL20.glBindAttribLocation( program, 0, "v_pos" );
GlStateManager.linkProgram( program );
boolean ok = GlStateManager.getProgram( program, GL20.GL_LINK_STATUS ) != 0;
String log = GlStateManager.getProgramInfoLog( program, Short.MAX_VALUE )
.trim();
if( !Strings.isNullOrEmpty( log ) )
{
ComputerCraft.log.warn( "Problems when linking monitor shader: {}", log );
}
GL20.glDetachShader( program, vertexShader );
GL20.glDetachShader( program, fragmentShader );
GlStateManager.deleteShader( vertexShader );
GlStateManager.deleteShader( fragmentShader );
if( !ok )
{
return false;
}
uniformMv = getUniformLocation( program, "u_mv" );
uniformFont = getUniformLocation( program, "u_font" );
uniformWidth = getUniformLocation( program, "u_width" );
uniformHeight = getUniformLocation( program, "u_height" );
uniformTbo = getUniformLocation( program, "u_tbo" );
uniformPalette = getUniformLocation( program, "u_palette" );
ComputerCraft.log.info( "Loaded monitor shader." );
return true;
}
catch( Exception e )
{
ComputerCraft.log.error( "Cannot load monitor shaders", e );
return false;
}
} }
private static int loadShader( int kind, String path ) @Override
public void bind()
{ {
InputStream stream = TileEntityMonitorRenderer.class.getClassLoader() super.bind();
.getResourceAsStream( path ); palette.upload();
if( stream == null )
{
throw new IllegalArgumentException( "Cannot find " + path );
}
String contents = TextureUtil.readAllToString( stream );
int shader = GlStateManager.createShader( kind );
GlStateManager.shaderSource( shader, contents );
GlStateManager.compileShader( shader );
boolean ok = GlStateManager.getShader( shader, GL20.GL_COMPILE_STATUS ) != 0;
String log = GlStateManager.getShaderInfoLog( shader, Short.MAX_VALUE )
.trim();
if( !Strings.isNullOrEmpty( log ) )
{
ComputerCraft.log.warn( "Problems when loading monitor shader {}: {}", path, log );
}
if( !ok )
{
throw new IllegalStateException( "Cannot compile shader " + path );
}
return shader;
} }
private static int getUniformLocation( int program, String name ) @Override
public void close()
{ {
int uniform = GlStateManager.getUniformLocation( program, name ); palette.close();
if( uniform == -1 ) super.close();
}
private void updateUniformLocation( GlUniform uniform )
{
int id = GlUniform.getUniformLocation( getProgramRef(), uniform.getName() );
if( id == -1 )
{ {
throw new IllegalStateException( "Cannot find uniform " + name ); LOGGER.warn( "Shader {} could not find uniform named {} in the specified shader program.", getName(), uniform.getName() );
} }
else
{
uniform.setLoc( id );
}
}
@Nullable
private GlUniform getUniformChecked( String name )
{
GlUniform uniform = getUniform( name );
if( uniform == null )
{
LOGGER.warn( "Monitor shader {} should have uniform {}, but it was not present.", getName(), name );
}
return uniform; return uniform;
} }
} }

View File

@@ -9,10 +9,9 @@ package dan200.computercraft.client.render;
import dan200.computercraft.client.gui.FixedWidthFontRenderer; import dan200.computercraft.client.gui.FixedWidthFontRenderer;
import dan200.computercraft.core.terminal.TextBuffer; import dan200.computercraft.core.terminal.TextBuffer;
import dan200.computercraft.shared.util.Palette; import dan200.computercraft.shared.util.Palette;
import net.minecraft.client.render.*; import net.minecraft.client.render.VertexConsumer;
import net.minecraft.util.Identifier; import net.minecraft.client.render.VertexConsumerProvider;
import net.minecraft.util.math.Matrix4f; import net.minecraft.util.math.Matrix4f;
import org.lwjgl.opengl.GL11;
import static dan200.computercraft.client.gui.FixedWidthFontRenderer.FONT_HEIGHT; import static dan200.computercraft.client.gui.FixedWidthFontRenderer.FONT_HEIGHT;
import static dan200.computercraft.shared.media.items.ItemPrintout.LINES_PER_PAGE; import static dan200.computercraft.shared.media.items.ItemPrintout.LINES_PER_PAGE;
@@ -39,7 +38,6 @@ public final class PrintoutRenderer
* Size of the leather cover. * Size of the leather cover.
*/ */
public static final int COVER_SIZE = 12; public static final int COVER_SIZE = 12;
private static final Identifier BG = new Identifier( "computercraft", "textures/gui/printout.png" );
private static final float BG_SIZE = 256.0f; private static final float BG_SIZE = 256.0f;
/** /**
* Width of the extra page texture. * Width of the extra page texture.
@@ -50,9 +48,9 @@ public final class PrintoutRenderer
private PrintoutRenderer() {} private PrintoutRenderer() {}
public static void drawText( Matrix4f transform, VertexConsumerProvider renderer, int x, int y, int start, TextBuffer[] text, TextBuffer[] colours ) public static void drawText( Matrix4f transform, VertexConsumerProvider renderer, int x, int y, int start, int light, TextBuffer[] text, TextBuffer[] colours )
{ {
VertexConsumer buffer = renderer.getBuffer( FixedWidthFontRenderer.TYPE ); VertexConsumer buffer = renderer.getBuffer( RenderTypes.PRINTOUT_TEXT );
for( int line = 0; line < LINES_PER_PAGE && line < text.length; line++ ) for( int line = 0; line < LINES_PER_PAGE && line < text.length; line++ )
{ {
FixedWidthFontRenderer.drawString( transform, FixedWidthFontRenderer.drawString( transform,
@@ -65,13 +63,14 @@ public final class PrintoutRenderer
Palette.DEFAULT, Palette.DEFAULT,
false, false,
0, 0,
0 ); 0,
light );
} }
} }
public static void drawText( Matrix4f transform, VertexConsumerProvider renderer, int x, int y, int start, String[] text, String[] colours ) public static void drawText( Matrix4f transform, VertexConsumerProvider renderer, int x, int y, int start, int light, String[] text, String[] colours )
{ {
VertexConsumer buffer = renderer.getBuffer( FixedWidthFontRenderer.TYPE ); VertexConsumer buffer = renderer.getBuffer( RenderTypes.PRINTOUT_TEXT );
for( int line = 0; line < LINES_PER_PAGE && line < text.length; line++ ) for( int line = 0; line < LINES_PER_PAGE && line < text.length; line++ )
{ {
FixedWidthFontRenderer.drawString( transform, FixedWidthFontRenderer.drawString( transform,
@@ -84,16 +83,17 @@ public final class PrintoutRenderer
Palette.DEFAULT, Palette.DEFAULT,
false, false,
0, 0,
0 ); 0,
light );
} }
} }
public static void drawBorder( Matrix4f transform, VertexConsumerProvider renderer, float x, float y, float z, int page, int pages, boolean isBook ) public static void drawBorder( Matrix4f transform, VertexConsumerProvider renderer, float x, float y, float z, int page, int pages, boolean isBook, int light )
{ {
int leftPages = page; int leftPages = page;
int rightPages = pages - page - 1; int rightPages = pages - page - 1;
VertexConsumer buffer = renderer.getBuffer( Type.TYPE ); VertexConsumer buffer = renderer.getBuffer( RenderTypes.PRINTOUT_BACKGROUND );
if( isBook ) if( isBook )
{ {
@@ -103,8 +103,8 @@ public final class PrintoutRenderer
float right = x + X_SIZE + offset - 4; float right = x + X_SIZE + offset - 4;
// Left and right border // Left and right border
drawTexture( transform, buffer, left - 4, y - 8, z - 0.02f, COVER_X, 0, COVER_SIZE, Y_SIZE + COVER_SIZE * 2 ); drawTexture( transform, buffer, left - 4, y - 8, z - 0.02f, COVER_X, 0, COVER_SIZE, Y_SIZE + COVER_SIZE * 2, light );
drawTexture( transform, buffer, right, y - 8, z - 0.02f, COVER_X + COVER_SIZE, 0, COVER_SIZE, Y_SIZE + COVER_SIZE * 2 ); drawTexture( transform, buffer, right, y - 8, z - 0.02f, COVER_X + COVER_SIZE, 0, COVER_SIZE, Y_SIZE + COVER_SIZE * 2, light );
// Draw centre panel (just stretched texture, sorry). // Draw centre panel (just stretched texture, sorry).
drawTexture( transform, drawTexture( transform,
@@ -117,34 +117,35 @@ public final class PrintoutRenderer
COVER_X + COVER_SIZE / 2.0f, COVER_X + COVER_SIZE / 2.0f,
COVER_SIZE, COVER_SIZE,
COVER_SIZE, COVER_SIZE,
Y_SIZE ); Y_SIZE,
light );
float borderX = left; float borderX = left;
while( borderX < right ) while( borderX < right )
{ {
double thisWidth = Math.min( right - borderX, X_SIZE ); double thisWidth = Math.min( right - borderX, X_SIZE );
drawTexture( transform, buffer, borderX, y - 8, z - 0.02f, 0, COVER_Y, (float) thisWidth, COVER_SIZE ); drawTexture( transform, buffer, borderX, y - 8, z - 0.02f, 0, COVER_Y, (float) thisWidth, COVER_SIZE, light );
drawTexture( transform, buffer, borderX, y + Y_SIZE - 4, z - 0.02f, 0, COVER_Y + COVER_SIZE, (float) thisWidth, COVER_SIZE ); drawTexture( transform, buffer, borderX, y + Y_SIZE - 4, z - 0.02f, 0, COVER_Y + COVER_SIZE, (float) thisWidth, COVER_SIZE, light );
borderX += thisWidth; borderX += thisWidth;
} }
} }
// Left half // Left half
drawTexture( transform, buffer, x, y, z, X_FOLD_SIZE * 2, 0, X_SIZE / 2.0f, Y_SIZE ); drawTexture( transform, buffer, x, y, z, X_FOLD_SIZE * 2, 0, X_SIZE / 2.0f, Y_SIZE, light );
for( int n = 0; n <= leftPages; n++ ) for( int n = 0; n <= leftPages; n++ )
{ {
drawTexture( transform, buffer, x - offsetAt( n ), y, z - 1e-3f * n, drawTexture( transform, buffer, x - offsetAt( n ), y, z - 1e-3f * n,
// Use the left "bold" fold for the outermost page // Use the left "bold" fold for the outermost page
n == leftPages ? 0 : X_FOLD_SIZE, 0, X_FOLD_SIZE, Y_SIZE ); n == leftPages ? 0 : X_FOLD_SIZE, 0, X_FOLD_SIZE, Y_SIZE, light );
} }
// Right half // Right half
drawTexture( transform, buffer, x + X_SIZE / 2.0f, y, z, X_FOLD_SIZE * 2 + X_SIZE / 2.0f, 0, X_SIZE / 2.0f, Y_SIZE ); drawTexture( transform, buffer, x + X_SIZE / 2.0f, y, z, X_FOLD_SIZE * 2 + X_SIZE / 2.0f, 0, X_SIZE / 2.0f, Y_SIZE, light );
for( int n = 0; n <= rightPages; n++ ) for( int n = 0; n <= rightPages; n++ )
{ {
drawTexture( transform, buffer, x + (X_SIZE - X_FOLD_SIZE) + offsetAt( n ), y, z - 1e-3f * n, drawTexture( transform, buffer, x + (X_SIZE - X_FOLD_SIZE) + offsetAt( n ), y, z - 1e-3f * n,
// Two folds, then the main page. Use the right "bold" fold for the outermost page. // Two folds, then the main page. Use the right "bold" fold for the outermost page.
X_FOLD_SIZE * 2 + X_SIZE + (n == rightPages ? X_FOLD_SIZE : 0), 0, X_FOLD_SIZE, Y_SIZE ); X_FOLD_SIZE * 2 + X_SIZE + (n == rightPages ? X_FOLD_SIZE : 0), 0, X_FOLD_SIZE, Y_SIZE, light );
} }
} }
@@ -153,57 +154,25 @@ public final class PrintoutRenderer
return (float) (32 * (1 - Math.pow( 1.2, -page ))); return (float) (32 * (1 - Math.pow( 1.2, -page )));
} }
private static void drawTexture( Matrix4f matrix, VertexConsumer buffer, float x, float y, float z, float u, float v, float width, float height ) private static void drawTexture( Matrix4f matrix, VertexConsumer buffer, float x, float y, float z, float u, float v, float width, float height, int light )
{ {
buffer.vertex( matrix, x, y + height, z ) vertex( buffer, matrix, x, y + height, z, u / BG_SIZE, (v + height) / BG_SIZE, light );
.texture( u / BG_SIZE, (v + height) / BG_SIZE ) vertex( buffer, matrix, x + width, y + height, z, (u + width) / BG_SIZE, (v + height) / BG_SIZE, light );
.next(); vertex( buffer, matrix, x + width, y, z, (u + width) / BG_SIZE, v / BG_SIZE, light );
buffer.vertex( matrix, x + width, y + height, z ) vertex( buffer, matrix, x, y, z, u / BG_SIZE, v / BG_SIZE, light );
.texture( (u + width) / BG_SIZE, (v + height) / BG_SIZE )
.next();
buffer.vertex( matrix, x + width, y, z )
.texture( (u + width) / BG_SIZE, v / BG_SIZE )
.next();
buffer.vertex( matrix, x, y, z )
.texture( u / BG_SIZE, v / BG_SIZE )
.next();
} }
private static void drawTexture( Matrix4f matrix, VertexConsumer buffer, float x, float y, float z, float width, float height, float u, float v, private static void drawTexture( Matrix4f matrix, VertexConsumer buffer, float x, float y, float z, float width, float height, float u, float v,
float tWidth, float tHeight ) float tWidth, float tHeight, int light )
{ {
buffer.vertex( matrix, x, y + height, z ) vertex( buffer, matrix, x, y + height, z, u / BG_SIZE, (v + tHeight) / BG_SIZE, light );
.texture( u / BG_SIZE, (v + tHeight) / BG_SIZE ) vertex( buffer, matrix, x + width, y + height, z, (u + tWidth) / BG_SIZE, (v + tHeight) / BG_SIZE, light );
.next(); vertex( buffer, matrix, x + width, y, z, (u + tWidth) / BG_SIZE, v / BG_SIZE, light );
buffer.vertex( matrix, x + width, y + height, z ) vertex( buffer, matrix, x, y, z, u / BG_SIZE, v / BG_SIZE, light );
.texture( (u + tWidth) / BG_SIZE, (v + tHeight) / BG_SIZE )
.next();
buffer.vertex( matrix, x + width, y, z )
.texture( (u + tWidth) / BG_SIZE, v / BG_SIZE )
.next();
buffer.vertex( matrix, x, y, z )
.texture( u / BG_SIZE, v / BG_SIZE )
.next();
} }
private static final class Type extends RenderPhase private static void vertex( VertexConsumer buffer, Matrix4f matrix, float x, float y, float z, float u, float v, int light )
{ {
static final RenderLayer TYPE = RenderLayer.of( "printout_background", buffer.vertex( matrix, x, y, z ).color( 255, 255, 255, 255 ).texture( u, v ).light( light ).next();
VertexFormats.POSITION_TEXTURE,
GL11.GL_QUADS,
1024,
false,
false,
// useDelegate, needsSorting
RenderLayer.MultiPhaseParameters.builder()
.texture( new RenderPhase.Texture( BG, false, false ) ) // blur, minimap
.alpha( ONE_TENTH_ALPHA )
.lightmap( DISABLE_LIGHTMAP )
.build( false ) );
private Type( String name, Runnable setup, Runnable destroy )
{
super( name, setup, destroy );
}
} }
} }

View File

@@ -0,0 +1,117 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.client.render;
import dan200.computercraft.client.gui.FixedWidthFontRenderer;
import net.minecraft.client.render.*;
import net.minecraft.util.Identifier;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public class RenderTypes
{
public static final int FULL_BRIGHT_LIGHTMAP = (0xF << 4) | (0xF << 20);
@Nullable
public static MonitorTextureBufferShader monitorTboShader;
@Nullable
public static Shader terminalShader;
public static final RenderLayer TERMINAL_WITHOUT_DEPTH = Types.TERMINAL_WITHOUT_DEPTH;
public static final RenderLayer MONITOR_TBO = Types.MONITOR_TBO;
public static final RenderLayer TERMINAL_BLOCKER = Types.BLOCKER;
public static final RenderLayer TERMINAL_WITH_DEPTH = Types.TERMINAL_WITH_DEPTH;
public static final RenderLayer PRINTOUT_TEXT = Types.PRINTOUT_TEXT;
public static final RenderLayer PRINTOUT_BACKGROUND = RenderLayer.getText( new Identifier( "computercraft", "textures/gui/printout.png" ) );
public static final RenderLayer POSITION_COLOR = Types.POSITION_COLOR;
@Nonnull
static MonitorTextureBufferShader getMonitorTextureBufferShader()
{
if( monitorTboShader == null ) throw new NullPointerException( "MonitorTboShader has not been registered" );
return monitorTboShader;
}
@Nonnull
static Shader getTerminalShader()
{
if( terminalShader == null ) throw new NullPointerException( "MonitorTboShader has not been registered" );
return terminalShader;
}
private static final class Types extends RenderPhase
{
private static final VertexFormat.DrawMode GL_MODE = VertexFormat.DrawMode.TRIANGLES;
private static final VertexFormat FORMAT = VertexFormats.POSITION_COLOR_TEXTURE;
private static final Shader TERM_SHADER = new Shader( RenderTypes::getTerminalShader );
private static final RenderPhase.Texture TERM_FONT_TEXTURE = new RenderPhase.Texture(
FixedWidthFontRenderer.FONT,
false, false // blur, minimap
);
public static final RenderLayer MONITOR_TBO = RenderLayer.of( "monitor_tbo", VertexFormats.POSITION_TEXTURE, VertexFormat.DrawMode.TRIANGLE_STRIP, 128, false, false, // useDelegate, needsSorting
RenderLayer.MultiPhaseParameters.builder()
.texture( TERM_FONT_TEXTURE ) // blur, minimap
.shader( new RenderPhase.Shader( RenderTypes::getMonitorTextureBufferShader ) )
.writeMaskState( RenderLayer.ALL_MASK )
.build( false ) );
static final RenderLayer TERMINAL_WITHOUT_DEPTH = RenderLayer.of(
"terminal_without_depth", FORMAT, GL_MODE, 1024,
false, false, // useDelegate, needsSorting
RenderLayer.MultiPhaseParameters.builder()
.texture( TERM_FONT_TEXTURE )
.shader( TERM_SHADER )
.writeMaskState( COLOR_MASK )
.build( false )
);
static final RenderLayer BLOCKER = RenderLayer.of( "terminal_blocker", FORMAT, GL_MODE, 256, false, false, // useDelegate, needsSorting
RenderLayer.MultiPhaseParameters.builder()
.texture( TERM_FONT_TEXTURE )
.shader( TERM_SHADER )
.writeMaskState( DEPTH_MASK )
.build( false ) );
static final RenderLayer TERMINAL_WITH_DEPTH = RenderLayer.of(
"terminal_with_depth", FORMAT, GL_MODE, 1024,
false, false, // useDelegate, needsSorting
RenderLayer.MultiPhaseParameters.builder()
.texture( TERM_FONT_TEXTURE )
.shader( TERM_SHADER )
.build( false )
);
static final RenderLayer PRINTOUT_TEXT = RenderLayer.of(
"printout_text", VertexFormats.POSITION_COLOR_TEXTURE_LIGHT, GL_MODE, 1024,
false, false, // useDelegate, needsSorting
RenderLayer.MultiPhaseParameters.builder()
.texture( TERM_FONT_TEXTURE )
.shader( RenderPhase.TEXT_SHADER )
.lightmap( RenderPhase.ENABLE_LIGHTMAP )
.build( false )
);
static final RenderLayer POSITION_COLOR = RenderLayer.of(
"position_color", VertexFormats.POSITION_COLOR, VertexFormat.DrawMode.QUADS, 128,
false, false, // useDelegate, needsSorting
RenderLayer.MultiPhaseParameters.builder()
.shader( COLOR_SHADER )
.build( false )
);
private Types( String name, Runnable setup, Runnable destroy )
{
super( name, setup, destroy );
}
}
}

View File

@@ -7,6 +7,8 @@
package dan200.computercraft.client.render; package dan200.computercraft.client.render;
import com.mojang.blaze3d.platform.GlStateManager; import com.mojang.blaze3d.platform.GlStateManager;
import com.mojang.blaze3d.systems.RenderSystem;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.client.FrameInfo; import dan200.computercraft.client.FrameInfo;
import dan200.computercraft.client.gui.FixedWidthFontRenderer; import dan200.computercraft.client.gui.FixedWidthFontRenderer;
import dan200.computercraft.core.terminal.Terminal; import dan200.computercraft.core.terminal.Terminal;
@@ -18,17 +20,11 @@ import dan200.computercraft.shared.util.Colour;
import dan200.computercraft.shared.util.DirectionUtil; import dan200.computercraft.shared.util.DirectionUtil;
import net.minecraft.client.gl.VertexBuffer; import net.minecraft.client.gl.VertexBuffer;
import net.minecraft.client.render.*; import net.minecraft.client.render.*;
import net.minecraft.client.render.block.entity.BlockEntityRenderDispatcher;
import net.minecraft.client.render.block.entity.BlockEntityRenderer; import net.minecraft.client.render.block.entity.BlockEntityRenderer;
import net.minecraft.client.util.GlAllocationUtils; import net.minecraft.client.render.block.entity.BlockEntityRendererFactory;
import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.util.math.AffineTransformation; import net.minecraft.util.math.*;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.util.math.Matrix4f;
import net.minecraft.util.math.Vec3f;
import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL13;
import org.lwjgl.opengl.GL20; import org.lwjgl.opengl.GL20;
import org.lwjgl.opengl.GL31; import org.lwjgl.opengl.GL31;
@@ -36,8 +32,9 @@ import javax.annotation.Nonnull;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import static dan200.computercraft.client.gui.FixedWidthFontRenderer.*; import static dan200.computercraft.client.gui.FixedWidthFontRenderer.*;
import static net.minecraft.client.util.GlAllocationUtils.allocateByteBuffer;
public class TileEntityMonitorRenderer extends BlockEntityRenderer<TileMonitor> public class TileEntityMonitorRenderer implements BlockEntityRenderer<TileMonitor>
{ {
/** /**
* {@link TileMonitor#RENDER_MARGIN}, but a tiny bit of additional padding to ensure that there is no space between the monitor frame and contents. * {@link TileMonitor#RENDER_MARGIN}, but a tiny bit of additional padding to ensure that there is no space between the monitor frame and contents.
@@ -47,11 +44,10 @@ public class TileEntityMonitorRenderer extends BlockEntityRenderer<TileMonitor>
.getMatrix(); .getMatrix();
private static ByteBuffer tboContents; private static ByteBuffer tboContents;
public TileEntityMonitorRenderer( BlockEntityRenderDispatcher rendererDispatcher ) public TileEntityMonitorRenderer( BlockEntityRendererFactory.Context context )
{ {
super( rendererDispatcher ); // super( context );
} }
@Override @Override
public void render( @Nonnull TileMonitor monitor, float partialTicks, @Nonnull MatrixStack transform, @Nonnull VertexConsumerProvider renderer, public void render( @Nonnull TileMonitor monitor, float partialTicks, @Nonnull MatrixStack transform, @Nonnull VertexConsumerProvider renderer,
int lightmapCoord, int overlayLight ) int lightmapCoord, int overlayLight )
@@ -97,17 +93,6 @@ public class TileEntityMonitorRenderer extends BlockEntityRenderer<TileMonitor>
double xSize = origin.getWidth() - 2.0 * (TileMonitor.RENDER_MARGIN + TileMonitor.RENDER_BORDER); double xSize = origin.getWidth() - 2.0 * (TileMonitor.RENDER_MARGIN + TileMonitor.RENDER_BORDER);
double ySize = origin.getHeight() - 2.0 * (TileMonitor.RENDER_MARGIN + TileMonitor.RENDER_BORDER); double ySize = origin.getHeight() - 2.0 * (TileMonitor.RENDER_MARGIN + TileMonitor.RENDER_BORDER);
// Draw the background blocker
FixedWidthFontRenderer.drawBlocker( transform.peek().getModel(),
renderer,
(float) -TileMonitor.RENDER_MARGIN,
(float) TileMonitor.RENDER_MARGIN,
(float) (xSize + 2 * TileMonitor.RENDER_MARGIN),
(float) -(ySize + TileMonitor.RENDER_MARGIN * 2) );
// Set the contents slightly off the surface to prevent z-fighting
transform.translate( 0.0, 0.0, 0.001 );
// Draw the contents // Draw the contents
Terminal terminal = originTerminal.getTerminal(); Terminal terminal = originTerminal.getTerminal();
if( terminal != null ) if( terminal != null )
@@ -122,23 +107,22 @@ public class TileEntityMonitorRenderer extends BlockEntityRenderer<TileMonitor>
Matrix4f matrix = transform.peek().getModel(); Matrix4f matrix = transform.peek().getModel();
// Sneaky hack here: we get a buffer now in order to flush existing ones and set up the appropriate renderTerminal( renderer, matrix, originTerminal, (float) (MARGIN / xScale), (float) (MARGIN / yScale) );
// render state. I've no clue how well this'll work in future versions of Minecraft, but it does the trick
// for now.
VertexConsumer buffer = renderer.getBuffer( FixedWidthFontRenderer.TYPE );
FixedWidthFontRenderer.TYPE.startDrawing();
renderTerminal( matrix, originTerminal, (float) (MARGIN / xScale), (float) (MARGIN / yScale) );
// We don't draw the cursor with the VBO, as it's dynamic and so we'll end up refreshing far more than is // We don't draw the cursor with the VBO, as it's dynamic and so we'll end up refreshing far more than is
// reasonable. // reasonable.
FixedWidthFontRenderer.drawCursor( matrix, buffer, 0, 0, terminal, !originTerminal.isColour() ); FixedWidthFontRenderer.drawCursor( matrix, renderer.getBuffer( RenderTypes.TERMINAL_WITHOUT_DEPTH ), 0, 0, terminal, !originTerminal.isColour() );
// To go along with sneaky hack above: make sure state changes are undone. I would have thought this would
// happen automatically after these buffers are drawn, but chests will render weird around monitors without this.
FixedWidthFontRenderer.TYPE.endDrawing();
transform.pop(); transform.pop();
// Draw the background blocker
FixedWidthFontRenderer.drawBlocker(
transform.peek().getModel(), renderer,
-MARGIN, MARGIN,
(float) (xSize + 2 * MARGIN), (float) -(ySize + MARGIN * 2)
);
renderer.getBuffer( RenderLayer.getSolid() );
} }
else else
{ {
@@ -154,7 +138,7 @@ public class TileEntityMonitorRenderer extends BlockEntityRenderer<TileMonitor>
transform.pop(); transform.pop();
} }
private static void renderTerminal( Matrix4f matrix, ClientMonitor monitor, float xMargin, float yMargin ) private static void renderTerminal( VertexConsumerProvider renderer, Matrix4f matrix, ClientMonitor monitor, float xMargin, float yMargin )
{ {
Terminal terminal = monitor.getTerminal(); Terminal terminal = monitor.getTerminal();
@@ -169,10 +153,6 @@ public class TileEntityMonitorRenderer extends BlockEntityRenderer<TileMonitor>
{ {
case TBO: case TBO:
{ {
if( !MonitorTextureBufferShader.use() )
{
return;
}
int width = terminal.getWidth(), height = terminal.getHeight(); int width = terminal.getWidth(), height = terminal.getHeight();
int pixelWidth = width * FONT_WIDTH, pixelHeight = height * FONT_HEIGHT; int pixelWidth = width * FONT_WIDTH, pixelHeight = height * FONT_HEIGHT;
@@ -182,7 +162,7 @@ public class TileEntityMonitorRenderer extends BlockEntityRenderer<TileMonitor>
int size = width * height * 3; int size = width * height * 3;
if( tboContents == null || tboContents.capacity() < size ) if( tboContents == null || tboContents.capacity() < size )
{ {
tboContents = GlAllocationUtils.allocateByteBuffer( size ); tboContents = allocateByteBuffer( size );
} }
ByteBuffer monitorBuffer = tboContents; ByteBuffer monitorBuffer = tboContents;
@@ -199,32 +179,27 @@ public class TileEntityMonitorRenderer extends BlockEntityRenderer<TileMonitor>
} }
monitorBuffer.flip(); monitorBuffer.flip();
GlStateManager.bindBuffers( GL31.GL_TEXTURE_BUFFER, monitor.tboBuffer ); GlStateManager._glBindBuffer( GL31.GL_TEXTURE_BUFFER, monitor.tboBuffer );
GlStateManager.bufferData( GL31.GL_TEXTURE_BUFFER, monitorBuffer, GL20.GL_STATIC_DRAW ); GlStateManager._glBufferData( GL31.GL_TEXTURE_BUFFER, monitorBuffer, GL20.GL_STATIC_DRAW );
GlStateManager.bindBuffers( GL31.GL_TEXTURE_BUFFER, 0 ); GlStateManager._glBindBuffer( GL31.GL_TEXTURE_BUFFER, 0 );
} }
// Nobody knows what they're doing! // Nobody knows what they're doing!
GlStateManager.activeTexture( MonitorTextureBufferShader.TEXTURE_INDEX ); int active = GlStateManager._getActiveTexture();
RenderSystem.activeTexture( MonitorTextureBufferShader.TEXTURE_INDEX );
GL11.glBindTexture( GL31.GL_TEXTURE_BUFFER, monitor.tboTexture ); GL11.glBindTexture( GL31.GL_TEXTURE_BUFFER, monitor.tboTexture );
GlStateManager.activeTexture( GL13.GL_TEXTURE0 ); RenderSystem.activeTexture( active );
MonitorTextureBufferShader.setupUniform( matrix, width, height, terminal.getPalette(), !monitor.isColour() ); MonitorTextureBufferShader shader = RenderTypes.getMonitorTextureBufferShader();
shader.setupUniform( width, height, terminal.getPalette(), !monitor.isColour() );
Tessellator tessellator = Tessellator.getInstance(); VertexConsumer buffer = renderer.getBuffer( RenderTypes.MONITOR_TBO );
BufferBuilder buffer = tessellator.getBuffer(); tboVertex( buffer, matrix, -xMargin, -yMargin );
buffer.begin( GL11.GL_TRIANGLE_STRIP, VertexFormats.POSITION ); tboVertex( buffer, matrix, -xMargin, pixelHeight + yMargin );
buffer.vertex( -xMargin, -yMargin, 0 ) tboVertex( buffer, matrix, pixelWidth + xMargin, -yMargin );
.next(); tboVertex( buffer, matrix, pixelWidth + xMargin, pixelHeight + yMargin );
buffer.vertex( -xMargin, pixelHeight + yMargin, 0 )
.next();
buffer.vertex( pixelWidth + xMargin, -yMargin, 0 )
.next();
buffer.vertex( pixelWidth + xMargin, pixelHeight + yMargin, 0 )
.next();
tessellator.draw();
GlStateManager.useProgram( 0 ); renderer.getBuffer( RenderTypes.TERMINAL_WITHOUT_DEPTH );
break; break;
} }
@@ -234,7 +209,7 @@ public class TileEntityMonitorRenderer extends BlockEntityRenderer<TileMonitor>
{ {
Tessellator tessellator = Tessellator.getInstance(); Tessellator tessellator = Tessellator.getInstance();
BufferBuilder builder = tessellator.getBuffer(); BufferBuilder builder = tessellator.getBuffer();
builder.begin( FixedWidthFontRenderer.TYPE.getDrawMode(), FixedWidthFontRenderer.TYPE.getVertexFormat() ); builder.begin( RenderTypes.TERMINAL_WITHOUT_DEPTH.getDrawMode(), RenderTypes.TERMINAL_WITHOUT_DEPTH.getVertexFormat() );
FixedWidthFontRenderer.drawTerminalWithoutCursor( IDENTITY, FixedWidthFontRenderer.drawTerminalWithoutCursor( IDENTITY,
builder, builder,
0, 0,
@@ -250,14 +225,23 @@ public class TileEntityMonitorRenderer extends BlockEntityRenderer<TileMonitor>
vbo.upload( builder ); vbo.upload( builder );
} }
vbo.bind(); renderer.getBuffer( RenderTypes.TERMINAL_WITHOUT_DEPTH );
FixedWidthFontRenderer.TYPE.getVertexFormat()
.startDrawing( 0L ); RenderTypes.TERMINAL_WITHOUT_DEPTH.startDrawing();
vbo.draw( matrix, FixedWidthFontRenderer.TYPE.getDrawMode() ); vbo.setShader( matrix, RenderSystem.getProjectionMatrix(), RenderTypes.getTerminalShader() );
VertexBuffer.unbind();
FixedWidthFontRenderer.TYPE.getVertexFormat()
.endDrawing();
break; break;
} }
} }
private static void tboVertex( VertexConsumer builder, Matrix4f matrix, float x, float y )
{
// We encode position in the UV, as that's not transformed by the matrix.
builder.vertex( matrix, x, y, 0 ).texture( x, y ).next();
}
@Override
public int getRenderDistance()
{
return ComputerCraft.monitorDistance;
}
} }

View File

@@ -3,7 +3,6 @@
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com * Send enquiries to dratcliffe@gmail.com
*/ */
package dan200.computercraft.client.render; package dan200.computercraft.client.render;
import dan200.computercraft.api.client.TransformedModel; import dan200.computercraft.api.client.TransformedModel;
@@ -21,11 +20,13 @@ import net.minecraft.client.render.VertexConsumer;
import net.minecraft.client.render.VertexConsumerProvider; import net.minecraft.client.render.VertexConsumerProvider;
import net.minecraft.client.render.block.entity.BlockEntityRenderDispatcher; import net.minecraft.client.render.block.entity.BlockEntityRenderDispatcher;
import net.minecraft.client.render.block.entity.BlockEntityRenderer; import net.minecraft.client.render.block.entity.BlockEntityRenderer;
import net.minecraft.client.render.block.entity.BlockEntityRendererFactory;
import net.minecraft.client.render.model.BakedModel; import net.minecraft.client.render.model.BakedModel;
import net.minecraft.client.render.model.BakedModelManager; import net.minecraft.client.render.model.BakedModelManager;
import net.minecraft.client.render.model.BakedQuad; import net.minecraft.client.render.model.BakedQuad;
import net.minecraft.client.util.ModelIdentifier; import net.minecraft.client.util.ModelIdentifier;
import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.util.math.Vec3f;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import net.minecraft.util.hit.BlockHitResult; import net.minecraft.util.hit.BlockHitResult;
import net.minecraft.util.hit.HitResult; import net.minecraft.util.hit.HitResult;
@@ -37,7 +38,7 @@ import javax.annotation.Nonnull;
import java.util.List; import java.util.List;
import java.util.Random; import java.util.Random;
public class TileEntityTurtleRenderer extends BlockEntityRenderer<TileTurtle> public class TileEntityTurtleRenderer implements BlockEntityRenderer<TileTurtle>
{ {
private static final ModelIdentifier NORMAL_TURTLE_MODEL = new ModelIdentifier( "computercraft:turtle_normal", "inventory" ); private static final ModelIdentifier NORMAL_TURTLE_MODEL = new ModelIdentifier( "computercraft:turtle_normal", "inventory" );
private static final ModelIdentifier ADVANCED_TURTLE_MODEL = new ModelIdentifier( "computercraft:turtle_advanced", "inventory" ); private static final ModelIdentifier ADVANCED_TURTLE_MODEL = new ModelIdentifier( "computercraft:turtle_advanced", "inventory" );
@@ -46,9 +47,11 @@ public class TileEntityTurtleRenderer extends BlockEntityRenderer<TileTurtle>
private final Random random = new Random( 0 ); private final Random random = new Random( 0 );
public TileEntityTurtleRenderer( BlockEntityRenderDispatcher renderDispatcher ) BlockEntityRenderDispatcher renderer;
public TileEntityTurtleRenderer( BlockEntityRendererFactory.Context context )
{ {
super( renderDispatcher ); renderer = context.getRenderDispatcher();
} }
public static ModelIdentifier getTurtleModel( ComputerFamily family, boolean coloured ) public static ModelIdentifier getTurtleModel( ComputerFamily family, boolean coloured )
@@ -76,6 +79,118 @@ public class TileEntityTurtleRenderer extends BlockEntityRenderer<TileTurtle>
return null; return null;
} }
@Override
public void render( @Nonnull TileTurtle turtle, float partialTicks, @Nonnull MatrixStack transform, @Nonnull VertexConsumerProvider buffers,
int lightmapCoord, int overlayLight )
{
// Render the label
String label = turtle.createProxy()
.getLabel();
HitResult hit = renderer.crosshairTarget;
if( label != null && hit.getType() == HitResult.Type.BLOCK && turtle.getPos()
.equals( ((BlockHitResult) hit).getBlockPos() ) )
{
MinecraftClient mc = MinecraftClient.getInstance();
TextRenderer font = mc.textRenderer;
transform.push();
transform.translate( 0.5, 1.2, 0.5 );
transform.multiply( mc.getEntityRenderDispatcher()
.getRotation() );
transform.scale( -0.025f, -0.025f, 0.025f );
Matrix4f matrix = transform.peek()
.getModel();
int opacity = (int) (mc.options.getTextBackgroundOpacity( 0.25f ) * 255) << 24;
float width = -font.getWidth( label ) / 2.0f;
font.draw( label, width, (float) 0, 0x20ffffff, false, matrix, buffers, true, opacity, lightmapCoord );
font.draw( label, width, (float) 0, 0xffffffff, false, matrix, buffers, false, 0, lightmapCoord );
transform.pop();
}
transform.push();
// Setup the transform.
Vec3d offset = turtle.getRenderOffset( partialTicks );
float yaw = turtle.getRenderYaw( partialTicks );
transform.translate( offset.x, offset.y, offset.z );
transform.translate( 0.5f, 0.5f, 0.5f );
transform.multiply( Vec3f.POSITIVE_Y.getDegreesQuaternion( 180.0f - yaw ) );
if( label != null && (label.equals( "Dinnerbone" ) || label.equals( "Grumm" )) )
{
// Flip the model
transform.scale( 1.0f, -1.0f, 1.0f );
}
transform.translate( -0.5f, -0.5f, -0.5f );
// Render the turtle
int colour = turtle.getColour();
ComputerFamily family = turtle.getFamily();
Identifier overlay = turtle.getOverlay();
VertexConsumer buffer = buffers.getBuffer( TexturedRenderLayers.getEntityTranslucentCull() );
renderModel( transform, buffer, lightmapCoord, overlayLight, getTurtleModel( family, colour != -1 ), colour == -1 ? null : new int[] { colour } );
// Render the overlay
ModelIdentifier overlayModel = getTurtleOverlayModel( overlay, HolidayUtil.getCurrentHoliday() == Holiday.CHRISTMAS );
if( overlayModel != null )
{
renderModel( transform, buffer, lightmapCoord, overlayLight, overlayModel, null );
}
// Render the upgrades
renderUpgrade( transform, buffer, lightmapCoord, overlayLight, turtle, TurtleSide.LEFT, partialTicks );
renderUpgrade( transform, buffer, lightmapCoord, overlayLight, turtle, TurtleSide.RIGHT, partialTicks );
transform.pop();
}
private void renderUpgrade( @Nonnull MatrixStack transform, @Nonnull VertexConsumer renderer, int lightmapCoord, int overlayLight, TileTurtle turtle,
TurtleSide side, float f )
{
ITurtleUpgrade upgrade = turtle.getUpgrade( side );
if( upgrade == null )
{
return;
}
transform.push();
float toolAngle = turtle.getToolRenderAngle( side, f );
transform.translate( 0.0f, 0.5f, 0.5f );
transform.multiply( Vec3f.NEGATIVE_X.getDegreesQuaternion( toolAngle ) );
transform.translate( 0.0f, -0.5f, -0.5f );
TransformedModel model = upgrade.getModel( turtle.getAccess(), side );
model.push( transform );
renderModel( transform, renderer, lightmapCoord, overlayLight, model.getModel(), null );
transform.pop();
transform.pop();
}
private void renderModel( @Nonnull MatrixStack transform, @Nonnull VertexConsumer renderer, int lightmapCoord, int overlayLight,
ModelIdentifier modelLocation, int[] tints )
{
BakedModelManager modelManager = MinecraftClient.getInstance()
.getItemRenderer()
.getModels()
.getModelManager();
renderModel( transform, renderer, lightmapCoord, overlayLight, modelManager.getModel( modelLocation ), tints );
}
private void renderModel( @Nonnull MatrixStack transform, @Nonnull VertexConsumer renderer, int lightmapCoord, int overlayLight, BakedModel model,
int[] tints )
{
random.setSeed( 0 );
renderQuads( transform, renderer, lightmapCoord, overlayLight, model.getQuads( null, null, random ), tints );
for( Direction facing : DirectionUtil.FACINGS )
{
renderQuads( transform, renderer, lightmapCoord, overlayLight, model.getQuads( null, facing, random ), tints );
}
}
private static void renderQuads( @Nonnull MatrixStack transform, @Nonnull VertexConsumer buffer, int lightmapCoord, int overlayLight, private static void renderQuads( @Nonnull MatrixStack transform, @Nonnull VertexConsumer buffer, int lightmapCoord, int overlayLight,
List<BakedQuad> quads, int[] tints ) List<BakedQuad> quads, int[] tints )
{ {
@@ -107,117 +222,4 @@ public class TileEntityTurtleRenderer extends BlockEntityRenderer<TileTurtle>
true ); true );
} }
} }
@Override
public void render( @Nonnull TileTurtle turtle, float partialTicks, @Nonnull MatrixStack transform, @Nonnull VertexConsumerProvider renderer,
int lightmapCoord, int overlayLight )
{
// Render the label
String label = turtle.createProxy()
.getLabel();
HitResult hit = dispatcher.crosshairTarget;
if( label != null && hit.getType() == HitResult.Type.BLOCK && turtle.getPos()
.equals( ((BlockHitResult) hit).getBlockPos() ) )
{
MinecraftClient mc = MinecraftClient.getInstance();
TextRenderer font = mc.textRenderer;
transform.push();
transform.translate( 0.5, 1.2, 0.5 );
transform.multiply( mc.getEntityRenderDispatcher()
.getRotation() );
transform.scale( -0.025f, -0.025f, 0.025f );
Matrix4f matrix = transform.peek()
.getModel();
int opacity = (int) (mc.options.getTextBackgroundOpacity( 0.25f ) * 255) << 24;
float width = -font.getWidth( label ) / 2.0f;
font.draw( label, width, (float) 0, 0x20ffffff, false, matrix, renderer, true, opacity, lightmapCoord );
font.draw( label, width, (float) 0, 0xffffffff, false, matrix, renderer, false, 0, lightmapCoord );
transform.pop();
}
transform.push();
// Setup the transform.
Vec3d offset = turtle.getRenderOffset( partialTicks );
float yaw = turtle.getRenderYaw( partialTicks );
transform.translate( offset.x, offset.y, offset.z );
transform.translate( 0.5f, 0.5f, 0.5f );
transform.multiply( Vec3f.POSITIVE_Y.getDegreesQuaternion( 180.0f - yaw ) );
if( label != null && (label.equals( "Dinnerbone" ) || label.equals( "Grumm" )) )
{
// Flip the model
transform.scale( 1.0f, -1.0f, 1.0f );
}
transform.translate( -0.5f, -0.5f, -0.5f );
// Render the turtle
int colour = turtle.getColour();
ComputerFamily family = turtle.getFamily();
Identifier overlay = turtle.getOverlay();
VertexConsumer buffer = renderer.getBuffer( TexturedRenderLayers.getEntityTranslucentCull() );
renderModel( transform, buffer, lightmapCoord, overlayLight, getTurtleModel( family, colour != -1 ), colour == -1 ? null : new int[] { colour } );
// Render the overlay
ModelIdentifier overlayModel = getTurtleOverlayModel( overlay, HolidayUtil.getCurrentHoliday() == Holiday.CHRISTMAS );
if( overlayModel != null )
{
renderModel( transform, buffer, lightmapCoord, overlayLight, overlayModel, null );
}
// Render the upgrades
renderUpgrade( transform, buffer, lightmapCoord, overlayLight, turtle, TurtleSide.LEFT, partialTicks );
renderUpgrade( transform, buffer, lightmapCoord, overlayLight, turtle, TurtleSide.RIGHT, partialTicks );
transform.pop();
}
public static void renderUpgrade( @Nonnull MatrixStack transform, @Nonnull VertexConsumer renderer, int lightmapCoord, int overlayLight, TileTurtle turtle,
TurtleSide side, float f )
{
ITurtleUpgrade upgrade = turtle.getUpgrade( side );
if( upgrade == null )
{
return;
}
transform.push();
float toolAngle = turtle.getToolRenderAngle( side, f );
transform.translate( 0.0f, 0.5f, 0.5f );
transform.multiply( Vec3f.NEGATIVE_X.getDegreesQuaternion( toolAngle ) );
transform.translate( 0.0f, -0.5f, -0.5f );
TransformedModel model = upgrade.getModel( turtle.getAccess(), side );
model.push( transform );
TileEntityTurtleRenderer.renderModel( transform, renderer, lightmapCoord, overlayLight, model.getModel(), null );
transform.pop();
transform.pop();
}
public static void renderModel( @Nonnull MatrixStack transform, @Nonnull VertexConsumer renderer, int lightmapCoord, int overlayLight,
ModelIdentifier modelLocation, int[] tints )
{
BakedModelManager modelManager = MinecraftClient.getInstance()
.getItemRenderer()
.getModels()
.getModelManager();
renderModel( transform, renderer, lightmapCoord, overlayLight, modelManager.getModel( modelLocation ), tints );
}
public static void renderModel( @Nonnull MatrixStack transform, @Nonnull VertexConsumer renderer, int lightmapCoord, int overlayLight, BakedModel model,
int[] tints )
{
Random random = new Random();
random.setSeed( 0 );
renderQuads( transform, renderer, lightmapCoord, overlayLight, model.getQuads( null, null, random ), tints );
for( Direction facing : DirectionUtil.FACINGS )
{
renderQuads( transform, renderer, lightmapCoord, overlayLight, model.getQuads( null, facing, random ), tints );
}
}
} }

View File

@@ -30,7 +30,7 @@ public class TurtleMultiModel implements BakedModel
private final TransformedModel leftUpgradeModel; private final TransformedModel leftUpgradeModel;
private final TransformedModel rightUpgradeModel; private final TransformedModel rightUpgradeModel;
private List<BakedQuad> generalQuads = null; private List<BakedQuad> generalQuads = null;
private Map<Direction, List<BakedQuad>> faceQuads = new EnumMap<>( Direction.class ); private final Map<Direction, List<BakedQuad>> faceQuads = new EnumMap<>( Direction.class );
public TurtleMultiModel( BakedModel baseModel, BakedModel overlayModel, AffineTransformation generalTransform, TransformedModel leftUpgradeModel, public TurtleMultiModel( BakedModel baseModel, BakedModel overlayModel, AffineTransformation generalTransform, TransformedModel leftUpgradeModel,
TransformedModel rightUpgradeModel ) TransformedModel rightUpgradeModel )
@@ -120,9 +120,9 @@ public class TurtleMultiModel implements BakedModel
@Nonnull @Nonnull
@Override @Override
@Deprecated @Deprecated
public Sprite getSprite() public Sprite getParticleSprite()
{ {
return baseModel.getSprite(); return baseModel.getParticleSprite();
} }
@Nonnull @Nonnull

View File

@@ -6,25 +6,19 @@
package dan200.computercraft.client.render; package dan200.computercraft.client.render;
import dan200.computercraft.shared.turtle.core.TurtlePlayer; import dan200.computercraft.shared.turtle.core.TurtlePlayer;
import net.fabricmc.fabric.api.client.rendereregistry.v1.EntityRendererRegistry;
import net.minecraft.client.render.VertexConsumerProvider; import net.minecraft.client.render.VertexConsumerProvider;
import net.minecraft.client.render.entity.EntityRenderDispatcher;
import net.minecraft.client.render.entity.EntityRenderer; import net.minecraft.client.render.entity.EntityRenderer;
import net.minecraft.client.render.entity.EntityRendererFactory;
import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
public class TurtlePlayerRenderer extends EntityRenderer<TurtlePlayer> public class TurtlePlayerRenderer extends EntityRenderer<TurtlePlayer>
{ { //FIXME Make sure this isn't an issue. Context was EntityRenderDispatcher.
public TurtlePlayerRenderer( EntityRenderDispatcher renderManager ) public TurtlePlayerRenderer( EntityRendererFactory.Context context )
{ {
super( renderManager ); super( context );
}
public TurtlePlayerRenderer( EntityRenderDispatcher entityRenderDispatcher, EntityRendererRegistry.Context context )
{
super( entityRenderDispatcher );
} }
@Override @Override

View File

@@ -3,7 +3,6 @@
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com * Send enquiries to dratcliffe@gmail.com
*/ */
package dan200.computercraft.client.render; package dan200.computercraft.client.render;
import com.google.common.base.Objects; import com.google.common.base.Objects;
@@ -24,6 +23,7 @@ import net.minecraft.client.render.model.json.ModelOverrideList;
import net.minecraft.client.render.model.json.ModelTransformation; import net.minecraft.client.render.model.json.ModelTransformation;
import net.minecraft.client.texture.Sprite; import net.minecraft.client.texture.Sprite;
import net.minecraft.client.util.ModelIdentifier; import net.minecraft.client.util.ModelIdentifier;
import net.minecraft.util.math.AffineTransformation;
import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.client.world.ClientWorld; import net.minecraft.client.world.ClientWorld;
import net.minecraft.entity.LivingEntity; import net.minecraft.entity.LivingEntity;
@@ -55,8 +55,60 @@ public class TurtleSmartItemModel implements BakedModel
.getModel() ); .getModel() );
} }
private static class TurtleModelCombination
{
final boolean colour;
final ITurtleUpgrade leftUpgrade;
final ITurtleUpgrade rightUpgrade;
final Identifier overlay;
final boolean christmas;
final boolean flip;
TurtleModelCombination( boolean colour, ITurtleUpgrade leftUpgrade, ITurtleUpgrade rightUpgrade, Identifier overlay, boolean christmas,
boolean flip )
{
this.colour = colour;
this.leftUpgrade = leftUpgrade;
this.rightUpgrade = rightUpgrade;
this.overlay = overlay;
this.christmas = christmas;
this.flip = flip;
}
@Override
public boolean equals( Object other )
{
if( other == this )
{
return true;
}
if( !(other instanceof TurtleModelCombination otherCombo) )
{
return false;
}
return otherCombo.colour == colour && otherCombo.leftUpgrade == leftUpgrade && otherCombo.rightUpgrade == rightUpgrade && Objects.equal(
otherCombo.overlay, overlay ) && otherCombo.christmas == christmas && otherCombo.flip == flip;
}
@Override
public int hashCode()
{
final int prime = 31;
int result = 0;
result = prime * result + (colour ? 1 : 0);
result = prime * result + (leftUpgrade != null ? leftUpgrade.hashCode() : 0);
result = prime * result + (rightUpgrade != null ? rightUpgrade.hashCode() : 0);
result = prime * result + (overlay != null ? overlay.hashCode() : 0);
result = prime * result + (christmas ? 1 : 0);
result = prime * result + (flip ? 1 : 0);
return result;
}
}
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 HashMap<TurtleModelCombination, BakedModel> cachedModels = new HashMap<>();
private final ModelOverrideList overrides; private final ModelOverrideList overrides;
@@ -70,8 +122,7 @@ public class TurtleSmartItemModel implements BakedModel
{ {
@Nonnull @Nonnull
@Override @Override
public BakedModel apply( @Nonnull BakedModel originalModel, @Nonnull ItemStack stack, @Nullable ClientWorld world, public BakedModel apply( BakedModel originalModel, ItemStack stack, @Nullable ClientWorld world, @Nullable LivingEntity entity, int seed )
@Nullable LivingEntity entity )
{ {
ItemTurtle turtle = (ItemTurtle) stack.getItem(); ItemTurtle turtle = (ItemTurtle) stack.getItem();
int colour = turtle.getColour( stack ); int colour = turtle.getColour( stack );
@@ -80,9 +131,7 @@ public class TurtleSmartItemModel implements BakedModel
Identifier overlay = turtle.getOverlay( stack ); Identifier overlay = turtle.getOverlay( stack );
boolean christmas = HolidayUtil.getCurrentHoliday() == Holiday.CHRISTMAS; boolean christmas = HolidayUtil.getCurrentHoliday() == Holiday.CHRISTMAS;
String label = turtle.getLabel( stack ); String label = turtle.getLabel( stack );
// TODO make upside down turtle items render properly (currently inivisible) boolean flip = label != null && (label.equals( "Dinnerbone" ) || label.equals( "Grumm" ));
//boolean flip = label != null && (label.equals("Dinnerbone") || label.equals("Grumm"));
boolean flip = false;
TurtleModelCombination combo = new TurtleModelCombination( colour != -1, leftUpgrade, rightUpgrade, overlay, christmas, flip ); TurtleModelCombination combo = new TurtleModelCombination( colour != -1, leftUpgrade, rightUpgrade, overlay, christmas, flip );
BakedModel model = cachedModels.get( combo ); BakedModel model = cachedModels.get( combo );
@@ -143,12 +192,18 @@ public class TurtleSmartItemModel implements BakedModel
return familyModel.isBuiltin(); return familyModel.isBuiltin();
} }
@Nonnull
@Override @Override
@Deprecated @Deprecated
public Sprite getSprite() public Sprite getParticleSprite()
{ {
return familyModel.getSprite(); return familyModel.getParticleSprite();
}
@Nonnull
@Override
public ModelOverrideList getOverrides()
{
return overrides;
} }
@Nonnull @Nonnull
@@ -159,63 +214,4 @@ public class TurtleSmartItemModel implements BakedModel
return familyModel.getTransformation(); return familyModel.getTransformation();
} }
@Nonnull
@Override
public ModelOverrideList getOverrides()
{
return overrides;
}
private static class TurtleModelCombination
{
final boolean colour;
final ITurtleUpgrade leftUpgrade;
final ITurtleUpgrade rightUpgrade;
final Identifier overlay;
final boolean christmas;
final boolean flip;
TurtleModelCombination( boolean colour, ITurtleUpgrade leftUpgrade, ITurtleUpgrade rightUpgrade, Identifier overlay, boolean christmas,
boolean flip )
{
this.colour = colour;
this.leftUpgrade = leftUpgrade;
this.rightUpgrade = rightUpgrade;
this.overlay = overlay;
this.christmas = christmas;
this.flip = flip;
}
@Override
public int hashCode()
{
final int prime = 31;
int result = 0;
result = prime * result + (colour ? 1 : 0);
result = prime * result + (leftUpgrade != null ? leftUpgrade.hashCode() : 0);
result = prime * result + (rightUpgrade != null ? rightUpgrade.hashCode() : 0);
result = prime * result + (overlay != null ? overlay.hashCode() : 0);
result = prime * result + (christmas ? 1 : 0);
result = prime * result + (flip ? 1 : 0);
return result;
}
@Override
public boolean equals( Object other )
{
if( other == this )
{
return true;
}
if( !(other instanceof TurtleModelCombination) )
{
return false;
}
TurtleModelCombination otherCombo = (TurtleModelCombination) other;
return otherCombo.colour == colour && otherCombo.leftUpgrade == leftUpgrade && otherCombo.rightUpgrade == rightUpgrade && Objects.equal(
otherCombo.overlay, overlay ) && otherCombo.christmas == christmas && otherCombo.flip == flip;
}
}
} }

View File

@@ -5,6 +5,7 @@
*/ */
package dan200.computercraft.core.apis; package dan200.computercraft.core.apis;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.api.filesystem.IMount; import dan200.computercraft.api.filesystem.IMount;
import dan200.computercraft.api.filesystem.IWritableMount; import dan200.computercraft.api.filesystem.IWritableMount;
import dan200.computercraft.api.peripheral.IComputerAccess; import dan200.computercraft.api.peripheral.IComputerAccess;
@@ -30,6 +31,10 @@ public abstract class ComputerAccess implements IComputerAccess
public void unmountAll() public void unmountAll()
{ {
FileSystem fileSystem = environment.getFileSystem(); FileSystem fileSystem = environment.getFileSystem();
if( !mounts.isEmpty() )
{
ComputerCraft.log.warn( "Peripheral or API called mount but did not call unmount for {}", mounts );
}
for( String mount : mounts ) for( String mount : mounts )
{ {
fileSystem.unmount( mount ); fileSystem.unmount( mount );

View File

@@ -62,6 +62,7 @@ public interface IAPIEnvironment
@Nullable @Nullable
IPeripheral getPeripheral( ComputerSide side ); IPeripheral getPeripheral( ComputerSide side );
@Nullable
String getLabel(); String getLabel();
void setLabel( @Nullable String label ); void setLabel( @Nullable String label );

View File

@@ -96,9 +96,8 @@ public abstract class HandleGeneric
protected static SeekableByteChannel asSeekable( Channel channel ) protected static SeekableByteChannel asSeekable( Channel channel )
{ {
if( !(channel instanceof SeekableByteChannel) ) return null; if( !(channel instanceof SeekableByteChannel seekable) ) return null;
SeekableByteChannel seekable = (SeekableByteChannel) channel;
try try
{ {
seekable.position( seekable.position() ); seekable.position( seekable.position() );

View File

@@ -20,6 +20,8 @@ import io.netty.handler.codec.http.websocketx.WebSocketHandshakeException;
import io.netty.handler.ssl.SslContext; import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.SslContextBuilder; import io.netty.handler.ssl.SslContextBuilder;
import io.netty.handler.timeout.ReadTimeoutException; import io.netty.handler.timeout.ReadTimeoutException;
import io.netty.handler.traffic.AbstractTrafficShapingHandler;
import io.netty.handler.traffic.GlobalTrafficShapingHandler;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.net.ssl.SSLException; import javax.net.ssl.SSLException;
@@ -28,9 +30,7 @@ import javax.net.ssl.TrustManagerFactory;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.net.URI; import java.net.URI;
import java.security.KeyStore; import java.security.KeyStore;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
/** /**
@@ -38,10 +38,8 @@ import java.util.concurrent.TimeUnit;
*/ */
public final class NetworkUtils public final class NetworkUtils
{ {
public static final ExecutorService EXECUTOR = new ThreadPoolExecutor( public static final ScheduledThreadPoolExecutor EXECUTOR = new ScheduledThreadPoolExecutor(
4, Integer.MAX_VALUE, 4,
60L, TimeUnit.SECONDS,
new SynchronousQueue<>(),
ThreadUtils.builder( "Network" ) ThreadUtils.builder( "Network" )
.setPriority( Thread.MIN_PRIORITY + (Thread.NORM_PRIORITY - Thread.MIN_PRIORITY) / 2 ) .setPriority( Thread.MIN_PRIORITY + (Thread.NORM_PRIORITY - Thread.MIN_PRIORITY) / 2 )
.build() .build()
@@ -52,6 +50,15 @@ public final class NetworkUtils
.build() .build()
); );
public static final AbstractTrafficShapingHandler SHAPING_HANDLER = new GlobalTrafficShapingHandler(
EXECUTOR, ComputerCraft.httpUploadBandwidth, ComputerCraft.httpDownloadBandwidth
);
static
{
EXECUTOR.setKeepAliveTime( 60, TimeUnit.SECONDS );
}
private NetworkUtils() private NetworkUtils()
{ {
} }
@@ -107,8 +114,18 @@ public final class NetworkUtils
} }
} }
public static void reloadConfig()
{
SHAPING_HANDLER.configure( ComputerCraft.httpUploadBandwidth, ComputerCraft.httpDownloadBandwidth );
}
public static void reset()
{
SHAPING_HANDLER.trafficCounter().resetCumulativeTime();
}
/** /**
* Create a {@link InetSocketAddress} from a {@link URI}. * Create a {@link InetSocketAddress} from a {@link java.net.URI}.
* *
* Note, this may require a DNS lookup, and so should not be executed on the main CC thread. * Note, this may require a DNS lookup, and so should not be executed on the main CC thread.
* *
@@ -184,7 +201,7 @@ public final class NetworkUtils
{ {
return "Timed out"; return "Timed out";
} }
else if( cause instanceof SSLHandshakeException || (cause instanceof DecoderException && cause.getCause() instanceof SSLHandshakeException) ) else if( cause instanceof SSLHandshakeException || cause instanceof DecoderException && cause.getCause() instanceof SSLHandshakeException )
{ {
return "Could not create a secure connection"; return "Could not create a secure connection";
} }

View File

@@ -75,7 +75,7 @@ public final class AddressRule
if( this.port != null && this.port != port ) return false; if( this.port != null && this.port != port ) return false;
return predicate.matches( domain ) return predicate.matches( domain )
|| predicate.matches( address ) || predicate.matches( address )
|| (ipv4Address != null && predicate.matches( ipv4Address )); || ipv4Address != null && predicate.matches( ipv4Address );
} }
public static Options apply( Iterable<? extends AddressRule> rules, String domain, InetSocketAddress socketAddress ) public static Options apply( Iterable<? extends AddressRule> rules, String domain, InetSocketAddress socketAddress )

View File

@@ -167,6 +167,7 @@ public class HttpRequest extends Resource<HttpRequest>
} }
ChannelPipeline p = ch.pipeline(); ChannelPipeline p = ch.pipeline();
p.addLast( NetworkUtils.SHAPING_HANDLER );
if( sslContext != null ) if( sslContext != null )
{ {
p.addLast( sslContext.newHandler( ch.alloc(), uri.getHost(), socketAddress.getPort() ) ); p.addLast( sslContext.newHandler( ch.alloc(), uri.getHost(), socketAddress.getPort() ) );

View File

@@ -100,9 +100,8 @@ public final class HttpRequestHandler extends SimpleChannelInboundHandler<HttpOb
{ {
if( closed || request.checkClosed() ) return; if( closed || request.checkClosed() ) return;
if( message instanceof HttpResponse ) if( message instanceof HttpResponse response )
{ {
HttpResponse response = (HttpResponse) message;
if( request.redirects.get() > 0 ) if( request.redirects.get() > 0 )
{ {
@@ -137,9 +136,8 @@ public final class HttpRequestHandler extends SimpleChannelInboundHandler<HttpOb
responseHeaders.add( response.headers() ); responseHeaders.add( response.headers() );
} }
if( message instanceof HttpContent ) if( message instanceof HttpContent content )
{ {
HttpContent content = (HttpContent) message;
if( responseBody == null ) if( responseBody == null )
{ {
@@ -162,9 +160,8 @@ public final class HttpRequestHandler extends SimpleChannelInboundHandler<HttpOb
responseBody.addComponent( true, partial.retain() ); responseBody.addComponent( true, partial.retain() );
} }
if( message instanceof LastHttpContent ) if( message instanceof LastHttpContent last )
{ {
LastHttpContent last = (LastHttpContent) message;
responseHeaders.add( last.trailingHeaders() ); responseHeaders.add( last.trailingHeaders() );
// Set the content length, if not already given. // Set the content length, if not already given.

View File

@@ -22,12 +22,12 @@ import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel; import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.http.HttpClientCodec; import io.netty.handler.codec.http.HttpClientCodec;
import io.netty.handler.codec.http.HttpHeaderNames;
import io.netty.handler.codec.http.HttpHeaders; import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.HttpObjectAggregator; import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.websocketx.WebSocketClientHandshaker; import io.netty.handler.codec.http.websocketx.WebSocketClientHandshaker;
import io.netty.handler.codec.http.websocketx.WebSocketClientHandshakerFactory; import io.netty.handler.codec.http.websocketx.WebSocketClientHandshakerFactory;
import io.netty.handler.codec.http.websocketx.WebSocketVersion; import io.netty.handler.codec.http.websocketx.WebSocketVersion;
import io.netty.handler.codec.http.websocketx.extensions.compression.WebSocketClientCompressionHandler;
import io.netty.handler.ssl.SslContext; import io.netty.handler.ssl.SslContext;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
@@ -145,20 +145,22 @@ public class Websocket extends Resource<Websocket>
protected void initChannel( SocketChannel ch ) protected void initChannel( SocketChannel ch )
{ {
ChannelPipeline p = ch.pipeline(); ChannelPipeline p = ch.pipeline();
p.addLast( NetworkUtils.SHAPING_HANDLER );
if( sslContext != null ) if( sslContext != null )
{ {
p.addLast( sslContext.newHandler( ch.alloc(), uri.getHost(), socketAddress.getPort() ) ); p.addLast( sslContext.newHandler( ch.alloc(), uri.getHost(), socketAddress.getPort() ) );
} }
String subprotocol = headers.get( HttpHeaderNames.SEC_WEBSOCKET_PROTOCOL );
WebSocketClientHandshaker handshaker = WebSocketClientHandshakerFactory.newHandshaker( WebSocketClientHandshaker handshaker = WebSocketClientHandshakerFactory.newHandshaker(
uri, WebSocketVersion.V13, null, true, headers, uri, WebSocketVersion.V13, subprotocol, true, headers,
options.websocketMessage <= 0 ? MAX_MESSAGE_SIZE : options.websocketMessage options.websocketMessage <= 0 ? MAX_MESSAGE_SIZE : options.websocketMessage
); );
p.addLast( p.addLast(
new HttpClientCodec(), new HttpClientCodec(),
new HttpObjectAggregator( 8192 ), new HttpObjectAggregator( 8192 ),
WebSocketClientCompressionHandler.INSTANCE, WebsocketCompressionHandler.INSTANCE,
new WebsocketHandler( Websocket.this, handshaker, options ) new WebsocketHandler( Websocket.this, handshaker, options )
); );
} }

View File

@@ -0,0 +1,38 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.core.apis.http.websocket;
import io.netty.channel.ChannelHandler;
import io.netty.handler.codec.compression.ZlibCodecFactory;
import io.netty.handler.codec.http.websocketx.extensions.WebSocketClientExtensionHandler;
import io.netty.handler.codec.http.websocketx.extensions.compression.DeflateFrameClientExtensionHandshaker;
import io.netty.handler.codec.http.websocketx.extensions.compression.PerMessageDeflateClientExtensionHandshaker;
import io.netty.handler.codec.http.websocketx.extensions.compression.WebSocketClientCompressionHandler;
import static io.netty.handler.codec.http.websocketx.extensions.compression.PerMessageDeflateServerExtensionHandshaker.MAX_WINDOW_SIZE;
/**
* An alternative to {@link WebSocketClientCompressionHandler} which supports the {@literal client_no_context_takeover}
* extension. Makes CC <em>slightly</em> more flexible.
*/
@ChannelHandler.Sharable
final class WebsocketCompressionHandler extends WebSocketClientExtensionHandler
{
public static final WebsocketCompressionHandler INSTANCE = new WebsocketCompressionHandler();
private WebsocketCompressionHandler()
{
super(
new PerMessageDeflateClientExtensionHandshaker(
6, ZlibCodecFactory.isSupportingWindowSizeAndMemLevel(), MAX_WINDOW_SIZE,
true, false
),
new DeflateFrameClientExtensionHandshaker( false ),
new DeflateFrameClientExtensionHandshaker( true )
);
}
}

View File

@@ -55,9 +55,8 @@ public class WebsocketHandler extends SimpleChannelInboundHandler<Object>
return; return;
} }
if( msg instanceof FullHttpResponse ) if( msg instanceof FullHttpResponse response )
{ {
FullHttpResponse response = (FullHttpResponse) msg;
throw new IllegalStateException( "Unexpected FullHttpResponse (getStatus=" + response.status() + ", content=" + response.content().toString( CharsetUtil.UTF_8 ) + ')' ); throw new IllegalStateException( "Unexpected FullHttpResponse (getStatus=" + response.status() + ", content=" + response.content().toString( CharsetUtil.UTF_8 ) + ')' );
} }
@@ -76,9 +75,8 @@ public class WebsocketHandler extends SimpleChannelInboundHandler<Object>
websocket.environment().addTrackingChange( TrackingField.WEBSOCKET_INCOMING, converted.length ); websocket.environment().addTrackingChange( TrackingField.WEBSOCKET_INCOMING, converted.length );
websocket.environment().queueEvent( MESSAGE_EVENT, websocket.address(), converted, true ); websocket.environment().queueEvent( MESSAGE_EVENT, websocket.address(), converted, true );
} }
else if( frame instanceof CloseWebSocketFrame ) else if( frame instanceof CloseWebSocketFrame closeFrame )
{ {
CloseWebSocketFrame closeFrame = (CloseWebSocketFrame) frame;
websocket.close( closeFrame.statusCode(), closeFrame.reasonText() ); websocket.close( closeFrame.statusCode(), closeFrame.reasonText() );
} }
else if( frame instanceof PingWebSocketFrame ) else if( frame instanceof PingWebSocketFrame )

View File

@@ -18,7 +18,7 @@ import static org.objectweb.asm.Opcodes.ICONST_0;
final class Reflect final class Reflect
{ {
static final Type OPTIONAL_IN = Optional.class.getTypeParameters()[0]; static final java.lang.reflect.Type OPTIONAL_IN = Optional.class.getTypeParameters()[0];
private Reflect() private Reflect()
{ {
@@ -52,12 +52,11 @@ final class Reflect
{ {
if( underlying instanceof Class<?> ) return (Class<?>) underlying; if( underlying instanceof Class<?> ) return (Class<?>) underlying;
if( underlying instanceof ParameterizedType ) if( underlying instanceof ParameterizedType type )
{ {
ParameterizedType type = (ParameterizedType) underlying;
if( !allowParameter ) if( !allowParameter )
{ {
for( Type arg : type.getActualTypeArguments() ) for( java.lang.reflect.Type arg : type.getActualTypeArguments() )
{ {
if( arg instanceof WildcardType ) continue; if( arg instanceof WildcardType ) continue;
if( arg instanceof TypeVariable && ((TypeVariable<?>) arg).getName().startsWith( "capture#" ) ) if( arg instanceof TypeVariable && ((TypeVariable<?>) arg).getName().startsWith( "capture#" ) )

View File

@@ -309,9 +309,9 @@ public final class Environment implements IAPIEnvironment
{ {
int index = side.ordinal(); int index = side.ordinal();
IPeripheral existing = peripherals[index]; IPeripheral existing = peripherals[index];
if( (existing == null && peripheral != null) || if( existing == null && peripheral != null ||
(existing != null && peripheral == null) || existing != null && peripheral == null ||
(existing != null && !existing.equals( peripheral )) ) existing != null && !existing.equals( peripheral ) )
{ {
peripherals[index] = peripheral; peripherals[index] = peripheral;
if( peripheralListener != null ) peripheralListener.onPeripheralChanged( side, peripheral ); if( peripheralListener != null ) peripheralListener.onPeripheralChanged( side, peripheral );

View File

@@ -293,9 +293,8 @@ class MountWrapper
private FileSystemException localExceptionOf( @Nullable String localPath, @Nonnull IOException e ) private FileSystemException localExceptionOf( @Nullable String localPath, @Nonnull IOException e )
{ {
if( !location.isEmpty() && e instanceof FileOperationException ) if( !location.isEmpty() && e instanceof FileOperationException ex )
{ {
FileOperationException ex = (FileOperationException) e;
if( ex.getFilename() != null ) return localExceptionOf( ex.getFilename(), ex.getMessage() ); if( ex.getFilename() != null ) return localExceptionOf( ex.getFilename(), ex.getMessage() );
} }

View File

@@ -17,10 +17,9 @@ import dan200.computercraft.shared.util.IoUtil;
import net.minecraft.resource.ReloadableResourceManager; import net.minecraft.resource.ReloadableResourceManager;
import net.minecraft.resource.Resource; import net.minecraft.resource.Resource;
import net.minecraft.resource.ResourceManager; import net.minecraft.resource.ResourceManager;
import net.minecraft.resource.ResourceReloader; import net.minecraft.resource.SynchronousResourceReloader;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import net.minecraft.util.InvalidIdentifierException; import net.minecraft.util.InvalidIdentifierException;
import net.minecraft.util.profiler.Profiler;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@@ -30,8 +29,6 @@ import java.io.InputStream;
import java.nio.channels.Channels; import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel; import java.nio.channels.ReadableByteChannel;
import java.util.*; import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
public final class ResourceMount implements IMount public final class ResourceMount implements IMount
@@ -114,6 +111,7 @@ public final class ResourceMount implements IMount
existingNamespace = file.getNamespace(); existingNamespace = file.getNamespace();
if( !file.getNamespace().equals( namespace ) ) continue; if( !file.getNamespace().equals( namespace ) ) continue;
if( !FileSystem.contains( subPath, file.getPath() ) ) continue; // Some packs seem to include the parent?
String localPath = FileSystem.toLocal( file.getPath(), subPath ); String localPath = FileSystem.toLocal( file.getPath(), subPath );
create( newRoot, localPath ); create( newRoot, localPath );
@@ -300,7 +298,7 @@ public final class ResourceMount implements IMount
* While people should really be keeping a permanent reference to this, some people construct it every * While people should really be keeping a permanent reference to this, some people construct it every
* method call, so let's make this as small as possible. * method call, so let's make this as small as possible.
*/ */
static class Listener implements ResourceReloader static class Listener implements SynchronousResourceReloader
{ {
private static final Listener INSTANCE = new Listener(); private static final Listener INSTANCE = new Listener();
@@ -308,19 +306,9 @@ public final class ResourceMount implements IMount
private final Set<ReloadableResourceManager> managers = Collections.newSetFromMap( new WeakHashMap<>() ); private final Set<ReloadableResourceManager> managers = Collections.newSetFromMap( new WeakHashMap<>() );
@Override @Override
public CompletableFuture<Void> reload( Synchronizer synchronizer, ResourceManager manager, Profiler prepareProfiler, Profiler applyProfiler, Executor prepareExecutor, Executor applyExecutor ) public void reload( @Nonnull ResourceManager manager )
{ {
return CompletableFuture.runAsync( () -> { for( ResourceMount mount : mounts ) mount.load();
prepareProfiler.push( "Mount reloading" );
try
{
for( ResourceMount mount : mounts ) mount.load();
}
finally
{
prepareProfiler.pop();
}
}, prepareExecutor );
} }
synchronized void add( ReloadableResourceManager manager, ResourceMount mount ) synchronized void add( ReloadableResourceManager manager, ResourceMount mount )

View File

@@ -97,7 +97,7 @@ public class CobaltLuaMachine implements ILuaMachine
globals.load( state, new CoroutineLib() ); globals.load( state, new CoroutineLib() );
globals.load( state, new Bit32Lib() ); globals.load( state, new Bit32Lib() );
globals.load( state, new Utf8Lib() ); globals.load( state, new Utf8Lib() );
if( ComputerCraft.debugEnable ) globals.load( state, new DebugLib() ); globals.load( state, new DebugLib() );
// Remove globals we don't want to expose // Remove globals we don't want to expose
globals.rawset( "collectgarbage", Constants.NIL ); globals.rawset( "collectgarbage", Constants.NIL );
@@ -260,14 +260,12 @@ public class CobaltLuaMachine implements ILuaMachine
if( object instanceof Number ) return valueOf( ((Number) object).doubleValue() ); if( object instanceof Number ) return valueOf( ((Number) object).doubleValue() );
if( object instanceof Boolean ) return valueOf( (Boolean) object ); if( object instanceof Boolean ) return valueOf( (Boolean) object );
if( object instanceof String ) return valueOf( object.toString() ); if( object instanceof String ) return valueOf( object.toString() );
if( object instanceof byte[] ) if( object instanceof byte[] b )
{ {
byte[] b = (byte[]) object;
return valueOf( Arrays.copyOf( b, b.length ) ); return valueOf( Arrays.copyOf( b, b.length ) );
} }
if( object instanceof ByteBuffer ) if( object instanceof ByteBuffer b )
{ {
ByteBuffer b = (ByteBuffer) object;
byte[] bytes = new byte[b.remaining()]; byte[] bytes = new byte[b.remaining()];
b.get( bytes ); b.get( bytes );
return valueOf( bytes ); return valueOf( bytes );
@@ -304,9 +302,8 @@ public class CobaltLuaMachine implements ILuaMachine
return table; return table;
} }
if( object instanceof Collection ) if( object instanceof Collection<?> objects )
{ {
Collection<?> objects = (Collection<?>) object;
LuaTable table = new LuaTable( objects.size(), 0 ); LuaTable table = new LuaTable( objects.size(), 0 );
values.put( object, table ); values.put( object, table );
int i = 0; int i = 0;
@@ -314,9 +311,8 @@ public class CobaltLuaMachine implements ILuaMachine
return table; return table;
} }
if( object instanceof Object[] ) if( object instanceof Object[] objects )
{ {
Object[] objects = (Object[]) object;
LuaTable table = new LuaTable( objects.length, 0 ); LuaTable table = new LuaTable( objects.length, 0 );
values.put( object, table ); values.put( object, table );
for( int i = 0; i < objects.length; i++ ) table.rawset( i + 1, toValue( objects[i], values ) ); for( int i = 0; i < objects.length; i++ ) table.rawset( i + 1, toValue( objects[i], values ) );
@@ -367,6 +363,7 @@ public class CobaltLuaMachine implements ILuaMachine
case Constants.TSTRING: case Constants.TSTRING:
return value.toString(); return value.toString();
case Constants.TTABLE: case Constants.TTABLE:
{
// Table: // Table:
// Start remembering stuff // Start remembering stuff
if( objects == null ) if( objects == null )
@@ -408,6 +405,7 @@ public class CobaltLuaMachine implements ILuaMachine
} }
} }
return table; return table;
}
default: default:
return null; return null;
} }

View File

@@ -9,6 +9,8 @@ import dan200.computercraft.ComputerCraft;
import dan200.computercraft.api.lua.ILuaContext; import dan200.computercraft.api.lua.ILuaContext;
import dan200.computercraft.api.lua.ILuaTask; import dan200.computercraft.api.lua.ILuaTask;
import dan200.computercraft.api.lua.LuaException; import dan200.computercraft.api.lua.LuaException;
import dan200.computercraft.api.lua.MethodResult;
import dan200.computercraft.core.asm.TaskCallback;
import dan200.computercraft.core.computer.Computer; import dan200.computercraft.core.computer.Computer;
import dan200.computercraft.core.computer.MainThread; import dan200.computercraft.core.computer.MainThread;
@@ -66,4 +68,11 @@ class LuaContext implements ILuaContext
throw new LuaException( "Task limit exceeded" ); throw new LuaException( "Task limit exceeded" );
} }
} }
@Nonnull
@Override
public MethodResult executeMainThreadTask( @Nonnull ILuaTask task ) throws LuaException
{
return TaskCallback.make( this, task );
}
} }

View File

@@ -419,6 +419,7 @@ public class Terminal
{ {
if( c >= '0' && c <= '9' ) return c - '0'; if( c >= '0' && c <= '9' ) return c - '0';
if( c >= 'a' && c <= 'f' ) return c - 'a' + 10; if( c >= 'a' && c <= 'f' ) return c - 'a' + 10;
if( c >= 'A' && c <= 'F' ) return c - 'A' + 10;
return 15 - def.ordinal(); return 15 - def.ordinal();
} }
} }

View File

@@ -79,6 +79,7 @@ public class TextBuffer
} }
} }
@Override
public String toString() public String toString()
{ {
return new String( text ); return new String( text );

View File

@@ -1,25 +0,0 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.fabric.mixin;
import net.minecraft.util.math.AffineTransformation;
import net.minecraft.util.math.Quaternion;
import net.minecraft.util.math.Vec3f;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
@Mixin( AffineTransformation.class )
public interface AffineTransformationAccess
{
@Accessor
Vec3f getTranslation();
@Accessor
Vec3f getScale();
@Accessor
Quaternion getRotation1();
}

View File

@@ -1,18 +0,0 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.fabric.mixin;
import net.minecraft.client.render.model.BakedQuad;
import net.minecraft.client.texture.Sprite;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
@Mixin( BakedQuad.class )
public interface BakedQuadAccess
{
@Accessor
Sprite getSprite();
}

View File

@@ -7,13 +7,18 @@ package dan200.computercraft.fabric.mixin;
import dan200.computercraft.shared.util.DropConsumer; import dan200.computercraft.shared.util.DropConsumer;
import net.minecraft.block.Block; import net.minecraft.block.Block;
import net.minecraft.entity.ItemEntity;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World; import net.minecraft.world.World;
import java.util.function.Supplier;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
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 org.spongepowered.asm.mixin.injection.callback.LocalCapture;
/** /**
* Captures block drops. * Captures block drops.
@@ -23,12 +28,16 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin( Block.class ) @Mixin( Block.class )
public class MixinBlock public class MixinBlock
{ {
@Inject( method = "dropStack", @Inject( method = "dropStack(Lnet/minecraft/world/World;Ljava/util/function/Supplier;Lnet/minecraft/item/ItemStack;)V",
at = @At( value = "INVOKE", target = "Lnet/minecraft/world/World;spawnEntity(Lnet/minecraft/entity/Entity;)Z" ), at = @At(
value = "INVOKE",
target = "Lnet/minecraft/entity/ItemEntity;setToDefaultPickupDelay()V"
),
locals = LocalCapture.CAPTURE_FAILSOFT,
cancellable = true ) cancellable = true )
private static void dropStack( World world, BlockPos pos, ItemStack stack, CallbackInfo callbackInfo ) private static void dropStack( World world, Supplier<ItemEntity> itemEntitySupplier, ItemStack stack, CallbackInfo callbackInfo, ItemEntity itemEntity )
{ {
if( DropConsumer.onHarvestDrops( world, pos, stack ) ) if( DropConsumer.onHarvestDrops( world, itemEntity.getBlockPos(), stack ) )
{ {
callbackInfo.cancel(); callbackInfo.cancel();
} }

View File

@@ -0,0 +1,43 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.fabric.mixin;
import com.mojang.datafixers.util.Pair;
import dan200.computercraft.client.render.MonitorTextureBufferShader;
import dan200.computercraft.client.render.RenderTypes;
import net.minecraft.client.gl.Program;
import net.minecraft.client.render.GameRenderer;
import net.minecraft.client.render.Shader;
import net.minecraft.resource.ResourceManager;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
import java.io.IOException;
import java.util.List;
import java.util.function.Consumer;
@Mixin( GameRenderer.class )
public class MixinGameRenderer
{
@Inject( method = "loadShaders", at = @At( value = "INVOKE_ASSIGN", target = "Ljava/util/List;add(Ljava/lang/Object;)Z", ordinal = 53 ), locals = LocalCapture.CAPTURE_FAILSOFT )
private void loadShaders( ResourceManager manager, CallbackInfo info, List<Program> list, List<Pair<Shader, Consumer<Shader>>> list2 ) throws IOException
{
list2.add( Pair.of( new Shader(
manager,
"terminal",
RenderTypes.TERMINAL_WITHOUT_DEPTH.getVertexFormat()
), shader -> RenderTypes.terminalShader = shader ) );
list2.add( Pair.of( new MonitorTextureBufferShader(
manager,
"monitor_tbo",
RenderTypes.MONITOR_TBO.getVertexFormat()
), shader -> RenderTypes.monitorTboShader = (MonitorTextureBufferShader) shader ) );
}
}

View File

@@ -12,6 +12,7 @@ import net.fabricmc.api.Environment;
import net.minecraft.client.render.VertexConsumerProvider; import net.minecraft.client.render.VertexConsumerProvider;
import net.minecraft.client.render.entity.ItemFrameEntityRenderer; import net.minecraft.client.render.entity.ItemFrameEntityRenderer;
import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.decoration.ItemFrameEntity; import net.minecraft.entity.decoration.ItemFrameEntity;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
@@ -23,16 +24,27 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Environment( EnvType.CLIENT ) @Environment( EnvType.CLIENT )
public class MixinItemFrameEntityRenderer public class MixinItemFrameEntityRenderer
{ {
@Inject( method = "render", at = @At( "HEAD" ), cancellable = true ) @Inject(
method = "render",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/client/util/math/MatrixStack;multiply(Lnet/minecraft/util/math/Quaternion;)V",
ordinal = 2,
shift = At.Shift.AFTER
),
cancellable = true )
private void renderItem( private void renderItem(
ItemFrameEntity itemFrameEntity, float f, float g, MatrixStack matrixStack, ItemFrameEntity itemFrameEntity, float f, float g, MatrixStack matrixStack,
VertexConsumerProvider vertexConsumerProvider, int i, CallbackInfo info VertexConsumerProvider vertexConsumerProvider, int itemFrameEntityLight, CallbackInfo info
) )
{ {
ItemStack stack = itemFrameEntity.getHeldItemStack(); ItemStack stack = itemFrameEntity.getHeldItemStack();
if( stack.getItem() instanceof ItemPrintout ) if( stack.getItem() instanceof ItemPrintout )
{ {
ItemPrintoutRenderer.INSTANCE.renderInFrame( matrixStack, vertexConsumerProvider, stack ); int light = itemFrameEntity.getType() == EntityType.GLOW_ITEM_FRAME ? 0xf000d2 : itemFrameEntityLight; // See getLightVal.
ItemPrintoutRenderer.INSTANCE.renderInFrame( matrixStack, vertexConsumerProvider, stack, light );
// TODO: need to find how to make if statement instead return, like it doing Forge
matrixStack.pop();
info.cancel(); info.cancel();
} }
} }

View File

@@ -0,0 +1,52 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.fabric.mixin;
import dan200.computercraft.fabric.mixininterface.IMatrix4f;
import net.minecraft.util.math.Matrix4f;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
@Mixin( Matrix4f.class )
public class MixinMatrix4f implements IMatrix4f
{
@Shadow protected float a00;
@Shadow protected float a01;
@Shadow protected float a02;
@Shadow protected float a03;
@Shadow protected float a10;
@Shadow protected float a11;
@Shadow protected float a12;
@Shadow protected float a13;
@Shadow protected float a20;
@Shadow protected float a21;
@Shadow protected float a22;
@Shadow protected float a23;
@Shadow protected float a30;
@Shadow protected float a31;
@Shadow protected float a32;
@Shadow protected float a33;
public void setFloatArray( float[] values )
{
a00 = values[0];
a01 = values[1];
a02 = values[2];
a03 = values[3];
a10 = values[4];
a11 = values[5];
a12 = values[6];
a13 = values[7];
a20 = values[8];
a21 = values[9];
a22 = values[10];
a23 = values[11];
a30 = values[12];
a31 = values[13];
a32 = values[14];
a33 = values[15];
}
}

View File

@@ -34,7 +34,7 @@ public class MixinServerPlayerInteractionManager
ActionResult actionResult = state.onUse( world, player, hand, hitResult ); ActionResult actionResult = state.onUse( world, player, hand, hitResult );
if( actionResult.isAccepted() ) if( actionResult.isAccepted() )
{ {
Criteria.ITEM_USED_ON_BLOCK.test( player, pos, stack ); Criteria.ITEM_USED_ON_BLOCK.trigger( player, pos, stack );
cir.setReturnValue( actionResult ); cir.setReturnValue( actionResult );
} }
} }

View File

@@ -7,7 +7,6 @@ package dan200.computercraft.fabric.mixin;
import dan200.computercraft.shared.common.TileGeneric; import dan200.computercraft.shared.common.TileGeneric;
import net.minecraft.block.entity.BlockEntity; import net.minecraft.block.entity.BlockEntity;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World; import net.minecraft.world.World;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Shadow;
@@ -29,10 +28,10 @@ public class MixinWorld
@Shadow @Shadow
protected boolean iteratingTickingBlockEntities; protected boolean iteratingTickingBlockEntities;
@Inject( method = "setBlockEntity", at = @At( "HEAD" ) ) @Inject( method = "addBlockEntity", at = @At( "HEAD" ) )
public void setBlockEntity( BlockPos pos, @Nullable BlockEntity entity, CallbackInfo info ) public void addBlockEntity( @Nullable BlockEntity entity, CallbackInfo info )
{ {
if( !World.isOutOfBuildLimitVertically( pos ) && entity != null && !entity.isRemoved() && iteratingTickingBlockEntities ) if( entity != null && !entity.isRemoved() && entity.getWorld().isInBuildLimit( entity.getPos() ) && iteratingTickingBlockEntities )
{ {
setWorld( entity, this ); setWorld( entity, this );
} }
@@ -42,11 +41,11 @@ public class MixinWorld
{ {
if( entity.getWorld() != world && entity instanceof TileGeneric ) if( entity.getWorld() != world && entity instanceof TileGeneric )
{ {
entity.setLocation( (World) world, entity.getPos() ); entity.setWorld( (World) world ); //TODO why?
} }
} }
@Inject( method = "addBlockEntities", at = @At( "HEAD" ) ) // @Inject( method = "addBlockEntities", at = @At( "HEAD" ) )
public void addBlockEntities( Collection<BlockEntity> entities, CallbackInfo info ) public void addBlockEntities( Collection<BlockEntity> entities, CallbackInfo info )
{ {
if( iteratingTickingBlockEntities ) if( iteratingTickingBlockEntities )

View File

@@ -1,18 +0,0 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.fabric.mixin;
import net.minecraft.item.MusicDiscItem;
import net.minecraft.sound.SoundEvent;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
@Mixin( MusicDiscItem.class )
public interface MusicDiscItemAccessor
{
@Accessor
SoundEvent getSound();
}

View File

@@ -14,5 +14,5 @@ import org.spongepowered.asm.mixin.gen.Accessor;
public interface SignBlockEntityAccess public interface SignBlockEntityAccess
{ {
@Accessor @Accessor
Text[] getText(); Text[] getTexts();
} }

View File

@@ -1,18 +0,0 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.fabric.mixin;
import net.minecraft.sound.SoundEvent;
import net.minecraft.util.Identifier;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
@Mixin( SoundEvent.class )
public interface SoundEventAccess
{
@Accessor
Identifier getId();
}

View File

@@ -0,0 +1,11 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.fabric.mixininterface;
public interface IMatrix4f
{
void setFloatArray( float[] values );
}

View File

@@ -14,25 +14,24 @@ import net.minecraft.util.math.Direction;
import net.minecraft.world.World; import net.minecraft.world.World;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import java.util.LinkedHashSet; import java.util.ArrayList;
import java.util.Objects; import java.util.Objects;
import java.util.Set;
public final class BundledRedstone public final class BundledRedstone
{ {
private static final Set<IBundledRedstoneProvider> providers = new LinkedHashSet<>(); private static final ArrayList<IBundledRedstoneProvider> providers = new ArrayList<>();
private BundledRedstone() {} private BundledRedstone() {}
public static synchronized void register( @Nonnull IBundledRedstoneProvider provider ) public static synchronized void register( @Nonnull IBundledRedstoneProvider provider )
{ {
Objects.requireNonNull( provider, "provider cannot be null" ); Objects.requireNonNull( provider, "provider cannot be null" );
providers.add( provider ); if( !providers.contains( provider ) ) providers.add( provider );
} }
public static int getDefaultOutput( @Nonnull World world, @Nonnull BlockPos pos, @Nonnull Direction side ) public static int getDefaultOutput( @Nonnull World world, @Nonnull BlockPos pos, @Nonnull Direction side )
{ {
return World.isInBuildLimit( pos ) ? DefaultBundledRedstoneProvider.getDefaultBundledRedstoneOutput( world, pos, side ) : -1; return world.isInBuildLimit( pos ) ? DefaultBundledRedstoneProvider.getDefaultBundledRedstoneOutput( world, pos, side ) : -1;
} }
public static int getOutput( World world, BlockPos pos, Direction side ) public static int getOutput( World world, BlockPos pos, Direction side )
@@ -43,7 +42,7 @@ public final class BundledRedstone
private static int getUnmaskedOutput( World world, BlockPos pos, Direction side ) private static int getUnmaskedOutput( World world, BlockPos pos, Direction side )
{ {
if( !World.isInBuildLimit( pos ) ) if( !world.isInBuildLimit( pos ) )
{ {
return -1; return -1;
} }

View File

@@ -13,12 +13,17 @@ import dan200.computercraft.shared.computer.blocks.BlockComputer;
import dan200.computercraft.shared.computer.blocks.TileCommandComputer; import dan200.computercraft.shared.computer.blocks.TileCommandComputer;
import dan200.computercraft.shared.computer.blocks.TileComputer; import dan200.computercraft.shared.computer.blocks.TileComputer;
import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.core.ComputerFamily;
import dan200.computercraft.shared.computer.inventory.ContainerComputer; import dan200.computercraft.shared.computer.inventory.ComputerMenuWithoutInventory;
import dan200.computercraft.shared.computer.inventory.ContainerComputerBase;
import dan200.computercraft.shared.computer.inventory.ContainerViewComputer; import dan200.computercraft.shared.computer.inventory.ContainerViewComputer;
import dan200.computercraft.shared.computer.items.ItemComputer; import dan200.computercraft.shared.computer.items.ItemComputer;
import dan200.computercraft.shared.media.items.ItemDisk; import dan200.computercraft.shared.media.items.ItemDisk;
import dan200.computercraft.shared.media.items.ItemPrintout; import dan200.computercraft.shared.media.items.ItemPrintout;
import dan200.computercraft.shared.media.items.ItemTreasureDisk; import dan200.computercraft.shared.media.items.ItemTreasureDisk;
import dan200.computercraft.shared.network.container.ComputerContainerData;
import dan200.computercraft.shared.network.container.ContainerData;
import dan200.computercraft.shared.network.container.HeldItemContainerData;
import dan200.computercraft.shared.network.container.ViewComputerContainerData;
import dan200.computercraft.shared.peripheral.diskdrive.BlockDiskDrive; import dan200.computercraft.shared.peripheral.diskdrive.BlockDiskDrive;
import dan200.computercraft.shared.peripheral.diskdrive.ContainerDiskDrive; import dan200.computercraft.shared.peripheral.diskdrive.ContainerDiskDrive;
import dan200.computercraft.shared.peripheral.diskdrive.TileDiskDrive; import dan200.computercraft.shared.peripheral.diskdrive.TileDiskDrive;
@@ -32,7 +37,6 @@ import dan200.computercraft.shared.peripheral.printer.ContainerPrinter;
import dan200.computercraft.shared.peripheral.printer.TilePrinter; import dan200.computercraft.shared.peripheral.printer.TilePrinter;
import dan200.computercraft.shared.peripheral.speaker.BlockSpeaker; import dan200.computercraft.shared.peripheral.speaker.BlockSpeaker;
import dan200.computercraft.shared.peripheral.speaker.TileSpeaker; import dan200.computercraft.shared.peripheral.speaker.TileSpeaker;
import dan200.computercraft.shared.pocket.inventory.ContainerPocketComputer;
import dan200.computercraft.shared.pocket.items.ItemPocketComputer; import dan200.computercraft.shared.pocket.items.ItemPocketComputer;
import dan200.computercraft.shared.pocket.peripherals.PocketModem; import dan200.computercraft.shared.pocket.peripherals.PocketModem;
import dan200.computercraft.shared.pocket.peripherals.PocketSpeaker; import dan200.computercraft.shared.pocket.peripherals.PocketSpeaker;
@@ -42,13 +46,10 @@ import dan200.computercraft.shared.turtle.core.TurtlePlayer;
import dan200.computercraft.shared.turtle.inventory.ContainerTurtle; import dan200.computercraft.shared.turtle.inventory.ContainerTurtle;
import dan200.computercraft.shared.turtle.items.ItemTurtle; import dan200.computercraft.shared.turtle.items.ItemTurtle;
import dan200.computercraft.shared.turtle.upgrades.*; import dan200.computercraft.shared.turtle.upgrades.*;
import dan200.computercraft.shared.util.FixedPointTileEntityType;
import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings; import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings;
import net.fabricmc.fabric.api.object.builder.v1.block.entity.FabricBlockEntityTypeBuilder;
import net.fabricmc.fabric.api.screenhandler.v1.ScreenHandlerRegistry; import net.fabricmc.fabric.api.screenhandler.v1.ScreenHandlerRegistry;
import net.minecraft.block.AbstractBlock; import net.minecraft.block.*;
import net.minecraft.block.Block;
import net.minecraft.block.Blocks;
import net.minecraft.block.Material;
import net.minecraft.block.entity.BlockEntity; import net.minecraft.block.entity.BlockEntity;
import net.minecraft.block.entity.BlockEntityType; import net.minecraft.block.entity.BlockEntityType;
import net.minecraft.entity.EntityType; import net.minecraft.entity.EntityType;
@@ -61,12 +62,10 @@ import net.minecraft.screen.ScreenHandler;
import net.minecraft.screen.ScreenHandlerType; import net.minecraft.screen.ScreenHandlerType;
import net.minecraft.sound.BlockSoundGroup; import net.minecraft.sound.BlockSoundGroup;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.registry.Registry; import net.minecraft.util.registry.Registry;
import java.util.Objects;
import java.util.function.BiFunction; import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Supplier;
import static net.minecraft.util.registry.Registry.BLOCK_ENTITY_TYPE; import static net.minecraft.util.registry.Registry.BLOCK_ENTITY_TYPE;
@@ -91,31 +90,31 @@ public final class ComputerCraftRegistry
public static final class ModBlocks public static final class ModBlocks
{ {
public static final BlockComputer COMPUTER_NORMAL = register( "computer_normal", public static final BlockComputer COMPUTER_NORMAL = register( "computer_normal",
new BlockComputer( properties(), ComputerFamily.NORMAL, ModTiles.COMPUTER_NORMAL ) ); new BlockComputer( properties(), ComputerFamily.NORMAL, ComputerCraftRegistry.ModTiles.COMPUTER_NORMAL ) );
public static final BlockComputer COMPUTER_ADVANCED = register( "computer_advanced", public static final BlockComputer COMPUTER_ADVANCED = register( "computer_advanced",
new BlockComputer( properties(), new BlockComputer( properties(),
ComputerFamily.ADVANCED, ComputerFamily.ADVANCED,
ModTiles.COMPUTER_ADVANCED ) ); ComputerCraftRegistry.ModTiles.COMPUTER_ADVANCED ) );
public static final BlockComputer COMPUTER_COMMAND = register( "computer_command", public static final BlockComputer COMPUTER_COMMAND = register( "computer_command",
new BlockComputer( FabricBlockSettings.copyOf( Blocks.STONE ) new BlockComputer( FabricBlockSettings.copyOf( Blocks.STONE )
.strength( -1, 6000000.0F ), .strength( -1, 6000000.0F ),
ComputerFamily.COMMAND, ComputerFamily.COMMAND,
ModTiles.COMPUTER_COMMAND ) ); ComputerCraftRegistry.ModTiles.COMPUTER_COMMAND ) );
public static final BlockTurtle TURTLE_NORMAL = register( "turtle_normal", public static final BlockTurtle TURTLE_NORMAL = register( "turtle_normal",
new BlockTurtle( turtleProperties(), ComputerFamily.NORMAL, ModTiles.TURTLE_NORMAL ) ); new BlockTurtle( turtleProperties(), ComputerFamily.NORMAL, ComputerCraftRegistry.ModTiles.TURTLE_NORMAL ) );
public static final BlockTurtle TURTLE_ADVANCED = register( "turtle_advanced", public static final BlockTurtle TURTLE_ADVANCED = register( "turtle_advanced",
new BlockTurtle( turtleProperties(), ComputerFamily.ADVANCED, ModTiles.TURTLE_ADVANCED ) ); new BlockTurtle( turtleProperties(), ComputerFamily.ADVANCED, ComputerCraftRegistry.ModTiles.TURTLE_ADVANCED ) );
public static final BlockSpeaker SPEAKER = register( "speaker", new BlockSpeaker( properties() ) ); public static final BlockSpeaker SPEAKER = register( "speaker", new BlockSpeaker( properties() ) );
public static final BlockDiskDrive DISK_DRIVE = register( "disk_drive", new BlockDiskDrive( properties() ) ); public static final BlockDiskDrive DISK_DRIVE = register( "disk_drive", new BlockDiskDrive( properties() ) );
public static final BlockPrinter PRINTER = register( "printer", new BlockPrinter( properties() ) ); public static final BlockPrinter PRINTER = register( "printer", new BlockPrinter( properties() ) );
public static final BlockMonitor MONITOR_NORMAL = register( "monitor_normal", new BlockMonitor( properties(), ModTiles.MONITOR_NORMAL ) ); public static final BlockMonitor MONITOR_NORMAL = register( "monitor_normal", new BlockMonitor( properties(), ModTiles.MONITOR_NORMAL, false ) );
public static final BlockMonitor MONITOR_ADVANCED = register( "monitor_advanced", new BlockMonitor( properties(), ModTiles.MONITOR_ADVANCED ) ); public static final BlockMonitor MONITOR_ADVANCED = register( "monitor_advanced", new BlockMonitor( properties(), ModTiles.MONITOR_ADVANCED, true ) );
public static final BlockWirelessModem WIRELESS_MODEM_NORMAL = register( "wireless_modem_normal", public static final BlockWirelessModem WIRELESS_MODEM_NORMAL = register( "wireless_modem_normal",
new BlockWirelessModem( properties(), ModTiles.WIRELESS_MODEM_NORMAL ) ); new BlockWirelessModem( properties(), ComputerCraftRegistry.ModTiles.WIRELESS_MODEM_NORMAL, ComputerFamily.NORMAL ) );
public static final BlockWirelessModem WIRELESS_MODEM_ADVANCED = register( "wireless_modem_advanced", public static final BlockWirelessModem WIRELESS_MODEM_ADVANCED = register( "wireless_modem_advanced",
new BlockWirelessModem( properties(), ModTiles.WIRELESS_MODEM_ADVANCED ) ); new BlockWirelessModem( properties(), ComputerCraftRegistry.ModTiles.WIRELESS_MODEM_ADVANCED, ComputerFamily.ADVANCED ) );
public static final BlockWiredModemFull WIRED_MODEM_FULL = register( "wired_modem_full", public static final BlockWiredModemFull WIRED_MODEM_FULL = register( "wired_modem_full",
new BlockWiredModemFull( emProperties(), ModTiles.WIRED_MODEM_FULL ) ); new BlockWiredModemFull( emProperties(), ComputerCraftRegistry.ModTiles.WIRED_MODEM_FULL ) );
public static final BlockCable CABLE = register( "cable", new BlockCable( emProperties() ) ); public static final BlockCable CABLE = register( "cable", new BlockCable( emProperties() ) );
private static Block.Settings properties() private static Block.Settings properties()
@@ -149,46 +148,52 @@ public final class ComputerCraftRegistry
public static class ModTiles public static class ModTiles
{ {
public static final BlockEntityType<TileMonitor> MONITOR_NORMAL = ofBlock( () -> ModBlocks.MONITOR_NORMAL, public static final BlockEntityType<TileMonitor> MONITOR_NORMAL = ofBlock( ModBlocks.MONITOR_NORMAL,
"monitor_normal", "monitor_normal",
f -> new TileMonitor( f, false ) ); ( blockPos, blockState ) -> new TileMonitor( ModTiles.MONITOR_NORMAL, false, blockPos, blockState ) );
public static final BlockEntityType<TileMonitor> MONITOR_ADVANCED = ofBlock( () -> ModBlocks.MONITOR_ADVANCED, public static final BlockEntityType<TileMonitor> MONITOR_ADVANCED = ofBlock( ModBlocks.MONITOR_ADVANCED,
"monitor_advanced", "monitor_advanced",
f -> new TileMonitor( f, true ) ); ( blockPos, blockState ) -> new TileMonitor( ModTiles.MONITOR_ADVANCED, true, blockPos, blockState ) );
public static final BlockEntityType<TileComputer> COMPUTER_NORMAL = ofBlock( () -> ModBlocks.COMPUTER_NORMAL, public static final BlockEntityType<TileComputer> COMPUTER_NORMAL = ofBlock( ModBlocks.COMPUTER_NORMAL,
"computer_normal", "computer_normal",
f -> new TileComputer( ComputerFamily.NORMAL, f ) ); ( blockPos, blockState ) -> new TileComputer( ComputerFamily.NORMAL, ModTiles.COMPUTER_NORMAL, blockPos, blockState ) );
public static final BlockEntityType<TileComputer> COMPUTER_ADVANCED = ofBlock( () -> ModBlocks.COMPUTER_ADVANCED, public static final BlockEntityType<TileComputer> COMPUTER_ADVANCED = ofBlock( ModBlocks.COMPUTER_ADVANCED,
"computer_advanced", "computer_advanced",
f -> new TileComputer( ComputerFamily.ADVANCED, f ) ); ( blockPos, blockState ) -> new TileComputer( ComputerFamily.ADVANCED, ModTiles.COMPUTER_ADVANCED, blockPos, blockState ) );
public static final BlockEntityType<TileCommandComputer> COMPUTER_COMMAND = ofBlock( () -> ModBlocks.COMPUTER_COMMAND, public static final BlockEntityType<TileCommandComputer> COMPUTER_COMMAND = ofBlock( ModBlocks.COMPUTER_COMMAND,
"computer_command", "computer_command",
f -> new TileCommandComputer( ComputerFamily.COMMAND, f ) ); ( blockPos, blockState ) -> new TileCommandComputer( ComputerFamily.COMMAND, ModTiles.COMPUTER_COMMAND, blockPos, blockState ) );
public static final BlockEntityType<TileTurtle> TURTLE_NORMAL = ofBlock( () -> ModBlocks.TURTLE_NORMAL, public static final BlockEntityType<TileTurtle> TURTLE_NORMAL = ofBlock( ModBlocks.TURTLE_NORMAL,
"turtle_normal", "turtle_normal",
f -> new TileTurtle( f, ComputerFamily.NORMAL ) ); ( blockPos, blockState ) -> new TileTurtle( ModTiles.TURTLE_NORMAL, blockPos, blockState, ComputerFamily.NORMAL ) );
public static final BlockEntityType<TileTurtle> TURTLE_ADVANCED = ofBlock( () -> ModBlocks.TURTLE_ADVANCED, public static final BlockEntityType<TileTurtle> TURTLE_ADVANCED = ofBlock( ModBlocks.TURTLE_ADVANCED,
"turtle_advanced", "turtle_advanced",
f -> new TileTurtle( f, ComputerFamily.ADVANCED ) ); ( blockPos, blockState ) -> new TileTurtle( ModTiles.TURTLE_ADVANCED, blockPos, blockState, ComputerFamily.ADVANCED ) );
public static final BlockEntityType<TileSpeaker> SPEAKER = ofBlock( () -> ModBlocks.SPEAKER, "speaker", TileSpeaker::new ); public static final BlockEntityType<TileSpeaker> SPEAKER = ofBlock( ModBlocks.SPEAKER, "speaker",
public static final BlockEntityType<TileDiskDrive> DISK_DRIVE = ofBlock( () -> ModBlocks.DISK_DRIVE, "disk_drive", TileDiskDrive::new ); ( blockPos, blockState ) -> new TileSpeaker( ModTiles.SPEAKER, blockPos, blockState ) );
public static final BlockEntityType<TilePrinter> PRINTER = ofBlock( () -> ModBlocks.PRINTER, "printer", TilePrinter::new ); public static final BlockEntityType<TileDiskDrive> DISK_DRIVE = ofBlock( ModBlocks.DISK_DRIVE, "disk_drive",
public static final BlockEntityType<TileWiredModemFull> WIRED_MODEM_FULL = ofBlock( () -> ModBlocks.WIRED_MODEM_FULL, ( blockPos, blockState ) -> new TileDiskDrive( ModTiles.DISK_DRIVE, blockPos, blockState ) );
public static final BlockEntityType<TilePrinter> PRINTER = ofBlock( ModBlocks.PRINTER, "printer",
( blockPos, blockState ) -> new TilePrinter( ModTiles.PRINTER, blockPos, blockState ) );
public static final BlockEntityType<TileWiredModemFull> WIRED_MODEM_FULL = ofBlock( ModBlocks.WIRED_MODEM_FULL,
"wired_modem_full", "wired_modem_full",
TileWiredModemFull::new ); ( blockPos, blockState ) -> new TileWiredModemFull( ModTiles.WIRED_MODEM_FULL, blockPos, blockState ) );
public static final BlockEntityType<TileCable> CABLE = ofBlock( () -> ModBlocks.CABLE, "cable", TileCable::new ); public static final BlockEntityType<TileCable> CABLE = ofBlock( ModBlocks.CABLE, "cable",
public static final BlockEntityType<TileWirelessModem> WIRELESS_MODEM_NORMAL = ofBlock( () -> ModBlocks.WIRELESS_MODEM_NORMAL, ( blockPos, blockState ) -> new TileCable( ModTiles.CABLE, blockPos, blockState ) );
public static final BlockEntityType<TileWirelessModem> WIRELESS_MODEM_NORMAL = ofBlock( ModBlocks.WIRELESS_MODEM_NORMAL,
"wireless_modem_normal", "wireless_modem_normal",
f -> new TileWirelessModem( f, false ) ); ( blockPos, blockState ) -> new TileWirelessModem( ModTiles.WIRELESS_MODEM_NORMAL, false, blockPos, blockState ) );
public static final BlockEntityType<TileWirelessModem> WIRELESS_MODEM_ADVANCED = ofBlock( () -> ModBlocks.WIRELESS_MODEM_ADVANCED, public static final BlockEntityType<TileWirelessModem> WIRELESS_MODEM_ADVANCED = ofBlock( ModBlocks.WIRELESS_MODEM_ADVANCED,
"wireless_modem_advanced", "wireless_modem_advanced",
f -> new TileWirelessModem( f, true ) ); ( blockPos, blockState ) -> new TileWirelessModem( ModTiles.WIRELESS_MODEM_ADVANCED, true, blockPos, blockState ) );
private static <T extends BlockEntity> BlockEntityType<T> ofBlock( Supplier<Block> block, String id, Function<BlockEntityType<T>, T> factory ) private static <T extends BlockEntity> BlockEntityType<T> ofBlock( Block block, String id, BiFunction<BlockPos, BlockState, T> factory )
{ {
BlockEntityType<T> blockEntityType = FabricBlockEntityTypeBuilder.create( factory::apply, block ).build();
return Registry.register( BLOCK_ENTITY_TYPE, return Registry.register( BLOCK_ENTITY_TYPE,
new Identifier( MOD_ID, id ), new Identifier( MOD_ID, id ),
FixedPointTileEntityType.create( Objects.requireNonNull( block ), factory ) ); blockEntityType
);
} }
} }
@@ -252,24 +257,20 @@ public final class ComputerCraftRegistry
public static class ModContainers public static class ModContainers
{ {
public static final ScreenHandlerType<ContainerComputer> COMPUTER = registerExtended( "computer", ContainerComputer::new ); public static final ScreenHandlerType<ContainerComputerBase> COMPUTER = ContainerData.toType( new Identifier( MOD_ID, "computer" ), ModContainers.COMPUTER, ComputerContainerData::new, ComputerMenuWithoutInventory::new );
public static final ScreenHandlerType<ContainerPocketComputer> POCKET_COMPUTER = registerExtended( "pocket_computer", ContainerPocketComputer::new ); public static final ScreenHandlerType<ContainerComputerBase> POCKET_COMPUTER = ContainerData.toType( new Identifier( MOD_ID, "pocket_computer" ), ModContainers.POCKET_COMPUTER, ComputerContainerData::new, ComputerMenuWithoutInventory::new );
public static final ScreenHandlerType<ContainerTurtle> TURTLE = registerExtended( "turtle", ContainerTurtle::new ); public static final ScreenHandlerType<ContainerComputerBase> POCKET_COMPUTER_NO_TERM = ContainerData.toType( new Identifier( MOD_ID, "pocket_computer_no_term" ), ModContainers.POCKET_COMPUTER_NO_TERM, ComputerContainerData::new, ComputerMenuWithoutInventory::new );
public static final ScreenHandlerType<ContainerTurtle> TURTLE = ContainerData.toType( new Identifier( MOD_ID, "turtle" ), ComputerContainerData::new, ContainerTurtle::new );
public static final ScreenHandlerType<ContainerDiskDrive> DISK_DRIVE = registerSimple( "disk_drive", ContainerDiskDrive::new ); public static final ScreenHandlerType<ContainerDiskDrive> DISK_DRIVE = registerSimple( "disk_drive", ContainerDiskDrive::new );
public static final ScreenHandlerType<ContainerPrinter> PRINTER = registerSimple( "printer", ContainerPrinter::new ); public static final ScreenHandlerType<ContainerPrinter> PRINTER = registerSimple( "printer", ContainerPrinter::new );
public static final ScreenHandlerType<ContainerHeldItem> PRINTOUT = registerExtended( "printout", ContainerHeldItem::createPrintout ); public static final ScreenHandlerType<ContainerHeldItem> PRINTOUT = ContainerData.toType( new Identifier( MOD_ID, "printout" ), HeldItemContainerData::new, ContainerHeldItem::createPrintout );
public static final ScreenHandlerType<ContainerViewComputer> VIEW_COMPUTER = registerExtended( "view_computer", ContainerViewComputer::new ); public static final ScreenHandlerType<ContainerViewComputer> VIEW_COMPUTER = ContainerData.toType( new Identifier( MOD_ID, "view_computer" ), ViewComputerContainerData::new, ContainerViewComputer::new );
private static <T extends ScreenHandler> ScreenHandlerType<T> registerSimple( String id, private static <T extends ScreenHandler> ScreenHandlerType<T> registerSimple( String id,
ScreenHandlerRegistry.SimpleClientHandlerFactory<T> function ) ScreenHandlerRegistry.SimpleClientHandlerFactory<T> function )
{ {
return ScreenHandlerRegistry.registerSimple( new Identifier( MOD_ID, id ), function ); return ScreenHandlerRegistry.registerSimple( new Identifier( MOD_ID, id ), function );
} }
private static <T extends ScreenHandler> ScreenHandlerType<T> registerExtended( String id, ScreenHandlerRegistry.ExtendedClientHandlerFactory<T> function )
{
return ScreenHandlerRegistry.registerExtended( new Identifier( MOD_ID, id ), function );
}
} }
public static final class TurtleUpgrades public static final class TurtleUpgrades

View File

@@ -35,7 +35,7 @@ public final class Peripherals
@Nullable @Nullable
public static IPeripheral getPeripheral( World world, BlockPos pos, Direction side ) public static IPeripheral getPeripheral( World world, BlockPos pos, Direction side )
{ {
return World.isInBuildLimit( pos ) && !world.isClient ? getPeripheralAt( world, pos, side ) : null; return world.isInBuildLimit( pos ) && !world.isClient ? getPeripheralAt( world, pos, side ) : null;
} }
@Nullable @Nullable

View File

@@ -3,12 +3,8 @@
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com * Send enquiries to dratcliffe@gmail.com
*/ */
package dan200.computercraft.shared; package dan200.computercraft.shared;
import com.google.common.eventbus.Subscribe;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.api.turtle.event.TurtleActionEvent;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.server.MinecraftServer; import net.minecraft.server.MinecraftServer;
import net.minecraft.server.world.ServerWorld; import net.minecraft.server.world.ServerWorld;
@@ -17,23 +13,14 @@ import net.minecraft.world.World;
public final class TurtlePermissions public final class TurtlePermissions
{ {
public static boolean isBlockEnterable( World world, BlockPos pos, PlayerEntity player )
{
MinecraftServer server = world.getServer();
return server == null || world.isClient || world instanceof ServerWorld && !server.isSpawnProtected( (ServerWorld) world, pos, player );
}
public static boolean isBlockEditable( World world, BlockPos pos, PlayerEntity player ) public static boolean isBlockEditable( World world, BlockPos pos, PlayerEntity player )
{ {
return isBlockEnterable( world, pos, player ); return isBlockEnterable( world, pos, player );
} }
public static boolean isBlockEnterable( World world, BlockPos pos, PlayerEntity player )
{
MinecraftServer server = world.getServer();
return server == null || world.isClient || (world instanceof ServerWorld && !server.isSpawnProtected( (ServerWorld) world, pos, player ));
}
@Subscribe
public void onTurtleAction( TurtleActionEvent event )
{
if( ComputerCraft.turtleDisabledActions.contains( event.getAction() ) )
{
event.setCanceled( true, "Action has been disabled" );
}
}
} }

View File

@@ -245,7 +245,7 @@ public final class CommandComputerCraft
@Override @Override
public ScreenHandler createMenu( int id, @Nonnull PlayerInventory player, @Nonnull PlayerEntity entity ) public ScreenHandler createMenu( int id, @Nonnull PlayerInventory player, @Nonnull PlayerEntity entity )
{ {
return new ContainerViewComputer( id, computer ); return new ContainerViewComputer( id, player, computer );
} }
} ); } );
return 1; return 1;

View File

@@ -56,18 +56,17 @@ public enum UserLevel implements Predicate<ServerCommandSource>
public boolean test( ServerCommandSource source ) public boolean test( ServerCommandSource source )
{ {
if( this == ANYONE ) return true; if( this == ANYONE ) return true;
if( this == OWNER ) return isOwner( source );
if( this == OWNER || this == OWNER_OP ) if( this == OWNER_OP && isOwner( source ) ) return true;
{
MinecraftServer server = source.getServer();
Entity sender = source.getEntity();
if( server.isSinglePlayer() && sender instanceof PlayerEntity &&
((PlayerEntity) sender).getGameProfile().getName().equalsIgnoreCase( server.getServerModName() ) )
{
return true;
}
}
return source.hasPermissionLevel( toLevel() ); return source.hasPermissionLevel( toLevel() );
} }
private static boolean isOwner( ServerCommandSource source )
{
MinecraftServer server = source.getServer();
Entity sender = source.getEntity();
return server.isDedicated()
? source.getEntity() == null && source.hasPermissionLevel( 4 ) && source.getName().equals( "Server" )
: sender instanceof PlayerEntity && ((PlayerEntity) sender).getGameProfile().getName().equalsIgnoreCase( server.getServerModName() );
}
} }

View File

@@ -18,7 +18,6 @@ import net.minecraft.util.ActionResult;
import net.minecraft.util.Hand; import net.minecraft.util.Hand;
import net.minecraft.util.hit.BlockHitResult; import net.minecraft.util.hit.BlockHitResult;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.world.BlockView;
import net.minecraft.world.World; import net.minecraft.world.World;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
@@ -35,6 +34,11 @@ public abstract class BlockGeneric extends BlockWithEntity
this.type = type; this.type = type;
} }
public BlockEntityType<? extends TileGeneric> getType()
{
return type;
}
@Override @Override
public BlockRenderType getRenderType( BlockState state ) public BlockRenderType getRenderType( BlockState state )
{ {
@@ -94,8 +98,12 @@ public abstract class BlockGeneric extends BlockWithEntity
@Nullable @Nullable
@Override @Override
public BlockEntity createBlockEntity( @Nonnull BlockView world ) public BlockEntity createBlockEntity( BlockPos pos, BlockState state )
{ {
return type.instantiate(); if ( this.type != null )
{
return type.instantiate( pos, state );
}
return null;
} }
} }

View File

@@ -36,11 +36,6 @@ public class ContainerHeldItem extends ScreenHandler
.copy(); .copy();
} }
public static ContainerHeldItem createPrintout( int id, PlayerInventory inventory, PacketByteBuf data )
{
return createPrintout( id, inventory, new HeldItemContainerData( data ) );
}
public static ContainerHeldItem createPrintout( int id, PlayerInventory inventory, HeldItemContainerData data ) public static ContainerHeldItem createPrintout( int id, PlayerInventory inventory, HeldItemContainerData data )
{ {
return new ContainerHeldItem( ComputerCraftRegistry.ModContainers.PRINTOUT, id, inventory.player, data.getHand() ); return new ContainerHeldItem( ComputerCraftRegistry.ModContainers.PRINTOUT, id, inventory.player, data.getHand() );

View File

@@ -8,6 +8,8 @@ package dan200.computercraft.shared.common;
import dan200.computercraft.core.terminal.Terminal; import dan200.computercraft.core.terminal.Terminal;
import dan200.computercraft.shared.network.client.TerminalState; import dan200.computercraft.shared.network.client.TerminalState;
import net.minecraft.nbt.NbtCompound;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
import net.minecraft.nbt.NbtCompound; import net.minecraft.nbt.NbtCompound;

View File

@@ -21,9 +21,9 @@ import javax.annotation.Nonnull;
public abstract class TileGeneric extends BlockEntity implements BlockEntityClientSerializable public abstract class TileGeneric extends BlockEntity implements BlockEntityClientSerializable
{ {
public TileGeneric( BlockEntityType<? extends TileGeneric> type ) public TileGeneric( BlockEntityType<? extends TileGeneric> type, BlockPos pos, BlockState state )
{ {
super( type ); super( type, pos, state );
} }
public void destroy() public void destroy()

View File

@@ -204,7 +204,7 @@ public class CommandAPI implements ILuaAPI
World world = computer.getWorld(); World world = computer.getWorld();
BlockPos min = new BlockPos( Math.min( minX, maxX ), Math.min( minY, maxY ), Math.min( minZ, maxZ ) ); BlockPos min = new BlockPos( Math.min( minX, maxX ), Math.min( minY, maxY ), Math.min( minZ, maxZ ) );
BlockPos max = new BlockPos( Math.max( minX, maxX ), Math.max( minY, maxY ), Math.max( minZ, maxZ ) ); BlockPos max = new BlockPos( Math.max( minX, maxX ), Math.max( minY, maxY ), Math.max( minZ, maxZ ) );
if( !World.isInBuildLimit( min ) || !World.isInBuildLimit( max ) ) if( !world.isInBuildLimit( min ) || !world.isInBuildLimit( max ) )
{ {
throw new LuaException( "Co-ordinates out of range" ); throw new LuaException( "Co-ordinates out of range" );
} }
@@ -289,7 +289,7 @@ public class CommandAPI implements ILuaAPI
// Get the details of the block // Get the details of the block
World world = computer.getWorld(); World world = computer.getWorld();
BlockPos position = new BlockPos( x, y, z ); BlockPos position = new BlockPos( x, y, z );
if( World.isInBuildLimit( position ) ) if( world.isInBuildLimit( position ) )
{ {
return getBlockInfo( world, position ); return getBlockInfo( world, position );
} }

View File

@@ -6,11 +6,13 @@
package dan200.computercraft.shared.computer.blocks; package dan200.computercraft.shared.computer.blocks;
import dan200.computercraft.shared.ComputerCraftRegistry;
import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.core.ComputerFamily;
import dan200.computercraft.shared.computer.core.ComputerState; import dan200.computercraft.shared.computer.core.ComputerState;
import dan200.computercraft.shared.computer.items.ComputerItemFactory; import dan200.computercraft.shared.computer.items.ComputerItemFactory;
import net.minecraft.block.Block; import net.minecraft.block.Block;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.block.entity.BlockEntityType; import net.minecraft.block.entity.BlockEntityType;
import net.minecraft.item.ItemPlacementContext; import net.minecraft.item.ItemPlacementContext;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
@@ -18,6 +20,7 @@ import net.minecraft.state.StateManager;
import net.minecraft.state.property.DirectionProperty; import net.minecraft.state.property.DirectionProperty;
import net.minecraft.state.property.EnumProperty; import net.minecraft.state.property.EnumProperty;
import net.minecraft.state.property.Properties; import net.minecraft.state.property.Properties;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction; import net.minecraft.util.math.Direction;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
@@ -56,4 +59,21 @@ public class BlockComputer extends BlockComputerBase<TileComputer>
{ {
return tile instanceof TileComputer ? ComputerItemFactory.create( (TileComputer) tile ) : ItemStack.EMPTY; return tile instanceof TileComputer ? ComputerItemFactory.create( (TileComputer) tile ) : ItemStack.EMPTY;
} }
public BlockEntityType<? extends TileComputer> getTypeByFamily( ComputerFamily family )
{
return switch ( family )
{
case COMMAND -> ComputerCraftRegistry.ModTiles.COMPUTER_COMMAND;
case ADVANCED -> ComputerCraftRegistry.ModTiles.COMPUTER_ADVANCED;
default -> ComputerCraftRegistry.ModTiles.COMPUTER_NORMAL;
};
}
@Nullable
@Override
public BlockEntity createBlockEntity( BlockPos pos, BlockState state )
{
return new TileComputer( getFamily(), getTypeByFamily( getFamily() ), pos, state );
}
} }

View File

@@ -15,6 +15,7 @@ import dan200.computercraft.shared.computer.core.ServerComputer;
import dan200.computercraft.shared.computer.items.IComputerItem; import dan200.computercraft.shared.computer.items.IComputerItem;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
import net.minecraft.block.entity.BlockEntity; import net.minecraft.block.entity.BlockEntity;
import net.minecraft.block.entity.BlockEntityTicker;
import net.minecraft.block.entity.BlockEntityType; import net.minecraft.block.entity.BlockEntityType;
import net.minecraft.entity.LivingEntity; import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
@@ -211,4 +212,16 @@ public abstract class BlockComputerBase<T extends TileComputerBase> extends Bloc
state.onStacksDropped( serverWorld, pos, player.getMainHandStack() ); state.onStacksDropped( serverWorld, pos, player.getMainHandStack() );
} }
} }
@Nullable
@Override
public <T extends BlockEntity> BlockEntityTicker<T> getTicker( World world, BlockState state, BlockEntityType<T> type )
{
return world.isClient ? null : ( world1, pos, state1, tile ) -> {
if ( tile instanceof TileComputerBase computer )
{
computer.serverTick();
}
};
}
} }

View File

@@ -10,6 +10,7 @@ import dan200.computercraft.ComputerCraft;
import dan200.computercraft.shared.computer.apis.CommandAPI; import dan200.computercraft.shared.computer.apis.CommandAPI;
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.block.BlockState;
import net.minecraft.block.entity.BlockEntityType; import net.minecraft.block.entity.BlockEntityType;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.server.MinecraftServer; import net.minecraft.server.MinecraftServer;
@@ -19,6 +20,7 @@ import net.minecraft.server.world.ServerWorld;
import net.minecraft.text.LiteralText; import net.minecraft.text.LiteralText;
import net.minecraft.text.Text; import net.minecraft.text.Text;
import net.minecraft.text.TranslatableText; import net.minecraft.text.TranslatableText;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec2f; import net.minecraft.util.math.Vec2f;
import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3d;
import net.minecraft.world.GameRules; import net.minecraft.world.GameRules;
@@ -32,9 +34,9 @@ public class TileCommandComputer extends TileComputer
{ {
private final CommandReceiver receiver; private final CommandReceiver receiver;
public TileCommandComputer( ComputerFamily family, BlockEntityType<? extends TileCommandComputer> type ) public TileCommandComputer( ComputerFamily family, BlockEntityType<? extends TileCommandComputer> type, BlockPos pos, BlockState state )
{ {
super( family, type ); super( family, type, pos, state );
receiver = new CommandReceiver(); receiver = new CommandReceiver();
} }

View File

@@ -8,15 +8,17 @@ package dan200.computercraft.shared.computer.blocks;
import dan200.computercraft.ComputerCraft; import dan200.computercraft.ComputerCraft;
import dan200.computercraft.core.computer.ComputerSide; import dan200.computercraft.core.computer.ComputerSide;
import dan200.computercraft.shared.ComputerCraftRegistry;
import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.core.ComputerFamily;
import dan200.computercraft.shared.computer.core.ComputerState; import dan200.computercraft.shared.computer.core.ComputerState;
import dan200.computercraft.shared.computer.core.ServerComputer; import dan200.computercraft.shared.computer.core.ServerComputer;
import dan200.computercraft.shared.computer.inventory.ContainerComputer; import dan200.computercraft.shared.computer.inventory.ComputerMenuWithoutInventory;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
import net.minecraft.block.entity.BlockEntityType; import net.minecraft.block.entity.BlockEntityType;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.player.PlayerInventory; import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.screen.ScreenHandler; import net.minecraft.screen.ScreenHandler;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction; import net.minecraft.util.math.Direction;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
@@ -26,9 +28,9 @@ public class TileComputer extends TileComputerBase
{ {
private ComputerProxy proxy; private ComputerProxy proxy;
public TileComputer( ComputerFamily family, BlockEntityType<? extends TileComputer> type ) public TileComputer( ComputerFamily family, BlockEntityType<? extends TileComputer> type, BlockPos pos, BlockState state )
{ {
super( type, family ); super( type, family, pos, state );
} }
public boolean isUsableByPlayer( PlayerEntity player ) public boolean isUsableByPlayer( PlayerEntity player )
@@ -103,7 +105,7 @@ public class TileComputer extends TileComputerBase
@Override @Override
public ScreenHandler createMenu( int id, @Nonnull PlayerInventory inventory, @Nonnull PlayerEntity player ) public ScreenHandler createMenu( int id, @Nonnull PlayerInventory inventory, @Nonnull PlayerEntity player )
{ {
return new ContainerComputer( id, this ); return new ComputerMenuWithoutInventory( ComputerCraftRegistry.ModContainers.COMPUTER, id, inventory, this::isUsableByPlayer, createServerComputer(), getFamily() );
} }
} }

View File

@@ -37,7 +37,6 @@ import net.minecraft.text.TranslatableText;
import net.minecraft.util.ActionResult; import net.minecraft.util.ActionResult;
import net.minecraft.util.Hand; import net.minecraft.util.Hand;
import net.minecraft.util.Nameable; import net.minecraft.util.Nameable;
import net.minecraft.util.Tickable;
import net.minecraft.util.hit.BlockHitResult; import net.minecraft.util.hit.BlockHitResult;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction; import net.minecraft.util.math.Direction;
@@ -47,7 +46,7 @@ import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.util.Objects; import java.util.Objects;
public abstract class TileComputerBase extends TileGeneric implements IComputerTile, Tickable, IPeripheralTile, Nameable, public abstract class TileComputerBase extends TileGeneric implements IComputerTile, IPeripheralTile, Nameable,
ExtendedScreenHandlerFactory ExtendedScreenHandlerFactory
{ {
private static final String NBT_ID = "ComputerId"; private static final String NBT_ID = "ComputerId";
@@ -61,9 +60,9 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT
private boolean on = false; private boolean on = false;
private boolean fresh = false; private boolean fresh = false;
public TileComputerBase( BlockEntityType<? extends TileGeneric> type, ComputerFamily family ) public TileComputerBase( BlockEntityType<? extends TileGeneric> type, ComputerFamily family, BlockPos pos, BlockState state )
{ {
super( type ); super( type, pos, state );
this.family = family; this.family = family;
} }
@@ -271,44 +270,40 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT
} }
} }
@Override public void serverTick()
public void tick()
{ {
if( !getWorld().isClient ) ServerComputer computer = createServerComputer();
if( computer == null )
{ {
ServerComputer computer = createServerComputer(); return;
if( computer == null ) }
{
return;
}
// If the computer isn't on and should be, then turn it on // If the computer isn't on and should be, then turn it on
if( startOn || (fresh && on) ) if( startOn || fresh && on )
{ {
computer.turnOn(); computer.turnOn();
startOn = false; startOn = false;
} }
computer.keepAlive(); computer.keepAlive();
fresh = false; fresh = false;
computerID = computer.getID(); computerID = computer.getID();
label = computer.getLabel(); label = computer.getLabel();
on = computer.isOn(); on = computer.isOn();
if( computer.hasOutputChanged() ) if( computer.hasOutputChanged() )
{ {
updateOutput(); updateOutput();
} }
// Update the block state if needed. We don't fire a block update intentionally, // Update the block state if needed. We don't fire a block update intentionally,
// as this only really is needed on the client side. // as this only really is needed on the client side.
updateBlockState( computer.getState() ); updateBlockState( computer.getState() );
if( computer.hasOutputChanged() ) if( computer.hasOutputChanged() )
{ {
updateOutput(); updateOutput();
}
} }
} }
@@ -325,9 +320,9 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT
protected abstract void updateBlockState( ComputerState newState ); protected abstract void updateBlockState( ComputerState newState );
@Override @Override
public void readNbt( @Nonnull BlockState state, @Nonnull NbtCompound nbt ) public void readNbt( @Nonnull NbtCompound nbt )
{ {
super.readNbt( state, nbt ); super.readNbt( nbt );
// Load ID, label and power state // Load ID, label and power state
computerID = nbt.contains( NBT_ID ) ? nbt.getInt( NBT_ID ) : -1; computerID = nbt.contains( NBT_ID ) ? nbt.getInt( NBT_ID ) : -1;
@@ -349,7 +344,6 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT
nbt.putString( NBT_LABEL, label ); nbt.putString( NBT_LABEL, label );
} }
nbt.putBoolean( NBT_ON, on ); nbt.putBoolean( NBT_ON, on );
return super.writeNbt( nbt ); return super.writeNbt( nbt );
} }
@@ -362,7 +356,7 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT
private void updateInput( BlockPos neighbour ) private void updateInput( BlockPos neighbour )
{ {
if( getWorld() == null || getWorld().isClient ) if( getWorld() == null || this.world.isClient )
{ {
return; return;
} }
@@ -384,12 +378,12 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT
} }
// If the position is not any adjacent one, update all inputs. // If the position is not any adjacent one, update all inputs.
updateInput(); this.updateInput();
} }
private void updateInput( Direction dir ) private void updateInput( Direction dir )
{ {
if( getWorld() == null || getWorld().isClient ) if( getWorld() == null || this.world.isClient )
{ {
return; return;
} }
@@ -412,7 +406,7 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT
@Override @Override
public final void setComputerID( int id ) public final void setComputerID( int id )
{ {
if( getWorld().isClient || computerID == id ) if( this.world.isClient || computerID == id )
{ {
return; return;
} }
@@ -437,7 +431,7 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT
@Override @Override
public final void setLabel( String label ) public final void setLabel( String label )
{ {
if( getWorld().isClient || Objects.equals( this.label, label ) ) if( this.world.isClient || Objects.equals( this.label, label ) )
{ {
return; return;
} }

View File

@@ -12,13 +12,15 @@ import javax.annotation.Nonnull;
public enum ComputerState implements StringIdentifiable public enum ComputerState implements StringIdentifiable
{ {
OFF( "off" ), ON( "on" ), BLINKING( "blinking" ); OFF( "off", "" ), ON( "on", "_on" ), BLINKING( "blinking", "_blink" );
private final String name; private final String name;
private final String texture;
ComputerState( String name ) ComputerState( String name, String texture )
{ {
this.name = name; this.name = name;
this.texture = texture;
} }
@Nonnull @Nonnull
@@ -33,4 +35,10 @@ public enum ComputerState implements StringIdentifiable
{ {
return name; return name;
} }
@Nonnull
public String getTexture()
{
return texture;
}
} }

View File

@@ -6,13 +6,19 @@
package dan200.computercraft.shared.computer.core; package dan200.computercraft.shared.computer.core;
import dan200.computercraft.shared.computer.upload.FileSlice;
import dan200.computercraft.shared.computer.upload.FileUpload;
import net.minecraft.server.network.ServerPlayerEntity;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.util.List;
import java.util.UUID;
/** /**
* An instance of {@link Container} which provides a computer. You should implement this if you provide custom computers/GUIs to interact with them. * An instance of {@link Container} which provides a computer. You should implement this if you provide custom computers/GUIs to interact with them.
*/ */
@FunctionalInterface //@FunctionalInterface
public interface IContainerComputer public interface IContainerComputer
{ {
/** /**
@@ -31,8 +37,37 @@ public interface IContainerComputer
* @return This container's input. * @return This container's input.
*/ */
@Nonnull @Nonnull
default InputState getInput() InputState getInput();
{
return new InputState( this ); /**
} * Start a file upload into this container.
*
* @param uploadId The unique ID of this upload.
* @param files The files to upload.
*/
void startUpload( @Nonnull UUID uploadId, @Nonnull List<FileUpload> files );
/**
* Append more data to partially uploaded files.
*
* @param uploadId The unique ID of this upload.
* @param slices Additional parts of file data to upload.
*/
void continueUpload( @Nonnull UUID uploadId, @Nonnull List<FileSlice> slices );
/**
* Finish off an upload. This either writes the uploaded files or
*
* @param uploader The player uploading files.
* @param uploadId The unique ID of this upload.
*/
void finishUpload( @Nonnull ServerPlayerEntity uploader, @Nonnull UUID uploadId );
/**
* Continue an upload.
*
* @param uploader The player uploading files.
* @param overwrite Whether the files should be overwritten or not.
*/
void confirmUpload( @Nonnull ServerPlayerEntity uploader, boolean overwrite );
} }

View File

@@ -0,0 +1,41 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.shared.computer.inventory;
import dan200.computercraft.shared.computer.core.ComputerFamily;
import dan200.computercraft.shared.computer.core.IComputer;
import dan200.computercraft.shared.network.container.ComputerContainerData;
import dan200.computercraft.shared.util.InvisibleSlot;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.screen.ScreenHandlerType;
import java.util.function.Predicate;
/**
* A computer menu which does not have any visible inventory.
*
* This adds invisible versions of the player's hotbars slots, to ensure they're synced to the client when changed.
*/
public class ComputerMenuWithoutInventory extends ContainerComputerBase
{
public ComputerMenuWithoutInventory( ScreenHandlerType<? extends ContainerComputerBase> type, int id, PlayerInventory player, Predicate<PlayerEntity> canUse, IComputer computer, ComputerFamily family )
{
super( type, id, canUse, computer, family );
addSlots( player );
}
public ComputerMenuWithoutInventory( ScreenHandlerType<? extends ContainerComputerBase> type, int id, PlayerInventory player, ComputerContainerData data )
{
super( type, id, player, data );
addSlots( player );
}
private void addSlots( PlayerInventory player )
{
for( int i = 0; i < 9; i++ ) addSlot( new InvisibleSlot( player, i ) );
}
}

View File

@@ -1,25 +0,0 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.shared.computer.inventory;
import dan200.computercraft.shared.ComputerCraftRegistry;
import dan200.computercraft.shared.computer.blocks.TileComputer;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.network.PacketByteBuf;
public class ContainerComputer extends ContainerComputerBase
{
public ContainerComputer( int id, TileComputer tile )
{
super( ComputerCraftRegistry.ModContainers.COMPUTER, id, tile::isUsableByPlayer, tile.createServerComputer(), tile.getFamily() );
}
public ContainerComputer( int i, PlayerInventory playerInventory, PacketByteBuf packetByteBuf )
{
super( ComputerCraftRegistry.ModContainers.COMPUTER, i, playerInventory, packetByteBuf );
}
}

View File

@@ -7,36 +7,53 @@
package dan200.computercraft.shared.computer.inventory; package dan200.computercraft.shared.computer.inventory;
import dan200.computercraft.ComputerCraft; import dan200.computercraft.ComputerCraft;
import dan200.computercraft.core.filesystem.FileSystem;
import dan200.computercraft.core.filesystem.FileSystemException;
import dan200.computercraft.core.filesystem.FileSystemWrapper;
import dan200.computercraft.shared.computer.core.*; import dan200.computercraft.shared.computer.core.*;
import dan200.computercraft.shared.computer.upload.FileSlice;
import dan200.computercraft.shared.computer.upload.FileUpload;
import dan200.computercraft.shared.computer.upload.UploadResult;
import dan200.computercraft.shared.network.NetworkHandler;
import dan200.computercraft.shared.network.client.UploadResultMessage;
import dan200.computercraft.shared.network.container.ComputerContainerData; import dan200.computercraft.shared.network.container.ComputerContainerData;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.player.PlayerInventory; import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.network.PacketByteBuf;
import net.minecraft.screen.ScreenHandler; import net.minecraft.screen.ScreenHandler;
import net.minecraft.screen.ScreenHandlerType; import net.minecraft.screen.ScreenHandlerType;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.TranslatableText;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.util.Objects; import java.io.IOException;
import java.nio.channels.WritableByteChannel;
import java.util.*;
import java.util.function.Function;
import java.util.function.Predicate; import java.util.function.Predicate;
public class ContainerComputerBase extends ScreenHandler implements IContainerComputer public abstract class ContainerComputerBase extends ScreenHandler implements IContainerComputer
{ {
private static final String LIST_PREFIX = "\n \u2022 ";
private final Predicate<PlayerEntity> canUse; private final Predicate<PlayerEntity> canUse;
private final IComputer computer; private final IComputer computer;
private final ComputerFamily family; private final ComputerFamily family;
private final InputState input = new InputState( this ); private final InputState input = new InputState( this );
protected ContainerComputerBase( ScreenHandlerType<? extends ContainerComputerBase> type, int id, PlayerInventory player, PacketByteBuf packetByteBuf ) private UUID toUploadId;
private List<FileUpload> toUpload;
public ContainerComputerBase( ScreenHandlerType<? extends ContainerComputerBase> type, int id, PlayerInventory player, ComputerContainerData data )
{ {
this( type, this( type,
id, id,
x -> true, x -> true,
getComputer( player, new ComputerContainerData( new PacketByteBuf( packetByteBuf.copy() ) ) ), getComputer( player, data ),
new ComputerContainerData( new PacketByteBuf( packetByteBuf.copy() ) ).getFamily() ); data.getFamily() );
} }
protected ContainerComputerBase( ScreenHandlerType<? extends ContainerComputerBase> type, int id, Predicate<PlayerEntity> canUse, IComputer computer, public ContainerComputerBase( ScreenHandlerType<? extends ContainerComputerBase> type, int id, Predicate<PlayerEntity> canUse, IComputer computer,
ComputerFamily family ) ComputerFamily family )
{ {
super( type, id ); super( type, id );
@@ -93,4 +110,121 @@ public class ContainerComputerBase extends ScreenHandler implements IContainerCo
{ {
return canUse.test( player ); return canUse.test( player );
} }
@Override
public void startUpload( @Nonnull UUID uuid, @Nonnull List<FileUpload> files )
{
toUploadId = uuid;
toUpload = files;
}
@Override
public void continueUpload( @Nonnull UUID uploadId, @Nonnull List<FileSlice> slices )
{
if( toUploadId == null || toUpload == null || !toUploadId.equals( uploadId ) )
{
ComputerCraft.log.warn( "Invalid continueUpload call, skipping." );
return;
}
for( FileSlice slice : slices ) slice.apply( toUpload );
}
@Override
public void finishUpload( @Nonnull ServerPlayerEntity uploader, @Nonnull UUID uploadId )
{
if( toUploadId == null || toUpload == null || toUpload.isEmpty() || !toUploadId.equals( uploadId ) )
{
ComputerCraft.log.warn( "Invalid finishUpload call, skipping." );
return;
}
UploadResultMessage message = finishUpload( false );
NetworkHandler.sendToPlayer( uploader, message );
}
@Override
public void confirmUpload( @Nonnull ServerPlayerEntity uploader, boolean overwrite )
{
if( toUploadId == null || toUpload == null || toUpload.isEmpty() )
{
ComputerCraft.log.warn( "Invalid finishUpload call, skipping." );
return;
}
UploadResultMessage message = finishUpload( true );
NetworkHandler.sendToPlayer( uploader, message );
}
@Nonnull
private UploadResultMessage finishUpload( boolean forceOverwrite )
{
ServerComputer computer = (ServerComputer) getComputer();
if( computer == null ) return UploadResultMessage.COMPUTER_OFF;
FileSystem fs = computer.getComputer().getEnvironment().getFileSystem();
if( fs == null ) return UploadResultMessage.COMPUTER_OFF;
for( FileUpload upload : toUpload )
{
if( !upload.checksumMatches() )
{
ComputerCraft.log.warn( "Checksum failed to match for {}.", upload.getName() );
return new UploadResultMessage( UploadResult.ERROR, new TranslatableText( "gui.computercraft.upload.failed.corrupted" ) );
}
}
try
{
List<String> overwrite = new ArrayList<>();
List<FileUpload> files = toUpload;
toUpload = null;
for( FileUpload upload : files )
{
if( !fs.exists( upload.getName() ) ) continue;
if( fs.isDir( upload.getName() ) )
{
return new UploadResultMessage(
UploadResult.ERROR,
new TranslatableText( "gui.computercraft.upload.failed.overwrite_dir", upload.getName() )
);
}
overwrite.add( upload.getName() );
}
if( !overwrite.isEmpty() && !forceOverwrite )
{
StringJoiner joiner = new StringJoiner( LIST_PREFIX, LIST_PREFIX, "" );
for( String value : overwrite ) joiner.add( value );
toUpload = files;
return new UploadResultMessage(
UploadResult.CONFIRM_OVERWRITE,
new TranslatableText( "gui.computercraft.upload.overwrite.detail", joiner.toString() )
);
}
long availableSpace = fs.getFreeSpace( "/" );
long neededSpace = 0;
for( FileUpload upload : files ) neededSpace += Math.max( 512, upload.getBytes().remaining() );
if( neededSpace > availableSpace ) return UploadResultMessage.OUT_OF_SPACE;
for( FileUpload file : files )
{
try( FileSystemWrapper<WritableByteChannel> channel = fs.openForWrite( file.getName(), false, Function.identity() ) )
{
channel.get().write( file.getBytes() );
}
}
return new UploadResultMessage(
UploadResult.SUCCESS, new TranslatableText( "gui.computercraft.upload.success.msg", files.size() )
);
}
catch( FileSystemException | IOException e )
{
ComputerCraft.log.error( "Error uploading files", e );
return new UploadResultMessage( UploadResult.ERROR, new TranslatableText( "gui.computercraft.upload.failed.generic", e.getMessage() ) );
}
}
} }

View File

@@ -14,25 +14,23 @@ import dan200.computercraft.shared.computer.core.ServerComputer;
import dan200.computercraft.shared.network.container.ViewComputerContainerData; import dan200.computercraft.shared.network.container.ViewComputerContainerData;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.player.PlayerInventory; import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.network.PacketByteBuf;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
public class ContainerViewComputer extends ContainerComputerBase public class ContainerViewComputer extends ComputerMenuWithoutInventory
{ {
private final int width; private final int width;
private final int height; private final int height;
public ContainerViewComputer( int id, ServerComputer computer ) public ContainerViewComputer( int id, PlayerInventory player, ServerComputer computer )
{ {
super( ComputerCraftRegistry.ModContainers.VIEW_COMPUTER, id, player -> canInteractWith( computer, player ), computer, computer.getFamily() ); super( ComputerCraftRegistry.ModContainers.VIEW_COMPUTER, id, player, p -> canInteractWith( computer, p ), computer, computer.getFamily() );
width = height = 0; width = height = 0;
} }
public ContainerViewComputer( int id, PlayerInventory player, PacketByteBuf packetByteBuf ) public ContainerViewComputer( int id, PlayerInventory player, ViewComputerContainerData data )
{ {
super( ComputerCraftRegistry.ModContainers.VIEW_COMPUTER, id, player, packetByteBuf ); super( ComputerCraftRegistry.ModContainers.VIEW_COMPUTER, id, player, data );
ViewComputerContainerData data = new ViewComputerContainerData( new PacketByteBuf( packetByteBuf.copy() ) );
width = data.getWidth(); width = data.getWidth();
height = data.getHeight(); height = data.getHeight();
} }

View File

@@ -9,6 +9,7 @@ package dan200.computercraft.shared.computer.items;
import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.core.ComputerFamily;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NbtCompound; import net.minecraft.nbt.NbtCompound;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
public interface IComputerItem public interface IComputerItem

View File

@@ -45,7 +45,7 @@ public abstract class ComputerFamilyRecipe extends ComputerConvertRecipe
ComputerFamily family = RecipeUtil.getFamily( json, "family" ); ComputerFamily family = RecipeUtil.getFamily( json, "family" );
RecipeUtil.ShapedTemplate template = RecipeUtil.getTemplate( json ); RecipeUtil.ShapedTemplate template = RecipeUtil.getTemplate( json );
ItemStack result = getItem( JsonHelper.getObject( json, "result" ) ); ItemStack result = outputFromJson( JsonHelper.getObject( json, "result" ) );
return create( identifier, group, template.width, template.height, template.ingredients, result, family ); return create( identifier, group, template.width, template.height, template.ingredients, result, family );
} }

View File

@@ -0,0 +1,63 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.shared.computer.upload;
import dan200.computercraft.ComputerCraft;
import java.nio.ByteBuffer;
import java.util.List;
public class FileSlice
{
private final int fileId;
private final int offset;
private final ByteBuffer bytes;
public FileSlice( int fileId, int offset, ByteBuffer bytes )
{
this.fileId = fileId;
this.offset = offset;
this.bytes = bytes;
}
public int getFileId()
{
return fileId;
}
public int getOffset()
{
return offset;
}
public ByteBuffer getBytes()
{
return bytes;
}
public void apply( List<FileUpload> files )
{
if( fileId < 0 || fileId >= files.size() )
{
ComputerCraft.log.warn( "File ID is out-of-bounds (0 <= {} < {})", fileId, files.size() );
return;
}
ByteBuffer file = files.get( fileId ).getBytes();
if( offset < 0 || offset + bytes.remaining() > file.capacity() )
{
ComputerCraft.log.warn( "File offset is out-of-bounds (0 <= {} <= {})", offset, file.capacity() - offset );
return;
}
bytes.rewind();
file.position( offset );
file.put( bytes );
file.rewind();
if( bytes.remaining() != 0 ) throw new IllegalStateException( "Should have read the whole buffer" );
}
}

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