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

Merge branch 'fabric' into 1.17-alpha

This commit is contained in:
Nikita Savyolov 2021-10-09 21:02:41 +03:00
commit 2ee07283fa
No known key found for this signature in database
GPG Key ID: 32C1EF023AFC184B
240 changed files with 5255 additions and 2663 deletions

View File

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

1
.gitignore vendored
View File

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

View File

@ -1,13 +1,13 @@
plugins {
id 'fabric-loom' version '0.8-SNAPSHOT'
id 'fabric-loom' version '0.9-SNAPSHOT'
id 'maven-publish'
id "checkstyle"
id "com.github.hierynomus.license" version "0.15.0"
id "com.github.hierynomus.license" version "0.16.1"
}
java {
toolchain {
languageVersion = JavaLanguageVersion.of(8)
languageVersion = JavaLanguageVersion.of(16)
vendor = JvmVendorSpec.ADOPTOPENJDK
}
}
@ -22,18 +22,23 @@ repositories {
maven { url 'https://jitpack.io' }
maven { url 'https://api.modrinth.com/maven'}
maven { url "https://maven.shedaniel.me/" }
maven { url "https://maven.terraformersmc.com/" }
maven {
name "SquidDev"
url "https://squiddev.cc/maven"
}
}
loom {
accessWidenerPath = file("src/main/resources/cc.accesswidener")
}
configurations {
implementation.extendsFrom shade
}
dependencies {
checkstyle "com.puppycrawl.tools:checkstyle:8.25"
checkstyle 'com.puppycrawl.tools:checkstyle:8.45.1'
minecraft "com.mojang:minecraft:${mc_version}"
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}") {
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}"
implementation 'com.electronwill.night-config:toml:3.6.3'
@ -56,21 +61,16 @@ dependencies {
include 'com.electronwill.night-config:toml:3.6.3'
include "me.shedaniel.cloth:cloth-config-fabric:${cloth_config_version}"
modRuntime "me.shedaniel:RoughlyEnoughItems-api:5.12.248"
modRuntime "me.shedaniel:RoughlyEnoughItems:5.12.248"
modRuntime "me.shedaniel:RoughlyEnoughItems-api-fabric:6.0.254-alpha"
modRuntime "me.shedaniel:RoughlyEnoughItems-fabric:6.0.254-alpha"
}
processResources {
inputs.property "version", project.version
from(sourceSets.main.resources.srcDirs) {
include "fabric.mod.json"
expand "version": project.version
}
from(sourceSets.main.resources.srcDirs) {
exclude "fabric.mod.json"
}
filesMatching("fabric.mod.json") {
expand "version": project.version
}
}
// 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="SimplifyBooleanReturn" />
<module name="StringLiteralEquality" />
<module name="UnnecessaryParentheses" />
<!-- <module name="UnnecessaryParentheses" /> -->
<module name="UnnecessarySemicolonAfterTypeMemberDeclaration" />
<module name="UnnecessarySemicolonInTryWithResources" />
<module name="UnnecessarySemicolonInEnumeration" />
<!-- Imports -->
<module name="CustomImportOrder" />
<!--<module name="CustomImportOrder" />-->
<module name="IllegalImport" />
<module name="RedundantImport" />
<module name="UnusedImports" />

View File

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

View File

@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
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
zipStorePath=wrapper/dists

View File

@ -73,6 +73,8 @@ public final class ComputerCraft implements ModInitializer
) );
public static int httpMaxRequests = 16;
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 int modemRange = 64;
@ -82,6 +84,7 @@ public final class ComputerCraft implements ModInitializer
public static int maxNotesPerTick = 8;
public static MonitorRenderer monitorRenderer = MonitorRenderer.BEST;
public static double monitorDistanceSq = 4096;
public static int monitorDistance = 65;
public static long monitorBandwidth = 1_000_000;
public static boolean turtlesNeedFuel = true;

View File

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

View File

@ -9,17 +9,18 @@ package dan200.computercraft.api.lua;
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
* with the computer.
* An interface passed to peripherals and {@link IDynamicLuaObject}s by computers or turtles, providing methods
* that allow the peripheral call to interface with the computer.
*/
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
* need to interact with the world in a thread-safe manner but do not care about the result or you wish to run asynchronously.
* 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 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
* error message if it failed.
* 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 error message if it failed.
*
* @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.
@ -27,4 +28,18 @@ public interface ILuaContext
* @see LuaFunction#mainThread() To run functions on the main thread and return their results synchronously.
*/
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;
import dan200.computercraft.shared.util.NonNullSupplier;
import net.minecraft.item.Item;
import net.minecraft.item.ItemConvertible;
import net.minecraft.item.ItemStack;
import net.minecraft.util.Identifier;
import net.minecraft.util.Util;
import javax.annotation.Nonnull;
import java.util.function.Supplier;
/**
* A base class for {@link IPocketUpgrade}s.
@ -22,27 +25,49 @@ public abstract class AbstractPocketUpgrade implements IPocketUpgrade
{
private final Identifier id;
private final String adjective;
private final ItemStack stack;
private final NonNullSupplier<ItemStack> stack;
protected AbstractPocketUpgrade( Identifier id, ItemConvertible item )
{
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 )
protected AbstractPocketUpgrade( Identifier id, String adjective, NonNullSupplier<ItemStack> stack )
{
this.id = id;
this.adjective = adjective;
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
@Override
@ -62,6 +87,32 @@ public abstract class AbstractPocketUpgrade implements IPocketUpgrade
@Override
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;
import dan200.computercraft.shared.util.NonNullSupplier;
import net.minecraft.item.Item;
import net.minecraft.item.ItemConvertible;
import net.minecraft.item.ItemStack;
import net.minecraft.util.Identifier;
import net.minecraft.util.Util;
import javax.annotation.Nonnull;
import java.util.function.Supplier;
/**
* A base class for {@link ITurtleUpgrade}s.
@ -23,14 +26,9 @@ public abstract class AbstractTurtleUpgrade implements ITurtleUpgrade
private final Identifier id;
private final TurtleUpgradeType type;
private final String adjective;
private final ItemStack stack;
private final NonNullSupplier<ItemStack> stack;
protected AbstractTurtleUpgrade( Identifier id, TurtleUpgradeType type, String adjective, ItemConvertible item )
{
this( id, type, adjective, new ItemStack( item ) );
}
protected AbstractTurtleUpgrade( Identifier id, TurtleUpgradeType type, String adjective, ItemStack stack )
protected AbstractTurtleUpgrade( Identifier id, TurtleUpgradeType type, String adjective, NonNullSupplier<ItemStack> stack )
{
this.id = id;
this.type = type;
@ -38,16 +36,40 @@ public abstract class AbstractTurtleUpgrade implements ITurtleUpgrade
this.stack = stack;
}
protected AbstractTurtleUpgrade( Identifier id, TurtleUpgradeType type, ItemConvertible item )
{
this( id, type, new ItemStack( item ) );
}
protected AbstractTurtleUpgrade( Identifier id, TurtleUpgradeType type, ItemStack stack )
protected AbstractTurtleUpgrade( Identifier id, TurtleUpgradeType type, NonNullSupplier<ItemStack> 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
@Override
@ -74,6 +96,32 @@ public abstract class AbstractTurtleUpgrade implements ITurtleUpgrade
@Override
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.recipe.Recipe;
import net.minecraft.screen.NamedScreenHandlerFactory;
import net.minecraft.screen.ScreenHandler;
import net.minecraft.server.network.ServerPlayNetworkHandler;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.server.network.ServerPlayerInteractionManager;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.sound.SoundCategory;
import net.minecraft.sound.SoundEvent;
import net.minecraft.text.Text;
import net.minecraft.util.Hand;
import net.minecraft.util.collection.DefaultedList;
import net.minecraft.util.math.ChunkPos;
import net.minecraft.util.math.Vec3d;
import net.minecraft.village.TradeOfferList;
import net.minecraft.world.GameMode;
import javax.annotation.Nullable;
import javax.crypto.Cipher;
@ -53,7 +49,7 @@ public class FakePlayer extends ServerPlayerEntity
{
public FakePlayer( ServerWorld world, GameProfile gameProfile )
{
super( world.getServer(), world, gameProfile, new ServerPlayerInteractionManager( world ) );
super( world.getServer(), world, gameProfile );
networkHandler = new FakeNetHandler( this );
}
@ -137,30 +133,30 @@ public class FakePlayer extends ServerPlayerEntity
{
}
@Override
public void onSlotUpdate( ScreenHandler container, int slot, ItemStack stack )
{
}
@Override
public void onHandlerRegistered( ScreenHandler container, DefaultedList<ItemStack> defaultedList )
{
}
@Override
public void onPropertyUpdate( ScreenHandler container, int key, int value )
{
}
// @Override
// public void onSlotUpdate( ScreenHandler container, int slot, ItemStack stack )
// {
// }
//
// @Override
// public void onHandlerRegistered( ScreenHandler container, DefaultedList<ItemStack> defaultedList )
// {
// }
//
// @Override
// public void onPropertyUpdate( ScreenHandler container, int key, int value )
// {
// }
@Override
public void closeHandledScreen()
{
}
@Override
public void updateCursorStack()
{
}
// @Override
// public void updateCursorStack()
// {
// }
@Override
public int unlockRecipes( Collection<Recipe<?>> recipes )
@ -196,12 +192,12 @@ public class FakePlayer extends ServerPlayerEntity
}
@Override
protected void onStatusEffectApplied( StatusEffectInstance statusEffectInstance )
protected void onStatusEffectApplied( StatusEffectInstance statusEffectInstance, @Nullable Entity source )
{
}
@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
public void changeGameMode( GameMode gameMode )
{
}
// @Override
// public void setGameMode( GameMode gameMode )
// {
// }
@Override
public void sendMessage( Text message, MessageType type, UUID senderUuid )
@ -232,15 +228,15 @@ public class FakePlayer extends ServerPlayerEntity
return "[Fake Player]";
}
@Override
public void sendResourcePackUrl( String url, String hash )
{
}
// @Override
// public void sendResourcePackUrl( String url, String hash )
// {
// }
@Override
public void onStoppedTracking( Entity entity )
{
}
// @Override
// public void onStoppedTracking( Entity entity )
// {
// }
@Override
public void setCameraEntity( Entity entity )
@ -347,10 +343,5 @@ public class FakePlayer extends ServerPlayerEntity
public void disableAutoRead()
{
}
@Override
public void setCompressionThreshold( int size )
{
}
}
}

View File

@ -77,7 +77,7 @@ public final class ClientRegistry
}
@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 )
{

View File

@ -21,10 +21,6 @@ import org.apache.commons.lang3.StringUtils;
import javax.annotation.Nullable;
@SuppressWarnings( {
"MethodCallSideOnly",
"LocalVariableDeclarationSideOnly"
} )
public class ClientTableFormatter implements TableFormatter
{
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;
import com.mojang.blaze3d.systems.RenderSystem;
import dan200.computercraft.client.FrameInfo;
import dan200.computercraft.client.render.RenderTypes;
import dan200.computercraft.core.terminal.Terminal;
import dan200.computercraft.core.terminal.TextBuffer;
import dan200.computercraft.shared.util.Colour;
import dan200.computercraft.shared.util.Palette;
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.math.AffineTransformation;
import net.minecraft.util.math.Matrix4f;
import org.lwjgl.opengl.GL11;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import static dan200.computercraft.client.render.RenderTypes.FULL_BRIGHT_LIGHTMAP;
public final class FixedWidthFontRenderer
{
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;
private static final Matrix4f IDENTITY = AffineTransformation.identity()
.getMatrix();
private static final Identifier FONT = new Identifier( "computercraft", "textures/gui/term_font.png" );
public static final RenderLayer TYPE = Type.MAIN;
public static final Identifier FONT = new Identifier( "computercraft", "textures/gui/term_font.png" );
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,
@Nonnull TextBuffer textColour, @Nullable TextBuffer backgroundColour, @Nonnull Palette palette, boolean greyscale,
float leftMarginSize, float rightMarginSize )
float leftMarginSize, float rightMarginSize, int light )
{
if( backgroundColour != null )
{
@ -99,7 +70,7 @@ public final class FixedWidthFontRenderer
{
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);
}
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.
if( index == '\0' || index == ' ' )
@ -187,26 +158,32 @@ public final class FixedWidthFontRenderer
buffer.vertex( transform, x, y, 0f )
.color( r, g, b, 1.0f )
.texture( xStart / WIDTH, yStart / WIDTH )
.light( light )
.next();
buffer.vertex( transform, x, y + FONT_HEIGHT, 0f )
.color( r, g, b, 1.0f )
.texture( xStart / WIDTH, (yStart + FONT_HEIGHT) / WIDTH )
.light( light )
.next();
buffer.vertex( transform, x + FONT_WIDTH, y, 0f )
.color( r, g, b, 1.0f )
.texture( (xStart + FONT_WIDTH) / WIDTH, yStart / WIDTH )
.light( light )
.next();
buffer.vertex( transform, x + FONT_WIDTH, y, 0f )
.color( r, g, b, 1.0f )
.texture( (xStart + FONT_WIDTH) / WIDTH, yStart / WIDTH )
.light( light )
.next();
buffer.vertex( transform, x, y + FONT_HEIGHT, 0f )
.color( r, g, b, 1.0f )
.texture( xStart / WIDTH, (yStart + FONT_HEIGHT) / WIDTH )
.light( light )
.next();
buffer.vertex( transform, x + FONT_WIDTH, y + FONT_HEIGHT, 0f )
.color( r, g, b, 1.0f )
.texture( (xStart + FONT_WIDTH) / WIDTH, (yStart + FONT_HEIGHT) / WIDTH )
.light( light )
.next();
}
@ -300,7 +277,7 @@ public final class FixedWidthFontRenderer
palette,
greyscale,
leftMarginSize,
rightMarginSize );
rightMarginSize, FULL_BRIGHT_LIGHTMAP );
}
}
@ -328,7 +305,7 @@ public final class FixedWidthFontRenderer
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,
float bottomMarginSize, float leftMarginSize, float rightMarginSize )
{
bindFont();
VertexConsumerProvider.Immediate renderer = MinecraftClient.getInstance()
.getBufferBuilders()
.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 );
renderer.draw( TYPE );
renderer.draw();
}
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 )
{
Colour colour = Colour.BLACK;
drawEmptyTerminal( IDENTITY, x, y, width, height );
}
public static void drawEmptyTerminal( @Nonnull Matrix4f transform, float x, float y, float width, float height )
{
bindFont();
VertexConsumerProvider.Immediate renderer = MinecraftClient.getInstance()
.getBufferBuilders()
.getEntityVertexConsumers();
@ -378,44 +352,12 @@ public final class FixedWidthFontRenderer
float height )
{
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 )
{
Colour colour = Colour.BLACK;
drawQuad( transform, renderer.getBuffer( Type.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 );
}
drawQuad( transform, renderer.getBuffer( RenderTypes.TERMINAL_BLOCKER ), x, y, width, height, colour.getR(), colour.getG(), colour.getB() );
}
}

View File

@ -6,54 +6,45 @@
package dan200.computercraft.client.gui;
import com.mojang.blaze3d.systems.RenderSystem;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.client.gui.widgets.ComputerSidebar;
import dan200.computercraft.client.gui.widgets.WidgetTerminal;
import dan200.computercraft.client.gui.widgets.WidgetWrapper;
import dan200.computercraft.client.render.ComputerBorderRenderer;
import dan200.computercraft.shared.computer.core.ClientComputer;
import dan200.computercraft.shared.computer.core.ComputerFamily;
import dan200.computercraft.shared.computer.inventory.ContainerComputer;
import dan200.computercraft.client.render.RenderTypes;
//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.pocket.inventory.ContainerPocketComputer;
import net.minecraft.client.gui.screen.ingame.HandledScreen;
//import dan200.computercraft.shared.pocket.inventory.ContainerPocketComputer;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.text.Text;
import org.lwjgl.glfw.GLFW;
import javax.annotation.Nonnull;
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 termHeight;
protected WidgetTerminal terminal;
protected WidgetWrapper terminalWrapper;
protected GuiComputer( T container, PlayerInventory player, Text title, int termWidth, int termHeight )
private GuiComputer( T container, PlayerInventory player, Text title, int termWidth, int termHeight )
{
super( container, player, title );
this.family = container.getFamily();
this.computer = (ClientComputer) container.getComputer();
super( container, player, title, BORDER );
this.termWidth = termWidth;
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 );
}
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 );
}
@ -63,96 +54,19 @@ public class GuiComputer<T extends ContainerComputerBase> extends HandledScreen<
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
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
public void drawBackground( @Nonnull MatrixStack stack, float partialTicks, int mouseX, int mouseY )
{
// Draw terminal
terminal.draw( terminalWrapper.getX(), terminalWrapper.getY() );
// Draw a border around the terminal
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();
ComputerBorderRenderer.render(
getTexture( family ), terminal.x, terminal.y, getZOffset(),
RenderTypes.FULL_BRIGHT_LIGHTMAP, terminal.getWidth(), terminal.getHeight() );
ComputerSidebar.renderBackground( stack, x, y + sidebarYOffset );
}
}

View File

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

View File

@ -25,14 +25,6 @@ public class GuiPrinter extends HandledScreen<ContainerPrinter>
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
public void render( @Nonnull MatrixStack stack, int mouseX, int mouseY, float partialTicks )
{
@ -44,9 +36,8 @@ public class GuiPrinter extends HandledScreen<ContainerPrinter>
@Override
protected void drawBackground( @Nonnull MatrixStack transform, float partialTicks, int mouseX, int mouseY )
{
RenderSystem.color4f( 1.0F, 1.0F, 1.0F, 1.0F );
client.getTextureManager()
.bindTexture( BACKGROUND );
RenderSystem.setShaderColor( 1.0F, 1.0F, 1.0F, 1.0F );
RenderSystem.setShaderTexture( 0, BACKGROUND );
drawTexture( transform, x, y, 0, 0, backgroundWidth, backgroundHeight );
if( getScreenHandler().isPrinting() )

View File

@ -22,6 +22,7 @@ import org.lwjgl.glfw.GLFW;
import javax.annotation.Nonnull;
import static dan200.computercraft.client.render.PrintoutRenderer.*;
import static dan200.computercraft.client.render.RenderTypes.FULL_BRIGHT_LIGHTMAP;
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 )
{
// 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();
VertexConsumerProvider.Immediate renderer = MinecraftClient.getInstance()
@ -116,8 +117,8 @@ public class GuiPrintout extends HandledScreen<ContainerHeldItem>
.getEntityVertexConsumers();
Matrix4f matrix = transform.peek()
.getModel();
drawBorder( matrix, renderer, x, y, getZOffset(), page, pages, book );
drawText( matrix, renderer, x + X_TEXT_MARGIN, y + Y_TEXT_MARGIN, ItemPrintout.LINES_PER_PAGE * page, text, colours );
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, FULL_BRIGHT_LIGHTMAP, text, colours );
renderer.draw();
}

View File

@ -8,6 +8,9 @@ package dan200.computercraft.client.gui;
import com.mojang.blaze3d.systems.RenderSystem;
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.turtle.inventory.ContainerTurtle;
import net.minecraft.client.util.math.MatrixStack;
@ -17,40 +20,46 @@ import net.minecraft.util.Identifier;
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_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 )
{
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
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
public void drawBackground( @Nonnull MatrixStack transform, float partialTicks, int mouseX, int mouseY )
{
// Draw term
Identifier texture = family == ComputerFamily.ADVANCED ? BACKGROUND_ADVANCED : BACKGROUND_NORMAL;
terminal.draw( terminalWrapper.getX(), terminalWrapper.getY() );
// 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 );
boolean advanced = family == ComputerFamily.ADVANCED;
RenderSystem.setShaderTexture( 0, advanced ? BACKGROUND_ADVANCED : BACKGROUND_NORMAL );
drawTexture( transform, x + ComputerSidebar.WIDTH, y, 0, 0, TEX_WIDTH, TEX_HEIGHT );
// Draw selection slot
int slot = container.getSelectedSlot();
int slot = getScreenHandler().getSelectedSlot();
if( slot >= 0 )
{
int slotX = slot % 4;
@ -61,5 +70,8 @@ public class GuiTurtle extends GuiComputer<ContainerTurtle>
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.core.terminal.Terminal;
import dan200.computercraft.shared.computer.core.ClientComputer;
import dan200.computercraft.shared.computer.core.IComputer;
import net.minecraft.SharedConstants;
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 javax.annotation.Nonnull;
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_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 final MinecraftClient client;
private final Supplier<ClientComputer> computer;
private final int termWidth;
private final int termHeight;
private final int leftMargin;
private final int rightMargin;
private final int topMargin;
private final int bottomMargin;
private final BitSet keysDown = new BitSet( 256 );
private boolean focused;
private final ClientComputer computer;
// The positions of the actual terminal
private final int innerX;
private final int innerY;
private final int innerWidth;
private final int innerHeight;
private float terminateTimer = -1;
private float rebootTimer = -1;
private float shutdownTimer = -1;
private int lastMouseButton = -1;
private int lastMouseX = -1;
private int lastMouseY = -1;
public WidgetTerminal( MinecraftClient client, Supplier<ClientComputer> computer, int termWidth, int termHeight, int leftMargin, int rightMargin,
int topMargin, int bottomMargin )
private final BitSet keysDown = new BitSet( 256 );
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.termWidth = termWidth;
this.termHeight = termHeight;
this.leftMargin = leftMargin;
this.rightMargin = rightMargin;
this.topMargin = topMargin;
this.bottomMargin = bottomMargin;
innerX = x + MARGIN;
innerY = y + MARGIN;
innerWidth = termWidth * FONT_WIDTH;
innerHeight = termHeight * FONT_HEIGHT;
}
@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
public boolean mouseClicked( double mouseX, double mouseY, int button )
{
ClientComputer computer = this.computer.get();
if( computer == null || !computer.isColour() || button < 0 || button > 2 )
{
return false;
}
if( !inTermRegion( mouseX, mouseY ) ) return false;
if( !computer.isColour() || button < 0 || button > 2 ) return false;
Terminal term = computer.getTerminal();
if( term != null )
{
int charX = (int) (mouseX / FONT_WIDTH);
int charY = (int) (mouseY / FONT_HEIGHT);
int charX = (int) ((mouseX - innerX) / FONT_WIDTH);
int charY = (int) ((mouseY - innerY) / FONT_HEIGHT);
charX = Math.min( Math.max( charX, 0 ), term.getWidth() - 1 );
charY = Math.min( Math.max( charY, 0 ), term.getHeight() - 1 );
@ -85,17 +103,14 @@ public class WidgetTerminal implements Element
@Override
public boolean mouseReleased( double mouseX, double mouseY, int button )
{
ClientComputer computer = this.computer.get();
if( computer == null || !computer.isColour() || button < 0 || button > 2 )
{
return false;
}
if( !inTermRegion( mouseX, mouseY ) ) return false;
if( !computer.isColour() || button < 0 || button > 2 ) return false;
Terminal term = computer.getTerminal();
if( term != null )
{
int charX = (int) (mouseX / FONT_WIDTH);
int charY = (int) (mouseY / FONT_HEIGHT);
int charX = (int) ((mouseX - innerX) / FONT_WIDTH);
int charY = (int) ((mouseY - innerY) / FONT_HEIGHT);
charX = Math.min( Math.max( charX, 0 ), term.getWidth() - 1 );
charY = Math.min( Math.max( charY, 0 ), term.getHeight() - 1 );
@ -115,17 +130,14 @@ public class WidgetTerminal implements Element
@Override
public boolean mouseDragged( double mouseX, double mouseY, int button, double v2, double v3 )
{
ClientComputer computer = this.computer.get();
if( computer == null || !computer.isColour() || button < 0 || button > 2 )
{
return false;
}
if( !inTermRegion( mouseX, mouseY ) ) return false;
if( !computer.isColour() || button < 0 || button > 2 ) return false;
Terminal term = computer.getTerminal();
if( term != null )
{
int charX = (int) (mouseX / FONT_WIDTH);
int charY = (int) (mouseY / FONT_HEIGHT);
int charX = (int) ((mouseX - innerX) / FONT_WIDTH);
int charY = (int) ((mouseY - innerY) / FONT_HEIGHT);
charX = Math.min( Math.max( charX, 0 ), term.getWidth() - 1 );
charY = Math.min( Math.max( charY, 0 ), term.getHeight() - 1 );
@ -143,17 +155,14 @@ public class WidgetTerminal implements Element
@Override
public boolean mouseScrolled( double mouseX, double mouseY, double delta )
{
ClientComputer computer = this.computer.get();
if( computer == null || !computer.isColour() || delta == 0 )
{
return false;
}
if( !inTermRegion( mouseX, mouseY ) ) return false;
if( !computer.isColour() || delta == 0 ) return false;
Terminal term = computer.getTerminal();
if( term != null )
{
int charX = (int) (mouseX / FONT_WIDTH);
int charY = (int) (mouseY / FONT_HEIGHT);
int charX = (int) ((mouseX - innerX) / FONT_WIDTH);
int charY = (int) ((mouseY - innerY) / FONT_HEIGHT);
charX = Math.min( Math.max( charX, 0 ), term.getWidth() - 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:
// Ctrl+V for paste
String clipboard = client.keyboard.getClipboard();
String clipboard = MinecraftClient.getInstance().keyboard.getClipboard();
if( clipboard != null )
{
// 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
boolean repeat = keysDown.get( key );
keysDown.set( key );
IComputer computer = this.computer.get();
if( computer != null )
{
computer.keyDown( key, repeat );
}
computer.keyDown( key, repeat );
}
return true;
@ -256,11 +261,7 @@ public class WidgetTerminal implements Element
if( key >= 0 && keysDown.get( key ) )
{
keysDown.set( key, false );
IComputer computer = this.computer.get();
if( computer != null )
{
computer.keyUp( key );
}
computer.keyUp( key );
}
switch( key )
@ -284,47 +285,26 @@ public class WidgetTerminal implements Element
}
@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
{
// Queue the "char" event
queueEvent( "char", Character.toString( ch ) );
}
return true;
}
@Override
public boolean changeFocus( boolean reversed )
{
if( focused )
if( !focused )
{
// When blurring, we should make all keys go up
for( int key = 0; key < keysDown.size(); key++ )
{
if( keysDown.get( key ) )
{
queueEvent( "key_up", key );
}
if( keysDown.get( key ) ) computer.keyUp( key );
}
keysDown.clear();
// When blurring, we should make the last mouse button go up
if( lastMouseButton > 0 )
{
IComputer computer = this.computer.get();
if( computer != null )
{
computer.mouseUp( lastMouseButton + 1, lastMouseX + 1, lastMouseY + 1 );
}
computer.mouseUp( lastMouseButton + 1, lastMouseX + 1, lastMouseY + 1 );
lastMouseButton = -1;
}
shutdownTimer = terminateTimer = rebootTimer = -1;
}
focused = !focused;
return true;
}
@Override
@ -335,11 +315,7 @@ public class WidgetTerminal implements Element
private void queueEvent( String event, Object... args )
{
ClientComputer computer = this.computer.get();
if( computer != null )
{
computer.queueEvent( event, args );
}
computer.queueEvent( event, args );
}
public void update()
@ -351,50 +327,53 @@ public class WidgetTerminal implements Element
if( shutdownTimer >= 0 && shutdownTimer < TERMINATE_TIME && (shutdownTimer += 0.05f) > TERMINATE_TIME )
{
ClientComputer computer = this.computer.get();
if( computer != null )
{
computer.shutdown();
}
computer.shutdown();
}
if( rebootTimer >= 0 && rebootTimer < TERMINATE_TIME && (rebootTimer += 0.05f) > TERMINATE_TIME )
{
ClientComputer computer = this.computer.get();
if( computer != null )
{
computer.reboot();
}
computer.reboot();
}
}
private void queueEvent( String event )
{
ClientComputer computer = this.computer.get();
ClientComputer computer = this.computer;
if( computer != null )
{
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
ClientComputer computer = this.computer.get();
Terminal terminal = computer != null ? computer.getTerminal() : null;
if( terminal != null )
{
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 );
}
FixedWidthFontRenderer.drawTerminal( matrix, innerX, innerY, terminal, !computer.isColour(), MARGIN, MARGIN, MARGIN, MARGIN );
}
else
{
FixedWidthFontRenderer.drawEmptyTerminal( matrix, x, y, width, height );
}
}
@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.IColouredItem;
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.peripheral.diskdrive.ContainerDiskDrive;
import dan200.computercraft.shared.peripheral.monitor.ClientMonitor;
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.turtle.inventory.ContainerTurtle;
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.ClientLifecycleEvents;
import net.fabricmc.fabric.api.client.model.ModelLoadingRegistry;
import net.fabricmc.fabric.api.client.rendereregistry.v1.BlockEntityRendererRegistry;
import net.fabricmc.fabric.api.client.rendereregistry.v1.EntityRendererRegistry;
import net.fabricmc.fabric.api.client.rendering.v1.BlockEntityRendererRegistry;
import net.fabricmc.fabric.api.client.rendering.v1.EntityRendererRegistry;
import net.fabricmc.fabric.api.client.screenhandler.v1.ScreenRegistry;
import net.fabricmc.fabric.api.event.client.ClientSpriteRegistryCallback;
import net.fabricmc.fabric.mixin.object.builder.ModelPredicateProviderRegistrySpecificAccessor;
import net.minecraft.client.item.ModelPredicateProvider;
import net.fabricmc.fabric.api.object.builder.v1.client.model.FabricModelPredicateProviderRegistry;
import net.minecraft.client.item.UnclampedModelPredicateProvider;
import net.minecraft.client.render.RenderLayer;
import net.minecraft.item.Item;
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.
BlockRenderLayerMap.INSTANCE.putBlock( ComputerCraftRegistry.ModBlocks.TURTLE_NORMAL, RenderLayer.getTranslucent() );
BlockRenderLayerMap.INSTANCE.putBlock( ComputerCraftRegistry.ModBlocks.TURTLE_ADVANCED, RenderLayer.getTranslucent() );
// 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_ADVANCED, RenderLayer.getCutout() );
// Setup TESRs
BlockEntityRendererRegistry.INSTANCE.register( ComputerCraftRegistry.ModTiles.MONITOR_NORMAL, TileEntityMonitorRenderer::new );
BlockEntityRendererRegistry.INSTANCE.register( ComputerCraftRegistry.ModTiles.MONITOR_ADVANCED, TileEntityMonitorRenderer::new );
BlockEntityRendererRegistry.INSTANCE.register( ComputerCraftRegistry.ModTiles.TURTLE_NORMAL, TileEntityTurtleRenderer::new );
BlockEntityRendererRegistry.INSTANCE.register( ComputerCraftRegistry.ModTiles.TURTLE_ADVANCED, TileEntityTurtleRenderer::new );
BlockEntityRendererRegistry.register( ComputerCraftRegistry.ModTiles.MONITOR_NORMAL, TileEntityMonitorRenderer::new );
BlockEntityRendererRegistry.register( ComputerCraftRegistry.ModTiles.MONITOR_ADVANCED, TileEntityMonitorRenderer::new );
BlockEntityRendererRegistry.register( ComputerCraftRegistry.ModTiles.TURTLE_NORMAL, TileEntityTurtleRenderer::new );
BlockEntityRendererRegistry.register( ComputerCraftRegistry.ModTiles.TURTLE_ADVANCED, TileEntityTurtleRenderer::new );
ClientSpriteRegistryCallback.event( PlayerScreenHandler.BLOCK_ATLAS_TEXTURE )
.register( ClientRegistry::onTextureStitchEvent );
ModelLoadingRegistry.INSTANCE.registerAppender( ClientRegistry::onModelBakeEvent );
ModelLoadingRegistry.INSTANCE.registerModelProvider( ClientRegistry::onModelBakeEvent );
ModelLoadingRegistry.INSTANCE.registerResourceProvider( loader -> ( name, context ) -> TurtleModelLoader.INSTANCE.accepts( name ) ?
TurtleModelLoader.INSTANCE.loadModel(
name ) : null );
EntityRendererRegistry.INSTANCE.register( ComputerCraftRegistry.ModEntities.TURTLE_PLAYER, TurtlePlayerRenderer::new );
EntityRendererRegistry.register( ComputerCraftRegistry.ModEntities.TURTLE_PLAYER, TurtlePlayerRenderer::new );
registerItemProperty( "state",
( stack, world, player ) -> ItemPocketComputer.getState( stack )
( stack, world, player, integer ) -> ItemPocketComputer.getState( stack )
.ordinal(),
() -> ComputerCraftRegistry.ModItems.POCKET_COMPUTER_NORMAL,
() -> ComputerCraftRegistry.ModItems.POCKET_COMPUTER_ADVANCED );
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_ADVANCED );
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.
private static void registerContainers()
{
ScreenRegistry.<ContainerComputer, GuiComputer<ContainerComputer>>register( ComputerCraftRegistry.ModContainers.COMPUTER, GuiComputer::create );
ScreenRegistry.<ContainerPocketComputer, GuiComputer<ContainerPocketComputer>>register( ComputerCraftRegistry.ModContainers.POCKET_COMPUTER,
ScreenRegistry.<ContainerComputerBase, GuiComputer<ContainerComputerBase>>register( ComputerCraftRegistry.ModContainers.COMPUTER, GuiComputer::create );
ScreenRegistry.<ContainerComputerBase, GuiComputer<ContainerComputerBase>>register( ComputerCraftRegistry.ModContainers.POCKET_COMPUTER,
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.<ContainerPrinter, GuiPrinter>register( ComputerCraftRegistry.ModContainers.PRINTER, GuiPrinter::new );
@ -127,12 +127,12 @@ public final class ComputerCraftProxyClient implements ClientModInitializer
}
@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 );
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.util.math.MatrixStack;
import net.minecraft.entity.Entity;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Matrix4f;
import net.minecraft.util.math.Vec3d;
import net.minecraft.util.math.*;
import net.minecraft.util.shape.VoxelShape;
@Environment( EnvType.CLIENT )
@ -49,17 +47,29 @@ public final class CableHighlightRenderer
state );
Vec3d cameraPos = info.getPos();
double xOffset = pos.getX() - cameraPos.getX();
double yOffset = pos.getY() - cameraPos.getY();
double zOffset = pos.getZ() - cameraPos.getZ();
Matrix4f matrix4f = stack.peek()
.getModel();
Matrix3f normal = stack.peek().getNormal();
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) )
.color( 0, 0, 0, 0.4f )
.normal( normal, xDelta, yDelta, zDelta )
.next();
consumer.vertex( matrix4f, (float) (x2 + xOffset), (float) (y2 + yOffset), (float) (z2 + zOffset) )
.color( 0, 0, 0, 0.4f )
.normal( normal, xDelta, yDelta, zDelta )
.next();
} );

View File

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

View File

@ -89,7 +89,7 @@ public abstract class ItemMapLikeRenderer
transform.multiply( Vec3f.POSITIVE_X.getDegreesQuaternion( rX * 20.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_Y.getDegreesQuaternion( offset * f2 * -30f ) );
renderItem( transform, render, stack );
renderItem( transform, render, stack, combinedLight );
transform.pop();
}
@ -144,6 +144,7 @@ public abstract class ItemMapLikeRenderer
* @param transform The matrix transformation stack
* @param render The buffer to render to
* @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.util.Colour;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.render.BufferBuilder;
import net.minecraft.client.render.Tessellator;
import net.minecraft.client.render.VertexConsumerProvider;
import net.minecraft.client.render.VertexFormats;
import net.minecraft.client.render.*;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.item.ItemStack;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.Matrix4f;
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_WIDTH;
@ -41,7 +38,7 @@ public final class ItemPocketRenderer extends ItemMapLikeRenderer
}
@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 );
Terminal terminal = computer == null ? null : computer.getTerminal();
@ -79,7 +76,7 @@ public final class ItemPocketRenderer extends ItemMapLikeRenderer
Matrix4f matrix = transform.peek()
.getModel();
renderFrame( matrix, family, frameColour, width, height );
renderFrame( matrix, render, family, frameColour, light, width, height );
// Render the light
int lightColour = ItemPocketComputer.getLightState( stack );
@ -91,7 +88,12 @@ public final class ItemPocketRenderer extends ItemMapLikeRenderer
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
{
@ -101,24 +103,20 @@ public final class ItemPocketRenderer extends ItemMapLikeRenderer
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();
MinecraftClient.getInstance()
.getTextureManager()
.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 g = ((colour >>> 8) & 0xFF) / 255.0f;
float b = (colour & 0xFF) / 255.0f;
Tessellator tessellator = Tessellator.getInstance();
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();
ComputerBorderRenderer.render( transform, render.getBuffer( RenderLayer.getText( texture ) ), 0, 0, 0, light, width, height, true, r, g, b );
}
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();
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 )
.color( r, g, b, 1.0f )
.next();

View File

@ -9,6 +9,7 @@ package dan200.computercraft.client.render;
import dan200.computercraft.shared.media.items.ItemPrintout;
import net.minecraft.client.render.VertexConsumerProvider;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.util.math.Vec3f;
import net.minecraft.item.ItemStack;
import net.minecraft.util.math.Matrix4f;
import net.minecraft.util.math.Vec3f;
@ -31,16 +32,16 @@ public final class ItemPrintoutRenderer extends ItemMapLikeRenderer
}
@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.scale( 0.42f, 0.42f, -0.42f );
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 );
boolean book = ((ItemPrintout) stack.getItem()).getType() == ItemPrintout.Type.BOOK;
@ -72,11 +73,11 @@ public final class ItemPrintoutRenderer extends ItemMapLikeRenderer
Matrix4f matrix = transform.peek()
.getModel();
drawBorder( matrix, render, 0, 0, -0.01f, 0, pages, book );
drawText( matrix, render, X_TEXT_MARGIN, Y_TEXT_MARGIN, 0, ItemPrintout.getText( stack ), ItemPrintout.getColours( stack ) );
drawBorder( matrix, render, 0, 0, -0.01f, 0, pages, book, light );
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) )
{
@ -89,7 +90,7 @@ public final class ItemPrintoutRenderer extends ItemMapLikeRenderer
matrixStack.scale( 0.95f, 0.95f, -0.95f );
matrixStack.translate( -0.5f, -0.5f, 0.0f );
drawPrintout( matrixStack, consumerProvider, stack );
drawPrintout( matrixStack, consumerProvider, stack, light );
return true;
}

View File

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

View File

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

View File

@ -5,180 +5,107 @@
*/
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.shared.util.Palette;
import net.minecraft.client.texture.TextureUtil;
import net.minecraft.util.math.Matrix4f;
import org.lwjgl.BufferUtils;
import net.minecraft.client.gl.GlUniform;
import net.minecraft.client.render.Shader;
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.GL20;
import java.io.InputStream;
import javax.annotation.Nullable;
import java.io.IOException;
import java.nio.FloatBuffer;
class MonitorTextureBufferShader
public class MonitorTextureBufferShader extends Shader
{
static final int TEXTURE_INDEX = GL13.GL_TEXTURE3;
private static final FloatBuffer MATRIX_BUFFER = BufferUtils.createFloatBuffer( 16 );
private static final FloatBuffer PALETTE_BUFFER = BufferUtils.createFloatBuffer( 16 * 3 );
private static final Logger LOGGER = LogManager.getLogger();
private static int uniformMv;
private final GlUniform palette;
private final GlUniform width;
private final GlUniform height;
private static int uniformFont;
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 )
public MonitorTextureBufferShader( ResourceFactory factory, String name, VertexFormat format ) throws IOException
{
MATRIX_BUFFER.rewind();
transform.writeColumnMajor( MATRIX_BUFFER );
MATRIX_BUFFER.rewind();
RenderSystem.glUniformMatrix4( uniformMv, false, MATRIX_BUFFER );
super( factory, name, format );
RenderSystem.glUniform1i( uniformWidth, width );
RenderSystem.glUniform1i( uniformHeight, height );
width = getUniformChecked( "Width" );
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++ )
{
double[] colour = palette.getColour( i );
if( greyscale )
{
float f = FixedWidthFontRenderer.toGreyscale( colour );
PALETTE_BUFFER.put( f )
.put( f )
.put( f );
paletteBuffer.put( f ).put( f ).put( f );
}
else
{
PALETTE_BUFFER.put( (float) colour[0] )
.put( (float) colour[1] )
.put( (float) colour[2] );
paletteBuffer.put( (float) colour[0] ).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()
.getResourceAsStream( path );
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;
super.bind();
palette.upload();
}
private static int getUniformLocation( int program, String name )
@Override
public void close()
{
int uniform = GlStateManager.getUniformLocation( program, name );
if( uniform == -1 )
palette.close();
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;
}
}

View File

@ -9,10 +9,9 @@ package dan200.computercraft.client.render;
import dan200.computercraft.client.gui.FixedWidthFontRenderer;
import dan200.computercraft.core.terminal.TextBuffer;
import dan200.computercraft.shared.util.Palette;
import net.minecraft.client.render.*;
import net.minecraft.util.Identifier;
import net.minecraft.client.render.VertexConsumer;
import net.minecraft.client.render.VertexConsumerProvider;
import net.minecraft.util.math.Matrix4f;
import org.lwjgl.opengl.GL11;
import static dan200.computercraft.client.gui.FixedWidthFontRenderer.FONT_HEIGHT;
import static dan200.computercraft.shared.media.items.ItemPrintout.LINES_PER_PAGE;
@ -39,7 +38,6 @@ public final class PrintoutRenderer
* Size of the leather cover.
*/
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;
/**
* Width of the extra page texture.
@ -50,9 +48,9 @@ public final class 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++ )
{
FixedWidthFontRenderer.drawString( transform,
@ -65,13 +63,14 @@ public final class PrintoutRenderer
Palette.DEFAULT,
false,
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++ )
{
FixedWidthFontRenderer.drawString( transform,
@ -84,16 +83,17 @@ public final class PrintoutRenderer
Palette.DEFAULT,
false,
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 rightPages = pages - page - 1;
VertexConsumer buffer = renderer.getBuffer( Type.TYPE );
VertexConsumer buffer = renderer.getBuffer( RenderTypes.PRINTOUT_BACKGROUND );
if( isBook )
{
@ -103,8 +103,8 @@ public final class PrintoutRenderer
float right = x + X_SIZE + offset - 4;
// 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, right, y - 8, z - 0.02f, COVER_X + COVER_SIZE, 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, light );
// Draw centre panel (just stretched texture, sorry).
drawTexture( transform,
@ -117,34 +117,35 @@ public final class PrintoutRenderer
COVER_X + COVER_SIZE / 2.0f,
COVER_SIZE,
COVER_SIZE,
Y_SIZE );
Y_SIZE,
light );
float borderX = left;
while( borderX < right )
{
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 + Y_SIZE - 4, z - 0.02f, 0, COVER_Y + COVER_SIZE, (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, light );
borderX += thisWidth;
}
}
// 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++ )
{
drawTexture( transform, buffer, x - offsetAt( n ), y, z - 1e-3f * n,
// 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
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++ )
{
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.
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 )));
}
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 )
.texture( u / BG_SIZE, (v + height) / BG_SIZE )
.next();
buffer.vertex( matrix, x + width, y + height, z )
.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();
vertex( buffer, matrix, x, y + height, z, u / BG_SIZE, (v + height) / BG_SIZE, light );
vertex( buffer, matrix, x + width, y + height, z, (u + width) / BG_SIZE, (v + height) / BG_SIZE, light );
vertex( buffer, matrix, x + width, y, z, (u + width) / BG_SIZE, v / BG_SIZE, light );
vertex( buffer, matrix, x, y, z, u / BG_SIZE, v / BG_SIZE, light );
}
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 )
.texture( u / BG_SIZE, (v + tHeight) / BG_SIZE )
.next();
buffer.vertex( matrix, x + width, y + height, z )
.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();
vertex( buffer, matrix, x, y + height, z, u / BG_SIZE, (v + tHeight) / BG_SIZE, light );
vertex( buffer, matrix, x + width, y + height, z, (u + tWidth) / BG_SIZE, (v + tHeight) / BG_SIZE, light );
vertex( buffer, matrix, x + width, y, z, (u + tWidth) / BG_SIZE, v / BG_SIZE, light );
vertex( buffer, matrix, x, y, z, u / BG_SIZE, v / BG_SIZE, light );
}
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",
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 );
}
buffer.vertex( matrix, x, y, z ).color( 255, 255, 255, 255 ).texture( u, v ).light( light ).next();
}
}

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;
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.gui.FixedWidthFontRenderer;
import dan200.computercraft.core.terminal.Terminal;
@ -18,17 +20,11 @@ import dan200.computercraft.shared.util.Colour;
import dan200.computercraft.shared.util.DirectionUtil;
import net.minecraft.client.gl.VertexBuffer;
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.util.GlAllocationUtils;
import net.minecraft.client.render.block.entity.BlockEntityRendererFactory;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.util.math.AffineTransformation;
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 net.minecraft.util.math.*;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL13;
import org.lwjgl.opengl.GL20;
import org.lwjgl.opengl.GL31;
@ -36,8 +32,9 @@ import javax.annotation.Nonnull;
import java.nio.ByteBuffer;
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.
@ -47,11 +44,10 @@ public class TileEntityMonitorRenderer extends BlockEntityRenderer<TileMonitor>
.getMatrix();
private static ByteBuffer tboContents;
public TileEntityMonitorRenderer( BlockEntityRenderDispatcher rendererDispatcher )
public TileEntityMonitorRenderer( BlockEntityRendererFactory.Context context )
{
super( rendererDispatcher );
// super( context );
}
@Override
public void render( @Nonnull TileMonitor monitor, float partialTicks, @Nonnull MatrixStack transform, @Nonnull VertexConsumerProvider renderer,
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 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
Terminal terminal = originTerminal.getTerminal();
if( terminal != null )
@ -122,23 +107,22 @@ public class TileEntityMonitorRenderer extends BlockEntityRenderer<TileMonitor>
Matrix4f matrix = transform.peek().getModel();
// Sneaky hack here: we get a buffer now in order to flush existing ones and set up the appropriate
// 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) );
renderTerminal( renderer, 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
// reasonable.
FixedWidthFontRenderer.drawCursor( matrix, buffer, 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();
FixedWidthFontRenderer.drawCursor( matrix, renderer.getBuffer( RenderTypes.TERMINAL_WITHOUT_DEPTH ), 0, 0, terminal, !originTerminal.isColour() );
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
{
@ -154,7 +138,7 @@ public class TileEntityMonitorRenderer extends BlockEntityRenderer<TileMonitor>
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();
@ -169,10 +153,6 @@ public class TileEntityMonitorRenderer extends BlockEntityRenderer<TileMonitor>
{
case TBO:
{
if( !MonitorTextureBufferShader.use() )
{
return;
}
int width = terminal.getWidth(), height = terminal.getHeight();
int pixelWidth = width * FONT_WIDTH, pixelHeight = height * FONT_HEIGHT;
@ -182,7 +162,7 @@ public class TileEntityMonitorRenderer extends BlockEntityRenderer<TileMonitor>
int size = width * height * 3;
if( tboContents == null || tboContents.capacity() < size )
{
tboContents = GlAllocationUtils.allocateByteBuffer( size );
tboContents = allocateByteBuffer( size );
}
ByteBuffer monitorBuffer = tboContents;
@ -199,32 +179,27 @@ public class TileEntityMonitorRenderer extends BlockEntityRenderer<TileMonitor>
}
monitorBuffer.flip();
GlStateManager.bindBuffers( GL31.GL_TEXTURE_BUFFER, monitor.tboBuffer );
GlStateManager.bufferData( GL31.GL_TEXTURE_BUFFER, monitorBuffer, GL20.GL_STATIC_DRAW );
GlStateManager.bindBuffers( GL31.GL_TEXTURE_BUFFER, 0 );
GlStateManager._glBindBuffer( GL31.GL_TEXTURE_BUFFER, monitor.tboBuffer );
GlStateManager._glBufferData( GL31.GL_TEXTURE_BUFFER, monitorBuffer, GL20.GL_STATIC_DRAW );
GlStateManager._glBindBuffer( GL31.GL_TEXTURE_BUFFER, 0 );
}
// 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 );
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();
BufferBuilder buffer = tessellator.getBuffer();
buffer.begin( GL11.GL_TRIANGLE_STRIP, VertexFormats.POSITION );
buffer.vertex( -xMargin, -yMargin, 0 )
.next();
buffer.vertex( -xMargin, pixelHeight + yMargin, 0 )
.next();
buffer.vertex( pixelWidth + xMargin, -yMargin, 0 )
.next();
buffer.vertex( pixelWidth + xMargin, pixelHeight + yMargin, 0 )
.next();
tessellator.draw();
VertexConsumer buffer = renderer.getBuffer( RenderTypes.MONITOR_TBO );
tboVertex( buffer, matrix, -xMargin, -yMargin );
tboVertex( buffer, matrix, -xMargin, pixelHeight + yMargin );
tboVertex( buffer, matrix, pixelWidth + xMargin, -yMargin );
tboVertex( buffer, matrix, pixelWidth + xMargin, pixelHeight + yMargin );
GlStateManager.useProgram( 0 );
renderer.getBuffer( RenderTypes.TERMINAL_WITHOUT_DEPTH );
break;
}
@ -234,7 +209,7 @@ public class TileEntityMonitorRenderer extends BlockEntityRenderer<TileMonitor>
{
Tessellator tessellator = Tessellator.getInstance();
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,
builder,
0,
@ -250,14 +225,23 @@ public class TileEntityMonitorRenderer extends BlockEntityRenderer<TileMonitor>
vbo.upload( builder );
}
vbo.bind();
FixedWidthFontRenderer.TYPE.getVertexFormat()
.startDrawing( 0L );
vbo.draw( matrix, FixedWidthFontRenderer.TYPE.getDrawMode() );
VertexBuffer.unbind();
FixedWidthFontRenderer.TYPE.getVertexFormat()
.endDrawing();
renderer.getBuffer( RenderTypes.TERMINAL_WITHOUT_DEPTH );
RenderTypes.TERMINAL_WITHOUT_DEPTH.startDrawing();
vbo.setShader( matrix, RenderSystem.getProjectionMatrix(), RenderTypes.getTerminalShader() );
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.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.client.render;
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.block.entity.BlockEntityRenderDispatcher;
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.BakedModelManager;
import net.minecraft.client.render.model.BakedQuad;
import net.minecraft.client.util.ModelIdentifier;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.util.math.Vec3f;
import net.minecraft.util.Identifier;
import net.minecraft.util.hit.BlockHitResult;
import net.minecraft.util.hit.HitResult;
@ -37,7 +38,7 @@ import javax.annotation.Nonnull;
import java.util.List;
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 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 );
public TileEntityTurtleRenderer( BlockEntityRenderDispatcher renderDispatcher )
BlockEntityRenderDispatcher renderer;
public TileEntityTurtleRenderer( BlockEntityRendererFactory.Context context )
{
super( renderDispatcher );
renderer = context.getRenderDispatcher();
}
public static ModelIdentifier getTurtleModel( ComputerFamily family, boolean coloured )
@ -76,6 +79,118 @@ public class TileEntityTurtleRenderer extends BlockEntityRenderer<TileTurtle>
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,
List<BakedQuad> quads, int[] tints )
{
@ -107,117 +222,4 @@ public class TileEntityTurtleRenderer extends BlockEntityRenderer<TileTurtle>
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 rightUpgradeModel;
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,
TransformedModel rightUpgradeModel )
@ -120,9 +120,9 @@ public class TurtleMultiModel implements BakedModel
@Nonnull
@Override
@Deprecated
public Sprite getSprite()
public Sprite getParticleSprite()
{
return baseModel.getSprite();
return baseModel.getParticleSprite();
}
@Nonnull

View File

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

View File

@ -3,7 +3,6 @@
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.client.render;
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.texture.Sprite;
import net.minecraft.client.util.ModelIdentifier;
import net.minecraft.util.math.AffineTransformation;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.client.world.ClientWorld;
import net.minecraft.entity.LivingEntity;
@ -55,8 +55,60 @@ public class TurtleSmartItemModel implements BakedModel
.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 colourModel;
private final HashMap<TurtleModelCombination, BakedModel> cachedModels = new HashMap<>();
private final ModelOverrideList overrides;
@ -70,8 +122,7 @@ public class TurtleSmartItemModel implements BakedModel
{
@Nonnull
@Override
public BakedModel apply( @Nonnull BakedModel originalModel, @Nonnull ItemStack stack, @Nullable ClientWorld world,
@Nullable LivingEntity entity )
public BakedModel apply( BakedModel originalModel, ItemStack stack, @Nullable ClientWorld world, @Nullable LivingEntity entity, int seed )
{
ItemTurtle turtle = (ItemTurtle) stack.getItem();
int colour = turtle.getColour( stack );
@ -80,9 +131,7 @@ public class TurtleSmartItemModel implements BakedModel
Identifier overlay = turtle.getOverlay( stack );
boolean christmas = HolidayUtil.getCurrentHoliday() == Holiday.CHRISTMAS;
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 = false;
boolean flip = label != null && (label.equals( "Dinnerbone" ) || label.equals( "Grumm" ));
TurtleModelCombination combo = new TurtleModelCombination( colour != -1, leftUpgrade, rightUpgrade, overlay, christmas, flip );
BakedModel model = cachedModels.get( combo );
@ -143,12 +192,18 @@ public class TurtleSmartItemModel implements BakedModel
return familyModel.isBuiltin();
}
@Nonnull
@Override
@Deprecated
public Sprite getSprite()
public Sprite getParticleSprite()
{
return familyModel.getSprite();
return familyModel.getParticleSprite();
}
@Nonnull
@Override
public ModelOverrideList getOverrides()
{
return overrides;
}
@Nonnull
@ -159,63 +214,4 @@ public class TurtleSmartItemModel implements BakedModel
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;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.api.filesystem.IMount;
import dan200.computercraft.api.filesystem.IWritableMount;
import dan200.computercraft.api.peripheral.IComputerAccess;
@ -30,6 +31,10 @@ public abstract class ComputerAccess implements IComputerAccess
public void unmountAll()
{
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 )
{
fileSystem.unmount( mount );

View File

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

View File

@ -96,9 +96,8 @@ public abstract class HandleGeneric
protected static SeekableByteChannel asSeekable( Channel channel )
{
if( !(channel instanceof SeekableByteChannel) ) return null;
if( !(channel instanceof SeekableByteChannel seekable) ) return null;
SeekableByteChannel seekable = (SeekableByteChannel) channel;
try
{
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.SslContextBuilder;
import io.netty.handler.timeout.ReadTimeoutException;
import io.netty.handler.traffic.AbstractTrafficShapingHandler;
import io.netty.handler.traffic.GlobalTrafficShapingHandler;
import javax.annotation.Nonnull;
import javax.net.ssl.SSLException;
@ -28,9 +30,7 @@ import javax.net.ssl.TrustManagerFactory;
import java.net.InetSocketAddress;
import java.net.URI;
import java.security.KeyStore;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
@ -38,10 +38,8 @@ import java.util.concurrent.TimeUnit;
*/
public final class NetworkUtils
{
public static final ExecutorService EXECUTOR = new ThreadPoolExecutor(
4, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<>(),
public static final ScheduledThreadPoolExecutor EXECUTOR = new ScheduledThreadPoolExecutor(
4,
ThreadUtils.builder( "Network" )
.setPriority( Thread.MIN_PRIORITY + (Thread.NORM_PRIORITY - Thread.MIN_PRIORITY) / 2 )
.build()
@ -52,6 +50,15 @@ public final class NetworkUtils
.build()
);
public static final AbstractTrafficShapingHandler SHAPING_HANDLER = new GlobalTrafficShapingHandler(
EXECUTOR, ComputerCraft.httpUploadBandwidth, ComputerCraft.httpDownloadBandwidth
);
static
{
EXECUTOR.setKeepAliveTime( 60, TimeUnit.SECONDS );
}
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.
*
@ -184,7 +201,7 @@ public final class NetworkUtils
{
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";
}

View File

@ -75,7 +75,7 @@ public final class AddressRule
if( this.port != null && this.port != port ) return false;
return predicate.matches( domain )
|| 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 )

View File

@ -167,6 +167,7 @@ public class HttpRequest extends Resource<HttpRequest>
}
ChannelPipeline p = ch.pipeline();
p.addLast( NetworkUtils.SHAPING_HANDLER );
if( sslContext != null )
{
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( message instanceof HttpResponse )
if( message instanceof HttpResponse response )
{
HttpResponse response = (HttpResponse) message;
if( request.redirects.get() > 0 )
{
@ -137,9 +136,8 @@ public final class HttpRequestHandler extends SimpleChannelInboundHandler<HttpOb
responseHeaders.add( response.headers() );
}
if( message instanceof HttpContent )
if( message instanceof HttpContent content )
{
HttpContent content = (HttpContent) message;
if( responseBody == null )
{
@ -162,9 +160,8 @@ public final class HttpRequestHandler extends SimpleChannelInboundHandler<HttpOb
responseBody.addComponent( true, partial.retain() );
}
if( message instanceof LastHttpContent )
if( message instanceof LastHttpContent last )
{
LastHttpContent last = (LastHttpContent) message;
responseHeaders.add( last.trailingHeaders() );
// 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.nio.NioSocketChannel;
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.HttpObjectAggregator;
import io.netty.handler.codec.http.websocketx.WebSocketClientHandshaker;
import io.netty.handler.codec.http.websocketx.WebSocketClientHandshakerFactory;
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 java.lang.ref.WeakReference;
@ -145,20 +145,22 @@ public class Websocket extends Resource<Websocket>
protected void initChannel( SocketChannel ch )
{
ChannelPipeline p = ch.pipeline();
p.addLast( NetworkUtils.SHAPING_HANDLER );
if( sslContext != null )
{
p.addLast( sslContext.newHandler( ch.alloc(), uri.getHost(), socketAddress.getPort() ) );
}
String subprotocol = headers.get( HttpHeaderNames.SEC_WEBSOCKET_PROTOCOL );
WebSocketClientHandshaker handshaker = WebSocketClientHandshakerFactory.newHandshaker(
uri, WebSocketVersion.V13, null, true, headers,
uri, WebSocketVersion.V13, subprotocol, true, headers,
options.websocketMessage <= 0 ? MAX_MESSAGE_SIZE : options.websocketMessage
);
p.addLast(
new HttpClientCodec(),
new HttpObjectAggregator( 8192 ),
WebSocketClientCompressionHandler.INSTANCE,
WebsocketCompressionHandler.INSTANCE,
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;
}
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 ) + ')' );
}
@ -76,9 +75,8 @@ public class WebsocketHandler extends SimpleChannelInboundHandler<Object>
websocket.environment().addTrackingChange( TrackingField.WEBSOCKET_INCOMING, converted.length );
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() );
}
else if( frame instanceof PingWebSocketFrame )

View File

@ -18,7 +18,7 @@ import static org.objectweb.asm.Opcodes.ICONST_0;
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()
{
@ -52,12 +52,11 @@ final class Reflect
{
if( underlying instanceof Class<?> ) return (Class<?>) underlying;
if( underlying instanceof ParameterizedType )
if( underlying instanceof ParameterizedType type )
{
ParameterizedType type = (ParameterizedType) underlying;
if( !allowParameter )
{
for( Type arg : type.getActualTypeArguments() )
for( java.lang.reflect.Type arg : type.getActualTypeArguments() )
{
if( arg instanceof WildcardType ) continue;
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();
IPeripheral existing = peripherals[index];
if( (existing == null && peripheral != null) ||
(existing != null && peripheral == null) ||
(existing != null && !existing.equals( peripheral )) )
if( existing == null && peripheral != null ||
existing != null && peripheral == null ||
existing != null && !existing.equals( peripheral ) )
{
peripherals[index] = 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 )
{
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() );
}

View File

@ -17,10 +17,9 @@ import dan200.computercraft.shared.util.IoUtil;
import net.minecraft.resource.ReloadableResourceManager;
import net.minecraft.resource.Resource;
import net.minecraft.resource.ResourceManager;
import net.minecraft.resource.ResourceReloader;
import net.minecraft.resource.SynchronousResourceReloader;
import net.minecraft.util.Identifier;
import net.minecraft.util.InvalidIdentifierException;
import net.minecraft.util.profiler.Profiler;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
@ -30,8 +29,6 @@ import java.io.InputStream;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
public final class ResourceMount implements IMount
@ -114,6 +111,7 @@ public final class ResourceMount implements IMount
existingNamespace = file.getNamespace();
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 );
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
* 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();
@ -308,19 +306,9 @@ public final class ResourceMount implements IMount
private final Set<ReloadableResourceManager> managers = Collections.newSetFromMap( new WeakHashMap<>() );
@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( () -> {
prepareProfiler.push( "Mount reloading" );
try
{
for( ResourceMount mount : mounts ) mount.load();
}
finally
{
prepareProfiler.pop();
}
}, prepareExecutor );
for( ResourceMount mount : mounts ) mount.load();
}
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 Bit32Lib() );
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
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 Boolean ) return valueOf( (Boolean) object );
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 ) );
}
if( object instanceof ByteBuffer )
if( object instanceof ByteBuffer b )
{
ByteBuffer b = (ByteBuffer) object;
byte[] bytes = new byte[b.remaining()];
b.get( bytes );
return valueOf( bytes );
@ -304,9 +302,8 @@ public class CobaltLuaMachine implements ILuaMachine
return table;
}
if( object instanceof Collection )
if( object instanceof Collection<?> objects )
{
Collection<?> objects = (Collection<?>) object;
LuaTable table = new LuaTable( objects.size(), 0 );
values.put( object, table );
int i = 0;
@ -314,9 +311,8 @@ public class CobaltLuaMachine implements ILuaMachine
return table;
}
if( object instanceof Object[] )
if( object instanceof Object[] objects )
{
Object[] objects = (Object[]) object;
LuaTable table = new LuaTable( objects.length, 0 );
values.put( object, table );
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:
return value.toString();
case Constants.TTABLE:
{
// Table:
// Start remembering stuff
if( objects == null )
@ -408,6 +405,7 @@ public class CobaltLuaMachine implements ILuaMachine
}
}
return table;
}
default:
return null;
}

View File

@ -9,6 +9,8 @@ import dan200.computercraft.ComputerCraft;
import dan200.computercraft.api.lua.ILuaContext;
import dan200.computercraft.api.lua.ILuaTask;
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.MainThread;
@ -66,4 +68,11 @@ class LuaContext implements ILuaContext
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 >= 'a' && c <= 'f' ) return c - 'a' + 10;
if( c >= 'A' && c <= 'F' ) return c - 'A' + 10;
return 15 - def.ordinal();
}
}

View File

@ -79,6 +79,7 @@ public class TextBuffer
}
}
@Override
public String toString()
{
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 net.minecraft.block.Block;
import net.minecraft.entity.ItemEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import java.util.function.Supplier;
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;
/**
* Captures block drops.
@ -23,12 +28,16 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin( Block.class )
public class MixinBlock
{
@Inject( method = "dropStack",
at = @At( value = "INVOKE", target = "Lnet/minecraft/world/World;spawnEntity(Lnet/minecraft/entity/Entity;)Z" ),
@Inject( method = "dropStack(Lnet/minecraft/world/World;Ljava/util/function/Supplier;Lnet/minecraft/item/ItemStack;)V",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/entity/ItemEntity;setToDefaultPickupDelay()V"
),
locals = LocalCapture.CAPTURE_FAILSOFT,
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();
}

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.entity.ItemFrameEntityRenderer;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.decoration.ItemFrameEntity;
import net.minecraft.item.ItemStack;
import org.spongepowered.asm.mixin.Mixin;
@ -23,16 +24,27 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Environment( EnvType.CLIENT )
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(
ItemFrameEntity itemFrameEntity, float f, float g, MatrixStack matrixStack,
VertexConsumerProvider vertexConsumerProvider, int i, CallbackInfo info
VertexConsumerProvider vertexConsumerProvider, int itemFrameEntityLight, CallbackInfo info
)
{
ItemStack stack = itemFrameEntity.getHeldItemStack();
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();
}
}

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 );
if( actionResult.isAccepted() )
{
Criteria.ITEM_USED_ON_BLOCK.test( player, pos, stack );
Criteria.ITEM_USED_ON_BLOCK.trigger( player, pos, stack );
cir.setReturnValue( actionResult );
}
}

View File

@ -7,7 +7,6 @@ package dan200.computercraft.fabric.mixin;
import dan200.computercraft.shared.common.TileGeneric;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
@ -29,10 +28,10 @@ public class MixinWorld
@Shadow
protected boolean iteratingTickingBlockEntities;
@Inject( method = "setBlockEntity", at = @At( "HEAD" ) )
public void setBlockEntity( BlockPos pos, @Nullable BlockEntity entity, CallbackInfo info )
@Inject( method = "addBlockEntity", at = @At( "HEAD" ) )
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 );
}
@ -42,11 +41,11 @@ public class MixinWorld
{
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 )
{
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
{
@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 javax.annotation.Nonnull;
import java.util.LinkedHashSet;
import java.util.ArrayList;
import java.util.Objects;
import java.util.Set;
public final class BundledRedstone
{
private static final Set<IBundledRedstoneProvider> providers = new LinkedHashSet<>();
private static final ArrayList<IBundledRedstoneProvider> providers = new ArrayList<>();
private BundledRedstone() {}
public static synchronized void register( @Nonnull IBundledRedstoneProvider provider )
{
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 )
{
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 )
@ -43,7 +42,7 @@ public final class BundledRedstone
private static int getUnmaskedOutput( World world, BlockPos pos, Direction side )
{
if( !World.isInBuildLimit( pos ) )
if( !world.isInBuildLimit( pos ) )
{
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.TileComputer;
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.items.ItemComputer;
import dan200.computercraft.shared.media.items.ItemDisk;
import dan200.computercraft.shared.media.items.ItemPrintout;
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.ContainerDiskDrive;
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.speaker.BlockSpeaker;
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.peripherals.PocketModem;
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.items.ItemTurtle;
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.entity.FabricBlockEntityTypeBuilder;
import net.fabricmc.fabric.api.screenhandler.v1.ScreenHandlerRegistry;
import net.minecraft.block.AbstractBlock;
import net.minecraft.block.Block;
import net.minecraft.block.Blocks;
import net.minecraft.block.Material;
import net.minecraft.block.*;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.block.entity.BlockEntityType;
import net.minecraft.entity.EntityType;
@ -61,12 +62,10 @@ import net.minecraft.screen.ScreenHandler;
import net.minecraft.screen.ScreenHandlerType;
import net.minecraft.sound.BlockSoundGroup;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.registry.Registry;
import java.util.Objects;
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;
@ -91,31 +90,31 @@ public final class ComputerCraftRegistry
public static final class ModBlocks
{
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",
new BlockComputer( properties(),
ComputerFamily.ADVANCED,
ModTiles.COMPUTER_ADVANCED ) );
ComputerCraftRegistry.ModTiles.COMPUTER_ADVANCED ) );
public static final BlockComputer COMPUTER_COMMAND = register( "computer_command",
new BlockComputer( FabricBlockSettings.copyOf( Blocks.STONE )
.strength( -1, 6000000.0F ),
ComputerFamily.COMMAND,
ModTiles.COMPUTER_COMMAND ) );
ComputerCraftRegistry.ModTiles.COMPUTER_COMMAND ) );
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",
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 BlockDiskDrive DISK_DRIVE = register( "disk_drive", new BlockDiskDrive( 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_ADVANCED = register( "monitor_advanced", new BlockMonitor( properties(), ModTiles.MONITOR_ADVANCED ) );
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, true ) );
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",
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",
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() ) );
private static Block.Settings properties()
@ -149,46 +148,52 @@ public final class ComputerCraftRegistry
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",
f -> new TileMonitor( f, false ) );
public static final BlockEntityType<TileMonitor> MONITOR_ADVANCED = ofBlock( () -> ModBlocks.MONITOR_ADVANCED,
( blockPos, blockState ) -> new TileMonitor( ModTiles.MONITOR_NORMAL, false, blockPos, blockState ) );
public static final BlockEntityType<TileMonitor> MONITOR_ADVANCED = ofBlock( ModBlocks.MONITOR_ADVANCED,
"monitor_advanced",
f -> new TileMonitor( f, true ) );
public static final BlockEntityType<TileComputer> COMPUTER_NORMAL = ofBlock( () -> ModBlocks.COMPUTER_NORMAL,
( blockPos, blockState ) -> new TileMonitor( ModTiles.MONITOR_ADVANCED, true, blockPos, blockState ) );
public static final BlockEntityType<TileComputer> COMPUTER_NORMAL = ofBlock( ModBlocks.COMPUTER_NORMAL,
"computer_normal",
f -> new TileComputer( ComputerFamily.NORMAL, f ) );
public static final BlockEntityType<TileComputer> COMPUTER_ADVANCED = ofBlock( () -> ModBlocks.COMPUTER_ADVANCED,
( blockPos, blockState ) -> new TileComputer( ComputerFamily.NORMAL, ModTiles.COMPUTER_NORMAL, blockPos, blockState ) );
public static final BlockEntityType<TileComputer> COMPUTER_ADVANCED = ofBlock( ModBlocks.COMPUTER_ADVANCED,
"computer_advanced",
f -> new TileComputer( ComputerFamily.ADVANCED, f ) );
public static final BlockEntityType<TileCommandComputer> COMPUTER_COMMAND = ofBlock( () -> ModBlocks.COMPUTER_COMMAND,
( blockPos, blockState ) -> new TileComputer( ComputerFamily.ADVANCED, ModTiles.COMPUTER_ADVANCED, blockPos, blockState ) );
public static final BlockEntityType<TileCommandComputer> COMPUTER_COMMAND = ofBlock( ModBlocks.COMPUTER_COMMAND,
"computer_command",
f -> new TileCommandComputer( ComputerFamily.COMMAND, f ) );
public static final BlockEntityType<TileTurtle> TURTLE_NORMAL = ofBlock( () -> ModBlocks.TURTLE_NORMAL,
( blockPos, blockState ) -> new TileCommandComputer( ComputerFamily.COMMAND, ModTiles.COMPUTER_COMMAND, blockPos, blockState ) );
public static final BlockEntityType<TileTurtle> TURTLE_NORMAL = ofBlock( ModBlocks.TURTLE_NORMAL,
"turtle_normal",
f -> new TileTurtle( f, ComputerFamily.NORMAL ) );
public static final BlockEntityType<TileTurtle> TURTLE_ADVANCED = ofBlock( () -> ModBlocks.TURTLE_ADVANCED,
( blockPos, blockState ) -> new TileTurtle( ModTiles.TURTLE_NORMAL, blockPos, blockState, ComputerFamily.NORMAL ) );
public static final BlockEntityType<TileTurtle> TURTLE_ADVANCED = ofBlock( ModBlocks.TURTLE_ADVANCED,
"turtle_advanced",
f -> new TileTurtle( f, ComputerFamily.ADVANCED ) );
public static final BlockEntityType<TileSpeaker> SPEAKER = ofBlock( () -> ModBlocks.SPEAKER, "speaker", TileSpeaker::new );
public static final BlockEntityType<TileDiskDrive> DISK_DRIVE = ofBlock( () -> ModBlocks.DISK_DRIVE, "disk_drive", TileDiskDrive::new );
public static final BlockEntityType<TilePrinter> PRINTER = ofBlock( () -> ModBlocks.PRINTER, "printer", TilePrinter::new );
public static final BlockEntityType<TileWiredModemFull> WIRED_MODEM_FULL = ofBlock( () -> ModBlocks.WIRED_MODEM_FULL,
( blockPos, blockState ) -> new TileTurtle( ModTiles.TURTLE_ADVANCED, blockPos, blockState, ComputerFamily.ADVANCED ) );
public static final BlockEntityType<TileSpeaker> SPEAKER = ofBlock( ModBlocks.SPEAKER, "speaker",
( blockPos, blockState ) -> new TileSpeaker( ModTiles.SPEAKER, blockPos, blockState ) );
public static final BlockEntityType<TileDiskDrive> DISK_DRIVE = ofBlock( ModBlocks.DISK_DRIVE, "disk_drive",
( 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",
TileWiredModemFull::new );
public static final BlockEntityType<TileCable> CABLE = ofBlock( () -> ModBlocks.CABLE, "cable", TileCable::new );
public static final BlockEntityType<TileWirelessModem> WIRELESS_MODEM_NORMAL = ofBlock( () -> ModBlocks.WIRELESS_MODEM_NORMAL,
( blockPos, blockState ) -> new TileWiredModemFull( ModTiles.WIRED_MODEM_FULL, blockPos, blockState ) );
public static final BlockEntityType<TileCable> CABLE = ofBlock( ModBlocks.CABLE, "cable",
( blockPos, blockState ) -> new TileCable( ModTiles.CABLE, blockPos, blockState ) );
public static final BlockEntityType<TileWirelessModem> WIRELESS_MODEM_NORMAL = ofBlock( ModBlocks.WIRELESS_MODEM_NORMAL,
"wireless_modem_normal",
f -> new TileWirelessModem( f, false ) );
public static final BlockEntityType<TileWirelessModem> WIRELESS_MODEM_ADVANCED = ofBlock( () -> ModBlocks.WIRELESS_MODEM_ADVANCED,
( blockPos, blockState ) -> new TileWirelessModem( ModTiles.WIRELESS_MODEM_NORMAL, false, blockPos, blockState ) );
public static final BlockEntityType<TileWirelessModem> WIRELESS_MODEM_ADVANCED = ofBlock( ModBlocks.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,
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 final ScreenHandlerType<ContainerComputer> COMPUTER = registerExtended( "computer", ContainerComputer::new );
public static final ScreenHandlerType<ContainerPocketComputer> POCKET_COMPUTER = registerExtended( "pocket_computer", ContainerPocketComputer::new );
public static final ScreenHandlerType<ContainerTurtle> TURTLE = registerExtended( "turtle", ContainerTurtle::new );
public static final ScreenHandlerType<ContainerComputerBase> COMPUTER = ContainerData.toType( new Identifier( MOD_ID, "computer" ), ModContainers.COMPUTER, ComputerContainerData::new, ComputerMenuWithoutInventory::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<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<ContainerPrinter> PRINTER = registerSimple( "printer", ContainerPrinter::new );
public static final ScreenHandlerType<ContainerHeldItem> PRINTOUT = registerExtended( "printout", ContainerHeldItem::createPrintout );
public static final ScreenHandlerType<ContainerViewComputer> VIEW_COMPUTER = registerExtended( "view_computer", ContainerViewComputer::new );
public static final ScreenHandlerType<ContainerHeldItem> PRINTOUT = ContainerData.toType( new Identifier( MOD_ID, "printout" ), HeldItemContainerData::new, ContainerHeldItem::createPrintout );
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,
ScreenHandlerRegistry.SimpleClientHandlerFactory<T> 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

View File

@ -35,7 +35,7 @@ public final class Peripherals
@Nullable
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

View File

@ -3,12 +3,8 @@
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
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.server.MinecraftServer;
import net.minecraft.server.world.ServerWorld;
@ -17,23 +13,14 @@ import net.minecraft.world.World;
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 )
{
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
public ScreenHandler createMenu( int id, @Nonnull PlayerInventory player, @Nonnull PlayerEntity entity )
{
return new ContainerViewComputer( id, computer );
return new ContainerViewComputer( id, player, computer );
}
} );
return 1;

View File

@ -56,18 +56,17 @@ public enum UserLevel implements Predicate<ServerCommandSource>
public boolean test( ServerCommandSource source )
{
if( this == ANYONE ) return true;
if( this == OWNER || this == OWNER_OP )
{
MinecraftServer server = source.getServer();
Entity sender = source.getEntity();
if( server.isSinglePlayer() && sender instanceof PlayerEntity &&
((PlayerEntity) sender).getGameProfile().getName().equalsIgnoreCase( server.getServerModName() ) )
{
return true;
}
}
if( this == OWNER ) return isOwner( source );
if( this == OWNER_OP && isOwner( source ) ) return true;
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.hit.BlockHitResult;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.BlockView;
import net.minecraft.world.World;
import javax.annotation.Nonnull;
@ -35,6 +34,11 @@ public abstract class BlockGeneric extends BlockWithEntity
this.type = type;
}
public BlockEntityType<? extends TileGeneric> getType()
{
return type;
}
@Override
public BlockRenderType getRenderType( BlockState state )
{
@ -94,8 +98,12 @@ public abstract class BlockGeneric extends BlockWithEntity
@Nullable
@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();
}
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 )
{
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.shared.network.client.TerminalState;
import net.minecraft.nbt.NbtCompound;
import java.util.concurrent.atomic.AtomicBoolean;
import net.minecraft.nbt.NbtCompound;

View File

@ -21,9 +21,9 @@ import javax.annotation.Nonnull;
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()

View File

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

View File

@ -6,11 +6,13 @@
package dan200.computercraft.shared.computer.blocks;
import dan200.computercraft.shared.ComputerCraftRegistry;
import dan200.computercraft.shared.computer.core.ComputerFamily;
import dan200.computercraft.shared.computer.core.ComputerState;
import dan200.computercraft.shared.computer.items.ComputerItemFactory;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.block.entity.BlockEntityType;
import net.minecraft.item.ItemPlacementContext;
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.EnumProperty;
import net.minecraft.state.property.Properties;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import javax.annotation.Nonnull;
@ -56,4 +59,21 @@ public class BlockComputer extends BlockComputerBase<TileComputer>
{
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 net.minecraft.block.BlockState;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.block.entity.BlockEntityTicker;
import net.minecraft.block.entity.BlockEntityType;
import net.minecraft.entity.LivingEntity;
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() );
}
}
@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.core.ComputerFamily;
import dan200.computercraft.shared.computer.core.ServerComputer;
import net.minecraft.block.BlockState;
import net.minecraft.block.entity.BlockEntityType;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.server.MinecraftServer;
@ -19,6 +20,7 @@ import net.minecraft.server.world.ServerWorld;
import net.minecraft.text.LiteralText;
import net.minecraft.text.Text;
import net.minecraft.text.TranslatableText;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec2f;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.GameRules;
@ -32,9 +34,9 @@ public class TileCommandComputer extends TileComputer
{
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();
}

View File

@ -8,15 +8,17 @@ package dan200.computercraft.shared.computer.blocks;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.core.computer.ComputerSide;
import dan200.computercraft.shared.ComputerCraftRegistry;
import dan200.computercraft.shared.computer.core.ComputerFamily;
import dan200.computercraft.shared.computer.core.ComputerState;
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.entity.BlockEntityType;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.screen.ScreenHandler;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import javax.annotation.Nonnull;
@ -26,9 +28,9 @@ public class TileComputer extends TileComputerBase
{
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 )
@ -103,7 +105,7 @@ public class TileComputer extends TileComputerBase
@Override
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.Hand;
import net.minecraft.util.Nameable;
import net.minecraft.util.Tickable;
import net.minecraft.util.hit.BlockHitResult;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
@ -47,7 +46,7 @@ import javax.annotation.Nonnull;
import javax.annotation.Nullable;
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
{
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 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;
}
@ -271,44 +270,40 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT
}
}
@Override
public void tick()
public void serverTick()
{
if( !getWorld().isClient )
ServerComputer computer = createServerComputer();
if( computer == null )
{
ServerComputer computer = createServerComputer();
if( computer == null )
{
return;
}
return;
}
// If the computer isn't on and should be, then turn it on
if( startOn || (fresh && on) )
{
computer.turnOn();
startOn = false;
}
// If the computer isn't on and should be, then turn it on
if( startOn || fresh && on )
{
computer.turnOn();
startOn = false;
}
computer.keepAlive();
computer.keepAlive();
fresh = false;
computerID = computer.getID();
label = computer.getLabel();
on = computer.isOn();
fresh = false;
computerID = computer.getID();
label = computer.getLabel();
on = computer.isOn();
if( computer.hasOutputChanged() )
{
updateOutput();
}
if( computer.hasOutputChanged() )
{
updateOutput();
}
// Update the block state if needed. We don't fire a block update intentionally,
// as this only really is needed on the client side.
updateBlockState( computer.getState() );
// Update the block state if needed. We don't fire a block update intentionally,
// as this only really is needed on the client side.
updateBlockState( computer.getState() );
if( computer.hasOutputChanged() )
{
updateOutput();
}
if( computer.hasOutputChanged() )
{
updateOutput();
}
}
@ -325,9 +320,9 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT
protected abstract void updateBlockState( ComputerState newState );
@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
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.putBoolean( NBT_ON, on );
return super.writeNbt( nbt );
}
@ -362,7 +356,7 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT
private void updateInput( BlockPos neighbour )
{
if( getWorld() == null || getWorld().isClient )
if( getWorld() == null || this.world.isClient )
{
return;
}
@ -384,12 +378,12 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT
}
// If the position is not any adjacent one, update all inputs.
updateInput();
this.updateInput();
}
private void updateInput( Direction dir )
{
if( getWorld() == null || getWorld().isClient )
if( getWorld() == null || this.world.isClient )
{
return;
}
@ -412,7 +406,7 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT
@Override
public final void setComputerID( int id )
{
if( getWorld().isClient || computerID == id )
if( this.world.isClient || computerID == id )
{
return;
}
@ -437,7 +431,7 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT
@Override
public final void setLabel( String label )
{
if( getWorld().isClient || Objects.equals( this.label, label ) )
if( this.world.isClient || Objects.equals( this.label, label ) )
{
return;
}

View File

@ -12,13 +12,15 @@ import javax.annotation.Nonnull;
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 texture;
ComputerState( String name )
ComputerState( String name, String texture )
{
this.name = name;
this.texture = texture;
}
@Nonnull
@ -33,4 +35,10 @@ public enum ComputerState implements StringIdentifiable
{
return name;
}
@Nonnull
public String getTexture()
{
return texture;
}
}

View File

@ -6,13 +6,19 @@
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.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.
*/
@FunctionalInterface
//@FunctionalInterface
public interface IContainerComputer
{
/**
@ -31,8 +37,37 @@ public interface IContainerComputer
* @return This container's input.
*/
@Nonnull
default InputState getInput()
{
return new InputState( this );
}
InputState getInput();
/**
* 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;
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.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 net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.network.PacketByteBuf;
import net.minecraft.screen.ScreenHandler;
import net.minecraft.screen.ScreenHandlerType;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.TranslatableText;
import javax.annotation.Nonnull;
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;
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 IComputer computer;
private final ComputerFamily family;
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,
id,
x -> true,
getComputer( player, new ComputerContainerData( new PacketByteBuf( packetByteBuf.copy() ) ) ),
new ComputerContainerData( new PacketByteBuf( packetByteBuf.copy() ) ).getFamily() );
getComputer( player, data ),
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 )
{
super( type, id );
@ -93,4 +110,121 @@ public class ContainerComputerBase extends ScreenHandler implements IContainerCo
{
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 net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.network.PacketByteBuf;
import javax.annotation.Nonnull;
public class ContainerViewComputer extends ContainerComputerBase
public class ContainerViewComputer extends ComputerMenuWithoutInventory
{
private final int width;
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;
}
public ContainerViewComputer( int id, PlayerInventory player, PacketByteBuf packetByteBuf )
public ContainerViewComputer( int id, PlayerInventory player, ViewComputerContainerData data )
{
super( ComputerCraftRegistry.ModContainers.VIEW_COMPUTER, id, player, packetByteBuf );
ViewComputerContainerData data = new ViewComputerContainerData( new PacketByteBuf( packetByteBuf.copy() ) );
super( ComputerCraftRegistry.ModContainers.VIEW_COMPUTER, id, player, data );
width = data.getWidth();
height = data.getHeight();
}

View File

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

View File

@ -45,7 +45,7 @@ public abstract class ComputerFamilyRecipe extends ComputerConvertRecipe
ComputerFamily family = RecipeUtil.getFamily( json, "family" );
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 );
}

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