1
0
mirror of https://github.com/SquidDev-CC/CC-Tweaked synced 2025-11-04 15:43:00 +00:00

Compare commits

...

13 Commits

Author SHA1 Message Date
SquidDev
3d7a81696d Merge branch 'mc-1.14.x' into mc-1.15.x 2020-04-23 10:58:30 +01:00
SquidDev
33260a7747 Merge branch 'mc-1.14.x' into mc-1.15.x 2020-04-23 10:04:37 +01:00
SquidDev
af40f5ae5c Add back CraftTweaker integration 2020-04-22 11:11:02 +01:00
SquidDev
759d02a249 Some post-merge cleanup 2020-04-22 11:04:29 +01:00
SquidDev
d7729337ac Merge branch 'mc-1.14.x' into mc-1.15.x 2020-04-22 10:39:00 +01:00
Jonathan Coates
f106733d71 Redo how http block/allow lists are stored. (#396)
This replaces the allow/block lists with a series of rules. Each rule
takes the form

    [[http.rules]]
    host = "127.0.0.0/8"
    action = "block"

This is pretty much the same as the previous config style, in that hosts
may be domains, wildcards or in CIDR notation. However, they may also be
mixed, so you could allow a specific IP, and then block all others.
2020-04-22 08:58:21 +01:00
SquidDev
2360a6e951 Remove several deprecated methods 2020-04-10 21:26:11 +01:00
SquidDev
f4f71185ae Add back map rendering
Closes #357. Also bump Forge and mappings versions - it includes a
couple of bug fixes we need.
2020-04-10 21:17:31 +01:00
SquidDev
649acbae1c Add back item frame rendering for printouts
Also fix a recipe loading issue, due to capitalisation of enums
2020-01-30 10:07:47 +00:00
SquidDev
05eada427b Add back custom block highlights
Also bump Forge version to enable this
2020-01-30 09:00:37 +00:00
SquidDev
f3a330e330 Normalise enums to use SHOUTY_CASE
PascalCase is more .NET than Java
2020-01-28 22:28:48 +00:00
SquidDev
044d2b2b06 Some API cleanup
- Remove *Stream methods on IMount/IWritableMount, and make the channel
   ones the primary.
 - Fix location of AbstractTurtleUpgrade
 - Make IComputerAccess.getAvailablePeripheral and .getMainThreadMonitor
   mandatory.
 - IComputerAccess throws a specialised NotAttachedException
2020-01-28 22:23:43 +00:00
SquidDev
fb440b0d2e Update to 1.15
Most of the port is pretty simple. The main problems are regarding
changes to Minecraft's rendering system.

 - Remove several rendering tweaks until Forge's compatibility it
   brought up-to-date
    - Map rendering for pocket computers and printouts
    - Item frame rendering for printouts
    - Custom block outlines for monitors and cables/wired modems
    - Custom breaking progress for cables/wired modems

 - Turtle "Dinnerbone" rendering is currently broken, as normals are not
   correctly transformed.

 - Rewrite FixedWidthFontRenderer to to the buffer in a single sweep.
   In order to do this, the term_font now also bundles a "background"
   section, which is just a blank region of the screen.

 - Render monitors using a VBO instead of a call list. I haven't
   compared performance yet, but it manages to render a 6x5 array of
   _static_ monitors at almost 60fps, which seems pretty reasonable.
2020-01-24 09:12:29 +00:00
147 changed files with 1551 additions and 2411 deletions

View File

@@ -9,7 +9,7 @@ buildscript {
} }
dependencies { dependencies {
classpath 'com.google.code.gson:gson:2.8.1' classpath 'com.google.code.gson:gson:2.8.1'
classpath 'net.minecraftforge.gradle:ForgeGradle:3.0.154' classpath 'net.minecraftforge.gradle:ForgeGradle:3.0.169'
classpath 'net.sf.proguard:proguard-gradle:6.1.0beta2' classpath 'net.sf.proguard:proguard-gradle:6.1.0beta2'
classpath 'org.ajoberstar.grgit:grgit-gradle:3.0.0' classpath 'org.ajoberstar.grgit:grgit-gradle:3.0.0'
} }
@@ -47,7 +47,7 @@ minecraft {
} }
server { server {
workingDirectory project.file('run') workingDirectory project.file("run/server-${mc_version}")
property 'forge.logging.markers', 'SCAN,REGISTRIES,REGISTRYDUMP' property 'forge.logging.markers', 'SCAN,REGISTRIES,REGISTRYDUMP'
property 'forge.logging.console.level', 'debug' property 'forge.logging.console.level', 'debug'
@@ -99,10 +99,10 @@ dependencies {
minecraft "net.minecraftforge:forge:${mc_version}-${forge_version}" minecraft "net.minecraftforge:forge:${mc_version}-${forge_version}"
compileOnly fg.deobf("mezz.jei:jei-1.14.4:6.0.0.27:api") compileOnly fg.deobf("mezz.jei:jei-1.15.2:6.0.0.3:api")
compileOnly fg.deobf("com.blamejared.crafttweaker:CraftTweaker-1.14.4:5.0.1.162") compileOnly fg.deobf("com.blamejared.crafttweaker:CraftTweaker-1.15.2:6.0.0.9")
runtimeOnly fg.deobf("mezz.jei:jei-1.14.4:6.0.0.27") runtimeOnly fg.deobf("mezz.jei:jei-1.15.2:6.0.0.3")
shade 'org.squiddev:Cobalt:0.5.1-SNAPSHOT' shade 'org.squiddev:Cobalt:0.5.1-SNAPSHOT'
@@ -373,7 +373,7 @@ curseforge {
apiKey = project.hasProperty('curseForgeApiKey') ? project.curseForgeApiKey : '' apiKey = project.hasProperty('curseForgeApiKey') ? project.curseForgeApiKey : ''
project { project {
id = '282001' id = '282001'
releaseType = 'release' releaseType = 'alpha'
changelog = "Release notes can be found on the GitHub repository (https://github.com/SquidDev-CC/CC-Tweaked/releases/tag/v${mc_version}-${mod_version})." changelog = "Release notes can be found on the GitHub repository (https://github.com/SquidDev-CC/CC-Tweaked/releases/tag/v${mc_version}-${mod_version})."
relations { relations {
@@ -451,7 +451,7 @@ githubRelease {
.takeWhile { it != 'Type "help changelog" to see the full version history.' } .takeWhile { it != 'Type "help changelog" to see the full version history.' }
.join("\n").trim() .join("\n").trim()
} }
prerelease false prerelease true
} }
def uploadTasks = ["uploadArchives", "curseforge", "githubRelease"] def uploadTasks = ["uploadArchives", "curseforge", "githubRelease"]

View File

@@ -10,6 +10,10 @@
<property name="file" value="config/checkstyle/suppressions.xml" /> <property name="file" value="config/checkstyle/suppressions.xml" />
</module> </module>
<module name="BeforeExecutionExclusionFileFilter">
<property name="fileNamePattern" value="render_old"/>
</module>
<module name="TreeWalker"> <module name="TreeWalker">
<!-- Annotations --> <!-- Annotations -->
<module name="AnnotationLocation" /> <module name="AnnotationLocation" />

View File

@@ -2,6 +2,6 @@
mod_version=1.87.0 mod_version=1.87.0
# Minecraft properties (update mods.toml when changing) # Minecraft properties (update mods.toml when changing)
mc_version=1.14.4 mc_version=1.15.2
forge_version=28.1.71 forge_version=31.1.41
mappings_version=20191123-1.14.3 mappings_version=20200410-1.15.1

View File

@@ -6,7 +6,7 @@
package dan200.computercraft; package dan200.computercraft;
import dan200.computercraft.api.turtle.event.TurtleAction; import dan200.computercraft.api.turtle.event.TurtleAction;
import dan200.computercraft.core.apis.AddressPredicate; import dan200.computercraft.core.apis.http.AddressRule;
import dan200.computercraft.shared.Config; import dan200.computercraft.shared.Config;
import dan200.computercraft.shared.computer.blocks.BlockComputer; import dan200.computercraft.shared.computer.blocks.BlockComputer;
import dan200.computercraft.shared.computer.core.ClientComputerRegistry; import dan200.computercraft.shared.computer.core.ClientComputerRegistry;
@@ -39,8 +39,13 @@ import org.apache.logging.log4j.Logger;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.util.Collections;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@Mod( ComputerCraft.MOD_ID ) @Mod( ComputerCraft.MOD_ID )
public final class ComputerCraft public final class ComputerCraft
@@ -50,8 +55,8 @@ public final class ComputerCraft
public static final int DATAFIXER_VERSION = 0; public static final int DATAFIXER_VERSION = 0;
// Configuration options // Configuration options
public static final String[] DEFAULT_HTTP_WHITELIST = new String[] { "*" }; public static final String[] DEFAULT_HTTP_ALLOW = new String[] { "*" };
public static final String[] DEFAULT_HTTP_BLACKLIST = new String[] { public static final String[] DEFAULT_HTTP_DENY = new String[] {
"127.0.0.0/8", "127.0.0.0/8",
"10.0.0.0/8", "10.0.0.0/8",
"172.16.0.0/12", "172.16.0.0/12",
@@ -71,10 +76,12 @@ public final class ComputerCraft
public static long maxMainGlobalTime = TimeUnit.MILLISECONDS.toNanos( 10 ); public static long maxMainGlobalTime = TimeUnit.MILLISECONDS.toNanos( 10 );
public static long maxMainComputerTime = TimeUnit.MILLISECONDS.toNanos( 5 ); public static long maxMainComputerTime = TimeUnit.MILLISECONDS.toNanos( 5 );
public static boolean http_enable = true; public static boolean httpEnabled = true;
public static boolean http_websocket_enable = true; public static boolean httpWebsocketEnabled = true;
public static AddressPredicate http_whitelist = new AddressPredicate( DEFAULT_HTTP_WHITELIST ); public static List<AddressRule> httpRules = Collections.unmodifiableList( Stream.concat(
public static AddressPredicate http_blacklist = new AddressPredicate( DEFAULT_HTTP_BLACKLIST ); Stream.of( DEFAULT_HTTP_DENY ).map( x -> AddressRule.parse( x, AddressRule.Action.DENY ) ).filter( Objects::nonNull ),
Stream.of( DEFAULT_HTTP_ALLOW ).map( x -> AddressRule.parse( x, AddressRule.Action.ALLOW ) ).filter( Objects::nonNull )
).collect( Collectors.toList() ) );
public static int httpTimeout = 30000; public static int httpTimeout = 30000;
public static int httpMaxRequests = 16; public static int httpMaxRequests = 16;

View File

@@ -112,31 +112,6 @@ public final class ComputerCraftAPI
return getInstance().createResourceMount( domain, subPath ); return getInstance().createResourceMount( domain, subPath );
} }
/**
* Creates a file system mount to a resource folder, and returns it.
*
* Use in conjunction with {@link IComputerAccess#mount} or {@link IComputerAccess#mountWritable} to mount a
* resource folder onto a computer's file system.
*
* The files in this mount will be a combination of files in all mod jar, and data packs that contain
* resources with the same domain and path.
*
* @param klass The mod class to which the files belong.
* @param domain The domain under which to look for resources. eg: "mymod".
* @param subPath The subPath under which to look for resources. eg: "lua/myfiles".
* @return The mount, or {@code null} if it could be created for some reason.
* @see IComputerAccess#mount(String, IMount)
* @see IComputerAccess#mountWritable(String, IWritableMount)
* @see IMount
* @deprecated Use {@link #createResourceMount(String, String)} instead.
*/
@Nullable
@Deprecated
public static IMount createResourceMount( Class<?> klass, @Nonnull String domain, @Nonnull String subPath )
{
return getInstance().createResourceMount( domain, subPath );
}
/** /**
* Registers a peripheral provider to convert blocks into {@link IPeripheral} implementations. * Registers a peripheral provider to convert blocks into {@link IPeripheral} implementations.
* *

View File

@@ -0,0 +1,61 @@
/*
* This file is part of the public ComputerCraft API - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only.
* For help using the API, and posting your mods, visit the forums at computercraft.info.
*/
package dan200.computercraft.api.client;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.TransformationMatrix;
import net.minecraft.client.renderer.model.IBakedModel;
import net.minecraft.client.renderer.model.ModelManager;
import net.minecraft.client.renderer.model.ModelResourceLocation;
import net.minecraft.item.ItemStack;
import javax.annotation.Nonnull;
import java.util.Objects;
/**
* A model to render, combined with a transformation matrix to apply.
*/
public final class TransformedModel
{
private final IBakedModel model;
private final TransformationMatrix matrix;
public TransformedModel( @Nonnull IBakedModel model, @Nonnull TransformationMatrix matrix )
{
this.model = Objects.requireNonNull( model );
this.matrix = Objects.requireNonNull( matrix );
}
public TransformedModel( @Nonnull IBakedModel model )
{
this.model = Objects.requireNonNull( model );
this.matrix = TransformationMatrix.identity();
}
public static TransformedModel of( @Nonnull ModelResourceLocation location )
{
ModelManager modelManager = Minecraft.getInstance().getModelManager();
return new TransformedModel( modelManager.getModel( location ) );
}
public static TransformedModel of( @Nonnull ItemStack item, @Nonnull TransformationMatrix transform )
{
IBakedModel model = Minecraft.getInstance().getItemRenderer().getItemModelMesher().getItemModel( item );
return new TransformedModel( model, transform );
}
@Nonnull
public IBakedModel getModel()
{
return model;
}
@Nonnull
public TransformationMatrix getMatrix()
{
return matrix;
}
}

View File

@@ -11,8 +11,6 @@ import net.minecraft.world.World;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel; import java.nio.channels.ReadableByteChannel;
import java.nio.file.attribute.BasicFileAttributes; import java.nio.file.attribute.BasicFileAttributes;
import java.util.List; import java.util.List;
@@ -23,10 +21,10 @@ import java.util.List;
* *
* Ready made implementations of this interface can be created using * Ready made implementations of this interface can be created using
* {@link ComputerCraftAPI#createSaveDirMount(World, String, long)} or * {@link ComputerCraftAPI#createSaveDirMount(World, String, long)} or
* {@link ComputerCraftAPI#createResourceMount(Class, String, String)}, or you're free to implement it yourselves! * {@link ComputerCraftAPI#createResourceMount(String, String)}, or you're free to implement it yourselves!
* *
* @see ComputerCraftAPI#createSaveDirMount(World, String, long) * @see ComputerCraftAPI#createSaveDirMount(World, String, long)
* @see ComputerCraftAPI#createResourceMount(Class, String, String) * @see ComputerCraftAPI#createResourceMount(String, String)
* @see IComputerAccess#mount(String, IMount) * @see IComputerAccess#mount(String, IMount)
* @see IWritableMount * @see IWritableMount
*/ */
@@ -68,18 +66,6 @@ public interface IMount
*/ */
long getSize( @Nonnull String path ) throws IOException; long getSize( @Nonnull String path ) throws IOException;
/**
* Opens a file with a given path, and returns an {@link InputStream} representing its contents.
*
* @param path A file path in normalised format, relative to the mount location. ie: "programs/myprogram".
* @return A stream representing the contents of the file.
* @throws IOException If the file does not exist, or could not be opened.
* @deprecated Use {@link #openChannelForRead(String)} instead
*/
@Nonnull
@Deprecated
InputStream openForRead( @Nonnull String path ) throws IOException;
/** /**
* Opens a file with a given path, and returns an {@link ReadableByteChannel} representing its contents. * Opens a file with a given path, and returns an {@link ReadableByteChannel} representing its contents.
* *
@@ -90,10 +76,7 @@ public interface IMount
* @throws IOException If the file does not exist, or could not be opened. * @throws IOException If the file does not exist, or could not be opened.
*/ */
@Nonnull @Nonnull
default ReadableByteChannel openChannelForRead( @Nonnull String path ) throws IOException ReadableByteChannel openForRead( @Nonnull String path ) throws IOException;
{
return Channels.newChannel( openForRead( path ) );
}
/** /**
* Get attributes about the given file. * Get attributes about the given file.

View File

@@ -12,7 +12,6 @@ import net.minecraft.world.World;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
import java.nio.channels.Channels;
import java.nio.channels.WritableByteChannel; import java.nio.channels.WritableByteChannel;
import java.util.OptionalLong; import java.util.OptionalLong;
@@ -46,18 +45,6 @@ public interface IWritableMount extends IMount
*/ */
void delete( @Nonnull String path ) throws IOException; void delete( @Nonnull String path ) throws IOException;
/**
* Opens a file with a given path, and returns an {@link OutputStream} for writing to it.
*
* @param path A file path in normalised format, relative to the mount location. ie: "programs/myprogram".
* @return A stream for writing to
* @throws IOException If the file could not be opened for writing.
* @deprecated Use {@link #openChannelForWrite(String)} instead.
*/
@Nonnull
@Deprecated
OutputStream openForWrite( @Nonnull String path ) throws IOException;
/** /**
* Opens a file with a given path, and returns an {@link OutputStream} for writing to it. * Opens a file with a given path, and returns an {@link OutputStream} for writing to it.
* *
@@ -67,22 +54,7 @@ public interface IWritableMount extends IMount
* @throws IOException If the file could not be opened for writing. * @throws IOException If the file could not be opened for writing.
*/ */
@Nonnull @Nonnull
default WritableByteChannel openChannelForWrite( @Nonnull String path ) throws IOException WritableByteChannel openForWrite( @Nonnull String path ) throws IOException;
{
return Channels.newChannel( openForWrite( path ) );
}
/**
* Opens a file with a given path, and returns an {@link OutputStream} for appending to it.
*
* @param path A file path in normalised format, relative to the mount location. ie: "programs/myprogram".
* @return A stream for writing to.
* @throws IOException If the file could not be opened for writing.
* @deprecated Use {@link #openChannelForAppend(String)} instead.
*/
@Nonnull
@Deprecated
OutputStream openForAppend( @Nonnull String path ) throws IOException;
/** /**
* Opens a file with a given path, and returns an {@link OutputStream} for appending to it. * Opens a file with a given path, and returns an {@link OutputStream} for appending to it.
@@ -93,10 +65,7 @@ public interface IWritableMount extends IMount
* @throws IOException If the file could not be opened for writing. * @throws IOException If the file could not be opened for writing.
*/ */
@Nonnull @Nonnull
default WritableByteChannel openChannelForAppend( @Nonnull String path ) throws IOException WritableByteChannel openForAppend( @Nonnull String path ) throws IOException;
{
return Channels.newChannel( openForAppend( path ) );
}
/** /**
* Get the amount of free space on the mount, in bytes. You should decrease this value as the user writes to the * Get the amount of free space on the mount, in bytes. You should decrease this value as the user writes to the

View File

@@ -79,7 +79,7 @@ public interface IMedia
* @see IMount * @see IMount
* @see dan200.computercraft.api.filesystem.IWritableMount * @see dan200.computercraft.api.filesystem.IWritableMount
* @see dan200.computercraft.api.ComputerCraftAPI#createSaveDirMount(World, String, long) * @see dan200.computercraft.api.ComputerCraftAPI#createSaveDirMount(World, String, long)
* @see dan200.computercraft.api.ComputerCraftAPI#createResourceMount(Class, String, String) * @see dan200.computercraft.api.ComputerCraftAPI#createResourceMount(String, String)
*/ */
@Nullable @Nullable
default IMount createDataMount( @Nonnull ItemStack stack, @Nonnull World world ) default IMount createDataMount( @Nonnull ItemStack stack, @Nonnull World world )

View File

@@ -14,7 +14,6 @@ import net.minecraft.world.World;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.util.Collections;
import java.util.Map; import java.util.Map;
/** /**
@@ -31,9 +30,9 @@ public interface IComputerAccess
* @param mount The mount object to mount on the computer. * @param mount The mount object to mount on the computer.
* @return The location on the computer's file system where you the mount mounted, or {@code null} if there was already a * @return The location on the computer's file system where you the mount mounted, or {@code null} if there was already a
* file in the desired location. Store this value if you wish to unmount the mount later. * file in the desired location. Store this value if you wish to unmount the mount later.
* @throws RuntimeException If the peripheral has been detached. * @throws NotAttachedException If the peripheral has been detached.
* @see ComputerCraftAPI#createSaveDirMount(World, String, long) * @see ComputerCraftAPI#createSaveDirMount(World, String, long)
* @see ComputerCraftAPI#createResourceMount(Class, String, String) * @see ComputerCraftAPI#createResourceMount(String, String)
* @see #mount(String, IMount, String) * @see #mount(String, IMount, String)
* @see #mountWritable(String, IWritableMount) * @see #mountWritable(String, IWritableMount)
* @see #unmount(String) * @see #unmount(String)
@@ -53,9 +52,9 @@ public interface IComputerAccess
* @param driveName A custom name to give for this mount location, as returned by {@code fs.getDrive()}. * @param driveName A custom name to give for this mount location, as returned by {@code fs.getDrive()}.
* @return The location on the computer's file system where you the mount mounted, or {@code null} if there was already a * @return The location on the computer's file system where you the mount mounted, or {@code null} if there was already a
* file in the desired location. Store this value if you wish to unmount the mount later. * file in the desired location. Store this value if you wish to unmount the mount later.
* @throws RuntimeException If the peripheral has been detached. * @throws NotAttachedException If the peripheral has been detached.
* @see ComputerCraftAPI#createSaveDirMount(World, String, long) * @see ComputerCraftAPI#createSaveDirMount(World, String, long)
* @see ComputerCraftAPI#createResourceMount(Class, String, String) * @see ComputerCraftAPI#createResourceMount(String, String)
* @see #mount(String, IMount) * @see #mount(String, IMount)
* @see #mountWritable(String, IWritableMount) * @see #mountWritable(String, IWritableMount)
* @see #unmount(String) * @see #unmount(String)
@@ -71,9 +70,9 @@ public interface IComputerAccess
* @param mount The mount object to mount on the computer. * @param mount The mount object to mount on the computer.
* @return The location on the computer's file system where you the mount mounted, or null if there was already a * @return The location on the computer's file system where you the mount mounted, or null if there was already a
* file in the desired location. Store this value if you wish to unmount the mount later. * file in the desired location. Store this value if you wish to unmount the mount later.
* @throws RuntimeException If the peripheral has been detached. * @throws NotAttachedException If the peripheral has been detached.
* @see ComputerCraftAPI#createSaveDirMount(World, String, long) * @see ComputerCraftAPI#createSaveDirMount(World, String, long)
* @see ComputerCraftAPI#createResourceMount(Class, String, String) * @see ComputerCraftAPI#createResourceMount(String, String)
* @see #mount(String, IMount) * @see #mount(String, IMount)
* @see #unmount(String) * @see #unmount(String)
* @see IMount * @see IMount
@@ -92,9 +91,9 @@ public interface IComputerAccess
* @param driveName A custom name to give for this mount location, as returned by {@code fs.getDrive()}. * @param driveName A custom name to give for this mount location, as returned by {@code fs.getDrive()}.
* @return The location on the computer's file system where you the mount mounted, or null if there was already a * @return The location on the computer's file system where you the mount mounted, or null if there was already a
* file in the desired location. Store this value if you wish to unmount the mount later. * file in the desired location. Store this value if you wish to unmount the mount later.
* @throws RuntimeException If the peripheral has been detached. * @throws NotAttachedException If the peripheral has been detached.
* @see ComputerCraftAPI#createSaveDirMount(World, String, long) * @see ComputerCraftAPI#createSaveDirMount(World, String, long)
* @see ComputerCraftAPI#createResourceMount(Class, String, String) * @see ComputerCraftAPI#createResourceMount(String, String)
* @see #mount(String, IMount) * @see #mount(String, IMount)
* @see #unmount(String) * @see #unmount(String)
* @see IMount * @see IMount
@@ -114,8 +113,8 @@ public interface IComputerAccess
* @param location The desired location in the computers file system of the directory to unmount. * @param location The desired location in the computers file system of the directory to unmount.
* This must be the location of a directory previously mounted by {@link #mount(String, IMount)} or * This must be the location of a directory previously mounted by {@link #mount(String, IMount)} or
* {@link #mountWritable(String, IWritableMount)}, as indicated by their return value. * {@link #mountWritable(String, IWritableMount)}, as indicated by their return value.
* @throws RuntimeException If the peripheral has been detached. * @throws NotAttachedException If the peripheral has been detached.
* @throws RuntimeException If the mount does not exist, or was mounted by another peripheral. * @throws IllegalStateException If the mount does not exist, or was mounted by another peripheral.
* @see #mount(String, IMount) * @see #mount(String, IMount)
* @see #mountWritable(String, IWritableMount) * @see #mountWritable(String, IWritableMount)
*/ */
@@ -146,7 +145,7 @@ public interface IComputerAccess
* to lua data types in the same fashion as the return values of IPeripheral.callMethod(). * to lua data types in the same fashion as the return values of IPeripheral.callMethod().
* *
* You may supply {@code null} to indicate that no arguments are to be supplied. * You may supply {@code null} to indicate that no arguments are to be supplied.
* @throws RuntimeException If the peripheral has been detached. * @throws NotAttachedException If the peripheral has been detached.
* @see IPeripheral#callMethod * @see IPeripheral#callMethod
*/ */
void queueEvent( @Nonnull String event, @Nullable Object[] arguments ); void queueEvent( @Nonnull String event, @Nullable Object[] arguments );
@@ -159,7 +158,7 @@ public interface IComputerAccess
* which peripheral the event came. * which peripheral the event came.
* *
* @return A string unique to the computer, but not globally. * @return A string unique to the computer, but not globally.
* @throws RuntimeException If the peripheral has been detached. * @throws NotAttachedException If the peripheral has been detached.
*/ */
@Nonnull @Nonnull
String getAttachmentName(); String getAttachmentName();
@@ -170,14 +169,12 @@ public interface IComputerAccess
* This may include other peripherals on the wired network or peripherals on other sides of the computer. * This may include other peripherals on the wired network or peripherals on other sides of the computer.
* *
* @return All reachable peripherals * @return All reachable peripherals
* @throws NotAttachedException If the peripheral has been detached.
* @see #getAttachmentName() * @see #getAttachmentName()
* @see #getAvailablePeripheral(String) * @see #getAvailablePeripheral(String)
*/ */
@Nonnull @Nonnull
default Map<String, IPeripheral> getAvailablePeripherals() Map<String, IPeripheral> getAvailablePeripherals();
{
return Collections.emptyMap();
}
/** /**
* Get a reachable peripheral with the given attachment name. This is a equivalent to * Get a reachable peripheral with the given attachment name. This is a equivalent to
@@ -188,10 +185,7 @@ public interface IComputerAccess
* @see #getAvailablePeripherals() * @see #getAvailablePeripherals()
*/ */
@Nullable @Nullable
default IPeripheral getAvailablePeripheral( @Nonnull String name ) IPeripheral getAvailablePeripheral( @Nonnull String name );
{
return null;
}
/** /**
* Get a {@link IWorkMonitor} for tasks your peripheral might execute on the main (server) thread. * Get a {@link IWorkMonitor} for tasks your peripheral might execute on the main (server) thread.
@@ -205,10 +199,8 @@ public interface IComputerAccess
* thread. * thread.
* *
* @return The work monitor for the main thread, or {@code null} if this computer does not have one. * @return The work monitor for the main thread, or {@code null} if this computer does not have one.
* @throws NotAttachedException If the peripheral has been detached.
*/ */
@Nullable @Nonnull
default IWorkMonitor getMainThreadMonitor() IWorkMonitor getMainThreadMonitor();
{
return null;
}
} }

View File

@@ -0,0 +1,25 @@
/*
* This file is part of the public ComputerCraft API - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2020. 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.peripheral;
/**
* Thrown when performing operations on {@link IComputerAccess} when the current peripheral is no longer attached to
* the computer.
*/
public class NotAttachedException extends IllegalStateException
{
private static final long serialVersionUID = 1221244785535553536L;
public NotAttachedException()
{
super( "You are not attached to this Computer" );
}
public NotAttachedException( String s )
{
super( s );
}
}

View File

@@ -3,10 +3,8 @@
* Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. * Copyright Daniel Ratcliffe, 2011-2020. 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. * For help using the API, and posting your mods, visit the forums at computercraft.info.
*/ */
package dan200.computercraft.api; package dan200.computercraft.api.turtle;
import dan200.computercraft.api.turtle.ITurtleUpgrade;
import dan200.computercraft.api.turtle.TurtleUpgradeType;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.util.IItemProvider; import net.minecraft.util.IItemProvider;
import net.minecraft.util.ResourceLocation; import net.minecraft.util.ResourceLocation;

View File

@@ -6,10 +6,10 @@
package dan200.computercraft.api.turtle; package dan200.computercraft.api.turtle;
import dan200.computercraft.api.ComputerCraftAPI; import dan200.computercraft.api.ComputerCraftAPI;
import dan200.computercraft.api.client.TransformedModel;
import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.api.peripheral.IPeripheral;
import dan200.computercraft.api.turtle.event.TurtleAttackEvent; import dan200.computercraft.api.turtle.event.TurtleAttackEvent;
import dan200.computercraft.api.turtle.event.TurtleBlockEvent; import dan200.computercraft.api.turtle.event.TurtleBlockEvent;
import net.minecraft.client.renderer.model.IBakedModel;
import net.minecraft.client.renderer.model.ModelResourceLocation; import net.minecraft.client.renderer.model.ModelResourceLocation;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.util.Direction; import net.minecraft.util.Direction;
@@ -18,11 +18,9 @@ import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn; import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.event.entity.player.AttackEntityEvent; import net.minecraftforge.event.entity.player.AttackEntityEvent;
import net.minecraftforge.event.world.BlockEvent; import net.minecraftforge.event.world.BlockEvent;
import org.apache.commons.lang3.tuple.Pair;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import javax.vecmath.Matrix4f;
/** /**
* The primary interface for defining an update for Turtles. A turtle update * The primary interface for defining an update for Turtles. A turtle update
@@ -126,12 +124,11 @@ public interface ITurtleUpgrade
* *
* @param turtle Access to the turtle that the upgrade resides on. This will be null when getting item models! * @param turtle Access to the turtle that the upgrade resides on. This will be null when getting item models!
* @param side Which side of the turtle (left or right) the upgrade resides on. * @param side Which side of the turtle (left or right) the upgrade resides on.
* @return The model that you wish to be used to render your upgrade, and a transformation to apply to it. Returning * @return The model that you wish to be used to render your upgrade.
* a transformation of {@code null} has the same effect as the identify matrix.
*/ */
@Nonnull @Nonnull
@OnlyIn( Dist.CLIENT ) @OnlyIn( Dist.CLIENT )
Pair<IBakedModel, Matrix4f> getModel( @Nullable ITurtleAccess turtle, @Nonnull TurtleSide side ); TransformedModel getModel( @Nullable ITurtleAccess turtle, @Nonnull TurtleSide side );
/** /**
* Called once per tick for each turtle which has the upgrade equipped. * Called once per tick for each turtle which has the upgrade equipped.

View File

@@ -17,70 +17,70 @@ public enum TurtleAnimation
/** /**
* An animation which does nothing. This takes no time to complete. * An animation which does nothing. This takes no time to complete.
* *
* @see #Wait * @see #WAIT
* @see #ShortWait * @see #SHORT_WAIT
*/ */
None, NONE,
/** /**
* Make the turtle move forward. Note that the animation starts from the block <em>behind</em> it, and * Make the turtle move forward. Note that the animation starts from the block <em>behind</em> it, and
* moves into this one. * moves into this one.
*/ */
MoveForward, MOVE_FORWARD,
/** /**
* Make the turtle move backwards. Note that the animation starts from the block <em>in front</em> it, and * Make the turtle move backwards. Note that the animation starts from the block <em>in front</em> it, and
* moves into this one. * moves into this one.
*/ */
MoveBack, MOVE_BACK,
/** /**
* Make the turtle move backwards. Note that the animation starts from the block <em>above</em> it, and * Make the turtle move backwards. Note that the animation starts from the block <em>above</em> it, and
* moves into this one. * moves into this one.
*/ */
MoveUp, MOVE_UP,
/** /**
* Make the turtle move backwards. Note that the animation starts from the block <em>below</em> it, and * Make the turtle move backwards. Note that the animation starts from the block <em>below</em> it, and
* moves into this one. * moves into this one.
*/ */
MoveDown, MOVE_DOWN,
/** /**
* Turn the turtle to the left. Note that the animation starts with the turtle facing <em>right</em>, and * Turn the turtle to the left. Note that the animation starts with the turtle facing <em>right</em>, and
* the turtle turns to face in the current direction. * the turtle turns to face in the current direction.
*/ */
TurnLeft, TURN_LEFT,
/** /**
* Turn the turtle to the left. Note that the animation starts with the turtle facing <em>right</em>, and * Turn the turtle to the left. Note that the animation starts with the turtle facing <em>right</em>, and
* the turtle turns to face in the current direction. * the turtle turns to face in the current direction.
*/ */
TurnRight, TURN_RIGHT,
/** /**
* Swing the tool on the left. * Swing the tool on the left.
*/ */
SwingLeftTool, SWING_LEFT_TOOL,
/** /**
* Swing the tool on the right. * Swing the tool on the right.
*/ */
SwingRightTool, SWING_RIGHT_TOOL,
/** /**
* Wait until the animation has finished, performing no movement. * Wait until the animation has finished, performing no movement.
* *
* @see #ShortWait * @see #SHORT_WAIT
* @see #None * @see #NONE
*/ */
Wait, WAIT,
/** /**
* Wait until the animation has finished, performing no movement. This takes 4 ticks to complete. * Wait until the animation has finished, performing no movement. This takes 4 ticks to complete.
* *
* @see #Wait * @see #WAIT
* @see #None * @see #NONE
*/ */
ShortWait, SHORT_WAIT,
} }

View File

@@ -13,10 +13,10 @@ public enum TurtleSide
/** /**
* The turtle's left side (where the pickaxe usually is on a Wireless Mining Turtle). * The turtle's left side (where the pickaxe usually is on a Wireless Mining Turtle).
*/ */
Left, LEFT,
/** /**
* The turtle's right side (where the modem usually is on a Wireless Mining Turtle). * The turtle's right side (where the modem usually is on a Wireless Mining Turtle).
*/ */
Right, RIGHT,
} }

View File

@@ -16,28 +16,28 @@ public enum TurtleUpgradeType
* A tool is rendered as an item on the side of the turtle, and responds to the {@code turtle.dig()} * A tool is rendered as an item on the side of the turtle, and responds to the {@code turtle.dig()}
* and {@code turtle.attack()} methods (Such as pickaxe or sword on Mining and Melee turtles). * and {@code turtle.attack()} methods (Such as pickaxe or sword on Mining and Melee turtles).
*/ */
Tool, TOOL,
/** /**
* A peripheral adds a special peripheral which is attached to the side of the turtle, * A peripheral adds a special peripheral which is attached to the side of the turtle,
* and can be interacted with the {@code peripheral} API (Such as the modem on Wireless Turtles). * and can be interacted with the {@code peripheral} API (Such as the modem on Wireless Turtles).
*/ */
Peripheral, PERIPHERAL,
/** /**
* An upgrade which provides both a tool and a peripheral. This can be used when you wish * An upgrade which provides both a tool and a peripheral. This can be used when you wish
* your upgrade to also provide methods. For example, a pickaxe could provide methods * your upgrade to also provide methods. For example, a pickaxe could provide methods
* determining whether it can break the given block or not. * determining whether it can break the given block or not.
*/ */
Both; BOTH;
public boolean isTool() public boolean isTool()
{ {
return this == Tool || this == Both; return this == TOOL || this == BOTH;
} }
public boolean isPeripheral() public boolean isPeripheral()
{ {
return this == Peripheral || this == Both; return this == PERIPHERAL || this == BOTH;
} }
} }

View File

@@ -19,10 +19,10 @@ public enum TurtleVerb
/** /**
* The turtle called {@code turtle.dig()}, {@code turtle.digUp()} or {@code turtle.digDown()}. * The turtle called {@code turtle.dig()}, {@code turtle.digUp()} or {@code turtle.digDown()}.
*/ */
Dig, DIG,
/** /**
* The turtle called {@code turtle.attack()}, {@code turtle.attackUp()} or {@code turtle.attackDown()}. * The turtle called {@code turtle.attack()}, {@code turtle.attackUp()} or {@code turtle.attackDown()}.
*/ */
Attack, ATTACK,
} }

View File

@@ -11,20 +11,19 @@ import dan200.computercraft.shared.common.IColouredItem;
import dan200.computercraft.shared.media.items.ItemDisk; import dan200.computercraft.shared.media.items.ItemDisk;
import dan200.computercraft.shared.pocket.items.ItemPocketComputer; import dan200.computercraft.shared.pocket.items.ItemPocketComputer;
import dan200.computercraft.shared.util.Colour; import dan200.computercraft.shared.util.Colour;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.model.IBakedModel; import net.minecraft.client.renderer.model.IBakedModel;
import net.minecraft.client.renderer.model.IUnbakedModel; import net.minecraft.client.renderer.model.IUnbakedModel;
import net.minecraft.client.renderer.model.ModelResourceLocation; import net.minecraft.client.renderer.model.ModelResourceLocation;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats; import net.minecraft.inventory.container.PlayerContainer;
import net.minecraft.util.ResourceLocation; import net.minecraft.util.ResourceLocation;
import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.client.event.ColorHandlerEvent; import net.minecraftforge.client.event.ColorHandlerEvent;
import net.minecraftforge.client.event.ModelBakeEvent; import net.minecraftforge.client.event.ModelBakeEvent;
import net.minecraftforge.client.event.ModelRegistryEvent; import net.minecraftforge.client.event.ModelRegistryEvent;
import net.minecraftforge.client.event.TextureStitchEvent; import net.minecraftforge.client.event.TextureStitchEvent;
import net.minecraftforge.client.model.BasicState;
import net.minecraftforge.client.model.ModelLoader; import net.minecraftforge.client.model.ModelLoader;
import net.minecraftforge.client.model.ModelLoaderRegistry; import net.minecraftforge.client.model.ModelLoaderRegistry;
import net.minecraftforge.client.model.SimpleModelTransform;
import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.Mod;
@@ -71,13 +70,13 @@ public final class ClientRegistry
@SubscribeEvent @SubscribeEvent
public static void registerModels( ModelRegistryEvent event ) public static void registerModels( ModelRegistryEvent event )
{ {
ModelLoaderRegistry.registerLoader( TurtleModelLoader.INSTANCE ); ModelLoaderRegistry.registerLoader( new ResourceLocation( ComputerCraft.MOD_ID, "turtle" ), TurtleModelLoader.INSTANCE );
} }
@SubscribeEvent @SubscribeEvent
public static void onTextureStitchEvent( TextureStitchEvent.Pre event ) public static void onTextureStitchEvent( TextureStitchEvent.Pre event )
{ {
if( event.getMap() != Minecraft.getInstance().getTextureMap() ) return; if( !event.getMap().getTextureLocation().equals( PlayerContainer.LOCATION_BLOCKS_TEXTURE ) ) return;
for( String extra : EXTRA_TEXTURES ) for( String extra : EXTRA_TEXTURES )
{ {
@@ -92,29 +91,18 @@ public final class ClientRegistry
ModelLoader loader = event.getModelLoader(); ModelLoader loader = event.getModelLoader();
Map<ResourceLocation, IBakedModel> registry = event.getModelRegistry(); Map<ResourceLocation, IBakedModel> registry = event.getModelRegistry();
for( String model : EXTRA_MODELS ) for( String modelName : EXTRA_MODELS )
{ {
IBakedModel bakedModel = bake( loader, loader.getUnbakedModel( new ResourceLocation( ComputerCraft.MOD_ID, "item/" + model ) ) ); ResourceLocation location = new ResourceLocation( ComputerCraft.MOD_ID, "item/" + modelName );
IUnbakedModel model = loader.getUnbakedModel( location );
model.getTextures( loader::getUnbakedModel, new HashSet<>() );
if( bakedModel != null ) IBakedModel baked = model.bakeModel( loader, ModelLoader.defaultTextureGetter(), SimpleModelTransform.IDENTITY, location );
if( baked != null )
{ {
registry.put( registry.put( new ModelResourceLocation( new ResourceLocation( ComputerCraft.MOD_ID, modelName ), "inventory" ), baked );
new ModelResourceLocation( new ResourceLocation( ComputerCraft.MOD_ID, model ), "inventory" ),
bakedModel
);
} }
} }
// And load the custom turtle models in too.
registry.put(
new ModelResourceLocation( new ResourceLocation( ComputerCraft.MOD_ID, "turtle_normal" ), "inventory" ),
bake( loader, TurtleModelLoader.INSTANCE.loadModel( new ResourceLocation( ComputerCraft.MOD_ID, "item/turtle_normal" ) ) )
);
registry.put(
new ModelResourceLocation( new ResourceLocation( ComputerCraft.MOD_ID, "turtle_advanced" ), "inventory" ),
bake( loader, TurtleModelLoader.INSTANCE.loadModel( new ResourceLocation( ComputerCraft.MOD_ID, "item/turtle_advanced" ) ) )
);
} }
@SubscribeEvent @SubscribeEvent
@@ -142,7 +130,7 @@ public final class ClientRegistry
case 2: // Light colour case 2: // Light colour
{ {
int light = ItemPocketComputer.getLightState( stack ); int light = ItemPocketComputer.getLightState( stack );
return light == -1 ? Colour.Black.getHex() : light; return light == -1 ? Colour.BLACK.getHex() : light;
} }
} }
}, ComputerCraft.Items.pocketComputerNormal, ComputerCraft.Items.pocketComputerAdvanced ); }, ComputerCraft.Items.pocketComputerNormal, ComputerCraft.Items.pocketComputerAdvanced );
@@ -153,15 +141,4 @@ public final class ClientRegistry
ComputerCraft.Blocks.turtleNormal, ComputerCraft.Blocks.turtleAdvanced ComputerCraft.Blocks.turtleNormal, ComputerCraft.Blocks.turtleAdvanced
); );
} }
private static IBakedModel bake( ModelLoader loader, IUnbakedModel model )
{
model.getTextures( loader::getUnbakedModel, new HashSet<>() );
return model.bake(
loader,
ModelLoader.defaultTextureGetter(),
new BasicState( model.getDefaultState(), false ), DefaultVertexFormats.BLOCK
);
}
} }

View File

@@ -5,15 +5,15 @@
*/ */
package dan200.computercraft.client.gui; package dan200.computercraft.client.gui;
import com.mojang.blaze3d.platform.GlStateManager; import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.IVertexBuilder;
import dan200.computercraft.client.FrameInfo; import dan200.computercraft.client.FrameInfo;
import dan200.computercraft.core.terminal.Terminal; import dan200.computercraft.core.terminal.Terminal;
import dan200.computercraft.core.terminal.TextBuffer; import dan200.computercraft.core.terminal.TextBuffer;
import dan200.computercraft.shared.util.Colour; import dan200.computercraft.shared.util.Colour;
import dan200.computercraft.shared.util.Palette; import dan200.computercraft.shared.util.Palette;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.BufferBuilder; import net.minecraft.client.renderer.*;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats; import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.client.renderer.vertex.VertexFormat; import net.minecraft.client.renderer.vertex.VertexFormat;
import net.minecraft.util.ResourceLocation; import net.minecraft.util.ResourceLocation;
@@ -24,21 +24,10 @@ import javax.annotation.Nullable;
public final class FixedWidthFontRenderer public final class FixedWidthFontRenderer
{ {
private static final Matrix4f IDENTITY = TransformationMatrix.identity().getMatrix();
private static final ResourceLocation FONT = new ResourceLocation( "computercraft", "textures/gui/term_font.png" ); private static final ResourceLocation FONT = new ResourceLocation( "computercraft", "textures/gui/term_font.png" );
/**
* Like {@link DefaultVertexFormats#POSITION_TEX_COLOR}, but flipped. This is backported from 1.15, hence the
* custom format.
*/
public static final VertexFormat POSITION_COLOR_TEX = new VertexFormat();
static
{
POSITION_COLOR_TEX.addElement( DefaultVertexFormats.POSITION_3F );
POSITION_COLOR_TEX.addElement( DefaultVertexFormats.COLOR_4UB );
POSITION_COLOR_TEX.addElement( DefaultVertexFormats.TEX_2F );
}
public static final int FONT_HEIGHT = 9; public static final int FONT_HEIGHT = 9;
public static final int FONT_WIDTH = 6; public static final int FONT_WIDTH = 6;
public static final float WIDTH = 256.0f; public static final float WIDTH = 256.0f;
@@ -46,6 +35,8 @@ public final class FixedWidthFontRenderer
public static final float BACKGROUND_START = (WIDTH - 6.0f) / WIDTH; public static final float BACKGROUND_START = (WIDTH - 6.0f) / WIDTH;
public static final float BACKGROUND_END = (WIDTH - 4.0f) / WIDTH; public static final float BACKGROUND_END = (WIDTH - 4.0f) / WIDTH;
public static final RenderType TYPE = Type.MAIN;
private FixedWidthFontRenderer() private FixedWidthFontRenderer()
{ {
} }
@@ -61,7 +52,7 @@ public final class FixedWidthFontRenderer
return i < 0 ? 0 : 15 - i; return i < 0 ? 0 : 15 - i;
} }
private static void drawChar( BufferBuilder buffer, float x, float y, int index, float r, float g, float b ) private static void drawChar( Matrix4f transform, IVertexBuilder buffer, float x, float y, int index, float r, float g, float b )
{ {
// Short circuit to avoid the common case - the texture should be blank here after all. // Short circuit to avoid the common case - the texture should be blank here after all.
if( index == '\0' || index == ' ' ) return; if( index == '\0' || index == ' ' ) return;
@@ -72,25 +63,25 @@ public final class FixedWidthFontRenderer
int xStart = 1 + column * (FONT_WIDTH + 2); int xStart = 1 + column * (FONT_WIDTH + 2);
int yStart = 1 + row * (FONT_HEIGHT + 2); int yStart = 1 + row * (FONT_HEIGHT + 2);
buffer.pos( x, y, 0f ).color( r, g, b, 1.0f ).tex( xStart / WIDTH, yStart / WIDTH ).endVertex(); buffer.pos( transform, x, y, 0f ).color( r, g, b, 1.0f ).tex( xStart / WIDTH, yStart / WIDTH ).endVertex();
buffer.pos( x, y + FONT_HEIGHT, 0f ).color( r, g, b, 1.0f ).tex( xStart / WIDTH, (yStart + FONT_HEIGHT) / WIDTH ).endVertex(); buffer.pos( transform, x, y + FONT_HEIGHT, 0f ).color( r, g, b, 1.0f ).tex( xStart / WIDTH, (yStart + FONT_HEIGHT) / WIDTH ).endVertex();
buffer.pos( x + FONT_WIDTH, y, 0f ).color( r, g, b, 1.0f ).tex( (xStart + FONT_WIDTH) / WIDTH, yStart / WIDTH ).endVertex(); buffer.pos( transform, x + FONT_WIDTH, y, 0f ).color( r, g, b, 1.0f ).tex( (xStart + FONT_WIDTH) / WIDTH, yStart / WIDTH ).endVertex();
buffer.pos( x + FONT_WIDTH, y, 0f ).color( r, g, b, 1.0f ).tex( (xStart + FONT_WIDTH) / WIDTH, yStart / WIDTH ).endVertex(); buffer.pos( transform, x + FONT_WIDTH, y, 0f ).color( r, g, b, 1.0f ).tex( (xStart + FONT_WIDTH) / WIDTH, yStart / WIDTH ).endVertex();
buffer.pos( x, y + FONT_HEIGHT, 0f ).color( r, g, b, 1.0f ).tex( xStart / WIDTH, (yStart + FONT_HEIGHT) / WIDTH ).endVertex(); buffer.pos( transform, x, y + FONT_HEIGHT, 0f ).color( r, g, b, 1.0f ).tex( xStart / WIDTH, (yStart + FONT_HEIGHT) / WIDTH ).endVertex();
buffer.pos( x + FONT_WIDTH, y + FONT_HEIGHT, 0f ).color( r, g, b, 1.0f ).tex( (xStart + FONT_WIDTH) / WIDTH, (yStart + FONT_HEIGHT) / WIDTH ).endVertex(); buffer.pos( transform, x + FONT_WIDTH, y + FONT_HEIGHT, 0f ).color( r, g, b, 1.0f ).tex( (xStart + FONT_WIDTH) / WIDTH, (yStart + FONT_HEIGHT) / WIDTH ).endVertex();
} }
private static void drawQuad( BufferBuilder buffer, float x, float y, float width, float height, float r, float g, float b ) private static void drawQuad( Matrix4f transform, IVertexBuilder buffer, float x, float y, float width, float height, float r, float g, float b )
{ {
buffer.pos( x, y, 0 ).color( r, g, b, 1.0f ).tex( BACKGROUND_START, BACKGROUND_START ).endVertex(); buffer.pos( transform, x, y, 0 ).color( r, g, b, 1.0f ).tex( BACKGROUND_START, BACKGROUND_START ).endVertex();
buffer.pos( x, y + height, 0 ).color( r, g, b, 1.0f ).tex( BACKGROUND_START, BACKGROUND_END ).endVertex(); buffer.pos( transform, x, y + height, 0 ).color( r, g, b, 1.0f ).tex( BACKGROUND_START, BACKGROUND_END ).endVertex();
buffer.pos( x + width, y, 0 ).color( r, g, b, 1.0f ).tex( BACKGROUND_END, BACKGROUND_START ).endVertex(); buffer.pos( transform, x + width, y, 0 ).color( r, g, b, 1.0f ).tex( BACKGROUND_END, BACKGROUND_START ).endVertex();
buffer.pos( x + width, y, 0 ).color( r, g, b, 1.0f ).tex( BACKGROUND_END, BACKGROUND_START ).endVertex(); buffer.pos( transform, x + width, y, 0 ).color( r, g, b, 1.0f ).tex( BACKGROUND_END, BACKGROUND_START ).endVertex();
buffer.pos( x, y + height, 0 ).color( r, g, b, 1.0f ).tex( BACKGROUND_START, BACKGROUND_END ).endVertex(); buffer.pos( transform, x, y + height, 0 ).color( r, g, b, 1.0f ).tex( BACKGROUND_START, BACKGROUND_END ).endVertex();
buffer.pos( x + width, y + height, 0 ).color( r, g, b, 1.0f ).tex( BACKGROUND_END, BACKGROUND_END ).endVertex(); buffer.pos( transform, x + width, y + height, 0 ).color( r, g, b, 1.0f ).tex( BACKGROUND_END, BACKGROUND_END ).endVertex();
} }
private static void drawQuad( BufferBuilder buffer, float x, float y, float width, float height, Palette palette, boolean greyscale, char colourIndex ) private static void drawQuad( Matrix4f transform, IVertexBuilder buffer, float x, float y, float width, float height, Palette palette, boolean greyscale, char colourIndex )
{ {
double[] colour = palette.getColour( getColour( colourIndex ) ); double[] colour = palette.getColour( getColour( colourIndex ) );
float r, g, b; float r, g, b;
@@ -105,23 +96,23 @@ public final class FixedWidthFontRenderer
b = (float) colour[2]; b = (float) colour[2];
} }
drawQuad( buffer, x, y, width, height, r, g, b ); drawQuad( transform, buffer, x, y, width, height, r, g, b );
} }
private static void drawBackground( private static void drawBackground(
@Nonnull BufferBuilder renderer, float x, float y, @Nonnull Matrix4f transform, @Nonnull IVertexBuilder renderer, float x, float y,
@Nonnull TextBuffer backgroundColour, @Nonnull Palette palette, boolean greyscale, @Nonnull TextBuffer backgroundColour, @Nonnull Palette palette, boolean greyscale,
float leftMarginSize, float rightMarginSize, float height float leftMarginSize, float rightMarginSize, float height
) )
{ {
if( leftMarginSize > 0 ) if( leftMarginSize > 0 )
{ {
drawQuad( renderer, x - leftMarginSize, y, leftMarginSize, height, palette, greyscale, backgroundColour.charAt( 0 ) ); drawQuad( transform, renderer, x - leftMarginSize, y, leftMarginSize, height, palette, greyscale, backgroundColour.charAt( 0 ) );
} }
if( rightMarginSize > 0 ) if( rightMarginSize > 0 )
{ {
drawQuad( renderer, x + backgroundColour.length() * FONT_WIDTH, y, rightMarginSize, height, palette, greyscale, backgroundColour.charAt( backgroundColour.length() - 1 ) ); drawQuad( transform, renderer, x + backgroundColour.length() * FONT_WIDTH, y, rightMarginSize, height, palette, greyscale, backgroundColour.charAt( backgroundColour.length() - 1 ) );
} }
// Batch together runs of identical background cells. // Batch together runs of identical background cells.
@@ -134,7 +125,7 @@ public final class FixedWidthFontRenderer
if( blockColour != '\0' ) if( blockColour != '\0' )
{ {
drawQuad( renderer, x + blockStart * FONT_WIDTH, y, FONT_WIDTH * (i - blockStart), height, palette, greyscale, blockColour ); drawQuad( transform, renderer, x + blockStart * FONT_WIDTH, y, FONT_WIDTH * (i - blockStart), height, palette, greyscale, blockColour );
} }
blockColour = colourIndex; blockColour = colourIndex;
@@ -143,24 +134,24 @@ public final class FixedWidthFontRenderer
if( blockColour != '\0' ) if( blockColour != '\0' )
{ {
drawQuad( renderer, x + blockStart * FONT_WIDTH, y, FONT_WIDTH * (backgroundColour.length() - blockStart), height, palette, greyscale, blockColour ); drawQuad( transform, renderer, x + blockStart * FONT_WIDTH, y, FONT_WIDTH * (backgroundColour.length() - blockStart), height, palette, greyscale, blockColour );
} }
} }
public static void drawString( public static void drawString(
@Nonnull BufferBuilder renderer, float x, float y, @Nonnull Matrix4f transform, @Nonnull IVertexBuilder renderer, float x, float y,
@Nonnull TextBuffer text, @Nonnull TextBuffer textColour, @Nullable TextBuffer backgroundColour, @Nonnull TextBuffer text, @Nonnull TextBuffer textColour, @Nullable TextBuffer backgroundColour,
@Nonnull Palette palette, boolean greyscale, float leftMarginSize, float rightMarginSize @Nonnull Palette palette, boolean greyscale, float leftMarginSize, float rightMarginSize
) )
{ {
if( backgroundColour != null ) if( backgroundColour != null )
{ {
drawBackground( renderer, x, y, backgroundColour, palette, greyscale, leftMarginSize, rightMarginSize, FONT_HEIGHT ); drawBackground( transform, renderer, x, y, backgroundColour, palette, greyscale, leftMarginSize, rightMarginSize, FONT_HEIGHT );
} }
for( int i = 0; i < text.length(); i++ ) for( int i = 0; i < text.length(); i++ )
{ {
double[] colour = palette.getColour( getColour( textColour.charAt( i ) ) ); double[] colour = palette.getColour( 15 - "0123456789abcdef".indexOf( textColour.charAt( i ) ) );
float r, g, b; float r, g, b;
if( greyscale ) if( greyscale )
{ {
@@ -176,7 +167,7 @@ public final class FixedWidthFontRenderer
// Draw char // Draw char
int index = text.charAt( i ); int index = text.charAt( i );
if( index > 255 ) index = '?'; if( index > 255 ) index = '?';
drawChar( renderer, x + i * FONT_WIDTH, y, index, r, g, b ); drawChar( transform, renderer, x + i * FONT_WIDTH, y, index, r, g, b );
} }
} }
@@ -188,15 +179,13 @@ public final class FixedWidthFontRenderer
{ {
bindFont(); bindFont();
Tessellator tessellator = Tessellator.getInstance(); IRenderTypeBuffer.Impl renderer = Minecraft.getInstance().getRenderTypeBuffers().getBufferSource();
BufferBuilder buffer = tessellator.getBuffer(); drawString( IDENTITY, ((IRenderTypeBuffer) renderer).getBuffer( TYPE ), x, y, text, textColour, backgroundColour, palette, greyscale, leftMarginSize, rightMarginSize );
begin( buffer ); renderer.finish();
drawString( buffer, x, y, text, textColour, backgroundColour, palette, greyscale, leftMarginSize, rightMarginSize );
tessellator.draw();
} }
public static void drawTerminalWithoutCursor( public static void drawTerminalWithoutCursor(
@Nonnull BufferBuilder buffer, float x, float y, @Nonnull Matrix4f transform, @Nonnull IVertexBuilder buffer, float x, float y,
@Nonnull Terminal terminal, boolean greyscale, @Nonnull Terminal terminal, boolean greyscale,
float topMarginSize, float bottomMarginSize, float leftMarginSize, float rightMarginSize float topMarginSize, float bottomMarginSize, float leftMarginSize, float rightMarginSize
) )
@@ -206,13 +195,13 @@ public final class FixedWidthFontRenderer
// Top and bottom margins // Top and bottom margins
drawBackground( drawBackground(
buffer, x, y - topMarginSize, transform, buffer, x, y - topMarginSize,
terminal.getBackgroundColourLine( 0 ), palette, greyscale, terminal.getBackgroundColourLine( 0 ), palette, greyscale,
leftMarginSize, rightMarginSize, topMarginSize leftMarginSize, rightMarginSize, topMarginSize
); );
drawBackground( drawBackground(
buffer, x, y + height * FONT_HEIGHT, transform, buffer, x, y + height * FONT_HEIGHT,
terminal.getBackgroundColourLine( height - 1 ), palette, greyscale, terminal.getBackgroundColourLine( height - 1 ), palette, greyscale,
leftMarginSize, rightMarginSize, bottomMarginSize leftMarginSize, rightMarginSize, bottomMarginSize
); );
@@ -221,7 +210,7 @@ public final class FixedWidthFontRenderer
for( int i = 0; i < height; i++ ) for( int i = 0; i < height; i++ )
{ {
drawString( drawString(
buffer, x, y + FixedWidthFontRenderer.FONT_HEIGHT * i, transform, buffer, x, y + FixedWidthFontRenderer.FONT_HEIGHT * i,
terminal.getLine( i ), terminal.getTextColourLine( i ), terminal.getBackgroundColourLine( i ), terminal.getLine( i ), terminal.getTextColourLine( i ), terminal.getBackgroundColourLine( i ),
palette, greyscale, leftMarginSize, rightMarginSize palette, greyscale, leftMarginSize, rightMarginSize
); );
@@ -229,7 +218,7 @@ public final class FixedWidthFontRenderer
} }
public static void drawCursor( public static void drawCursor(
@Nonnull BufferBuilder buffer, float x, float y, @Nonnull Matrix4f transform, @Nonnull IVertexBuilder buffer, float x, float y,
@Nonnull Terminal terminal, boolean greyscale @Nonnull Terminal terminal, boolean greyscale
) )
{ {
@@ -254,75 +243,104 @@ public final class FixedWidthFontRenderer
b = (float) colour[2]; b = (float) colour[2];
} }
drawChar( 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 );
} }
} }
public static void drawTerminal( public static void drawTerminal(
@Nonnull BufferBuilder buffer, float x, float y, @Nonnull Matrix4f transform, @Nonnull IVertexBuilder buffer, float x, float y,
@Nonnull Terminal terminal, boolean greyscale, @Nonnull Terminal terminal, boolean greyscale,
float topMarginSize, float bottomMarginSize, float leftMarginSize, float rightMarginSize float topMarginSize, float bottomMarginSize, float leftMarginSize, float rightMarginSize
) )
{ {
drawTerminalWithoutCursor( buffer, x, y, terminal, greyscale, topMarginSize, bottomMarginSize, leftMarginSize, rightMarginSize ); drawTerminalWithoutCursor( transform, buffer, x, y, terminal, greyscale, topMarginSize, bottomMarginSize, leftMarginSize, rightMarginSize );
drawCursor( buffer, x, y, terminal, greyscale ); drawCursor( transform, buffer, x, y, terminal, greyscale );
}
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();
IRenderTypeBuffer.Impl renderer = Minecraft.getInstance().getRenderTypeBuffers().getBufferSource();
IVertexBuilder buffer = renderer.getBuffer( TYPE );
drawTerminal( transform, buffer, x, y, terminal, greyscale, topMarginSize, bottomMarginSize, leftMarginSize, rightMarginSize );
renderer.finish( TYPE );
} }
public static void drawTerminal( public static void drawTerminal(
float x, float y, @Nonnull Terminal terminal, boolean greyscale, float x, float y, @Nonnull Terminal terminal, boolean greyscale,
float topMarginSize, float bottomMarginSize, float leftMarginSize, float rightMarginSize float topMarginSize, float bottomMarginSize, float leftMarginSize, float rightMarginSize
) )
{
drawTerminal( IDENTITY, x, y, terminal, greyscale, topMarginSize, bottomMarginSize, leftMarginSize, rightMarginSize );
}
public static void drawEmptyTerminal( @Nonnull Matrix4f transform, @Nonnull IRenderTypeBuffer renderer, float x, float y, float width, float height )
{
Colour colour = Colour.BLACK;
drawQuad( transform, renderer.getBuffer( TYPE ), x, y, width, height, colour.getR(), colour.getG(), colour.getB() );
}
public static void drawEmptyTerminal( @Nonnull Matrix4f transform, float x, float y, float width, float height )
{ {
bindFont(); bindFont();
Tessellator tessellator = Tessellator.getInstance(); IRenderTypeBuffer.Impl renderer = Minecraft.getInstance().getRenderTypeBuffers().getBufferSource();
BufferBuilder buffer = tessellator.getBuffer(); drawEmptyTerminal( transform, renderer, x, y, width, height );
begin( buffer ); renderer.finish();
drawTerminal( buffer, x, y, terminal, greyscale, topMarginSize, bottomMarginSize, leftMarginSize, rightMarginSize );
tessellator.draw();
} }
public static void drawEmptyTerminal( float x, float y, float width, float height ) public static void drawEmptyTerminal( float x, float y, float width, float height )
{ {
bindFont(); drawEmptyTerminal( IDENTITY, x, y, width, height );
Tessellator tessellator = Tessellator.getInstance();
BufferBuilder buffer = tessellator.getBuffer();
begin( buffer );
Colour colour = Colour.Black;
drawQuad( buffer, x, y, width, height, colour.getR(), colour.getG(), colour.getB() );
tessellator.draw();
} }
public static void drawBlocker( @Nonnull BufferBuilder buffer, float x, float y, float width, float height ) public static void drawBlocker( @Nonnull Matrix4f transform, @Nonnull IRenderTypeBuffer renderer, float x, float y, float width, float height )
{ {
Colour colour = Colour.Black; Colour colour = Colour.BLACK;
drawQuad( buffer, x, y, width, height, colour.getR(), colour.getG(), colour.getB() ); drawQuad( transform, renderer.getBuffer( Type.BLOCKER ), x, y, width, height, colour.getR(), colour.getG(), colour.getB() );
} }
public static void drawBlocker( float x, float y, float width, float height ) private static void bindFont()
{
bindFont();
Tessellator tessellator = Tessellator.getInstance();
BufferBuilder buffer = tessellator.getBuffer();
begin( buffer );
drawBlocker( buffer, x, y, width, height );
tessellator.draw();
}
public static void bindFont()
{ {
Minecraft.getInstance().getTextureManager().bindTexture( FONT ); Minecraft.getInstance().getTextureManager().bindTexture( FONT );
GlStateManager.texParameter( GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_CLAMP ); RenderSystem.texParameter( GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_CLAMP );
GlStateManager.enableTexture();
} }
public static void begin( BufferBuilder buffer ) private static final class Type extends RenderState
{ {
buffer.begin( GL11.GL_TRIANGLES, POSITION_COLOR_TEX ); private static final int GL_MODE = GL11.GL_TRIANGLES;
private static final VertexFormat FORMAT = DefaultVertexFormats.POSITION_COLOR_TEX;
static final RenderType MAIN = RenderType.makeType(
"terminal_font", FORMAT, GL_MODE, 1024,
false, false, // useDelegate, needsSorting
RenderType.State.getBuilder()
.texture( new RenderState.TextureState( FONT, false, false ) ) // blur, minimap
.alpha( DEFAULT_ALPHA )
.lightmap( LIGHTMAP_DISABLED )
.writeMask( COLOR_WRITE )
.build( false )
);
static final RenderType BLOCKER = RenderType.makeType(
"terminal_blocker", FORMAT, GL_MODE, 256,
false, false, // useDelegate, needsSorting
RenderType.State.getBuilder()
.texture( new RenderState.TextureState( FONT, false, false ) ) // blur, minimap
.alpha( DEFAULT_ALPHA )
.writeMask( DEPTH_WRITE )
.lightmap( LIGHTMAP_DISABLED )
.build( false )
);
private Type( String name, Runnable setup, Runnable destroy )
{
super( name, setup, destroy );
}
} }
} }

View File

@@ -5,7 +5,7 @@
*/ */
package dan200.computercraft.client.gui; package dan200.computercraft.client.gui;
import com.mojang.blaze3d.platform.GlStateManager; import com.mojang.blaze3d.systems.RenderSystem;
import dan200.computercraft.ComputerCraft; import dan200.computercraft.ComputerCraft;
import dan200.computercraft.client.gui.widgets.WidgetTerminal; import dan200.computercraft.client.gui.widgets.WidgetTerminal;
import dan200.computercraft.client.gui.widgets.WidgetWrapper; import dan200.computercraft.client.gui.widgets.WidgetWrapper;
@@ -134,17 +134,17 @@ public final class GuiComputer<T extends ContainerComputerBase> extends Containe
terminal.draw( terminalWrapper.getX(), terminalWrapper.getY() ); terminal.draw( terminalWrapper.getX(), terminalWrapper.getY() );
// Draw a border around the terminal // Draw a border around the terminal
GlStateManager.color4f( 1.0f, 1.0f, 1.0f, 1.0f ); RenderSystem.color4f( 1.0f, 1.0f, 1.0f, 1.0f );
switch( m_family ) switch( m_family )
{ {
case Normal: case NORMAL:
default: default:
minecraft.getTextureManager().bindTexture( BACKGROUND_NORMAL ); minecraft.getTextureManager().bindTexture( BACKGROUND_NORMAL );
break; break;
case Advanced: case ADVANCED:
minecraft.getTextureManager().bindTexture( BACKGROUND_ADVANCED ); minecraft.getTextureManager().bindTexture( BACKGROUND_ADVANCED );
break; break;
case Command: case COMMAND:
minecraft.getTextureManager().bindTexture( BACKGROUND_COMMAND ); minecraft.getTextureManager().bindTexture( BACKGROUND_COMMAND );
break; break;
} }

View File

@@ -5,7 +5,7 @@
*/ */
package dan200.computercraft.client.gui; package dan200.computercraft.client.gui;
import com.mojang.blaze3d.platform.GlStateManager; import com.mojang.blaze3d.systems.RenderSystem;
import dan200.computercraft.shared.peripheral.diskdrive.ContainerDiskDrive; import dan200.computercraft.shared.peripheral.diskdrive.ContainerDiskDrive;
import net.minecraft.client.gui.screen.inventory.ContainerScreen; import net.minecraft.client.gui.screen.inventory.ContainerScreen;
import net.minecraft.entity.player.PlayerInventory; import net.minecraft.entity.player.PlayerInventory;
@@ -32,7 +32,7 @@ public class GuiDiskDrive extends ContainerScreen<ContainerDiskDrive>
@Override @Override
protected void drawGuiContainerBackgroundLayer( float partialTicks, int mouseX, int mouseY ) protected void drawGuiContainerBackgroundLayer( float partialTicks, int mouseX, int mouseY )
{ {
GlStateManager.color4f( 1.0F, 1.0F, 1.0F, 1.0F ); RenderSystem.color4f( 1.0F, 1.0F, 1.0F, 1.0F );
minecraft.getTextureManager().bindTexture( BACKGROUND ); minecraft.getTextureManager().bindTexture( BACKGROUND );
blit( guiLeft, guiTop, 0, 0, xSize, ySize ); blit( guiLeft, guiTop, 0, 0, xSize, ySize );
} }

View File

@@ -5,7 +5,7 @@
*/ */
package dan200.computercraft.client.gui; package dan200.computercraft.client.gui;
import com.mojang.blaze3d.platform.GlStateManager; import com.mojang.blaze3d.systems.RenderSystem;
import dan200.computercraft.shared.peripheral.printer.ContainerPrinter; import dan200.computercraft.shared.peripheral.printer.ContainerPrinter;
import net.minecraft.client.gui.screen.inventory.ContainerScreen; import net.minecraft.client.gui.screen.inventory.ContainerScreen;
import net.minecraft.client.resources.I18n; import net.minecraft.client.resources.I18n;
@@ -33,7 +33,7 @@ public class GuiPrinter extends ContainerScreen<ContainerPrinter>
@Override @Override
protected void drawGuiContainerBackgroundLayer( float partialTicks, int mouseX, int mouseY ) protected void drawGuiContainerBackgroundLayer( float partialTicks, int mouseX, int mouseY )
{ {
GlStateManager.color4f( 1.0F, 1.0F, 1.0F, 1.0F ); RenderSystem.color4f( 1.0F, 1.0F, 1.0F, 1.0F );
minecraft.getTextureManager().bindTexture( BACKGROUND ); minecraft.getTextureManager().bindTexture( BACKGROUND );
blit( guiLeft, guiTop, 0, 0, xSize, ySize ); blit( guiLeft, guiTop, 0, 0, xSize, ySize );

View File

@@ -5,11 +5,15 @@
*/ */
package dan200.computercraft.client.gui; package dan200.computercraft.client.gui;
import com.mojang.blaze3d.platform.GlStateManager; import com.mojang.blaze3d.systems.RenderSystem;
import dan200.computercraft.core.terminal.TextBuffer; import dan200.computercraft.core.terminal.TextBuffer;
import dan200.computercraft.shared.common.ContainerHeldItem; import dan200.computercraft.shared.common.ContainerHeldItem;
import dan200.computercraft.shared.media.items.ItemPrintout; import dan200.computercraft.shared.media.items.ItemPrintout;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.screen.inventory.ContainerScreen; import net.minecraft.client.gui.screen.inventory.ContainerScreen;
import net.minecraft.client.renderer.IRenderTypeBuffer;
import net.minecraft.client.renderer.Matrix4f;
import net.minecraft.client.renderer.TransformationMatrix;
import net.minecraft.entity.player.PlayerInventory; import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.util.text.ITextComponent; import net.minecraft.util.text.ITextComponent;
import org.lwjgl.glfw.GLFW; import org.lwjgl.glfw.GLFW;
@@ -18,6 +22,8 @@ import static dan200.computercraft.client.render.PrintoutRenderer.*;
public class GuiPrintout extends ContainerScreen<ContainerHeldItem> public class GuiPrintout extends ContainerScreen<ContainerHeldItem>
{ {
private static final Matrix4f IDENTITY = TransformationMatrix.identity().getMatrix();
private final boolean m_book; private final boolean m_book;
private final int m_pages; private final int m_pages;
private final TextBuffer[] m_text; private final TextBuffer[] m_text;
@@ -88,20 +94,22 @@ public class GuiPrintout extends ContainerScreen<ContainerHeldItem>
public void drawGuiContainerBackgroundLayer( float partialTicks, int mouseX, int mouseY ) public void drawGuiContainerBackgroundLayer( float partialTicks, int mouseX, int mouseY )
{ {
// Draw the printout // Draw the printout
GlStateManager.color4f( 1.0f, 1.0f, 1.0f, 1.0f ); RenderSystem.color4f( 1.0f, 1.0f, 1.0f, 1.0f );
GlStateManager.enableDepthTest(); RenderSystem.enableDepthTest();
drawBorder( guiLeft, guiTop, blitOffset, m_page, m_pages, m_book ); IRenderTypeBuffer.Impl renderer = Minecraft.getInstance().getRenderTypeBuffers().getBufferSource();
drawText( guiLeft + X_TEXT_MARGIN, guiTop + Y_TEXT_MARGIN, ItemPrintout.LINES_PER_PAGE * m_page, m_text, m_colours ); drawBorder( IDENTITY, renderer, guiLeft, guiTop, getBlitOffset(), m_page, m_pages, m_book );
drawText( IDENTITY, renderer, guiLeft + X_TEXT_MARGIN, guiTop + Y_TEXT_MARGIN, ItemPrintout.LINES_PER_PAGE * m_page, m_text, m_colours );
renderer.finish();
} }
@Override @Override
public void render( int mouseX, int mouseY, float partialTicks ) public void render( int mouseX, int mouseY, float partialTicks )
{ {
// We must take the background further back in order to not overlap with our printed pages. // We must take the background further back in order to not overlap with our printed pages.
blitOffset--; setBlitOffset( getBlitOffset() - 1 );
renderBackground(); renderBackground();
blitOffset++; setBlitOffset( getBlitOffset() + 1 );
super.render( mouseX, mouseY, partialTicks ); super.render( mouseX, mouseY, partialTicks );
renderHoveredToolTip( mouseX, mouseY ); renderHoveredToolTip( mouseX, mouseY );

View File

@@ -5,7 +5,7 @@
*/ */
package dan200.computercraft.client.gui; package dan200.computercraft.client.gui;
import com.mojang.blaze3d.platform.GlStateManager; import com.mojang.blaze3d.systems.RenderSystem;
import dan200.computercraft.ComputerCraft; import dan200.computercraft.ComputerCraft;
import dan200.computercraft.client.gui.widgets.WidgetTerminal; import dan200.computercraft.client.gui.widgets.WidgetTerminal;
import dan200.computercraft.client.gui.widgets.WidgetWrapper; import dan200.computercraft.client.gui.widgets.WidgetWrapper;
@@ -98,7 +98,7 @@ public class GuiTurtle extends ContainerScreen<ContainerTurtle>
int slot = m_container.getSelectedSlot(); int slot = m_container.getSelectedSlot();
if( slot >= 0 ) if( slot >= 0 )
{ {
GlStateManager.color4f( 1.0F, 1.0F, 1.0F, 1.0F ); RenderSystem.color4f( 1.0F, 1.0F, 1.0F, 1.0F );
int slotX = slot % 4; int slotX = slot % 4;
int slotY = slot / 4; int slotY = slot / 4;
minecraft.getTextureManager().bindTexture( advanced ? BACKGROUND_ADVANCED : BACKGROUND_NORMAL ); minecraft.getTextureManager().bindTexture( advanced ? BACKGROUND_ADVANCED : BACKGROUND_NORMAL );
@@ -110,11 +110,11 @@ public class GuiTurtle extends ContainerScreen<ContainerTurtle>
protected void drawGuiContainerBackgroundLayer( float partialTicks, int mouseX, int mouseY ) protected void drawGuiContainerBackgroundLayer( float partialTicks, int mouseX, int mouseY )
{ {
// Draw term // Draw term
boolean advanced = m_family == ComputerFamily.Advanced; boolean advanced = m_family == ComputerFamily.ADVANCED;
terminal.draw( terminalWrapper.getX(), terminalWrapper.getY() ); terminal.draw( terminalWrapper.getX(), terminalWrapper.getY() );
// Draw border/inventory // Draw border/inventory
GlStateManager.color4f( 1.0F, 1.0F, 1.0F, 1.0F ); RenderSystem.color4f( 1.0F, 1.0F, 1.0F, 1.0F );
minecraft.getTextureManager().bindTexture( advanced ? BACKGROUND_ADVANCED : BACKGROUND_NORMAL ); minecraft.getTextureManager().bindTexture( advanced ? BACKGROUND_ADVANCED : BACKGROUND_NORMAL );
blit( guiLeft, guiTop, 0, 0, xSize, ySize ); blit( guiLeft, guiTop, 0, 0, xSize, ySize );

View File

@@ -17,6 +17,9 @@ import org.lwjgl.glfw.GLFW;
import java.util.BitSet; import java.util.BitSet;
import java.util.function.Supplier; import java.util.function.Supplier;
import static dan200.computercraft.client.gui.FixedWidthFontRenderer.FONT_HEIGHT;
import static dan200.computercraft.client.gui.FixedWidthFontRenderer.FONT_WIDTH;
public class WidgetTerminal implements IGuiEventListener public class WidgetTerminal implements IGuiEventListener
{ {
private static final float TERMINATE_TIME = 0.5f; private static final float TERMINATE_TIME = 0.5f;
@@ -173,8 +176,8 @@ public class WidgetTerminal implements IGuiEventListener
Terminal term = computer.getTerminal(); Terminal term = computer.getTerminal();
if( term != null ) if( term != null )
{ {
int charX = (int) (mouseX / FixedWidthFontRenderer.FONT_WIDTH); int charX = (int) (mouseX / FONT_WIDTH);
int charY = (int) (mouseY / FixedWidthFontRenderer.FONT_HEIGHT); int charY = (int) (mouseY / FONT_HEIGHT);
charX = Math.min( Math.max( charX, 0 ), term.getWidth() - 1 ); charX = Math.min( Math.max( charX, 0 ), term.getWidth() - 1 );
charY = Math.min( Math.max( charY, 0 ), term.getHeight() - 1 ); charY = Math.min( Math.max( charY, 0 ), term.getHeight() - 1 );
@@ -197,8 +200,8 @@ public class WidgetTerminal implements IGuiEventListener
Terminal term = computer.getTerminal(); Terminal term = computer.getTerminal();
if( term != null ) if( term != null )
{ {
int charX = (int) (mouseX / FixedWidthFontRenderer.FONT_WIDTH); int charX = (int) (mouseX / FONT_WIDTH);
int charY = (int) (mouseY / FixedWidthFontRenderer.FONT_HEIGHT); int charY = (int) (mouseY / FONT_HEIGHT);
charX = Math.min( Math.max( charX, 0 ), term.getWidth() - 1 ); charX = Math.min( Math.max( charX, 0 ), term.getWidth() - 1 );
charY = Math.min( Math.max( charY, 0 ), term.getHeight() - 1 ); charY = Math.min( Math.max( charY, 0 ), term.getHeight() - 1 );
@@ -224,8 +227,8 @@ public class WidgetTerminal implements IGuiEventListener
Terminal term = computer.getTerminal(); Terminal term = computer.getTerminal();
if( term != null ) if( term != null )
{ {
int charX = (int) (mouseX / FixedWidthFontRenderer.FONT_WIDTH); int charX = (int) (mouseX / FONT_WIDTH);
int charY = (int) (mouseY / FixedWidthFontRenderer.FONT_HEIGHT); int charY = (int) (mouseY / FONT_HEIGHT);
charX = Math.min( Math.max( charX, 0 ), term.getWidth() - 1 ); charX = Math.min( Math.max( charX, 0 ), term.getWidth() - 1 );
charY = Math.min( Math.max( charY, 0 ), term.getHeight() - 1 ); charY = Math.min( Math.max( charY, 0 ), term.getHeight() - 1 );
@@ -249,8 +252,8 @@ public class WidgetTerminal implements IGuiEventListener
Terminal term = computer.getTerminal(); Terminal term = computer.getTerminal();
if( term != null ) if( term != null )
{ {
int charX = (int) (mouseX / FixedWidthFontRenderer.FONT_WIDTH); int charX = (int) (mouseX / FONT_WIDTH);
int charY = (int) (mouseY / FixedWidthFontRenderer.FONT_HEIGHT); int charY = (int) (mouseY / FONT_HEIGHT);
charX = Math.min( Math.max( charX, 0 ), term.getWidth() - 1 ); charX = Math.min( Math.max( charX, 0 ), term.getWidth() - 1 );
charY = Math.min( Math.max( charY, 0 ), term.getHeight() - 1 ); charY = Math.min( Math.max( charY, 0 ), term.getHeight() - 1 );
@@ -318,19 +321,15 @@ public class WidgetTerminal implements IGuiEventListener
Terminal terminal = computer != null ? computer.getTerminal() : null; Terminal terminal = computer != null ? computer.getTerminal() : null;
if( terminal != null ) if( terminal != null )
{ {
FixedWidthFontRenderer.drawTerminal( FixedWidthFontRenderer.drawTerminal( originX, originY, terminal, !computer.isColour(), topMargin, bottomMargin, leftMargin, rightMargin );
originX, originY,
terminal, !computer.isColour(), topMargin, bottomMargin, leftMargin, rightMargin
);
} }
else else
{ {
int x = originX - leftMargin; FixedWidthFontRenderer.drawEmptyTerminal(
int y = originY - rightMargin; originX - leftMargin, originY - rightMargin,
int width = termWidth * FixedWidthFontRenderer.FONT_WIDTH + leftMargin + rightMargin; termWidth * FONT_WIDTH + leftMargin + rightMargin,
int height = termHeight * FixedWidthFontRenderer.FONT_HEIGHT + topMargin + bottomMargin; termHeight * FONT_HEIGHT + topMargin + bottomMargin
);
FixedWidthFontRenderer.drawEmptyTerminal( x, y, width, height );
} }
} }
} }

View File

@@ -7,7 +7,6 @@ package dan200.computercraft.client.proxy;
import dan200.computercraft.ComputerCraft; import dan200.computercraft.ComputerCraft;
import dan200.computercraft.client.gui.*; import dan200.computercraft.client.gui.*;
import dan200.computercraft.client.render.TileEntityCableRenderer;
import dan200.computercraft.client.render.TileEntityMonitorRenderer; import dan200.computercraft.client.render.TileEntityMonitorRenderer;
import dan200.computercraft.client.render.TileEntityTurtleRenderer; import dan200.computercraft.client.render.TileEntityTurtleRenderer;
import dan200.computercraft.client.render.TurtlePlayerRenderer; import dan200.computercraft.client.render.TurtlePlayerRenderer;
@@ -15,7 +14,6 @@ import dan200.computercraft.shared.common.ContainerHeldItem;
import dan200.computercraft.shared.computer.inventory.ContainerComputer; import dan200.computercraft.shared.computer.inventory.ContainerComputer;
import dan200.computercraft.shared.computer.inventory.ContainerViewComputer; import dan200.computercraft.shared.computer.inventory.ContainerViewComputer;
import dan200.computercraft.shared.peripheral.diskdrive.ContainerDiskDrive; import dan200.computercraft.shared.peripheral.diskdrive.ContainerDiskDrive;
import dan200.computercraft.shared.peripheral.modem.wired.TileCable;
import dan200.computercraft.shared.peripheral.monitor.ClientMonitor; import dan200.computercraft.shared.peripheral.monitor.ClientMonitor;
import dan200.computercraft.shared.peripheral.monitor.TileMonitor; import dan200.computercraft.shared.peripheral.monitor.TileMonitor;
import dan200.computercraft.shared.peripheral.printer.ContainerPrinter; import dan200.computercraft.shared.peripheral.printer.ContainerPrinter;
@@ -24,6 +22,8 @@ import dan200.computercraft.shared.turtle.blocks.TileTurtle;
import dan200.computercraft.shared.turtle.core.TurtlePlayer; import dan200.computercraft.shared.turtle.core.TurtlePlayer;
import dan200.computercraft.shared.turtle.inventory.ContainerTurtle; import dan200.computercraft.shared.turtle.inventory.ContainerTurtle;
import net.minecraft.client.gui.ScreenManager; import net.minecraft.client.gui.ScreenManager;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.RenderTypeLookup;
import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.event.world.WorldEvent; import net.minecraftforge.event.world.WorldEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.eventbus.api.SubscribeEvent;
@@ -40,12 +40,22 @@ public final class ComputerCraftProxyClient
{ {
registerContainers(); registerContainers();
// Setup TESRs // While turtles themselves are not transparent, their upgrades may be.
ClientRegistry.bindTileEntitySpecialRenderer( TileMonitor.class, new TileEntityMonitorRenderer() ); RenderTypeLookup.setRenderLayer( ComputerCraft.Blocks.turtleNormal, RenderType.getTranslucent() );
ClientRegistry.bindTileEntitySpecialRenderer( TileCable.class, new TileEntityCableRenderer() ); RenderTypeLookup.setRenderLayer( ComputerCraft.Blocks.turtleAdvanced, RenderType.getTranslucent() );
ClientRegistry.bindTileEntitySpecialRenderer( TileTurtle.class, new TileEntityTurtleRenderer() );
RenderingRegistry.registerEntityRenderingHandler( TurtlePlayer.class, TurtlePlayerRenderer::new ); // Monitors' textures have transparent fronts and so count as cutouts.
RenderTypeLookup.setRenderLayer( ComputerCraft.Blocks.monitorNormal, RenderType.getCutout() );
RenderTypeLookup.setRenderLayer( ComputerCraft.Blocks.monitorAdvanced, RenderType.getCutout() );
// Setup TESRs
ClientRegistry.bindTileEntityRenderer( TileMonitor.FACTORY_NORMAL, TileEntityMonitorRenderer::new );
ClientRegistry.bindTileEntityRenderer( TileMonitor.FACTORY_ADVANCED, TileEntityMonitorRenderer::new );
ClientRegistry.bindTileEntityRenderer( TileTurtle.FACTORY_NORMAL, TileEntityTurtleRenderer::new );
ClientRegistry.bindTileEntityRenderer( TileTurtle.FACTORY_ADVANCED, TileEntityTurtleRenderer::new );
// TODO: ClientRegistry.bindTileEntityRenderer( TileCable.FACTORY, x -> new TileEntityCableRenderer() );
RenderingRegistry.registerEntityRenderingHandler( TurtlePlayer.TYPE, TurtlePlayerRenderer::new );
} }
private static void registerContainers() private static void registerContainers()

View File

@@ -5,26 +5,27 @@
*/ */
package dan200.computercraft.client.render; package dan200.computercraft.client.render;
import com.mojang.blaze3d.platform.GlStateManager; import com.mojang.blaze3d.matrix.MatrixStack;
import com.mojang.blaze3d.vertex.IVertexBuilder;
import dan200.computercraft.ComputerCraft; import dan200.computercraft.ComputerCraft;
import dan200.computercraft.shared.peripheral.modem.wired.BlockCable; import dan200.computercraft.shared.peripheral.modem.wired.BlockCable;
import dan200.computercraft.shared.peripheral.modem.wired.CableShapes; import dan200.computercraft.shared.peripheral.modem.wired.CableShapes;
import dan200.computercraft.shared.util.WorldUtil; import dan200.computercraft.shared.util.WorldUtil;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.ActiveRenderInfo; import net.minecraft.client.renderer.ActiveRenderInfo;
import net.minecraft.client.renderer.Matrix4f;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.WorldRenderer; import net.minecraft.client.renderer.WorldRenderer;
import net.minecraft.entity.Entity;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.BlockRayTraceResult; import net.minecraft.util.math.BlockRayTraceResult;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3d;
import net.minecraft.util.math.shapes.VoxelShape; import net.minecraft.util.math.shapes.VoxelShape;
import net.minecraft.world.World; import net.minecraft.world.World;
import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.client.event.DrawBlockHighlightEvent; import net.minecraftforge.client.event.DrawHighlightEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.Mod;
import org.lwjgl.opengl.GL11;
@Mod.EventBusSubscriber( modid = ComputerCraft.MOD_ID, value = Dist.CLIENT ) @Mod.EventBusSubscriber( modid = ComputerCraft.MOD_ID, value = Dist.CLIENT )
public final class CableHighlightRenderer public final class CableHighlightRenderer
@@ -37,14 +38,12 @@ public final class CableHighlightRenderer
* Draw an outline for a specific part of a cable "Multipart". * Draw an outline for a specific part of a cable "Multipart".
* *
* @param event The event to observe * @param event The event to observe
* @see WorldRenderer#drawSelectionBox(ActiveRenderInfo, RayTraceResult, int) * @see WorldRenderer#drawSelectionBox(MatrixStack, IVertexBuilder, Entity, double, double, double, BlockPos, BlockState)
*/ */
@SubscribeEvent @SubscribeEvent
public static void drawHighlight( DrawBlockHighlightEvent event ) public static void drawHighlight( DrawHighlightEvent.HighlightBlock event )
{ {
if( event.getTarget().getType() != RayTraceResult.Type.BLOCK ) return; BlockRayTraceResult hit = event.getTarget();
BlockRayTraceResult hit = (BlockRayTraceResult) event.getTarget();
BlockPos pos = hit.getPos(); BlockPos pos = hit.getPos();
World world = event.getInfo().getRenderViewEntity().getEntityWorld(); World world = event.getInfo().getRenderViewEntity().getEntityWorld();
ActiveRenderInfo info = event.getInfo(); ActiveRenderInfo info = event.getInfo();
@@ -59,31 +58,22 @@ public final class CableHighlightRenderer
event.setCanceled( true ); event.setCanceled( true );
Minecraft mc = Minecraft.getInstance();
GlStateManager.enableBlend();
GlStateManager.blendFuncSeparate( GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA, GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ZERO );
GlStateManager.lineWidth( Math.max( 2.5F, mc.mainWindow.getFramebufferWidth() / 1920.0F * 2.5F ) );
GlStateManager.disableTexture();
GlStateManager.depthMask( false );
GlStateManager.matrixMode( GL11.GL_PROJECTION );
GlStateManager.pushMatrix();
GlStateManager.scalef( 1.0F, 1.0F, 0.999F );
VoxelShape shape = WorldUtil.isVecInside( CableShapes.getModemShape( state ), hit.getHitVec().subtract( pos.getX(), pos.getY(), pos.getZ() ) ) VoxelShape shape = WorldUtil.isVecInside( CableShapes.getModemShape( state ), hit.getHitVec().subtract( pos.getX(), pos.getY(), pos.getZ() ) )
? CableShapes.getModemShape( state ) ? CableShapes.getModemShape( state )
: CableShapes.getCableShape( state ); : CableShapes.getCableShape( state );
Vec3d cameraPos = info.getProjectedView(); Vec3d cameraPos = info.getProjectedView();
WorldRenderer.drawShape( double xOffset = pos.getX() - cameraPos.getX();
shape, pos.getX() - cameraPos.getX(), pos.getY() - cameraPos.getY(), pos.getZ() - cameraPos.getZ(), double yOffset = pos.getY() - cameraPos.getY();
0.0F, 0.0F, 0.0F, 0.4F double zOffset = pos.getZ() - cameraPos.getZ();
);
GlStateManager.popMatrix(); IVertexBuilder buffer = event.getBuffers().getBuffer( RenderType.getLines() );
GlStateManager.matrixMode( GL11.GL_MODELVIEW ); Matrix4f matrix4f = event.getMatrix().getLast().getMatrix();
GlStateManager.depthMask( true ); shape.forEachEdge( ( x1, y1, z1, x2, y2, z2 ) -> {
GlStateManager.enableTexture(); buffer.pos( matrix4f, (float) (x1 + xOffset), (float) (y1 + yOffset), (float) (z1 + zOffset) )
GlStateManager.disableBlend(); .color( 0, 0, 0, 0.4f ).endVertex();
buffer.pos( matrix4f, (float) (x2 + xOffset), (float) (y2 + yOffset), (float) (z2 + zOffset) )
.color( 0, 0, 0, 0.4f ).endVertex();
} );
} }
} }

View File

@@ -5,9 +5,12 @@
*/ */
package dan200.computercraft.client.render; package dan200.computercraft.client.render;
import com.mojang.blaze3d.platform.GlStateManager; import com.mojang.blaze3d.matrix.MatrixStack;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.entity.player.AbstractClientPlayerEntity;
import net.minecraft.client.renderer.FirstPersonRenderer; import net.minecraft.client.renderer.FirstPersonRenderer;
import net.minecraft.client.renderer.IRenderTypeBuffer;
import net.minecraft.client.renderer.Vector3f;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.util.Hand; import net.minecraft.util.Hand;
@@ -19,99 +22,118 @@ public abstract class ItemMapLikeRenderer
/** /**
* The main rendering method for the item. * The main rendering method for the item.
* *
* @param stack The stack to render * @param transform The matrix transformation stack
* @see FirstPersonRenderer#renderMapFirstPerson(ItemStack) * @param render The buffer to render to
* @param stack The stack to render
* @see FirstPersonRenderer#renderItemInFirstPerson(AbstractClientPlayerEntity, float, float, Hand, float, ItemStack, float, MatrixStack, IRenderTypeBuffer, int)
*/ */
protected abstract void renderItem( ItemStack stack ); protected abstract void renderItem( MatrixStack transform, IRenderTypeBuffer render, ItemStack stack );
protected void renderItemFirstPerson( Hand hand, float pitch, float equipProgress, float swingProgress, ItemStack stack ) protected void renderItemFirstPerson( MatrixStack transform, IRenderTypeBuffer render, int lightTexture, Hand hand, float pitch, float equipProgress, float swingProgress, ItemStack stack )
{ {
PlayerEntity player = Minecraft.getInstance().player; PlayerEntity player = Minecraft.getInstance().player;
GlStateManager.pushMatrix(); transform.push();
if( hand == Hand.MAIN_HAND && player.getHeldItemOffhand().isEmpty() ) if( hand == Hand.MAIN_HAND && player.getHeldItemOffhand().isEmpty() )
{ {
renderItemFirstPersonCenter( pitch, equipProgress, swingProgress, stack ); renderItemFirstPersonCenter( transform, render, lightTexture, pitch, equipProgress, swingProgress, stack );
} }
else else
{ {
renderItemFirstPersonSide( renderItemFirstPersonSide(
transform, render, lightTexture,
hand == Hand.MAIN_HAND ? player.getPrimaryHand() : player.getPrimaryHand().opposite(), hand == Hand.MAIN_HAND ? player.getPrimaryHand() : player.getPrimaryHand().opposite(),
equipProgress, swingProgress, stack equipProgress, swingProgress, stack
); );
} }
GlStateManager.popMatrix(); transform.pop();
} }
/** /**
* Renders the item to one side of the player. * Renders the item to one side of the player.
* *
* @param transform The matrix transformation stack
* @param render The buffer to render to
* @param combinedLight The current light level
* @param side The side to render on * @param side The side to render on
* @param equipProgress The equip progress of this item * @param equipProgress The equip progress of this item
* @param swingProgress The swing progress of this item * @param swingProgress The swing progress of this item
* @param stack The stack to render * @param stack The stack to render
* @see FirstPersonRenderer#renderMapFirstPersonSide(float, HandSide, float, ItemStack) * @see FirstPersonRenderer#renderMapFirstPersonSide(MatrixStack, IRenderTypeBuffer, int, float, HandSide, float, ItemStack)
*/ */
private void renderItemFirstPersonSide( HandSide side, float equipProgress, float swingProgress, ItemStack stack ) private void renderItemFirstPersonSide( MatrixStack transform, IRenderTypeBuffer render, int combinedLight, HandSide side, float equipProgress, float swingProgress, ItemStack stack )
{ {
Minecraft minecraft = Minecraft.getInstance(); Minecraft minecraft = Minecraft.getInstance();
float offset = side == HandSide.RIGHT ? 1f : -1f; float offset = side == HandSide.RIGHT ? 1f : -1f;
GlStateManager.translatef( offset * 0.125f, -0.125f, 0f ); transform.translate( offset * 0.125f, -0.125f, 0f );
// If the player is not invisible then render a single arm // If the player is not invisible then render a single arm
if( !minecraft.player.isInvisible() ) if( !minecraft.player.isInvisible() )
{ {
GlStateManager.pushMatrix(); transform.push();
GlStateManager.rotatef( offset * 10f, 0f, 0f, 1f ); transform.rotate( Vector3f.ZP.rotationDegrees( offset * 10f ) );
minecraft.getFirstPersonRenderer().renderArmFirstPerson( equipProgress, swingProgress, side ); minecraft.getFirstPersonRenderer().renderArmFirstPerson( transform, render, combinedLight, equipProgress, swingProgress, side );
GlStateManager.popMatrix(); transform.pop();
} }
// Setup the appropriate transformations. This is just copied from the // Setup the appropriate transformations. This is just copied from the
// corresponding method in ItemRenderer. // corresponding method in ItemRenderer.
GlStateManager.pushMatrix(); transform.push();
GlStateManager.translatef( offset * 0.51f, -0.08f + equipProgress * -1.2f, -0.75f ); transform.translate( offset * 0.51f, -0.08f + equipProgress * -1.2f, -0.75f );
float f1 = MathHelper.sqrt( swingProgress ); float f1 = MathHelper.sqrt( swingProgress );
float f2 = MathHelper.sin( f1 * (float) Math.PI ); float f2 = MathHelper.sin( f1 * (float) Math.PI );
float f3 = -0.5f * f2; float f3 = -0.5f * f2;
float f4 = 0.4f * MathHelper.sin( f1 * ((float) Math.PI * 2f) ); float f4 = 0.4f * MathHelper.sin( f1 * ((float) Math.PI * 2f) );
float f5 = -0.3f * MathHelper.sin( swingProgress * (float) Math.PI ); float f5 = -0.3f * MathHelper.sin( swingProgress * (float) Math.PI );
GlStateManager.translatef( offset * f3, f4 - 0.3f * f2, f5 ); transform.translate( offset * f3, f4 - 0.3f * f2, f5 );
GlStateManager.rotatef( f2 * -45f, 1f, 0f, 0f ); transform.rotate( Vector3f.XP.rotationDegrees( f2 * -45f ) );
GlStateManager.rotatef( offset * f2 * -30f, 0f, 1f, 0f ); transform.rotate( Vector3f.YP.rotationDegrees( offset * f2 * -30f ) );
renderItem( stack ); renderItem( transform, render, stack );
GlStateManager.popMatrix(); transform.pop();
} }
/** /**
* Render an item in the middle of the screen. * Render an item in the middle of the screen.
* *
* @param transform The matrix transformation stack
* @param render The buffer to render to
* @param combinedLight The current light level
* @param pitch The pitch of the player * @param pitch The pitch of the player
* @param equipProgress The equip progress of this item * @param equipProgress The equip progress of this item
* @param swingProgress The swing progress of this item * @param swingProgress The swing progress of this item
* @param stack The stack to render * @param stack The stack to render
* @see FirstPersonRenderer#renderMapFirstPerson(float, float, float) * @see FirstPersonRenderer#renderMapFirstPerson(MatrixStack, IRenderTypeBuffer, int, float, float, float)
*/ */
private void renderItemFirstPersonCenter( float pitch, float equipProgress, float swingProgress, ItemStack stack ) private void renderItemFirstPersonCenter( MatrixStack transform, IRenderTypeBuffer render, int combinedLight, float pitch, float equipProgress, float swingProgress, ItemStack stack )
{ {
FirstPersonRenderer renderer = Minecraft.getInstance().getFirstPersonRenderer(); Minecraft minecraft = Minecraft.getInstance();
FirstPersonRenderer renderer = minecraft.getFirstPersonRenderer();
// Setup the appropriate transformations. This is just copied from the // Setup the appropriate transformations. This is just copied from the
// corresponding method in ItemRenderer. // corresponding method in ItemRenderer.
float swingRt = MathHelper.sqrt( swingProgress ); float swingRt = MathHelper.sqrt( swingProgress );
float tX = -0.2f * MathHelper.sin( swingProgress * (float) Math.PI ); float tX = -0.2f * MathHelper.sin( swingProgress * (float) Math.PI );
float tZ = -0.4f * MathHelper.sin( swingRt * (float) Math.PI ); float tZ = -0.4f * MathHelper.sin( swingRt * (float) Math.PI );
GlStateManager.translatef( 0f, -tX / 2f, tZ ); transform.translate( 0, -tX / 2, tZ );
float pitchAngle = renderer.getMapAngleFromPitch( pitch );
GlStateManager.translatef( 0f, 0.04f + equipProgress * -1.2f + pitchAngle * -0.5f, -0.72f );
GlStateManager.rotatef( pitchAngle * -85f, 1f, 0f, 0f );
renderer.renderArms();
float rX = MathHelper.sin( swingRt * (float) Math.PI );
GlStateManager.rotatef( rX * 20f, 1f, 0f, 0f );
GlStateManager.scalef( 2f, 2f, 2f );
renderItem( stack ); float pitchAngle = renderer.getMapAngleFromPitch( pitch );
transform.translate( 0, 0.04F + equipProgress * -1.2f + pitchAngle * -0.5f, -0.72f );
transform.rotate( Vector3f.XP.rotationDegrees( pitchAngle * -85.0f ) );
if( !minecraft.player.isInvisible() )
{
transform.push();
transform.rotate( Vector3f.YP.rotationDegrees( 90.0F ) );
renderer.renderArm( transform, render, combinedLight, HandSide.RIGHT );
renderer.renderArm( transform, render, combinedLight, HandSide.LEFT );
transform.pop();
}
float rX = MathHelper.sin( swingRt * (float) Math.PI );
transform.rotate( Vector3f.XP.rotationDegrees( rX * 20.0F ) );
transform.scale( 2.0F, 2.0F, 2.0F );
renderItem( transform, render, stack );
} }
} }

View File

@@ -5,7 +5,9 @@
*/ */
package dan200.computercraft.client.render; package dan200.computercraft.client.render;
import com.mojang.blaze3d.platform.GlStateManager; import com.mojang.blaze3d.matrix.MatrixStack;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.IVertexBuilder;
import dan200.computercraft.ComputerCraft; import dan200.computercraft.ComputerCraft;
import dan200.computercraft.client.gui.FixedWidthFontRenderer; import dan200.computercraft.client.gui.FixedWidthFontRenderer;
import dan200.computercraft.core.terminal.Terminal; import dan200.computercraft.core.terminal.Terminal;
@@ -14,12 +16,11 @@ import dan200.computercraft.shared.computer.core.ComputerFamily;
import dan200.computercraft.shared.pocket.items.ItemPocketComputer; import dan200.computercraft.shared.pocket.items.ItemPocketComputer;
import dan200.computercraft.shared.util.Colour; import dan200.computercraft.shared.util.Colour;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.BufferBuilder; import net.minecraft.client.renderer.*;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats; import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.client.event.RenderSpecificHandEvent; import net.minecraftforge.client.event.RenderHandEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.Mod;
import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL11;
@@ -45,17 +46,20 @@ public final class ItemPocketRenderer extends ItemMapLikeRenderer
} }
@SubscribeEvent @SubscribeEvent
public static void renderItem( RenderSpecificHandEvent event ) public static void onRenderInHand( RenderHandEvent event )
{ {
ItemStack stack = event.getItemStack(); ItemStack stack = event.getItemStack();
if( !(stack.getItem() instanceof ItemPocketComputer) ) return; if( !(stack.getItem() instanceof ItemPocketComputer) ) return;
event.setCanceled( true ); event.setCanceled( true );
INSTANCE.renderItemFirstPerson( event.getHand(), event.getInterpolatedPitch(), event.getEquipProgress(), event.getSwingProgress(), event.getItemStack() ); INSTANCE.renderItemFirstPerson(
event.getMatrixStack(), event.getBuffers(), event.getLight(),
event.getHand(), event.getInterpolatedPitch(), event.getEquipProgress(), event.getSwingProgress(), event.getItemStack()
);
} }
@Override @Override
protected void renderItem( ItemStack stack ) protected void renderItem( MatrixStack transform, IRenderTypeBuffer render, ItemStack stack )
{ {
ClientComputer computer = ItemPocketComputer.createClientComputer( stack ); ClientComputer computer = ItemPocketComputer.createClientComputer( stack );
Terminal terminal = computer == null ? null : computer.getTerminal(); Terminal terminal = computer == null ? null : computer.getTerminal();
@@ -77,50 +81,45 @@ public final class ItemPocketRenderer extends ItemMapLikeRenderer
// Setup various transformations. Note that these are partially adapted from the corresponding method // Setup various transformations. Note that these are partially adapted from the corresponding method
// in ItemRenderer // in ItemRenderer
GlStateManager.pushMatrix(); transform.push();
transform.rotate( Vector3f.YP.rotationDegrees( 180f ) );
transform.rotate( Vector3f.ZP.rotationDegrees( 180f ) );
transform.scale( 0.5f, 0.5f, 0.5f );
GlStateManager.disableLighting(); float scale = 0.75f / Math.max( width + FRAME * 2, height + FRAME * 2 + LIGHT_HEIGHT );
GlStateManager.disableDepthTest(); transform.scale( scale, scale, 0 );
transform.translate( -0.5 * width, -0.5 * height, 0 );
GlStateManager.rotatef( 180f, 0f, 1f, 0f );
GlStateManager.rotatef( 180f, 0f, 0f, 1f );
GlStateManager.scalef( 0.5f, 0.5f, 0.5f );
double scale = 0.75 / Math.max( width + FRAME * 2, height + FRAME * 2 + LIGHT_HEIGHT );
GlStateManager.scaled( scale, scale, 0 );
GlStateManager.translated( -0.5 * width, -0.5 * height, 0 );
// Render the main frame // Render the main frame
ItemPocketComputer item = (ItemPocketComputer) stack.getItem(); ItemPocketComputer item = (ItemPocketComputer) stack.getItem();
ComputerFamily family = item.getFamily(); ComputerFamily family = item.getFamily();
int frameColour = item.getColour( stack ); int frameColour = item.getColour( stack );
renderFrame( family, frameColour, width, height );
Matrix4f matrix = transform.getLast().getMatrix();
renderFrame( matrix, family, frameColour, width, height );
// Render the light // Render the light
int lightColour = ItemPocketComputer.getLightState( stack ); int lightColour = ItemPocketComputer.getLightState( stack );
if( lightColour == -1 ) lightColour = Colour.Black.getHex(); if( lightColour == -1 ) lightColour = Colour.BLACK.getHex();
renderLight( lightColour, width, height ); renderLight( matrix, lightColour, width, height );
if( computer != null && terminal != null ) if( computer != null && terminal != null )
{ {
FixedWidthFontRenderer.drawTerminal( MARGIN, MARGIN, terminal, !computer.isColour(), MARGIN, MARGIN, MARGIN, MARGIN ); FixedWidthFontRenderer.drawTerminal( matrix, MARGIN, MARGIN, terminal, !computer.isColour(), MARGIN, MARGIN, MARGIN, MARGIN );
} }
else else
{ {
FixedWidthFontRenderer.drawEmptyTerminal( 0, 0, width, height ); FixedWidthFontRenderer.drawEmptyTerminal( matrix, 0, 0, width, height );
} }
GlStateManager.enableDepthTest(); transform.pop();
GlStateManager.enableLighting();
GlStateManager.popMatrix();
} }
private static void renderFrame( ComputerFamily family, int colour, int width, int height ) private static void renderFrame( Matrix4f transform, ComputerFamily family, int colour, int width, int height )
{ {
Minecraft.getInstance().getTextureManager().bindTexture( colour != -1 Minecraft.getInstance().getTextureManager().bindTexture( colour != -1
? BACKGROUND_COLOUR ? BACKGROUND_COLOUR
: family == ComputerFamily.Normal ? BACKGROUND_NORMAL : BACKGROUND_ADVANCED : family == ComputerFamily.NORMAL ? BACKGROUND_NORMAL : BACKGROUND_ADVANCED
); );
float r = ((colour >>> 16) & 0xFF) / 255.0f; float r = ((colour >>> 16) & 0xFF) / 255.0f;
@@ -129,38 +128,38 @@ public final class ItemPocketRenderer extends ItemMapLikeRenderer
Tessellator tessellator = Tessellator.getInstance(); Tessellator tessellator = Tessellator.getInstance();
BufferBuilder buffer = tessellator.getBuffer(); BufferBuilder buffer = tessellator.getBuffer();
buffer.begin( GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX_COLOR ); buffer.begin( GL11.GL_QUADS, DefaultVertexFormats.POSITION_COLOR_TEX );
// Top left, middle, right // Top left, middle, right
renderTexture( buffer, -FRAME, -FRAME, 12, 28, FRAME, FRAME, r, g, b ); renderTexture( transform, buffer, -FRAME, -FRAME, 12, 28, FRAME, FRAME, r, g, b );
renderTexture( buffer, 0, -FRAME, 0, 0, width, FRAME, r, g, b ); renderTexture( transform, buffer, 0, -FRAME, 0, 0, width, FRAME, r, g, b );
renderTexture( buffer, width, -FRAME, 24, 28, FRAME, FRAME, r, g, b ); renderTexture( transform, buffer, width, -FRAME, 24, 28, FRAME, FRAME, r, g, b );
// Left and bright border // Left and bright border
renderTexture( buffer, -FRAME, 0, 0, 28, FRAME, height, r, g, b ); renderTexture( transform, buffer, -FRAME, 0, 0, 28, FRAME, height, r, g, b );
renderTexture( buffer, width, 0, 36, 28, FRAME, height, r, g, b ); renderTexture( transform, buffer, width, 0, 36, 28, FRAME, height, r, g, b );
// Bottom left, middle, right. We do this in three portions: the top inner corners, an extended region for // Bottom left, middle, right. We do this in three portions: the top inner corners, an extended region for
// lights, and then the bottom outer corners. // lights, and then the bottom outer corners.
renderTexture( buffer, -FRAME, height, 12, 40, FRAME, FRAME / 2, r, g, b ); renderTexture( transform, buffer, -FRAME, height, 12, 40, FRAME, FRAME / 2, r, g, b );
renderTexture( buffer, 0, height, 0, 12, width, FRAME / 2, r, g, b ); renderTexture( transform, buffer, 0, height, 0, 12, width, FRAME / 2, r, g, b );
renderTexture( buffer, width, height, 24, 40, FRAME, FRAME / 2, r, g, b ); renderTexture( transform, buffer, width, height, 24, 40, FRAME, FRAME / 2, r, g, b );
renderTexture( buffer, -FRAME, height + FRAME / 2, 12, 44, FRAME, LIGHT_HEIGHT, FRAME, 4, r, g, b ); renderTexture( transform, buffer, -FRAME, height + FRAME / 2, 12, 44, FRAME, LIGHT_HEIGHT, FRAME, 4, r, g, b );
renderTexture( buffer, 0, height + FRAME / 2, 0, 16, width, LIGHT_HEIGHT, FRAME, 4, r, g, b ); renderTexture( transform, buffer, 0, height + FRAME / 2, 0, 16, width, LIGHT_HEIGHT, FRAME, 4, r, g, b );
renderTexture( buffer, width, height + FRAME / 2, 24, 44, FRAME, LIGHT_HEIGHT, FRAME, 4, r, g, b ); renderTexture( transform, buffer, width, height + FRAME / 2, 24, 44, FRAME, LIGHT_HEIGHT, FRAME, 4, r, g, b );
renderTexture( buffer, -FRAME, height + LIGHT_HEIGHT + FRAME / 2, 12, 40 + FRAME / 2, FRAME, FRAME / 2, r, g, b ); renderTexture( transform, buffer, -FRAME, height + LIGHT_HEIGHT + FRAME / 2, 12, 40 + FRAME / 2, FRAME, FRAME / 2, r, g, b );
renderTexture( buffer, 0, height + LIGHT_HEIGHT + FRAME / 2, 0, 12 + FRAME / 2, width, FRAME / 2, r, g, b ); renderTexture( transform, buffer, 0, height + LIGHT_HEIGHT + FRAME / 2, 0, 12 + FRAME / 2, width, FRAME / 2, r, g, b );
renderTexture( buffer, width, height + LIGHT_HEIGHT + FRAME / 2, 24, 40 + FRAME / 2, FRAME, FRAME / 2, r, g, b ); renderTexture( transform, buffer, width, height + LIGHT_HEIGHT + FRAME / 2, 24, 40 + FRAME / 2, FRAME, FRAME / 2, r, g, b );
tessellator.draw(); tessellator.draw();
} }
private static void renderLight( int colour, int width, int height ) private static void renderLight( Matrix4f transform, int colour, int width, int height )
{ {
GlStateManager.enableBlend(); RenderSystem.enableBlend();
GlStateManager.disableTexture(); RenderSystem.disableTexture();
float r = ((colour >>> 16) & 0xFF) / 255.0f; float r = ((colour >>> 16) & 0xFF) / 255.0f;
float g = ((colour >>> 8) & 0xFF) / 255.0f; float g = ((colour >>> 8) & 0xFF) / 255.0f;
@@ -169,26 +168,26 @@ public final class ItemPocketRenderer extends ItemMapLikeRenderer
Tessellator tessellator = Tessellator.getInstance(); Tessellator tessellator = Tessellator.getInstance();
BufferBuilder buffer = tessellator.getBuffer(); BufferBuilder buffer = tessellator.getBuffer();
buffer.begin( GL11.GL_QUADS, DefaultVertexFormats.POSITION_COLOR ); buffer.begin( GL11.GL_QUADS, DefaultVertexFormats.POSITION_COLOR );
buffer.pos( width - LIGHT_HEIGHT * 2, height + LIGHT_HEIGHT + FRAME / 2.0f, 0.0D ).color( r, g, b, 1.0f ).endVertex(); buffer.pos( transform, width - LIGHT_HEIGHT * 2, height + LIGHT_HEIGHT + FRAME / 2.0f, 0 ).color( r, g, b, 1.0f ).endVertex();
buffer.pos( width, height + LIGHT_HEIGHT + FRAME / 2.0f, 0.0D ).color( r, g, b, 1.0f ).endVertex(); buffer.pos( transform, width, height + LIGHT_HEIGHT + FRAME / 2.0f, 0 ).color( r, g, b, 1.0f ).endVertex();
buffer.pos( width, height + FRAME / 2.0f, 0.0D ).color( r, g, b, 1.0f ).endVertex(); buffer.pos( transform, width, height + FRAME / 2.0f, 0 ).color( r, g, b, 1.0f ).endVertex();
buffer.pos( width - LIGHT_HEIGHT * 2, height + FRAME / 2.0f, 0.0D ).color( r, g, b, 1.0f ).endVertex(); buffer.pos( transform, width - LIGHT_HEIGHT * 2, height + FRAME / 2.0f, 0 ).color( r, g, b, 1.0f ).endVertex();
tessellator.draw(); tessellator.draw();
GlStateManager.enableTexture(); RenderSystem.enableTexture();
} }
private static void renderTexture( BufferBuilder builder, int x, int y, int textureX, int textureY, int width, int height, float r, float g, float b ) private static void renderTexture( Matrix4f transform, IVertexBuilder builder, int x, int y, int textureX, int textureY, int width, int height, float r, float g, float b )
{ {
renderTexture( builder, x, y, textureX, textureY, width, height, width, height, r, g, b ); renderTexture( transform, builder, x, y, textureX, textureY, width, height, width, height, r, g, b );
} }
private static void renderTexture( BufferBuilder builder, int x, int y, int textureX, int textureY, int width, int height, int textureWidth, int textureHeight, float r, float g, float b ) private static void renderTexture( Matrix4f transform, IVertexBuilder builder, int x, int y, int textureX, int textureY, int width, int height, int textureWidth, int textureHeight, float r, float g, float b )
{ {
float scale = 1 / 255.0f; float scale = 1 / 255.0f;
builder.pos( x, y + height, 0 ).tex( textureX * scale, (textureY + textureHeight) * scale ).color( r, g, b, 1.0f ).endVertex(); builder.pos( transform, x, y + height, 0 ).color( r, g, b, 1.0f ).tex( textureX * scale, (textureY + textureHeight) * scale ).endVertex();
builder.pos( x + width, y + height, 0 ).tex( (textureX + textureWidth) * scale, (textureY + textureHeight) * scale ).color( r, g, b, 1.0f ).endVertex(); builder.pos( transform, x + width, y + height, 0 ).color( r, g, b, 1.0f ).tex( (textureX + textureWidth) * scale, (textureY + textureHeight) * scale ).endVertex();
builder.pos( x + width, y, 0 ).tex( (textureX + textureWidth) * scale, textureY * scale ).color( r, g, b, 1.0f ).endVertex(); builder.pos( transform, x + width, y, 0 ).color( r, g, b, 1.0f ).tex( (textureX + textureWidth) * scale, textureY * scale ).endVertex();
builder.pos( x, y, 0 ).tex( textureX * scale, textureY * scale ).color( r, g, b, 1.0f ).endVertex(); builder.pos( transform, x, y, 0 ).color( r, g, b, 1.0f ).tex( textureX * scale, textureY * scale ).endVertex();
} }
} }

View File

@@ -5,13 +5,16 @@
*/ */
package dan200.computercraft.client.render; package dan200.computercraft.client.render;
import com.mojang.blaze3d.platform.GlStateManager; import com.mojang.blaze3d.matrix.MatrixStack;
import dan200.computercraft.ComputerCraft; import dan200.computercraft.ComputerCraft;
import dan200.computercraft.shared.media.items.ItemPrintout; import dan200.computercraft.shared.media.items.ItemPrintout;
import net.minecraft.client.renderer.IRenderTypeBuffer;
import net.minecraft.client.renderer.Matrix4f;
import net.minecraft.client.renderer.Vector3f;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.client.event.RenderHandEvent;
import net.minecraftforge.client.event.RenderItemInFrameEvent; import net.minecraftforge.client.event.RenderItemInFrameEvent;
import net.minecraftforge.client.event.RenderSpecificHandEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.Mod;
@@ -34,30 +37,26 @@ public final class ItemPrintoutRenderer extends ItemMapLikeRenderer
} }
@SubscribeEvent @SubscribeEvent
public static void onRenderInHand( RenderSpecificHandEvent event ) public static void onRenderInHand( RenderHandEvent event )
{ {
ItemStack stack = event.getItemStack(); ItemStack stack = event.getItemStack();
if( !(stack.getItem() instanceof ItemPrintout) ) return; if( !(stack.getItem() instanceof ItemPrintout) ) return;
event.setCanceled( true ); event.setCanceled( true );
INSTANCE.renderItemFirstPerson( event.getHand(), event.getInterpolatedPitch(), event.getEquipProgress(), event.getSwingProgress(), event.getItemStack() ); INSTANCE.renderItemFirstPerson(
event.getMatrixStack(), event.getBuffers(), event.getLight(),
event.getHand(), event.getInterpolatedPitch(), event.getEquipProgress(), event.getSwingProgress(), event.getItemStack()
);
} }
@Override @Override
protected void renderItem( ItemStack stack ) protected void renderItem( MatrixStack transform, IRenderTypeBuffer render, ItemStack stack )
{ {
// Setup various transformations. Note that these are partially adapated from the corresponding method transform.rotate( Vector3f.XP.rotationDegrees( 180f ) );
// in FirstPersonRenderer.renderFirstPersonMap transform.scale( 0.42f, 0.42f, -0.42f );
GlStateManager.disableLighting(); transform.translate( -0.5f, -0.48f, 0.0f );
GlStateManager.rotatef( 180f, 0f, 1f, 0f ); drawPrintout( transform, render, stack );
GlStateManager.rotatef( 180f, 0f, 0f, 1f );
GlStateManager.scalef( 0.42f, 0.42f, -0.42f );
GlStateManager.translatef( -0.5f, -0.48f, 0.0f );
drawPrintout( stack );
GlStateManager.enableLighting();
} }
@SubscribeEvent @SubscribeEvent
@@ -65,24 +64,20 @@ public final class ItemPrintoutRenderer extends ItemMapLikeRenderer
{ {
ItemStack stack = event.getItem(); ItemStack stack = event.getItem();
if( !(stack.getItem() instanceof ItemPrintout) ) return; if( !(stack.getItem() instanceof ItemPrintout) ) return;
event.setCanceled( true ); event.setCanceled( true );
GlStateManager.disableLighting(); MatrixStack transform = event.getMatrix();
// Move a little bit forward to ensure we're not clipping with the frame // Move a little bit forward to ensure we're not clipping with the frame
GlStateManager.translatef( 0.0f, 0.0f, -0.001f ); transform.translate( 0.0f, 0.0f, -0.001f );
GlStateManager.rotatef( 180f, 0f, 0f, 1f ); transform.rotate( Vector3f.ZP.rotationDegrees( 180f ) );
GlStateManager.scalef( 0.95f, 0.95f, -0.95f ); transform.scale( 0.95f, 0.95f, -0.95f );
GlStateManager.translatef( -0.5f, -0.5f, 0.0f ); transform.translate( -0.5f, -0.5f, 0.0f );
drawPrintout( stack ); drawPrintout( transform, event.getBuffers(), stack );
GlStateManager.enableLighting();
GlStateManager.disableBlend();
} }
private static void drawPrintout( ItemStack stack ) private static void drawPrintout( MatrixStack transform, IRenderTypeBuffer render, ItemStack stack )
{ {
int pages = ItemPrintout.getPageCount( stack ); int pages = ItemPrintout.getPageCount( stack );
boolean book = ((ItemPrintout) stack.getItem()).getType() == ItemPrintout.Type.BOOK; boolean book = ((ItemPrintout) stack.getItem()).getType() == ItemPrintout.Type.BOOK;
@@ -105,11 +100,14 @@ public final class ItemPrintoutRenderer extends ItemMapLikeRenderer
double max = Math.max( visualHeight, visualWidth ); double max = Math.max( visualHeight, visualWidth );
// Scale the printout to fit correctly. // Scale the printout to fit correctly.
double scale = 1.0 / max; float scale = (float) (1.0 / max);
GlStateManager.scaled( scale, scale, scale ); transform.scale( scale, scale, scale );
GlStateManager.translated( (max - width) / 2.0, (max - height) / 2.0, 0.0 ); transform.translate( (max - width) / 2.0, (max - height) / 2.0, 0.0 );
drawBorder( 0, 0, -0.01, 0, pages, book ); Matrix4f matrix = transform.getLast().getMatrix();
drawText( X_TEXT_MARGIN, Y_TEXT_MARGIN, 0, ItemPrintout.getText( stack ), ItemPrintout.getColours( stack ) ); 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 )
);
} }
} }

View File

@@ -1,269 +0,0 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.client.render;
import net.minecraft.client.renderer.model.BakedQuad;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.renderer.vertex.VertexFormat;
import net.minecraft.util.Direction;
import net.minecraftforge.client.model.pipeline.IVertexConsumer;
import net.minecraftforge.client.model.pipeline.LightUtil;
import net.minecraftforge.client.model.pipeline.VertexTransformer;
import net.minecraftforge.common.model.TRSRTransformation;
import javax.annotation.Nonnull;
import javax.vecmath.Matrix4f;
import javax.vecmath.Point3f;
import javax.vecmath.Vector3f;
import java.util.List;
/**
* Transforms vertices of a model, remaining aware of winding order, and rearranging
* vertices if needed.
*/
public final class ModelTransformer
{
private static final Matrix4f identity;
static
{
identity = new Matrix4f();
identity.setIdentity();
}
private ModelTransformer()
{
}
public static void transformQuadsTo( List<BakedQuad> output, List<BakedQuad> input, Matrix4f transform )
{
if( transform == null || transform.equals( identity ) )
{
output.addAll( input );
}
else
{
Matrix4f normalMatrix = new Matrix4f( transform );
normalMatrix.invert();
normalMatrix.transpose();
for( BakedQuad quad : input ) output.add( doTransformQuad( quad, transform, normalMatrix ) );
}
}
public static BakedQuad transformQuad( BakedQuad input, Matrix4f transform )
{
if( transform == null || transform.equals( identity ) ) return input;
Matrix4f normalMatrix = new Matrix4f( transform );
normalMatrix.invert();
normalMatrix.transpose();
return doTransformQuad( input, transform, normalMatrix );
}
private static BakedQuad doTransformQuad( BakedQuad input, Matrix4f positionMatrix, Matrix4f normalMatrix )
{
BakedQuadBuilder builder = new BakedQuadBuilder( input.getFormat() );
NormalAwareTransformer transformer = new NormalAwareTransformer( builder, positionMatrix, normalMatrix );
input.pipe( transformer );
if( transformer.areNormalsInverted() )
{
builder.swap( 1, 3 );
transformer.areNormalsInverted();
}
return builder.build();
}
/**
* A vertex transformer that tracks whether the normals have been inverted and so the vertices
* should be reordered so backface culling works as expected.
*/
private static class NormalAwareTransformer extends VertexTransformer
{
private final Matrix4f positionMatrix;
private final Matrix4f normalMatrix;
private int vertexIndex = 0, elementIndex = 0;
private final Point3f[] before = new Point3f[4];
private final Point3f[] after = new Point3f[4];
NormalAwareTransformer( IVertexConsumer parent, Matrix4f positionMatrix, Matrix4f normalMatrix )
{
super( parent );
this.positionMatrix = positionMatrix;
this.normalMatrix = normalMatrix;
}
@Override
public void setQuadOrientation( @Nonnull Direction orientation )
{
super.setQuadOrientation( orientation == null ? orientation : TRSRTransformation.rotate( positionMatrix, orientation ) );
}
@Override
public void put( int element, @Nonnull float... data )
{
switch( getVertexFormat().getElement( element ).getUsage() )
{
case POSITION:
{
Point3f vec = new Point3f( data );
Point3f newVec = new Point3f();
positionMatrix.transform( vec, newVec );
float[] newData = new float[4];
newVec.get( newData );
super.put( element, newData );
before[vertexIndex] = vec;
after[vertexIndex] = newVec;
break;
}
case NORMAL:
{
Vector3f vec = new Vector3f( data );
normalMatrix.transform( vec );
float[] newData = new float[4];
vec.get( newData );
super.put( element, newData );
break;
}
default:
super.put( element, data );
break;
}
elementIndex++;
if( elementIndex == getVertexFormat().getElementCount() )
{
vertexIndex++;
elementIndex = 0;
}
}
public boolean areNormalsInverted()
{
Vector3f temp1 = new Vector3f(), temp2 = new Vector3f();
Vector3f crossBefore = new Vector3f(), crossAfter = new Vector3f();
// Determine what cross product we expect to have
temp1.sub( before[1], before[0] );
temp2.sub( before[1], before[2] );
crossBefore.cross( temp1, temp2 );
normalMatrix.transform( crossBefore );
// And determine what cross product we actually have
temp1.sub( after[1], after[0] );
temp2.sub( after[1], after[2] );
crossAfter.cross( temp1, temp2 );
// If the angle between expected and actual cross product is greater than
// pi/2 radians then we will need to reorder our quads.
return Math.abs( crossBefore.angle( crossAfter ) ) >= Math.PI / 2;
}
}
/**
* A vertex consumer which is capable of building {@link BakedQuad}s.
*
* Equivalent to {@link net.minecraftforge.client.model.pipeline.UnpackedBakedQuad.Builder} but more memory
* efficient.
*
* This also provides the ability to swap vertices through {@link #swap(int, int)} to allow reordering.
*/
private static final class BakedQuadBuilder implements IVertexConsumer
{
private final VertexFormat format;
private final int[] vertexData;
private int vertexIndex = 0, elementIndex = 0;
private Direction orientation;
private int quadTint;
private boolean diffuse;
private TextureAtlasSprite texture;
private BakedQuadBuilder( VertexFormat format )
{
this.format = format;
vertexData = new int[format.getSize()];
}
@Nonnull
@Override
public VertexFormat getVertexFormat()
{
return format;
}
@Override
public void setQuadTint( int tint )
{
quadTint = tint;
}
@Override
public void setQuadOrientation( @Nonnull Direction orientation )
{
this.orientation = orientation;
}
@Override
public void setApplyDiffuseLighting( boolean diffuse )
{
this.diffuse = diffuse;
}
@Override
public void setTexture( @Nonnull TextureAtlasSprite texture )
{
this.texture = texture;
}
@Override
public void put( int element, @Nonnull float... data )
{
LightUtil.pack( data, vertexData, format, vertexIndex, element );
elementIndex++;
if( elementIndex == getVertexFormat().getElementCount() )
{
vertexIndex++;
elementIndex = 0;
}
}
public void swap( int a, int b )
{
int length = vertexData.length / 4;
for( int i = 0; i < length; i++ )
{
int temp = vertexData[a * length + i];
vertexData[a * length + i] = vertexData[b * length + i];
vertexData[b * length + i] = temp;
}
}
public BakedQuad build()
{
if( elementIndex != 0 || vertexIndex != 4 )
{
throw new IllegalStateException( "Got an unexpected number of elements/vertices" );
}
if( texture == null )
{
throw new IllegalStateException( "Texture has not been set" );
}
return new BakedQuad( vertexData, quadTint, orientation, texture, diffuse, format );
}
}
}

View File

@@ -5,49 +5,45 @@
*/ */
package dan200.computercraft.client.render; package dan200.computercraft.client.render;
import com.mojang.blaze3d.platform.GlStateManager; import com.mojang.blaze3d.matrix.MatrixStack;
import com.mojang.blaze3d.vertex.IVertexBuilder;
import dan200.computercraft.ComputerCraft; import dan200.computercraft.ComputerCraft;
import dan200.computercraft.shared.peripheral.monitor.TileMonitor; import dan200.computercraft.shared.peripheral.monitor.TileMonitor;
import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.Matrix4f;
import net.minecraft.client.renderer.BufferBuilder; import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.Direction; import net.minecraft.util.Direction;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.BlockRayTraceResult;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World; import net.minecraft.world.World;
import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.client.event.DrawBlockHighlightEvent; import net.minecraftforge.client.event.DrawHighlightEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.Mod;
import org.lwjgl.opengl.GL11;
import java.util.EnumSet; import java.util.EnumSet;
import static net.minecraft.util.Direction.*; import static net.minecraft.util.Direction.*;
/**
* Overrides monitor highlighting to only render the outline of the <em>whole</em> monitor, rather than the current
* block. This means you do not get an intrusive outline on top of the screen.
*/
@Mod.EventBusSubscriber( modid = ComputerCraft.MOD_ID, value = Dist.CLIENT ) @Mod.EventBusSubscriber( modid = ComputerCraft.MOD_ID, value = Dist.CLIENT )
public final class MonitorHighlightRenderer public final class MonitorHighlightRenderer
{ {
private static final float EXPAND = 0.002f;
private MonitorHighlightRenderer() private MonitorHighlightRenderer()
{ {
} }
@SubscribeEvent @SubscribeEvent
public static void drawHighlight( DrawBlockHighlightEvent event ) public static void drawHighlight( DrawHighlightEvent.HighlightBlock event )
{ {
if( event.getTarget().getType() != RayTraceResult.Type.BLOCK || event.getInfo().getRenderViewEntity().isSneaking() ) // Preserve normal behaviour when crouching.
{ if( event.getInfo().getRenderViewEntity().isCrouching() ) return;
return;
}
World world = event.getInfo().getRenderViewEntity().getEntityWorld(); World world = event.getInfo().getRenderViewEntity().getEntityWorld();
BlockPos pos = ((BlockRayTraceResult) event.getTarget()).getPos(); BlockPos pos = event.getTarget().getPos();
TileEntity tile = world.getTileEntity( pos ); TileEntity tile = world.getTileEntity( pos );
if( !(tile instanceof TileMonitor) ) return; if( !(tile instanceof TileMonitor) ) return;
@@ -64,53 +60,37 @@ public final class MonitorHighlightRenderer
if( monitor.getYIndex() != 0 ) faces.remove( monitor.getDown().getOpposite() ); if( monitor.getYIndex() != 0 ) faces.remove( monitor.getDown().getOpposite() );
if( monitor.getYIndex() != monitor.getHeight() - 1 ) faces.remove( monitor.getDown() ); if( monitor.getYIndex() != monitor.getHeight() - 1 ) faces.remove( monitor.getDown() );
GlStateManager.enableBlend(); MatrixStack transformStack = event.getMatrix();
GlStateManager.blendFuncSeparate( GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA, GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ZERO );
GlStateManager.lineWidth( Math.max( 2.5F, (float) Minecraft.getInstance().mainWindow.getFramebufferWidth() / 1920.0F * 2.5F ) );
GlStateManager.disableTexture();
GlStateManager.depthMask( false );
GlStateManager.pushMatrix();
Vec3d cameraPos = event.getInfo().getProjectedView(); Vec3d cameraPos = event.getInfo().getProjectedView();
GlStateManager.translated( pos.getX() - cameraPos.getX(), pos.getY() - cameraPos.getY(), pos.getZ() - cameraPos.getZ() ); transformStack.push();
transformStack.translate( pos.getX() - cameraPos.getX(), pos.getY() - cameraPos.getY(), pos.getZ() - cameraPos.getZ() );
Tessellator tessellator = Tessellator.getInstance();
BufferBuilder buffer = tessellator.getBuffer();
buffer.begin( GL11.GL_LINES, DefaultVertexFormats.POSITION_COLOR );
// I wish I could think of a better way to do this // I wish I could think of a better way to do this
if( faces.contains( NORTH ) || faces.contains( WEST ) ) line( buffer, 0, 0, 0, UP ); IVertexBuilder buffer = event.getBuffers().getBuffer( RenderType.getLines() );
if( faces.contains( SOUTH ) || faces.contains( WEST ) ) line( buffer, 0, 0, 1, UP ); Matrix4f transform = transformStack.getLast().getMatrix();
if( faces.contains( NORTH ) || faces.contains( EAST ) ) line( buffer, 1, 0, 0, UP ); if( faces.contains( NORTH ) || faces.contains( WEST ) ) line( buffer, transform, 0, 0, 0, UP );
if( faces.contains( SOUTH ) || faces.contains( EAST ) ) line( buffer, 1, 0, 1, UP ); if( faces.contains( SOUTH ) || faces.contains( WEST ) ) line( buffer, transform, 0, 0, 1, UP );
if( faces.contains( NORTH ) || faces.contains( DOWN ) ) line( buffer, 0, 0, 0, EAST ); if( faces.contains( NORTH ) || faces.contains( EAST ) ) line( buffer, transform, 1, 0, 0, UP );
if( faces.contains( SOUTH ) || faces.contains( DOWN ) ) line( buffer, 0, 0, 1, EAST ); if( faces.contains( SOUTH ) || faces.contains( EAST ) ) line( buffer, transform, 1, 0, 1, UP );
if( faces.contains( NORTH ) || faces.contains( UP ) ) line( buffer, 0, 1, 0, EAST ); if( faces.contains( NORTH ) || faces.contains( DOWN ) ) line( buffer, transform, 0, 0, 0, EAST );
if( faces.contains( SOUTH ) || faces.contains( UP ) ) line( buffer, 0, 1, 1, EAST ); if( faces.contains( SOUTH ) || faces.contains( DOWN ) ) line( buffer, transform, 0, 0, 1, EAST );
if( faces.contains( WEST ) || faces.contains( DOWN ) ) line( buffer, 0, 0, 0, SOUTH ); if( faces.contains( NORTH ) || faces.contains( UP ) ) line( buffer, transform, 0, 1, 0, EAST );
if( faces.contains( EAST ) || faces.contains( DOWN ) ) line( buffer, 1, 0, 0, SOUTH ); if( faces.contains( SOUTH ) || faces.contains( UP ) ) line( buffer, transform, 0, 1, 1, EAST );
if( faces.contains( WEST ) || faces.contains( UP ) ) line( buffer, 0, 1, 0, SOUTH ); if( faces.contains( WEST ) || faces.contains( DOWN ) ) line( buffer, transform, 0, 0, 0, SOUTH );
if( faces.contains( EAST ) || faces.contains( UP ) ) line( buffer, 1, 1, 0, SOUTH ); if( faces.contains( EAST ) || faces.contains( DOWN ) ) line( buffer, transform, 1, 0, 0, SOUTH );
if( faces.contains( WEST ) || faces.contains( UP ) ) line( buffer, transform, 0, 1, 0, SOUTH );
if( faces.contains( EAST ) || faces.contains( UP ) ) line( buffer, transform, 1, 1, 0, SOUTH );
tessellator.draw(); transformStack.pop();
GlStateManager.popMatrix();
GlStateManager.depthMask( true );
GlStateManager.enableTexture();
GlStateManager.disableBlend();
} }
private static void line( BufferBuilder buffer, int x, int y, int z, Direction direction ) private static void line( IVertexBuilder buffer, Matrix4f transform, float x, float y, float z, Direction direction )
{ {
double minX = x == 0 ? -EXPAND : 1 + EXPAND; buffer.pos( transform, x, y, z ).color( 0, 0, 0, 0.4f ).endVertex();
double minY = y == 0 ? -EXPAND : 1 + EXPAND; buffer.pos( transform,
double minZ = z == 0 ? -EXPAND : 1 + EXPAND; x + direction.getXOffset(),
y + direction.getYOffset(),
buffer.pos( minX, minY, minZ ).color( 0, 0, 0, 0.4f ).endVertex(); z + direction.getZOffset()
buffer.pos(
minX + direction.getXOffset() * (1 + EXPAND * 2),
minY + direction.getYOffset() * (1 + EXPAND * 2),
minZ + direction.getZOffset() * (1 + EXPAND * 2)
).color( 0, 0, 0, 0.4f ).endVertex(); ).color( 0, 0, 0, 0.4f ).endVertex();
} }
} }

View File

@@ -5,15 +5,14 @@
*/ */
package dan200.computercraft.client.render; package dan200.computercraft.client.render;
import com.mojang.blaze3d.platform.GlStateManager; import com.mojang.blaze3d.vertex.IVertexBuilder;
import com.mojang.blaze3d.platform.GlStateManager.DestFactor;
import com.mojang.blaze3d.platform.GlStateManager.SourceFactor;
import dan200.computercraft.client.gui.FixedWidthFontRenderer; import dan200.computercraft.client.gui.FixedWidthFontRenderer;
import dan200.computercraft.core.terminal.TextBuffer; import dan200.computercraft.core.terminal.TextBuffer;
import dan200.computercraft.shared.util.Palette; import dan200.computercraft.shared.util.Palette;
import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.IRenderTypeBuffer;
import net.minecraft.client.renderer.BufferBuilder; import net.minecraft.client.renderer.Matrix4f;
import net.minecraft.client.renderer.Tessellator; import net.minecraft.client.renderer.RenderState;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats; import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.util.ResourceLocation; import net.minecraft.util.ResourceLocation;
import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL11;
@@ -24,7 +23,7 @@ import static dan200.computercraft.shared.media.items.ItemPrintout.LINES_PER_PAG
public final class PrintoutRenderer public final class PrintoutRenderer
{ {
private static final ResourceLocation BG = new ResourceLocation( "computercraft", "textures/gui/printout.png" ); private static final ResourceLocation BG = new ResourceLocation( "computercraft", "textures/gui/printout.png" );
private static final double BG_SIZE = 256.0; private static final float BG_SIZE = 256.0f;
/** /**
* Width of a page. * Width of a page.
@@ -61,27 +60,24 @@ public final class PrintoutRenderer
private PrintoutRenderer() {} private PrintoutRenderer() {}
public static void drawText( int x, int y, int start, TextBuffer[] text, TextBuffer[] colours ) public static void drawText( Matrix4f transform, IRenderTypeBuffer renderer, int x, int y, int start, TextBuffer[] text, TextBuffer[] colours )
{ {
IVertexBuilder buffer = renderer.getBuffer( FixedWidthFontRenderer.TYPE );
for( int line = 0; line < LINES_PER_PAGE && line < text.length; line++ ) for( int line = 0; line < LINES_PER_PAGE && line < text.length; line++ )
{ {
FixedWidthFontRenderer.drawString( FixedWidthFontRenderer.drawString( transform, buffer,
x, y + line * FONT_HEIGHT, text[start + line], colours[start + line], null, Palette.DEFAULT, x, y + line * FONT_HEIGHT, text[start + line], colours[start + line], null, Palette.DEFAULT,
false, 0, 0 false, 0, 0
); );
} }
} }
public static void drawText( int x, int y, int start, String[] text, String[] colours ) public static void drawText( Matrix4f transform, IRenderTypeBuffer renderer, int x, int y, int start, String[] text, String[] colours )
{ {
GlStateManager.color4f( 1.0f, 1.0f, 1.0f, 1.0f ); IVertexBuilder buffer = renderer.getBuffer( FixedWidthFontRenderer.TYPE );
GlStateManager.enableBlend();
GlStateManager.enableTexture();
GlStateManager.blendFuncSeparate( SourceFactor.SRC_ALPHA, DestFactor.ONE_MINUS_SRC_ALPHA, SourceFactor.ONE, DestFactor.ZERO );
for( int line = 0; line < LINES_PER_PAGE && line < text.length; line++ ) for( int line = 0; line < LINES_PER_PAGE && line < text.length; line++ )
{ {
FixedWidthFontRenderer.drawString( FixedWidthFontRenderer.drawString( transform, buffer,
x, y + line * FONT_HEIGHT, x, y + line * FONT_HEIGHT,
new TextBuffer( text[start + line] ), new TextBuffer( colours[start + line] ), new TextBuffer( text[start + line] ), new TextBuffer( colours[start + line] ),
null, Palette.DEFAULT, false, 0, 0 null, Palette.DEFAULT, false, 0, 0
@@ -89,55 +85,46 @@ public final class PrintoutRenderer
} }
} }
public static void drawBorder( double x, double y, double z, int page, int pages, boolean isBook ) public static void drawBorder( Matrix4f transform, IRenderTypeBuffer renderer, float x, float y, float z, int page, int pages, boolean isBook )
{ {
GlStateManager.color4f( 1.0f, 1.0f, 1.0f, 1.0f );
GlStateManager.enableBlend();
GlStateManager.enableTexture();
GlStateManager.blendFuncSeparate( SourceFactor.SRC_ALPHA, DestFactor.ONE_MINUS_SRC_ALPHA, SourceFactor.ONE, DestFactor.ZERO );
Minecraft.getInstance().getTextureManager().bindTexture( BG );
Tessellator tessellator = Tessellator.getInstance();
BufferBuilder buffer = tessellator.getBuffer();
buffer.begin( GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX );
int leftPages = page; int leftPages = page;
int rightPages = pages - page - 1; int rightPages = pages - page - 1;
IVertexBuilder buffer = renderer.getBuffer( Type.TYPE );
if( isBook ) if( isBook )
{ {
// Border // Border
double offset = offsetAt( pages ); float offset = offsetAt( pages );
final double left = x - 4 - offset; float left = x - 4 - offset;
final double right = x + X_SIZE + offset - 4; float right = x + X_SIZE + offset - 4;
// Left and right border // Left and right border
drawTexture( buffer, left - 4, y - 8, z - 0.02, COVER_X, 0, COVER_SIZE, Y_SIZE + COVER_SIZE * 2 ); drawTexture( transform, buffer, left - 4, y - 8, z - 0.02f, COVER_X, 0, COVER_SIZE, Y_SIZE + COVER_SIZE * 2 );
drawTexture( buffer, right, y - 8, z - 0.02, COVER_X + COVER_SIZE, 0, COVER_SIZE, Y_SIZE + COVER_SIZE * 2 ); drawTexture( transform, buffer, right, y - 8, z - 0.02f, COVER_X + COVER_SIZE, 0, COVER_SIZE, Y_SIZE + COVER_SIZE * 2 );
// Draw centre panel (just stretched texture, sorry). // Draw centre panel (just stretched texture, sorry).
drawTexture( buffer, drawTexture( transform, buffer,
x - offset, y, z - 0.02, X_SIZE + offset * 2, Y_SIZE, x - offset, y, z - 0.02f, X_SIZE + offset * 2, Y_SIZE,
COVER_X + COVER_SIZE / 2.0f, COVER_SIZE, COVER_SIZE, Y_SIZE COVER_X + COVER_SIZE / 2.0f, COVER_SIZE, COVER_SIZE, Y_SIZE
); );
double borderX = left; float borderX = left;
while( borderX < right ) while( borderX < right )
{ {
double thisWidth = Math.min( right - borderX, X_SIZE ); double thisWidth = Math.min( right - borderX, X_SIZE );
drawTexture( buffer, borderX, y - 8, z - 0.02, 0, COVER_Y, thisWidth, COVER_SIZE ); drawTexture( transform, buffer, borderX, y - 8, z - 0.02f, 0, COVER_Y, (float) thisWidth, COVER_SIZE );
drawTexture( buffer, borderX, y + Y_SIZE - 4, z - 0.02, 0, COVER_Y + COVER_SIZE, thisWidth, COVER_SIZE ); drawTexture( transform, buffer, borderX, y + Y_SIZE - 4, z - 0.02f, 0, COVER_Y + COVER_SIZE, (float) thisWidth, COVER_SIZE );
borderX += thisWidth; borderX += thisWidth;
} }
} }
// Left half // Left half
drawTexture( 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 );
for( int n = 0; n <= leftPages; n++ ) for( int n = 0; n <= leftPages; n++ )
{ {
drawTexture( buffer, drawTexture( transform, buffer,
x - offsetAt( n ), y, z - 1e-3 * n, x - offsetAt( n ), y, z - 1e-3f * n,
// Use the left "bold" fold for the outermost page // Use the left "bold" fold for the outermost page
n == leftPages ? 0 : X_FOLD_SIZE, 0, n == leftPages ? 0 : X_FOLD_SIZE, 0,
X_FOLD_SIZE, Y_SIZE X_FOLD_SIZE, Y_SIZE
@@ -145,38 +132,54 @@ public final class PrintoutRenderer
} }
// Right half // Right half
drawTexture( 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 );
for( int n = 0; n <= rightPages; n++ ) for( int n = 0; n <= rightPages; n++ )
{ {
drawTexture( buffer, drawTexture( transform, buffer,
x + (X_SIZE - X_FOLD_SIZE) + offsetAt( n ), y, z - 1e-3 * n, x + (X_SIZE - X_FOLD_SIZE) + offsetAt( n ), y, z - 1e-3f * n,
// Two folds, then the main page. Use the right "bold" fold for the outermost page. // Two folds, then the main page. Use the right "bold" fold for the outermost page.
X_FOLD_SIZE * 2 + X_SIZE + (n == rightPages ? X_FOLD_SIZE : 0), 0, X_FOLD_SIZE * 2 + X_SIZE + (n == rightPages ? X_FOLD_SIZE : 0), 0,
X_FOLD_SIZE, Y_SIZE X_FOLD_SIZE, Y_SIZE
); );
} }
tessellator.draw();
} }
private static void drawTexture( BufferBuilder buffer, double x, double y, double z, double u, double v, double width, double height ) private static void drawTexture( Matrix4f matrix, IVertexBuilder buffer, float x, float y, float z, float u, float v, float width, float height )
{ {
buffer.pos( x, y + height, z ).tex( u / BG_SIZE, (v + height) / BG_SIZE ).endVertex(); buffer.pos( matrix, x, y + height, z ).tex( u / BG_SIZE, (v + height) / BG_SIZE ).endVertex();
buffer.pos( x + width, y + height, z ).tex( (u + width) / BG_SIZE, (v + height) / BG_SIZE ).endVertex(); buffer.pos( matrix, x + width, y + height, z ).tex( (u + width) / BG_SIZE, (v + height) / BG_SIZE ).endVertex();
buffer.pos( x + width, y, z ).tex( (u + width) / BG_SIZE, v / BG_SIZE ).endVertex(); buffer.pos( matrix, x + width, y, z ).tex( (u + width) / BG_SIZE, v / BG_SIZE ).endVertex();
buffer.pos( x, y, z ).tex( u / BG_SIZE, v / BG_SIZE ).endVertex(); buffer.pos( matrix, x, y, z ).tex( u / BG_SIZE, v / BG_SIZE ).endVertex();
} }
private static void drawTexture( BufferBuilder buffer, double x, double y, double z, double width, double height, double u, double v, double tWidth, double tHeight ) private static void drawTexture( Matrix4f matrix, IVertexBuilder buffer, float x, float y, float z, float width, float height, float u, float v, float tWidth, float tHeight )
{ {
buffer.pos( x, y + height, z ).tex( u / BG_SIZE, (v + tHeight) / BG_SIZE ).endVertex(); buffer.pos( matrix, x, y + height, z ).tex( u / BG_SIZE, (v + tHeight) / BG_SIZE ).endVertex();
buffer.pos( x + width, y + height, z ).tex( (u + tWidth) / BG_SIZE, (v + tHeight) / BG_SIZE ).endVertex(); buffer.pos( matrix, x + width, y + height, z ).tex( (u + tWidth) / BG_SIZE, (v + tHeight) / BG_SIZE ).endVertex();
buffer.pos( x + width, y, z ).tex( (u + tWidth) / BG_SIZE, v / BG_SIZE ).endVertex(); buffer.pos( matrix, x + width, y, z ).tex( (u + tWidth) / BG_SIZE, v / BG_SIZE ).endVertex();
buffer.pos( x, y, z ).tex( u / BG_SIZE, v / BG_SIZE ).endVertex(); buffer.pos( matrix, x, y, z ).tex( u / BG_SIZE, v / BG_SIZE ).endVertex();
} }
public static double offsetAt( int page ) public static float offsetAt( int page )
{ {
return 32 * (1 - Math.pow( 1.2, -page )); return (float) (32 * (1 - Math.pow( 1.2, -page )));
}
private static final class Type extends RenderState
{
static final RenderType TYPE = RenderType.makeType(
"printout_background", DefaultVertexFormats.POSITION_TEX, GL11.GL_QUADS, 1024,
false, false, // useDelegate, needsSorting
RenderType.State.getBuilder()
.texture( new RenderState.TextureState( BG, false, false ) ) // blur, minimap
.alpha( DEFAULT_ALPHA )
.lightmap( LIGHTMAP_DISABLED )
.build( false )
);
private Type( String name, Runnable setup, Runnable destroy )
{
super( name, setup, destroy );
}
} }
} }

View File

@@ -1,140 +0,0 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.client.render;
import com.mojang.blaze3d.platform.GlStateManager;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.shared.peripheral.modem.wired.BlockCable;
import dan200.computercraft.shared.peripheral.modem.wired.CableModemVariant;
import dan200.computercraft.shared.peripheral.modem.wired.CableShapes;
import dan200.computercraft.shared.peripheral.modem.wired.TileCable;
import dan200.computercraft.shared.util.WorldUtil;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.BufferBuilder;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.WorldRenderer;
import net.minecraft.client.renderer.model.IBakedModel;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.renderer.tileentity.TileEntityRenderer;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.util.BlockRenderLayer;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.BlockRayTraceResult;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.world.World;
import net.minecraftforge.client.ForgeHooksClient;
import net.minecraftforge.client.model.data.EmptyModelData;
import org.lwjgl.opengl.GL11;
import javax.annotation.Nonnull;
import java.util.Random;
/**
* Render breaking animation only over part of a {@link TileCable}.
*/
public class TileEntityCableRenderer extends TileEntityRenderer<TileCable>
{
private static final ResourceLocation[] DESTROY_STAGES = new ResourceLocation[10];
private static final Random random = new Random();
static
{
for( int i = 0; i < DESTROY_STAGES.length; i++ )
{
DESTROY_STAGES[i] = new ResourceLocation( "block/destroy_stage_" + i );
}
}
@Override
public void render( @Nonnull TileCable te, double x, double y, double z, float partialTicks, int destroyStage )
{
if( destroyStage < 0 ) return;
BlockPos pos = te.getPos();
Minecraft mc = Minecraft.getInstance();
RayTraceResult hit = mc.objectMouseOver;
if( hit == null || hit.getType() != RayTraceResult.Type.BLOCK || !((BlockRayTraceResult) hit).getPos().equals( pos ) )
{
return;
}
World world = te.getWorld();
BlockState state = world.getBlockState( pos );
Block block = state.getBlock();
if( block != ComputerCraft.Blocks.cable ) return;
state = WorldUtil.isVecInside( CableShapes.getModemShape( state ), hit.getHitVec().subtract( pos.getX(), pos.getY(), pos.getZ() ) )
? block.getDefaultState().with( BlockCable.MODEM, state.get( BlockCable.MODEM ) )
: state.with( BlockCable.MODEM, CableModemVariant.None );
IBakedModel model = mc.getBlockRendererDispatcher().getModelForState( state );
preRenderDamagedBlocks();
ForgeHooksClient.setRenderLayer( block.getRenderLayer() );
// See BlockRendererDispatcher#renderBlockDamage
TextureAtlasSprite breakingTexture = mc.getTextureMap().getSprite( DESTROY_STAGES[destroyStage] );
BufferBuilder buffer = Tessellator.getInstance().getBuffer();
buffer.begin( GL11.GL_QUADS, DefaultVertexFormats.BLOCK );
buffer.setTranslation( x - pos.getX(), y - pos.getY(), z - pos.getZ() );
buffer.noColor();
mc.getBlockRendererDispatcher().getBlockModelRenderer().renderModel(
world,
ForgeHooksClient.getDamageModel( model, breakingTexture, state, world, pos, 0 ),
state, pos, buffer, true, random, state.getPositionRandom( pos ), EmptyModelData.INSTANCE
);
ForgeHooksClient.setRenderLayer( BlockRenderLayer.SOLID );
buffer.setTranslation( 0, 0, 0 );
Tessellator.getInstance().draw();
postRenderDamagedBlocks();
}
/**
* Set up the state for rendering block-breaking progress.
*
* @see WorldRenderer#preRenderDamagedBlocks()
*/
private void preRenderDamagedBlocks()
{
GlStateManager.disableLighting();
GlStateManager.enableBlend();
GlStateManager.blendFuncSeparate( GlStateManager.SourceFactor.DST_COLOR, GlStateManager.DestFactor.SRC_COLOR, GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ZERO );
GlStateManager.enableBlend();
GlStateManager.color4f( 1.0F, 1.0F, 1.0F, 0.5F );
GlStateManager.polygonOffset( -3.0F, -3.0F );
GlStateManager.enablePolygonOffset();
GlStateManager.alphaFunc( 516, 0.1F );
GlStateManager.enableAlphaTest();
GlStateManager.pushMatrix();
}
/**
* Tear down the state for rendering block-breaking progress.
*
* @see WorldRenderer#postRenderDamagedBlocks()
*/
private void postRenderDamagedBlocks()
{
GlStateManager.disableAlphaTest();
GlStateManager.polygonOffset( 0.0F, 0.0F );
GlStateManager.disablePolygonOffset();
GlStateManager.disablePolygonOffset();
GlStateManager.depthMask( true );
GlStateManager.popMatrix();
}
}

View File

@@ -5,8 +5,8 @@
*/ */
package dan200.computercraft.client.render; package dan200.computercraft.client.render;
import com.mojang.blaze3d.platform.GLX; import com.mojang.blaze3d.matrix.MatrixStack;
import com.mojang.blaze3d.platform.GlStateManager; import com.mojang.blaze3d.vertex.IVertexBuilder;
import dan200.computercraft.client.FrameInfo; import dan200.computercraft.client.FrameInfo;
import dan200.computercraft.client.gui.FixedWidthFontRenderer; import dan200.computercraft.client.gui.FixedWidthFontRenderer;
import dan200.computercraft.core.terminal.Terminal; import dan200.computercraft.core.terminal.Terminal;
@@ -14,25 +14,32 @@ import dan200.computercraft.shared.peripheral.monitor.ClientMonitor;
import dan200.computercraft.shared.peripheral.monitor.MonitorRenderer; import dan200.computercraft.shared.peripheral.monitor.MonitorRenderer;
import dan200.computercraft.shared.peripheral.monitor.TileMonitor; import dan200.computercraft.shared.peripheral.monitor.TileMonitor;
import dan200.computercraft.shared.util.DirectionUtil; import dan200.computercraft.shared.util.DirectionUtil;
import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.*;
import net.minecraft.client.renderer.BufferBuilder;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.tileentity.TileEntityRenderer; import net.minecraft.client.renderer.tileentity.TileEntityRenderer;
import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher;
import net.minecraft.client.renderer.vertex.VertexBuffer; import net.minecraft.client.renderer.vertex.VertexBuffer;
import net.minecraft.util.Direction; import net.minecraft.util.Direction;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import org.lwjgl.opengl.GL11;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import static dan200.computercraft.shared.peripheral.monitor.TileMonitor.RENDER_MARGIN;
public class TileEntityMonitorRenderer extends TileEntityRenderer<TileMonitor> public class TileEntityMonitorRenderer extends TileEntityRenderer<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.
*/
private static final float MARGIN = (float) (TileMonitor.RENDER_MARGIN * 1.1); private static final float MARGIN = (float) (TileMonitor.RENDER_MARGIN * 1.1);
private static final Matrix4f IDENTITY = TransformationMatrix.identity().getMatrix();
public TileEntityMonitorRenderer( TileEntityRendererDispatcher rendererDispatcher )
{
super( rendererDispatcher );
}
@Override @Override
public void render( @Nonnull TileMonitor monitor, double posX, double posY, double posZ, float f, int i ) public void render( @Nonnull TileMonitor monitor, float partialTicks, @Nonnull MatrixStack transform, @Nonnull IRenderTypeBuffer renderer, int lightmapCoord, int overlayLight )
{ {
// Render from the origin monitor // Render from the origin monitor
ClientMonitor originTerminal = monitor.getClientMonitor(); ClientMonitor originTerminal = monitor.getClientMonitor();
@@ -54,9 +61,6 @@ public class TileEntityMonitorRenderer extends TileEntityRenderer<TileMonitor>
originTerminal.lastRenderPos = monitorPos; originTerminal.lastRenderPos = monitorPos;
BlockPos originPos = origin.getPos(); BlockPos originPos = origin.getPos();
posX += originPos.getX() - monitorPos.getX();
posY += originPos.getY() - monitorPos.getY();
posZ += originPos.getZ() - monitorPos.getZ();
// Determine orientation // Determine orientation
Direction dir = origin.getDirection(); Direction dir = origin.getDirection();
@@ -64,130 +68,94 @@ public class TileEntityMonitorRenderer extends TileEntityRenderer<TileMonitor>
float yaw = dir.getHorizontalAngle(); float yaw = dir.getHorizontalAngle();
float pitch = DirectionUtil.toPitchAngle( front ); float pitch = DirectionUtil.toPitchAngle( front );
GlStateManager.pushMatrix();
// Setup initial transform // Setup initial transform
GlStateManager.translated( posX + 0.5, posY + 0.5, posZ + 0.5 ); transform.push();
GlStateManager.rotatef( -yaw, 0.0f, 1.0f, 0.0f ); transform.translate(
GlStateManager.rotatef( pitch, 1.0f, 0.0f, 0.0f ); originPos.getX() - monitorPos.getX() + 0.5,
GlStateManager.translated( originPos.getY() - monitorPos.getY() + 0.5,
-0.5 + TileMonitor.RENDER_BORDER + RENDER_MARGIN, originPos.getZ() - monitorPos.getZ() + 0.5
origin.getHeight() - 0.5 - (TileMonitor.RENDER_BORDER + RENDER_MARGIN) + 0, );
transform.rotate( Vector3f.YN.rotationDegrees( yaw ) );
transform.rotate( Vector3f.XP.rotationDegrees( pitch ) );
transform.translate(
-0.5 + TileMonitor.RENDER_BORDER + TileMonitor.RENDER_MARGIN,
origin.getHeight() - 0.5 - (TileMonitor.RENDER_BORDER + TileMonitor.RENDER_MARGIN) + 0,
0.5 0.5
); );
double xSize = origin.getWidth() - 2.0 * (RENDER_MARGIN + TileMonitor.RENDER_BORDER); double xSize = origin.getWidth() - 2.0 * (TileMonitor.RENDER_MARGIN + TileMonitor.RENDER_BORDER);
double ySize = origin.getHeight() - 2.0 * (RENDER_MARGIN + TileMonitor.RENDER_BORDER); double ySize = origin.getHeight() - 2.0 * (TileMonitor.RENDER_MARGIN + TileMonitor.RENDER_BORDER);
// Get renderers
Minecraft mc = Minecraft.getInstance();
// Set up render state for monitors. We disable writing to the depth buffer (we draw a "blocker" later),
// and setup lighting so that we render with a glow.
GlStateManager.depthMask( false );
GLX.glMultiTexCoord2f( GLX.GL_TEXTURE1, 0xFFFF, 0xFFFF );
GlStateManager.disableLighting();
mc.gameRenderer.disableLightmap();
// Draw the contents
Terminal terminal = originTerminal.getTerminal(); Terminal terminal = originTerminal.getTerminal();
if( terminal != null ) if( terminal != null )
{ {
boolean redraw = originTerminal.pollTerminalChanged();
if( originTerminal.buffer == null )
{
originTerminal.createBuffer( MonitorRenderer.VBO );
redraw = true;
}
VertexBuffer vbo = originTerminal.buffer;
// Draw a terminal // Draw a terminal
double xScale = xSize / (terminal.getWidth() * FixedWidthFontRenderer.FONT_WIDTH); double xScale = xSize / (terminal.getWidth() * FixedWidthFontRenderer.FONT_WIDTH);
double yScale = ySize / (terminal.getHeight() * FixedWidthFontRenderer.FONT_HEIGHT); double yScale = ySize / (terminal.getHeight() * FixedWidthFontRenderer.FONT_HEIGHT);
transform.push();
transform.scale( (float) xScale, (float) -yScale, 1.0f );
GlStateManager.pushMatrix(); float xMargin = (float) (MARGIN / xScale);
GlStateManager.scaled( (float) xScale, (float) -yScale, 1.0f ); float yMargin = (float) (MARGIN / yScale);
renderTerminal( originTerminal, (float) (MARGIN / xScale), (float) (MARGIN / yScale) ); Matrix4f matrix = transform.getLast().getMatrix();
GlStateManager.popMatrix(); if( redraw )
{
Tessellator tessellator = Tessellator.getInstance();
BufferBuilder builder = tessellator.getBuffer();
builder.begin( FixedWidthFontRenderer.TYPE.getDrawMode(), FixedWidthFontRenderer.TYPE.getVertexFormat() );
FixedWidthFontRenderer.drawTerminalWithoutCursor(
IDENTITY, builder, 0, 0,
terminal, !originTerminal.isColour(), yMargin, yMargin, xMargin, xMargin
);
builder.finishDrawing();
vbo.upload( builder );
}
// 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.
IVertexBuilder buffer = renderer.getBuffer( FixedWidthFontRenderer.TYPE );
FixedWidthFontRenderer.TYPE.setupRenderState();
vbo.bindBuffer();
FixedWidthFontRenderer.TYPE.getVertexFormat().setupBufferState( 0L );
vbo.draw( matrix, FixedWidthFontRenderer.TYPE.getDrawMode() );
VertexBuffer.unbindBuffer();
FixedWidthFontRenderer.TYPE.getVertexFormat().clearBufferState();
// 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() );
transform.pop();
} }
else else
{ {
FixedWidthFontRenderer.drawEmptyTerminal( FixedWidthFontRenderer.drawEmptyTerminal(
transform.getLast().getMatrix(), renderer,
-MARGIN, MARGIN, -MARGIN, MARGIN,
(float) (xSize + 2 * MARGIN), (float) -(ySize + MARGIN * 2) (float) (xSize + 2 * MARGIN), (float) -(ySize + MARGIN * 2)
); );
} }
// Tear down render state for monitors.
GlStateManager.depthMask( true );
mc.gameRenderer.enableLightmap();
GlStateManager.enableLighting();
// Draw the depth blocker
GlStateManager.colorMask( false, false, false, false );
FixedWidthFontRenderer.drawBlocker( FixedWidthFontRenderer.drawBlocker(
transform.getLast().getMatrix(), renderer,
(float) -TileMonitor.RENDER_MARGIN, (float) TileMonitor.RENDER_MARGIN, (float) -TileMonitor.RENDER_MARGIN, (float) TileMonitor.RENDER_MARGIN,
(float) (xSize + 2 * TileMonitor.RENDER_MARGIN), (float) -(ySize + TileMonitor.RENDER_MARGIN * 2) (float) (xSize + 2 * TileMonitor.RENDER_MARGIN), (float) -(ySize + TileMonitor.RENDER_MARGIN * 2)
); );
GlStateManager.colorMask( true, true, true, true );
GlStateManager.popMatrix(); transform.pop();
}
private static void renderTerminal( ClientMonitor monitor, float xMargin, float yMargin )
{
Tessellator tessellator = Tessellator.getInstance();
BufferBuilder buffer = tessellator.getBuffer();
boolean redraw = monitor.pollTerminalChanged();
// Setup the buffers if needed. We get the renderer here, to avoid the (unlikely) race condition between
// creating the buffers and rendering.
MonitorRenderer renderer = MonitorRenderer.current();
if( monitor.createBuffer( renderer ) ) redraw = true;
FixedWidthFontRenderer.bindFont();
switch( renderer )
{
case VBO:
{
VertexBuffer vbo = monitor.buffer;
if( redraw )
{
renderTerminalTo( monitor, buffer, xMargin, yMargin );
buffer.finishDrawing();
buffer.reset();
vbo.bufferData( buffer.getByteBuffer() );
}
vbo.bindBuffer();
setupBufferFormat();
vbo.drawArrays( GL11.GL_TRIANGLES );
VertexBuffer.unbindBuffer();
break;
}
}
// We don't draw the cursor with a buffer, as it's dynamic and so we'll end up refreshing far more than is
// reasonable.
FixedWidthFontRenderer.begin( buffer );
FixedWidthFontRenderer.drawCursor( buffer, 0, 0, monitor.getTerminal(), !monitor.isColour() );
tessellator.draw();
}
private static void renderTerminalTo( ClientMonitor monitor, BufferBuilder buffer, float xMargin, float yMargin )
{
FixedWidthFontRenderer.begin( buffer );
FixedWidthFontRenderer.drawTerminalWithoutCursor(
buffer, 0, 0,
monitor.getTerminal(), !monitor.isColour(), yMargin, yMargin, xMargin, xMargin
);
}
public static void setupBufferFormat()
{
int stride = FixedWidthFontRenderer.POSITION_COLOR_TEX.getSize();
GlStateManager.vertexPointer( 3, GL11.GL_FLOAT, stride, 0 );
GlStateManager.enableClientState( GL11.GL_VERTEX_ARRAY );
GlStateManager.colorPointer( 4, GL11.GL_UNSIGNED_BYTE, stride, 12 );
GlStateManager.enableClientState( GL11.GL_COLOR_ARRAY );
GlStateManager.texCoordPointer( 2, GL11.GL_FLOAT, stride, 16 );
GlStateManager.enableClientState( GL11.GL_TEXTURE_COORD_ARRAY );
} }
} }

View File

@@ -5,7 +5,9 @@
*/ */
package dan200.computercraft.client.render; package dan200.computercraft.client.render;
import com.mojang.blaze3d.platform.GlStateManager; import com.mojang.blaze3d.matrix.MatrixStack;
import com.mojang.blaze3d.vertex.IVertexBuilder;
import dan200.computercraft.api.client.TransformedModel;
import dan200.computercraft.api.turtle.ITurtleUpgrade; import dan200.computercraft.api.turtle.ITurtleUpgrade;
import dan200.computercraft.api.turtle.TurtleSide; import dan200.computercraft.api.turtle.TurtleSide;
import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.core.ComputerFamily;
@@ -13,31 +15,26 @@ import dan200.computercraft.shared.turtle.blocks.TileTurtle;
import dan200.computercraft.shared.util.DirectionUtil; import dan200.computercraft.shared.util.DirectionUtil;
import dan200.computercraft.shared.util.Holiday; import dan200.computercraft.shared.util.Holiday;
import dan200.computercraft.shared.util.HolidayUtil; import dan200.computercraft.shared.util.HolidayUtil;
import net.minecraft.block.BlockState;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.BufferBuilder; import net.minecraft.client.gui.FontRenderer;
import net.minecraft.client.renderer.GameRenderer; import net.minecraft.client.renderer.Atlases;
import net.minecraft.client.renderer.Tessellator; import net.minecraft.client.renderer.IRenderTypeBuffer;
import net.minecraft.client.renderer.Matrix4f;
import net.minecraft.client.renderer.Vector3f;
import net.minecraft.client.renderer.model.BakedQuad; import net.minecraft.client.renderer.model.BakedQuad;
import net.minecraft.client.renderer.model.IBakedModel; import net.minecraft.client.renderer.model.IBakedModel;
import net.minecraft.client.renderer.model.ModelManager; import net.minecraft.client.renderer.model.ModelManager;
import net.minecraft.client.renderer.model.ModelResourceLocation; import net.minecraft.client.renderer.model.ModelResourceLocation;
import net.minecraft.client.renderer.texture.AtlasTexture;
import net.minecraft.client.renderer.tileentity.TileEntityRenderer; import net.minecraft.client.renderer.tileentity.TileEntityRenderer;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats; import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher;
import net.minecraft.client.renderer.vertex.VertexFormat;
import net.minecraft.util.Direction; import net.minecraft.util.Direction;
import net.minecraft.util.ResourceLocation; import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.BlockRayTraceResult; import net.minecraft.util.math.BlockRayTraceResult;
import net.minecraft.util.math.RayTraceResult; import net.minecraft.util.math.RayTraceResult;
import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3d;
import net.minecraftforge.client.ForgeHooksClient;
import net.minecraftforge.client.model.data.EmptyModelData; import net.minecraftforge.client.model.data.EmptyModelData;
import net.minecraftforge.client.model.pipeline.LightUtil;
import org.apache.commons.lang3.tuple.Pair;
import org.lwjgl.opengl.GL11;
import javax.vecmath.Matrix4f; import javax.annotation.Nonnull;
import java.util.List; import java.util.List;
import java.util.Random; import java.util.Random;
@@ -48,189 +45,147 @@ public class TileEntityTurtleRenderer extends TileEntityRenderer<TileTurtle>
private static final ModelResourceLocation COLOUR_TURTLE_MODEL = new ModelResourceLocation( "computercraft:turtle_colour", "inventory" ); private static final ModelResourceLocation COLOUR_TURTLE_MODEL = new ModelResourceLocation( "computercraft:turtle_colour", "inventory" );
private static final ModelResourceLocation ELF_OVERLAY_MODEL = new ModelResourceLocation( "computercraft:turtle_elf_overlay", "inventory" ); private static final ModelResourceLocation ELF_OVERLAY_MODEL = new ModelResourceLocation( "computercraft:turtle_elf_overlay", "inventory" );
@Override private final Random random = new Random( 0 );
public void render( TileTurtle tileEntity, double posX, double posY, double posZ, float partialTicks, int breaking )
public TileEntityTurtleRenderer( TileEntityRendererDispatcher renderDispatcher )
{ {
if( tileEntity != null ) renderTurtleAt( tileEntity, posX, posY, posZ, partialTicks ); super( renderDispatcher );
} }
public static ModelResourceLocation getTurtleModel( ComputerFamily family, boolean coloured ) public static ModelResourceLocation getTurtleModel( ComputerFamily family, boolean coloured )
{ {
switch( family ) switch( family )
{ {
case Normal: case NORMAL:
default: default:
return coloured ? COLOUR_TURTLE_MODEL : NORMAL_TURTLE_MODEL; return coloured ? COLOUR_TURTLE_MODEL : NORMAL_TURTLE_MODEL;
case Advanced: case ADVANCED:
return coloured ? COLOUR_TURTLE_MODEL : ADVANCED_TURTLE_MODEL; return coloured ? COLOUR_TURTLE_MODEL : ADVANCED_TURTLE_MODEL;
} }
} }
public static ModelResourceLocation getTurtleOverlayModel( ResourceLocation overlay, boolean christmas ) public static ModelResourceLocation getTurtleOverlayModel( ResourceLocation overlay, boolean christmas )
{ {
if( overlay != null ) if( overlay != null ) return new ModelResourceLocation( overlay, "inventory" );
{ if( christmas ) return ELF_OVERLAY_MODEL;
return new ModelResourceLocation( overlay, "inventory" ); return null;
}
else if( christmas )
{
return ELF_OVERLAY_MODEL;
}
else
{
return null;
}
} }
private void renderTurtleAt( TileTurtle turtle, double posX, double posY, double posZ, float partialTicks ) @Override
public void render( @Nonnull TileTurtle turtle, float partialTicks, @Nonnull MatrixStack transform, @Nonnull IRenderTypeBuffer renderer, int lightmapCoord, int overlayLight )
{ {
// Render the label // Render the label
String label = turtle.createProxy().getLabel(); String label = turtle.createProxy().getLabel();
RayTraceResult hit = rendererDispatcher.cameraHitResult; RayTraceResult hit = renderDispatcher.cameraHitResult;
if( label != null && hit.getType() == RayTraceResult.Type.BLOCK && turtle.getPos().equals( ((BlockRayTraceResult) hit).getPos() ) ) if( label != null && hit.getType() == RayTraceResult.Type.BLOCK && turtle.getPos().equals( ((BlockRayTraceResult) hit).getPos() ) )
{ {
setLightmapDisabled( true ); Minecraft mc = Minecraft.getInstance();
GameRenderer.drawNameplate( FontRenderer font = renderDispatcher.fontRenderer;
getFontRenderer(), label,
(float) posX + 0.5F, (float) posY + 1.2F, (float) posZ + 0.5F, 0, transform.push();
rendererDispatcher.renderInfo.getYaw(), rendererDispatcher.renderInfo.getPitch(), false transform.translate( 0.5, 1.2, 0.5 );
); transform.rotate( mc.getRenderManager().getCameraOrientation() );
setLightmapDisabled( false ); transform.scale( -0.025f, -0.025f, 0.025f );
Matrix4f matrix = transform.getLast().getMatrix();
int opacity = (int) (mc.gameSettings.getTextBackgroundOpacity( 0.25f ) * 255) << 24;
float width = -font.getStringWidth( label ) / 2.0f;
font.renderString( label, width, (float) 0, 0x20ffffff, false, matrix, renderer, true, opacity, lightmapCoord );
font.renderString( label, width, (float) 0, 0xffffffff, false, matrix, renderer, false, 0, lightmapCoord );
transform.pop();
} }
GlStateManager.pushMatrix(); transform.push();
try
// 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.rotate( Vector3f.YP.rotationDegrees( 180.0f - yaw ) );
if( label != null && (label.equals( "Dinnerbone" ) || label.equals( "Grumm" )) )
{ {
BlockState state = turtle.getBlockState(); // Flip the model
// Setup the transform transform.scale( 1.0f, -1.0f, 1.0f );
Vec3d offset = turtle.getRenderOffset( partialTicks );
float yaw = turtle.getRenderYaw( partialTicks );
GlStateManager.translated( posX + offset.x, posY + offset.y, posZ + offset.z );
// Render the turtle
GlStateManager.translatef( 0.5f, 0.5f, 0.5f );
GlStateManager.rotatef( 180.0f - yaw, 0.0f, 1.0f, 0.0f );
if( label != null && (label.equals( "Dinnerbone" ) || label.equals( "Grumm" )) )
{
// Flip the model and swap the cull face as winding order will have changed.
GlStateManager.scalef( 1.0f, -1.0f, 1.0f );
GlStateManager.cullFace( GlStateManager.CullFace.FRONT );
}
GlStateManager.translatef( -0.5f, -0.5f, -0.5f );
// Render the turtle
int colour = turtle.getColour();
ComputerFamily family = turtle.getFamily();
ResourceLocation overlay = turtle.getOverlay();
renderModel( state, getTurtleModel( family, colour != -1 ), colour == -1 ? null : new int[] { colour } );
// Render the overlay
ModelResourceLocation overlayModel = getTurtleOverlayModel(
overlay,
HolidayUtil.getCurrentHoliday() == Holiday.Christmas
);
if( overlayModel != null )
{
GlStateManager.disableCull();
GlStateManager.enableBlend();
GlStateManager.blendFunc( GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA );
try
{
renderModel( state, overlayModel, null );
}
finally
{
GlStateManager.disableBlend();
GlStateManager.enableCull();
}
}
// Render the upgrades
renderUpgrade( state, turtle, TurtleSide.Left, partialTicks );
renderUpgrade( state, turtle, TurtleSide.Right, partialTicks );
} }
finally transform.translate( -0.5f, -0.5f, -0.5f );
// Render the turtle
int colour = turtle.getColour();
ComputerFamily family = turtle.getFamily();
ResourceLocation overlay = turtle.getOverlay();
IVertexBuilder buffer = renderer.getBuffer( Atlases.getTranslucentCullBlockType() );
renderModel( transform, buffer, lightmapCoord, overlayLight, getTurtleModel( family, colour != -1 ), colour == -1 ? null : new int[] { colour } );
// Render the overlay
ModelResourceLocation overlayModel = getTurtleOverlayModel( overlay, HolidayUtil.getCurrentHoliday() == Holiday.CHRISTMAS );
if( overlayModel != null )
{ {
GlStateManager.popMatrix(); renderModel( transform, buffer, lightmapCoord, overlayLight, overlayModel, null );
GlStateManager.cullFace( GlStateManager.CullFace.BACK );
} }
// 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( BlockState state, TileTurtle turtle, TurtleSide side, float f ) private void renderUpgrade( @Nonnull MatrixStack transform, @Nonnull IVertexBuilder renderer, int lightmapCoord, int overlayLight, TileTurtle turtle, TurtleSide side, float f )
{ {
ITurtleUpgrade upgrade = turtle.getUpgrade( side ); ITurtleUpgrade upgrade = turtle.getUpgrade( side );
if( upgrade != null ) if( upgrade == null ) return;
{ transform.push();
GlStateManager.pushMatrix();
try
{
float toolAngle = turtle.getToolRenderAngle( side, f );
GlStateManager.translatef( 0.0f, 0.5f, 0.5f );
GlStateManager.rotatef( -toolAngle, 1.0f, 0.0f, 0.0f );
GlStateManager.translatef( 0.0f, -0.5f, -0.5f );
Pair<IBakedModel, Matrix4f> pair = upgrade.getModel( turtle.getAccess(), side ); float toolAngle = turtle.getToolRenderAngle( side, f );
if( pair != null ) transform.translate( 0.0f, 0.5f, 0.5f );
{ transform.rotate( Vector3f.XN.rotationDegrees( toolAngle ) );
if( pair.getRight() != null ) transform.translate( 0.0f, -0.5f, -0.5f );
{
ForgeHooksClient.multiplyCurrentGlMatrix( pair.getRight() ); TransformedModel model = upgrade.getModel( turtle.getAccess(), side );
} model.getMatrix().push( transform );
if( pair.getLeft() != null ) renderModel( transform, renderer, lightmapCoord, overlayLight, model.getModel(), null );
{ transform.pop();
renderModel( state, pair.getLeft(), null );
} transform.pop();
}
}
finally
{
GlStateManager.popMatrix();
}
}
} }
private void renderModel( BlockState state, ModelResourceLocation modelLocation, int[] tints ) private void renderModel( @Nonnull MatrixStack transform, @Nonnull IVertexBuilder renderer, int lightmapCoord, int overlayLight, ModelResourceLocation modelLocation, int[] tints )
{ {
Minecraft mc = Minecraft.getInstance(); ModelManager modelManager = Minecraft.getInstance().getItemRenderer().getItemModelMesher().getModelManager();
ModelManager modelManager = mc.getItemRenderer().getItemModelMesher().getModelManager(); renderModel( transform, renderer, lightmapCoord, overlayLight, modelManager.getModel( modelLocation ), tints );
renderModel( state, modelManager.getModel( modelLocation ), tints );
} }
private void renderModel( BlockState state, IBakedModel model, int[] tints ) private void renderModel( @Nonnull MatrixStack transform, @Nonnull IVertexBuilder renderer, int lightmapCoord, int overlayLight, IBakedModel model, int[] tints )
{ {
Random random = new Random( 0 ); random.setSeed( 0 );
Tessellator tessellator = Tessellator.getInstance(); renderQuads( transform, renderer, lightmapCoord, overlayLight, model.getQuads( null, null, random, EmptyModelData.INSTANCE ), tints );
rendererDispatcher.textureManager.bindTexture( AtlasTexture.LOCATION_BLOCKS_TEXTURE );
renderQuads( tessellator, model.getQuads( state, null, random, EmptyModelData.INSTANCE ), tints );
for( Direction facing : DirectionUtil.FACINGS ) for( Direction facing : DirectionUtil.FACINGS )
{ {
renderQuads( tessellator, model.getQuads( state, facing, random, EmptyModelData.INSTANCE ), tints ); renderQuads( transform, renderer, lightmapCoord, overlayLight, model.getQuads( null, facing, random, EmptyModelData.INSTANCE ), tints );
} }
} }
private static void renderQuads( Tessellator tessellator, List<BakedQuad> quads, int[] tints ) private static void renderQuads( @Nonnull MatrixStack transform, @Nonnull IVertexBuilder buffer, int lightmapCoord, int overlayLight, List<BakedQuad> quads, int[] tints )
{ {
BufferBuilder buffer = tessellator.getBuffer(); MatrixStack.Entry matrix = transform.getLast();
VertexFormat format = DefaultVertexFormats.ITEM;
buffer.begin( GL11.GL_QUADS, format ); for( BakedQuad bakedquad : quads )
for( BakedQuad quad : quads )
{ {
VertexFormat quadFormat = quad.getFormat(); int tint = -1;
if( quadFormat != format ) if( tints != null && bakedquad.hasTintIndex() )
{ {
tessellator.draw(); int idx = bakedquad.getTintIndex();
format = quadFormat; if( idx >= 0 && idx < tints.length ) tint = tints[bakedquad.getTintIndex()];
buffer.begin( GL11.GL_QUADS, format );
} }
int colour = 0xFFFFFFFF; float f = (float) (tint >> 16 & 255) / 255.0F;
if( quad.hasTintIndex() && tints != null ) float f1 = (float) (tint >> 8 & 255) / 255.0F;
{ float f2 = (float) (tint & 255) / 255.0F;
int index = quad.getTintIndex(); buffer.addVertexData( matrix, bakedquad, f, f1, f2, lightmapCoord, overlayLight, true );
if( index >= 0 && index < tints.length ) colour = tints[index] | 0xFF000000;
}
LightUtil.renderQuadColor( buffer, quad, colour );
} }
tessellator.draw();
} }
} }

View File

@@ -5,28 +5,27 @@
*/ */
package dan200.computercraft.client.render; package dan200.computercraft.client.render;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonObject;
import com.mojang.datafixers.util.Pair;
import dan200.computercraft.ComputerCraft; import dan200.computercraft.ComputerCraft;
import net.minecraft.client.renderer.model.IBakedModel; import net.minecraft.client.renderer.model.*;
import net.minecraft.client.renderer.model.IUnbakedModel;
import net.minecraft.client.renderer.model.ModelBakery;
import net.minecraft.client.renderer.texture.ISprite;
import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.renderer.vertex.VertexFormat;
import net.minecraft.resources.IResourceManager; import net.minecraft.resources.IResourceManager;
import net.minecraft.util.JSONUtils;
import net.minecraft.util.ResourceLocation; import net.minecraft.util.ResourceLocation;
import net.minecraftforge.client.model.ICustomModelLoader; import net.minecraftforge.client.model.IModelConfiguration;
import net.minecraftforge.client.model.IModelLoader;
import net.minecraftforge.client.model.geometry.IModelGeometry;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.HashSet;
import java.util.Set; import java.util.Set;
import java.util.function.Function; import java.util.function.Function;
import java.util.stream.Collectors;
public final class TurtleModelLoader implements ICustomModelLoader public final class TurtleModelLoader implements IModelLoader<TurtleModelLoader.TurtleModel>
{ {
private static final ResourceLocation NORMAL_TURTLE_MODEL = new ResourceLocation( ComputerCraft.MOD_ID, "block/turtle_normal" );
private static final ResourceLocation ADVANCED_TURTLE_MODEL = new ResourceLocation( ComputerCraft.MOD_ID, "block/turtle_advanced" );
private static final ResourceLocation COLOUR_TURTLE_MODEL = new ResourceLocation( ComputerCraft.MOD_ID, "block/turtle_colour" ); private static final ResourceLocation COLOUR_TURTLE_MODEL = new ResourceLocation( ComputerCraft.MOD_ID, "block/turtle_colour" );
public static final TurtleModelLoader INSTANCE = new TurtleModelLoader(); public static final TurtleModelLoader INSTANCE = new TurtleModelLoader();
@@ -40,32 +39,15 @@ public final class TurtleModelLoader implements ICustomModelLoader
{ {
} }
@Override
public boolean accepts( @Nonnull ResourceLocation name )
{
return name.getNamespace().equals( ComputerCraft.MOD_ID )
&& (name.getPath().equals( "item/turtle_normal" ) || name.getPath().equals( "item/turtle_advanced" ));
}
@Nonnull @Nonnull
@Override @Override
public IUnbakedModel loadModel( @Nonnull ResourceLocation name ) public TurtleModel read( @Nonnull JsonDeserializationContext deserializationContext, @Nonnull JsonObject modelContents )
{ {
if( name.getNamespace().equals( ComputerCraft.MOD_ID ) ) ResourceLocation model = new ResourceLocation( JSONUtils.getString( modelContents, "model" ) );
{ return new TurtleModel( model );
switch( name.getPath() )
{
case "item/turtle_normal":
return new TurtleModel( NORMAL_TURTLE_MODEL );
case "item/turtle_advanced":
return new TurtleModel( ADVANCED_TURTLE_MODEL );
}
}
throw new IllegalStateException( "Loader does not accept " + name );
} }
private static final class TurtleModel implements IUnbakedModel public static final class TurtleModel implements IModelGeometry<TurtleModel>
{ {
private final ResourceLocation family; private final ResourceLocation family;
@@ -74,29 +56,21 @@ public final class TurtleModelLoader implements ICustomModelLoader
this.family = family; this.family = family;
} }
@Nonnull
@Override @Override
public Collection<ResourceLocation> getDependencies() public Collection<Material> getTextures( IModelConfiguration owner, Function<ResourceLocation, IUnbakedModel> modelGetter, Set<Pair<String, String>> missingTextureErrors )
{ {
return Arrays.asList( family, COLOUR_TURTLE_MODEL ); Set<Material> materials = new HashSet<>();
materials.addAll( modelGetter.apply( family ).getTextures( modelGetter, missingTextureErrors ) );
materials.addAll( modelGetter.apply( COLOUR_TURTLE_MODEL ).getTextures( modelGetter, missingTextureErrors ) );
return materials;
} }
@Nonnull
@Override @Override
public Collection<ResourceLocation> getTextures( @Nonnull Function<ResourceLocation, IUnbakedModel> modelGetter, @Nonnull Set<String> missingTextureErrors ) public IBakedModel bake( IModelConfiguration owner, ModelBakery bakery, Function<Material, TextureAtlasSprite> spriteGetter, IModelTransform transform, ItemOverrideList overrides, ResourceLocation modelLocation )
{
return getDependencies().stream()
.flatMap( x -> modelGetter.apply( x ).getTextures( modelGetter, missingTextureErrors ).stream() )
.collect( Collectors.toSet() );
}
@Nonnull
@Override
public IBakedModel bake( @Nonnull ModelBakery bakery, @Nonnull Function<ResourceLocation, TextureAtlasSprite> spriteGetter, @Nonnull ISprite sprite, @Nonnull VertexFormat format )
{ {
return new TurtleSmartItemModel( return new TurtleSmartItemModel(
bakery.getBakedModel( family, sprite, spriteGetter, format ), bakery.getBakedModel( family, transform, spriteGetter ),
bakery.getBakedModel( COLOUR_TURTLE_MODEL, sprite, spriteGetter, format ) bakery.getBakedModel( COLOUR_TURTLE_MODEL, transform, spriteGetter )
); );
} }
} }

View File

@@ -5,7 +5,9 @@
*/ */
package dan200.computercraft.client.render; package dan200.computercraft.client.render;
import dan200.computercraft.api.client.TransformedModel;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
import net.minecraft.client.renderer.TransformationMatrix;
import net.minecraft.client.renderer.model.BakedQuad; import net.minecraft.client.renderer.model.BakedQuad;
import net.minecraft.client.renderer.model.IBakedModel; import net.minecraft.client.renderer.model.IBakedModel;
import net.minecraft.client.renderer.model.ItemOverrideList; import net.minecraft.client.renderer.model.ItemOverrideList;
@@ -13,32 +15,29 @@ import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.util.Direction; import net.minecraft.util.Direction;
import net.minecraftforge.client.model.data.EmptyModelData; import net.minecraftforge.client.model.data.EmptyModelData;
import net.minecraftforge.client.model.data.IModelData; import net.minecraftforge.client.model.data.IModelData;
import net.minecraftforge.client.model.pipeline.BakedQuadBuilder;
import net.minecraftforge.client.model.pipeline.TRSRTransformer;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.vecmath.Matrix4f;
import java.util.*; import java.util.*;
public class TurtleMultiModel implements IBakedModel public class TurtleMultiModel implements IBakedModel
{ {
private final IBakedModel m_baseModel; private final IBakedModel m_baseModel;
private final IBakedModel m_overlayModel; private final IBakedModel m_overlayModel;
private final Matrix4f m_generalTransform; private final TransformationMatrix m_generalTransform;
private final IBakedModel m_leftUpgradeModel; private final TransformedModel m_leftUpgradeModel;
private final Matrix4f m_leftUpgradeTransform; private final TransformedModel m_rightUpgradeModel;
private final IBakedModel m_rightUpgradeModel;
private final Matrix4f m_rightUpgradeTransform;
private List<BakedQuad> m_generalQuads = null; private List<BakedQuad> m_generalQuads = null;
private Map<Direction, List<BakedQuad>> m_faceQuads = new EnumMap<>( Direction.class ); private Map<Direction, List<BakedQuad>> m_faceQuads = new EnumMap<>( Direction.class );
public TurtleMultiModel( IBakedModel baseModel, IBakedModel overlayModel, Matrix4f generalTransform, IBakedModel leftUpgradeModel, Matrix4f leftUpgradeTransform, IBakedModel rightUpgradeModel, Matrix4f rightUpgradeTransform ) public TurtleMultiModel( IBakedModel baseModel, IBakedModel overlayModel, TransformationMatrix generalTransform, TransformedModel leftUpgradeModel, TransformedModel rightUpgradeModel )
{ {
// Get the models // Get the models
m_baseModel = baseModel; m_baseModel = baseModel;
m_overlayModel = overlayModel; m_overlayModel = overlayModel;
m_leftUpgradeModel = leftUpgradeModel; m_leftUpgradeModel = leftUpgradeModel;
m_leftUpgradeTransform = leftUpgradeTransform;
m_rightUpgradeModel = rightUpgradeModel; m_rightUpgradeModel = rightUpgradeModel;
m_rightUpgradeTransform = rightUpgradeTransform;
m_generalTransform = generalTransform; m_generalTransform = generalTransform;
} }
@@ -69,30 +68,22 @@ public class TurtleMultiModel implements IBakedModel
private List<BakedQuad> buildQuads( BlockState state, Direction side, Random rand ) private List<BakedQuad> buildQuads( BlockState state, Direction side, Random rand )
{ {
ArrayList<BakedQuad> quads = new ArrayList<>(); ArrayList<BakedQuad> quads = new ArrayList<>();
ModelTransformer.transformQuadsTo( quads, m_baseModel.getQuads( state, side, rand, EmptyModelData.INSTANCE ), m_generalTransform );
transformQuadsTo( quads, m_baseModel.getQuads( state, side, rand, EmptyModelData.INSTANCE ), m_generalTransform );
if( m_overlayModel != null ) if( m_overlayModel != null )
{ {
ModelTransformer.transformQuadsTo( quads, m_overlayModel.getQuads( state, side, rand, EmptyModelData.INSTANCE ), m_generalTransform ); transformQuadsTo( quads, m_overlayModel.getQuads( state, side, rand, EmptyModelData.INSTANCE ), m_generalTransform );
} }
if( m_leftUpgradeModel != null ) if( m_leftUpgradeModel != null )
{ {
Matrix4f upgradeTransform = m_generalTransform; TransformationMatrix upgradeTransform = m_generalTransform.compose( m_leftUpgradeModel.getMatrix() );
if( m_leftUpgradeTransform != null ) transformQuadsTo( quads, m_leftUpgradeModel.getModel().getQuads( state, side, rand, EmptyModelData.INSTANCE ), upgradeTransform );
{
upgradeTransform = new Matrix4f( m_generalTransform );
upgradeTransform.mul( m_leftUpgradeTransform );
}
ModelTransformer.transformQuadsTo( quads, m_leftUpgradeModel.getQuads( state, side, rand, EmptyModelData.INSTANCE ), upgradeTransform );
} }
if( m_rightUpgradeModel != null ) if( m_rightUpgradeModel != null )
{ {
Matrix4f upgradeTransform = m_generalTransform; TransformationMatrix upgradeTransform = m_generalTransform.compose( m_rightUpgradeModel.getMatrix() );
if( m_rightUpgradeTransform != null ) transformQuadsTo( quads, m_rightUpgradeModel.getModel().getQuads( state, side, rand, EmptyModelData.INSTANCE ), upgradeTransform );
{
upgradeTransform = new Matrix4f( m_generalTransform );
upgradeTransform.mul( m_rightUpgradeTransform );
}
ModelTransformer.transformQuadsTo( quads, m_rightUpgradeModel.getQuads( state, side, rand, EmptyModelData.INSTANCE ), upgradeTransform );
} }
quads.trimToSize(); quads.trimToSize();
return quads; return quads;
@@ -116,6 +107,12 @@ public class TurtleMultiModel implements IBakedModel
return m_baseModel.isBuiltInRenderer(); return m_baseModel.isBuiltInRenderer();
} }
@Override
public boolean func_230044_c_()
{
return m_baseModel.func_230044_c_();
}
@Nonnull @Nonnull
@Override @Override
@Deprecated @Deprecated
@@ -138,4 +135,15 @@ public class TurtleMultiModel implements IBakedModel
{ {
return ItemOverrideList.EMPTY; return ItemOverrideList.EMPTY;
} }
private void transformQuadsTo( List<BakedQuad> output, List<BakedQuad> quads, TransformationMatrix transform )
{
for( BakedQuad quad : quads )
{
BakedQuadBuilder builder = new BakedQuadBuilder();
TRSRTransformer transformer = new TRSRTransformer( builder, transform );
quad.pipe( transformer );
output.add( builder.build() );
}
}
} }

View File

@@ -6,14 +6,15 @@
package dan200.computercraft.client.render; package dan200.computercraft.client.render;
import dan200.computercraft.ComputerCraft; import com.mojang.blaze3d.matrix.MatrixStack;
import dan200.computercraft.client.gui.GuiComputer;
import dan200.computercraft.shared.turtle.core.TurtlePlayer; import dan200.computercraft.shared.turtle.core.TurtlePlayer;
import net.minecraft.client.renderer.IRenderTypeBuffer;
import net.minecraft.client.renderer.entity.EntityRenderer; import net.minecraft.client.renderer.entity.EntityRenderer;
import net.minecraft.client.renderer.entity.EntityRendererManager; import net.minecraft.client.renderer.entity.EntityRendererManager;
import net.minecraft.util.ResourceLocation; import net.minecraft.util.ResourceLocation;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public class TurtlePlayerRenderer extends EntityRenderer<TurtlePlayer> public class TurtlePlayerRenderer extends EntityRenderer<TurtlePlayer>
{ {
@@ -22,16 +23,15 @@ public class TurtlePlayerRenderer extends EntityRenderer<TurtlePlayer>
super( renderManager ); super( renderManager );
} }
@Nonnull
@Override @Override
public void doRender( @Nonnull TurtlePlayer entity, double x, double y, double z, float entityYaw, float partialTicks ) public ResourceLocation getEntityTexture( @Nonnull TurtlePlayer entity )
{ {
ComputerCraft.log.error( "Rendering TurtlePlayer on the client side, at {}", entity.getPosition() ); return GuiComputer.BACKGROUND_NORMAL;
} }
@Nullable
@Override @Override
protected ResourceLocation getEntityTexture( @Nonnull TurtlePlayer entity ) public void render( @Nonnull TurtlePlayer entityIn, float entityYaw, float partialTicks, @Nonnull MatrixStack transform, @Nonnull IRenderTypeBuffer buffer, int packedLightIn )
{ {
return null;
} }
} }

View File

@@ -6,6 +6,8 @@
package dan200.computercraft.client.render; package dan200.computercraft.client.render;
import com.google.common.base.Objects; import com.google.common.base.Objects;
import com.mojang.blaze3d.matrix.MatrixStack;
import dan200.computercraft.api.client.TransformedModel;
import dan200.computercraft.api.turtle.ITurtleUpgrade; import dan200.computercraft.api.turtle.ITurtleUpgrade;
import dan200.computercraft.api.turtle.TurtleSide; import dan200.computercraft.api.turtle.TurtleSide;
import dan200.computercraft.shared.turtle.items.ItemTurtle; import dan200.computercraft.shared.turtle.items.ItemTurtle;
@@ -13,6 +15,7 @@ import dan200.computercraft.shared.util.Holiday;
import dan200.computercraft.shared.util.HolidayUtil; import dan200.computercraft.shared.util.HolidayUtil;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.TransformationMatrix;
import net.minecraft.client.renderer.model.*; import net.minecraft.client.renderer.model.*;
import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.entity.LivingEntity; import net.minecraft.entity.LivingEntity;
@@ -21,28 +24,25 @@ import net.minecraft.util.Direction;
import net.minecraft.util.ResourceLocation; import net.minecraft.util.ResourceLocation;
import net.minecraft.world.World; import net.minecraft.world.World;
import net.minecraftforge.client.model.data.IModelData; import net.minecraftforge.client.model.data.IModelData;
import org.apache.commons.lang3.tuple.Pair;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import javax.vecmath.Matrix4f;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Random; import java.util.Random;
public class TurtleSmartItemModel implements IBakedModel public class TurtleSmartItemModel implements IBakedModel
{ {
private static final Matrix4f s_identity, s_flip; private static final TransformationMatrix identity, flip;
static static
{ {
s_identity = new Matrix4f(); MatrixStack stack = new MatrixStack();
s_identity.setIdentity(); stack.scale( 0, -1, 0 );
stack.translate( 0, 0, 1 );
s_flip = new Matrix4f(); identity = TransformationMatrix.identity();
s_flip.setIdentity(); flip = new TransformationMatrix( stack.getLast().getMatrix() );
s_flip.m11 = -1; // Flip on the y axis
s_flip.m13 = 1; // Models go from (0,0,0) to (1,1,1), so push back up.
} }
private static class TurtleModelCombination private static class TurtleModelCombination
@@ -97,15 +97,14 @@ public class TurtleSmartItemModel implements IBakedModel
private final IBakedModel familyModel; private final IBakedModel familyModel;
private final IBakedModel colourModel; private final IBakedModel colourModel;
private HashMap<TurtleModelCombination, IBakedModel> m_cachedModels; private final HashMap<TurtleModelCombination, IBakedModel> m_cachedModels = new HashMap<>();
private ItemOverrideList m_overrides; private final ItemOverrideList m_overrides;
public TurtleSmartItemModel( IBakedModel familyModel, IBakedModel colourModel ) public TurtleSmartItemModel( IBakedModel familyModel, IBakedModel colourModel )
{ {
this.familyModel = familyModel; this.familyModel = familyModel;
this.colourModel = colourModel; this.colourModel = colourModel;
m_cachedModels = new HashMap<>();
m_overrides = new ItemOverrideList() m_overrides = new ItemOverrideList()
{ {
@Nonnull @Nonnull
@@ -114,10 +113,10 @@ public class TurtleSmartItemModel implements IBakedModel
{ {
ItemTurtle turtle = (ItemTurtle) stack.getItem(); ItemTurtle turtle = (ItemTurtle) stack.getItem();
int colour = turtle.getColour( stack ); int colour = turtle.getColour( stack );
ITurtleUpgrade leftUpgrade = turtle.getUpgrade( stack, TurtleSide.Left ); ITurtleUpgrade leftUpgrade = turtle.getUpgrade( stack, TurtleSide.LEFT );
ITurtleUpgrade rightUpgrade = turtle.getUpgrade( stack, TurtleSide.Right ); ITurtleUpgrade rightUpgrade = turtle.getUpgrade( stack, TurtleSide.RIGHT );
ResourceLocation overlay = turtle.getOverlay( stack ); ResourceLocation overlay = turtle.getOverlay( stack );
boolean christmas = HolidayUtil.getCurrentHoliday() == Holiday.Christmas; boolean christmas = HolidayUtil.getCurrentHoliday() == Holiday.CHRISTMAS;
String label = turtle.getLabel( stack ); String label = turtle.getLabel( stack );
boolean flip = label != null && (label.equals( "Dinnerbone" ) || label.equals( "Grumm" )); boolean flip = label != null && (label.equals( "Dinnerbone" ) || label.equals( "Grumm" ));
TurtleModelCombination combo = new TurtleModelCombination( colour != -1, leftUpgrade, rightUpgrade, overlay, christmas, flip ); TurtleModelCombination combo = new TurtleModelCombination( colour != -1, leftUpgrade, rightUpgrade, overlay, christmas, flip );
@@ -144,25 +143,10 @@ public class TurtleSmartItemModel implements IBakedModel
IBakedModel baseModel = combo.m_colour ? colourModel : familyModel; IBakedModel baseModel = combo.m_colour ? colourModel : familyModel;
IBakedModel overlayModel = overlayModelLocation != null ? modelManager.getModel( overlayModelLocation ) : null; IBakedModel overlayModel = overlayModelLocation != null ? modelManager.getModel( overlayModelLocation ) : null;
Matrix4f transform = combo.m_flip ? s_flip : s_identity; TransformationMatrix transform = combo.m_flip ? flip : identity;
Pair<IBakedModel, Matrix4f> leftModel = combo.m_leftUpgrade != null ? combo.m_leftUpgrade.getModel( null, TurtleSide.Left ) : null; TransformedModel leftModel = combo.m_leftUpgrade != null ? combo.m_leftUpgrade.getModel( null, TurtleSide.LEFT ) : null;
Pair<IBakedModel, Matrix4f> rightModel = combo.m_rightUpgrade != null ? combo.m_rightUpgrade.getModel( null, TurtleSide.Right ) : null; TransformedModel rightModel = combo.m_rightUpgrade != null ? combo.m_rightUpgrade.getModel( null, TurtleSide.RIGHT ) : null;
if( leftModel != null && rightModel != null ) return new TurtleMultiModel( baseModel, overlayModel, transform, leftModel, rightModel );
{
return new TurtleMultiModel( baseModel, overlayModel, transform, leftModel.getLeft(), leftModel.getRight(), rightModel.getLeft(), rightModel.getRight() );
}
else if( leftModel != null )
{
return new TurtleMultiModel( baseModel, overlayModel, transform, leftModel.getLeft(), leftModel.getRight(), null, null );
}
else if( rightModel != null )
{
return new TurtleMultiModel( baseModel, overlayModel, transform, null, null, rightModel.getLeft(), rightModel.getRight() );
}
else
{
return new TurtleMultiModel( baseModel, overlayModel, transform, null, null, null, null );
}
} }
@Nonnull @Nonnull
@@ -199,6 +183,12 @@ public class TurtleSmartItemModel implements IBakedModel
return familyModel.isBuiltInRenderer(); return familyModel.isBuiltInRenderer();
} }
@Override
public boolean func_230044_c_()
{
return familyModel.func_230044_c_();
}
@Nonnull @Nonnull
@Override @Override
@Deprecated @Deprecated

View File

@@ -1,181 +0,0 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.core.apis;
import com.google.common.net.InetAddresses;
import dan200.computercraft.ComputerCraft;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Pattern;
/**
* Used to determine whether a domain or IP address matches a series of patterns.
*/
public class AddressPredicate
{
private static final class HostRange
{
private final byte[] min;
private final byte[] max;
private HostRange( byte[] min, byte[] max )
{
this.min = min;
this.max = max;
}
public boolean contains( InetAddress address )
{
byte[] entry = address.getAddress();
if( entry.length != min.length ) return false;
for( int i = 0; i < entry.length; i++ )
{
int value = 0xFF & entry[i];
if( value < (0xFF & min[i]) || value > (0xFF & max[i]) ) return false;
}
return true;
}
}
private final List<Pattern> wildcards;
private final List<HostRange> ranges;
public AddressPredicate( String... filters )
{
this( Arrays.asList( filters ) );
}
public AddressPredicate( Iterable<? extends String> filters )
{
List<Pattern> wildcards = this.wildcards = new ArrayList<>();
List<HostRange> ranges = this.ranges = new ArrayList<>();
for( String filter : filters )
{
int cidr = filter.indexOf( '/' );
if( cidr >= 0 )
{
String addressStr = filter.substring( 0, cidr );
String prefixSizeStr = filter.substring( cidr + 1 );
int prefixSize;
try
{
prefixSize = Integer.parseInt( prefixSizeStr );
}
catch( NumberFormatException e )
{
ComputerCraft.log.error(
"Malformed http whitelist/blacklist entry '{}': Cannot extract size of CIDR mask from '{}'.",
filter, prefixSizeStr
);
continue;
}
InetAddress address;
try
{
address = InetAddresses.forString( addressStr );
}
catch( IllegalArgumentException e )
{
ComputerCraft.log.error(
"Malformed http whitelist/blacklist entry '{}': Cannot extract IP address from '{}'.",
filter, prefixSizeStr
);
continue;
}
// Mask the bytes of the IP address.
byte[] minBytes = address.getAddress(), maxBytes = address.getAddress();
int size = prefixSize;
for( int i = 0; i < minBytes.length; i++ )
{
if( size <= 0 )
{
minBytes[i] &= 0;
maxBytes[i] |= 0xFF;
}
else if( size < 8 )
{
minBytes[i] &= 0xFF << (8 - size);
maxBytes[i] |= ~(0xFF << (8 - size));
}
size -= 8;
}
ranges.add( new HostRange( minBytes, maxBytes ) );
}
else
{
wildcards.add( Pattern.compile( "^\\Q" + filter.replaceAll( "\\*", "\\\\E.*\\\\Q" ) + "\\E$" ) );
}
}
}
/**
* Determine whether a host name matches a series of patterns.
*
* This is intended to allow early exiting, before one has to look up the IP address. You should use
* {@link #matches(InetAddress)} instead of/in addition to this one.
*
* @param domain The domain to match.
* @return Whether the patterns were matched.
*/
public boolean matches( String domain )
{
for( Pattern domainPattern : wildcards )
{
if( domainPattern.matcher( domain ).matches() ) return true;
}
return false;
}
private boolean matchesAddress( InetAddress address )
{
String addressString = address.getHostAddress();
for( Pattern domainPattern : wildcards )
{
if( domainPattern.matcher( addressString ).matches() ) return true;
}
for( HostRange range : ranges )
{
if( range.contains( address ) ) return true;
}
return false;
}
/**
* Determine whether the given address matches a series of patterns.
*
* @param address The address to check.
* @return Whether it matches any of these patterns.
*/
public boolean matches( InetAddress address )
{
// Match the host name
String host = address.getHostName();
if( host != null && matches( host ) ) return true;
// Match the normal address
if( matchesAddress( address ) ) return true;
// If we're an IPv4 address in disguise then let's check that.
return address instanceof Inet6Address && InetAddresses.is6to4Address( (Inet6Address) address )
&& matchesAddress( InetAddresses.get6to4IPv4Address( (Inet6Address) address ) );
}
}

View File

@@ -1,117 +0,0 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.core.apis;
import dan200.computercraft.api.lua.LuaException;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.Map;
/**
* A stub for any mods which depended on this version of the argument helper.
*
* @deprecated Use {@link dan200.computercraft.api.lua.ArgumentHelper}.
*/
@Deprecated
public final class ArgumentHelper
{
private ArgumentHelper()
{
}
@Nonnull
public static String getType( @Nullable Object type )
{
return dan200.computercraft.api.lua.ArgumentHelper.getType( type );
}
@Nonnull
public static LuaException badArgument( int index, @Nonnull String expected, @Nullable Object actual )
{
return dan200.computercraft.api.lua.ArgumentHelper.badArgumentOf( index, expected, actual );
}
@Nonnull
public static LuaException badArgument( int index, @Nonnull String expected, @Nonnull String actual )
{
return dan200.computercraft.api.lua.ArgumentHelper.badArgument( index, expected, actual );
}
public static double getNumber( @Nonnull Object[] args, int index ) throws LuaException
{
return dan200.computercraft.api.lua.ArgumentHelper.getDouble( args, index );
}
public static int getInt( @Nonnull Object[] args, int index ) throws LuaException
{
return dan200.computercraft.api.lua.ArgumentHelper.getInt( args, index );
}
public static long getLong( @Nonnull Object[] args, int index ) throws LuaException
{
return dan200.computercraft.api.lua.ArgumentHelper.getLong( args, index );
}
public static double getReal( @Nonnull Object[] args, int index ) throws LuaException
{
return dan200.computercraft.api.lua.ArgumentHelper.getFiniteDouble( args, index );
}
public static boolean getBoolean( @Nonnull Object[] args, int index ) throws LuaException
{
return dan200.computercraft.api.lua.ArgumentHelper.getBoolean( args, index );
}
@Nonnull
public static String getString( @Nonnull Object[] args, int index ) throws LuaException
{
return dan200.computercraft.api.lua.ArgumentHelper.getString( args, index );
}
@Nonnull
@SuppressWarnings( "unchecked" )
public static Map<Object, Object> getTable( @Nonnull Object[] args, int index ) throws LuaException
{
return (Map<Object, Object>) dan200.computercraft.api.lua.ArgumentHelper.getTable( args, index );
}
public static double optNumber( @Nonnull Object[] args, int index, double def ) throws LuaException
{
return dan200.computercraft.api.lua.ArgumentHelper.optDouble( args, index, def );
}
public static int optInt( @Nonnull Object[] args, int index, int def ) throws LuaException
{
return dan200.computercraft.api.lua.ArgumentHelper.optInt( args, index, def );
}
public static long optLong( @Nonnull Object[] args, int index, long def ) throws LuaException
{
return dan200.computercraft.api.lua.ArgumentHelper.optLong( args, index, def );
}
public static double optReal( @Nonnull Object[] args, int index, double def ) throws LuaException
{
return dan200.computercraft.api.lua.ArgumentHelper.optFiniteDouble( args, index, def );
}
public static boolean optBoolean( @Nonnull Object[] args, int index, boolean def ) throws LuaException
{
return dan200.computercraft.api.lua.ArgumentHelper.optBoolean( args, index, def );
}
public static String optString( @Nonnull Object[] args, int index, String def ) throws LuaException
{
return dan200.computercraft.api.lua.ArgumentHelper.optString( args, index, def );
}
@SuppressWarnings( "unchecked" )
public static Map<Object, Object> optTable( @Nonnull Object[] args, int index, Map<Object, Object> def ) throws LuaException
{
return (Map<Object, Object>) dan200.computercraft.api.lua.ArgumentHelper.optTable( args, index, def );
}
}

View File

@@ -13,7 +13,6 @@ import dan200.computercraft.core.filesystem.FileSystem;
import dan200.computercraft.core.filesystem.FileSystemException; import dan200.computercraft.core.filesystem.FileSystemException;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.HashSet; import java.util.HashSet;
import java.util.Objects; import java.util.Objects;
import java.util.Set; import java.util.Set;
@@ -123,7 +122,7 @@ public abstract class ComputerAccess implements IComputerAccess
m_environment.queueEvent( event, arguments ); m_environment.queueEvent( event, arguments );
} }
@Nullable @Nonnull
@Override @Override
public IWorkMonitor getMainThreadMonitor() public IWorkMonitor getMainThreadMonitor()
{ {

View File

@@ -173,7 +173,7 @@ public class HTTPAPI implements ILuaAPI
String address = getString( args, 0 ); String address = getString( args, 0 );
Map<?, ?> headerTbl = optTable( args, 1, Collections.emptyMap() ); Map<?, ?> headerTbl = optTable( args, 1, Collections.emptyMap() );
if( !ComputerCraft.http_websocket_enable ) if( !ComputerCraft.httpWebsocketEnabled )
{ {
throw new LuaException( "Websocket connections are disabled" ); throw new LuaException( "Websocket connections are disabled" );
} }

View File

@@ -1,24 +0,0 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.core.apis;
/**
* This exists purely to ensure binary compatibility.
*
* @see dan200.computercraft.api.lua.ILuaAPI
* @deprecated Use the version in the public API. Only exists for compatibility with CCEmuX.
*/
@Deprecated
public interface ILuaAPI extends dan200.computercraft.api.lua.ILuaAPI
{
void advance( double v );
@Override
default void update()
{
advance( 0.05 );
}
}

View File

@@ -103,7 +103,7 @@ public class OSAPI implements ILuaAPI
double t = alarm.m_day * 24.0 + alarm.m_time; double t = alarm.m_day * 24.0 + alarm.m_time;
if( now >= t ) if( now >= t )
{ {
queueLuaEvent( "alarm", new Object[] { entry.getKey() } ); queueLuaEvent( "alarm", new Object[] { entry.getIntKey() } );
it.remove(); it.remove();
} }
} }

View File

@@ -11,6 +11,8 @@ import dan200.computercraft.api.lua.ILuaAPI;
import dan200.computercraft.api.lua.ILuaContext; import dan200.computercraft.api.lua.ILuaContext;
import dan200.computercraft.api.lua.LuaException; import dan200.computercraft.api.lua.LuaException;
import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.api.peripheral.IPeripheral;
import dan200.computercraft.api.peripheral.IWorkMonitor;
import dan200.computercraft.api.peripheral.NotAttachedException;
import dan200.computercraft.core.computer.ComputerSide; import dan200.computercraft.core.computer.ComputerSide;
import dan200.computercraft.core.tracking.TrackingField; import dan200.computercraft.core.tracking.TrackingField;
@@ -122,53 +124,35 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange
@Override @Override
public synchronized String mount( @Nonnull String desiredLoc, @Nonnull IMount mount, @Nonnull String driveName ) public synchronized String mount( @Nonnull String desiredLoc, @Nonnull IMount mount, @Nonnull String driveName )
{ {
if( !m_attached ) if( !m_attached ) throw new NotAttachedException();
{
throw new RuntimeException( "You are not attached to this Computer" );
}
return super.mount( desiredLoc, mount, driveName ); return super.mount( desiredLoc, mount, driveName );
} }
@Override @Override
public synchronized String mountWritable( @Nonnull String desiredLoc, @Nonnull IWritableMount mount, @Nonnull String driveName ) public synchronized String mountWritable( @Nonnull String desiredLoc, @Nonnull IWritableMount mount, @Nonnull String driveName )
{ {
if( !m_attached ) if( !m_attached ) throw new NotAttachedException();
{
throw new RuntimeException( "You are not attached to this Computer" );
}
return super.mountWritable( desiredLoc, mount, driveName ); return super.mountWritable( desiredLoc, mount, driveName );
} }
@Override @Override
public synchronized void unmount( String location ) public synchronized void unmount( String location )
{ {
if( !m_attached ) if( !m_attached ) throw new NotAttachedException();
{
throw new RuntimeException( "You are not attached to this Computer" );
}
super.unmount( location ); super.unmount( location );
} }
@Override @Override
public int getID() public int getID()
{ {
if( !m_attached ) if( !m_attached ) throw new NotAttachedException();
{
throw new RuntimeException( "You are not attached to this Computer" );
}
return super.getID(); return super.getID();
} }
@Override @Override
public void queueEvent( @Nonnull final String event, final Object[] arguments ) public void queueEvent( @Nonnull final String event, final Object[] arguments )
{ {
if( !m_attached ) if( !m_attached ) throw new NotAttachedException();
{
throw new RuntimeException( "You are not attached to this Computer" );
}
super.queueEvent( event, arguments ); super.queueEvent( event, arguments );
} }
@@ -176,10 +160,7 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange
@Override @Override
public String getAttachmentName() public String getAttachmentName()
{ {
if( !m_attached ) if( !m_attached ) throw new NotAttachedException();
{
throw new RuntimeException( "You are not attached to this Computer" );
}
return m_side; return m_side;
} }
@@ -187,10 +168,7 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange
@Override @Override
public Map<String, IPeripheral> getAvailablePeripherals() public Map<String, IPeripheral> getAvailablePeripherals()
{ {
if( !m_attached ) if( !m_attached ) throw new NotAttachedException();
{
throw new RuntimeException( "You are not attached to this Computer" );
}
Map<String, IPeripheral> peripherals = new HashMap<>(); Map<String, IPeripheral> peripherals = new HashMap<>();
for( PeripheralWrapper wrapper : m_peripherals ) for( PeripheralWrapper wrapper : m_peripherals )
@@ -208,10 +186,7 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange
@Override @Override
public IPeripheral getAvailablePeripheral( @Nonnull String name ) public IPeripheral getAvailablePeripheral( @Nonnull String name )
{ {
if( !m_attached ) if( !m_attached ) throw new NotAttachedException();
{
throw new RuntimeException( "You are not attached to this Computer" );
}
for( PeripheralWrapper wrapper : m_peripherals ) for( PeripheralWrapper wrapper : m_peripherals )
{ {
@@ -222,6 +197,14 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange
} }
return null; return null;
} }
@Nonnull
@Override
public IWorkMonitor getMainThreadMonitor()
{
if( !m_attached ) throw new NotAttachedException();
return super.getMainThreadMonitor();
}
} }
private final IAPIEnvironment m_environment; private final IAPIEnvironment m_environment;

View File

@@ -0,0 +1,167 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.core.apis.http;
import com.google.common.net.InetAddresses;
import dan200.computercraft.ComputerCraft;
import javax.annotation.Nullable;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.util.regex.Pattern;
/**
* A pattern which matches an address, and controls whether it is accessible or not.
*/
public final class AddressRule
{
private static final class HostRange
{
private final byte[] min;
private final byte[] max;
private HostRange( byte[] min, byte[] max )
{
this.min = min;
this.max = max;
}
public boolean contains( InetAddress address )
{
byte[] entry = address.getAddress();
if( entry.length != min.length ) return false;
for( int i = 0; i < entry.length; i++ )
{
int value = 0xFF & entry[i];
if( value < (0xFF & min[i]) || value > (0xFF & max[i]) ) return false;
}
return true;
}
}
public enum Action
{
ALLOW,
DENY,
}
private final HostRange ip;
private final Pattern domainPattern;
private final Action action;
private AddressRule( HostRange ip, Pattern domainPattern, Action action )
{
this.ip = ip;
this.domainPattern = domainPattern;
this.action = action;
}
@Nullable
public static AddressRule parse( String filter, Action action )
{
int cidr = filter.indexOf( '/' );
if( cidr >= 0 )
{
String addressStr = filter.substring( 0, cidr );
String prefixSizeStr = filter.substring( cidr + 1 );
int prefixSize;
try
{
prefixSize = Integer.parseInt( prefixSizeStr );
}
catch( NumberFormatException e )
{
ComputerCraft.log.error(
"Malformed http whitelist/blacklist entry '{}': Cannot extract size of CIDR mask from '{}'.",
filter, prefixSizeStr
);
return null;
}
InetAddress address;
try
{
address = InetAddresses.forString( addressStr );
}
catch( IllegalArgumentException e )
{
ComputerCraft.log.error(
"Malformed http whitelist/blacklist entry '{}': Cannot extract IP address from '{}'.",
filter, prefixSizeStr
);
return null;
}
// Mask the bytes of the IP address.
byte[] minBytes = address.getAddress(), maxBytes = address.getAddress();
int size = prefixSize;
for( int i = 0; i < minBytes.length; i++ )
{
if( size <= 0 )
{
minBytes[i] &= 0;
maxBytes[i] |= 0xFF;
}
else if( size < 8 )
{
minBytes[i] &= 0xFF << (8 - size);
maxBytes[i] |= ~(0xFF << (8 - size));
}
size -= 8;
}
return new AddressRule( new HostRange( minBytes, maxBytes ), null, action );
}
else
{
Pattern pattern = Pattern.compile( "^\\Q" + filter.replaceAll( "\\*", "\\\\E.*\\\\Q" ) + "\\E$" );
return new AddressRule( null, pattern, action );
}
}
/**
* Determine whether the given address matches a series of patterns.
*
* @param domain The domain to match
* @param address The address to check.
* @return Whether it matches any of these patterns.
*/
public boolean matches( String domain, InetAddress address )
{
if( domainPattern != null )
{
if( domainPattern.matcher( domain ).matches() ) return true;
if( domainPattern.matcher( address.getHostName() ).matches() ) return true;
}
// Match the normal address
if( matchesAddress( address ) ) return true;
// If we're an IPv4 address in disguise then let's check that.
return address instanceof Inet6Address && InetAddresses.is6to4Address( (Inet6Address) address )
&& matchesAddress( InetAddresses.get6to4IPv4Address( (Inet6Address) address ) );
}
private boolean matchesAddress( InetAddress address )
{
if( domainPattern != null && domainPattern.matcher( address.getHostAddress() ).matches() ) return true;
return ip != null && ip.contains( address );
}
public static Action apply( Iterable<? extends AddressRule> rules, String domain, InetAddress address )
{
for( AddressRule rule : rules )
{
if( rule.matches( domain, address ) ) return rule.action;
}
return Action.DENY;
}
}

View File

@@ -97,20 +97,6 @@ public final class NetworkUtils
} }
} }
/**
* Checks a host is allowed.
*
* @param host The domain to check against
* @throws HTTPRequestException If the host is not permitted.
*/
public static void checkHost( String host ) throws HTTPRequestException
{
if( !ComputerCraft.http_whitelist.matches( host ) || ComputerCraft.http_blacklist.matches( host ) )
{
throw new HTTPRequestException( "Domain not permitted" );
}
}
/** /**
* Create a {@link InetSocketAddress} from the resolved {@code host} and port. * Create a {@link InetSocketAddress} from the resolved {@code host} and port.
* *
@@ -130,7 +116,7 @@ public final class NetworkUtils
if( socketAddress.isUnresolved() ) throw new HTTPRequestException( "Unknown host" ); if( socketAddress.isUnresolved() ) throw new HTTPRequestException( "Unknown host" );
InetAddress address = socketAddress.getAddress(); InetAddress address = socketAddress.getAddress();
if( !ComputerCraft.http_whitelist.matches( address ) || ComputerCraft.http_blacklist.matches( address ) ) if( AddressRule.apply( ComputerCraft.httpRules, host, address ) == AddressRule.Action.DENY )
{ {
throw new HTTPRequestException( "Domain not permitted" ); throw new HTTPRequestException( "Domain not permitted" );
} }

View File

@@ -119,8 +119,6 @@ public class HttpRequest extends Resource<HttpRequest>
{ {
throw new HTTPRequestException( "Invalid protocol '" + scheme + "'" ); throw new HTTPRequestException( "Invalid protocol '" + scheme + "'" );
} }
NetworkUtils.checkHost( url.getHost() );
} }
public void request( URI uri, HttpMethod method ) public void request( URI uri, HttpMethod method )

View File

@@ -110,7 +110,6 @@ public class Websocket extends Resource<Websocket>
throw new HTTPRequestException( "Invalid scheme '" + scheme + "'" ); throw new HTTPRequestException( "Invalid scheme '" + scheme + "'" );
} }
NetworkUtils.checkHost( uri.getHost() );
return uri; return uri;
} }

View File

@@ -171,7 +171,7 @@ final class ComputerExecutor
apis.add( new FSAPI( environment ) ); apis.add( new FSAPI( environment ) );
apis.add( new PeripheralAPI( environment ) ); apis.add( new PeripheralAPI( environment ) );
apis.add( new OSAPI( environment ) ); apis.add( new OSAPI( environment ) );
if( ComputerCraft.http_enable ) apis.add( new HTTPAPI( environment ) ); if( ComputerCraft.httpEnabled ) apis.add( new HTTPAPI( environment ) );
// Load in the externally registered APIs. // Load in the externally registered APIs.
for( ILuaAPIFactory factory : ApiFactories.getAll() ) for( ILuaAPIFactory factory : ApiFactories.getAll() )
@@ -611,7 +611,7 @@ final class ComputerExecutor
terminal.reset(); terminal.reset();
// Display our primary error message // Display our primary error message
if( colour ) terminal.setTextColour( 15 - Colour.Red.ordinal() ); if( colour ) terminal.setTextColour( 15 - Colour.RED.ordinal() );
terminal.write( message ); terminal.write( message );
if( extra != null ) if( extra != null )
@@ -624,7 +624,7 @@ final class ComputerExecutor
// And display our generic "CC may be installed incorrectly" message. // And display our generic "CC may be installed incorrectly" message.
terminal.setCursorPos( 0, terminal.getCursorY() + 1 ); terminal.setCursorPos( 0, terminal.getCursorY() + 1 );
if( colour ) terminal.setTextColour( 15 - Colour.White.ordinal() ); if( colour ) terminal.setTextColour( 15 - Colour.WHITE.ordinal() );
terminal.write( "ComputerCraft may be installed incorrectly" ); terminal.write( "ComputerCraft may be installed incorrectly" );
} }

View File

@@ -9,12 +9,15 @@ import dan200.computercraft.api.filesystem.IFileSystem;
import dan200.computercraft.api.lua.IComputerSystem; import dan200.computercraft.api.lua.IComputerSystem;
import dan200.computercraft.api.lua.ILuaAPIFactory; import dan200.computercraft.api.lua.ILuaAPIFactory;
import dan200.computercraft.api.peripheral.IComputerAccess; import dan200.computercraft.api.peripheral.IComputerAccess;
import dan200.computercraft.api.peripheral.IPeripheral;
import dan200.computercraft.core.apis.ComputerAccess; import dan200.computercraft.core.apis.ComputerAccess;
import dan200.computercraft.core.apis.IAPIEnvironment; import dan200.computercraft.core.apis.IAPIEnvironment;
import dan200.computercraft.core.filesystem.FileSystem; import dan200.computercraft.core.filesystem.FileSystem;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.util.Collections;
import java.util.Map;
/** /**
* Implementation of {@link IComputerAccess}/{@link IComputerSystem} for usage by externally registered APIs. * Implementation of {@link IComputerAccess}/{@link IComputerSystem} for usage by externally registered APIs.
@@ -54,4 +57,19 @@ public class ComputerSystem extends ComputerAccess implements IComputerSystem
{ {
return environment.getLabel(); return environment.getLabel();
} }
@Nonnull
@Override
public Map<String, IPeripheral> getAvailablePeripherals()
{
// TODO: Should this return peripherals on the current computer?
return Collections.emptyMap();
}
@Nullable
@Override
public IPeripheral getAvailablePeripheral( @Nonnull String name )
{
return null;
}
} }

View File

@@ -10,7 +10,6 @@ import dan200.computercraft.api.filesystem.IMount;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.nio.channels.ReadableByteChannel; import java.nio.channels.ReadableByteChannel;
import java.nio.file.attribute.BasicFileAttributes; import java.nio.file.attribute.BasicFileAttributes;
import java.util.ArrayList; import java.util.ArrayList;
@@ -116,8 +115,7 @@ public class ComboMount implements IMount
@Nonnull @Nonnull
@Override @Override
@Deprecated public ReadableByteChannel openForRead( @Nonnull String path ) throws IOException
public InputStream openForRead( @Nonnull String path ) throws IOException
{ {
for( int i = m_parts.length - 1; i >= 0; --i ) for( int i = m_parts.length - 1; i >= 0; --i )
{ {
@@ -130,21 +128,6 @@ public class ComboMount implements IMount
throw new FileOperationException( path, "No such file" ); throw new FileOperationException( path, "No such file" );
} }
@Nonnull
@Override
public ReadableByteChannel openChannelForRead( @Nonnull String path ) throws IOException
{
for( int i = m_parts.length - 1; i >= 0; --i )
{
IMount part = m_parts[i];
if( part.exists( path ) && !part.isDirectory( path ) )
{
return part.openChannelForRead( path );
}
}
throw new FileOperationException( path, "No such file" );
}
@Nonnull @Nonnull
@Override @Override
public BasicFileAttributes getAttributes( @Nonnull String path ) throws IOException public BasicFileAttributes getAttributes( @Nonnull String path ) throws IOException

View File

@@ -10,7 +10,6 @@ import dan200.computercraft.api.filesystem.IMount;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.nio.channels.ReadableByteChannel; import java.nio.channels.ReadableByteChannel;
import java.util.List; import java.util.List;
@@ -41,16 +40,7 @@ public class EmptyMount implements IMount
@Nonnull @Nonnull
@Override @Override
@Deprecated public ReadableByteChannel openForRead( @Nonnull String path ) throws IOException
public InputStream openForRead( @Nonnull String path ) throws IOException
{
throw new FileOperationException( path, "No such file" );
}
@Nonnull
@Override
@Deprecated
public ReadableByteChannel openChannelForRead( @Nonnull String path ) throws IOException
{ {
throw new FileOperationException( path, "No such file" ); throw new FileOperationException( path, "No such file" );
} }

View File

@@ -11,7 +11,8 @@ import dan200.computercraft.api.filesystem.FileOperationException;
import dan200.computercraft.api.filesystem.IWritableMount; import dan200.computercraft.api.filesystem.IWritableMount;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import java.io.*; import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.channels.*; import java.nio.channels.*;
import java.nio.file.*; import java.nio.file.*;
@@ -200,21 +201,7 @@ public class FileMount implements IWritableMount
@Nonnull @Nonnull
@Override @Override
@Deprecated public ReadableByteChannel openForRead( @Nonnull String path ) throws IOException
public InputStream openForRead( @Nonnull String path ) throws IOException
{
if( created() )
{
File file = getRealPath( path );
if( file.exists() && !file.isDirectory() ) return new FileInputStream( file );
}
throw new FileOperationException( path, "No such file" );
}
@Nonnull
@Override
public ReadableByteChannel openChannelForRead( @Nonnull String path ) throws IOException
{ {
if( created() ) if( created() )
{ {
@@ -313,23 +300,7 @@ public class FileMount implements IWritableMount
@Nonnull @Nonnull
@Override @Override
@Deprecated public WritableByteChannel openForWrite( @Nonnull String path ) throws IOException
public OutputStream openForWrite( @Nonnull String path ) throws IOException
{
return Channels.newOutputStream( openChannelForWrite( path ) );
}
@Nonnull
@Override
@Deprecated
public OutputStream openForAppend( @Nonnull String path ) throws IOException
{
return Channels.newOutputStream( openChannelForAppend( path ) );
}
@Nonnull
@Override
public WritableByteChannel openChannelForWrite( @Nonnull String path ) throws IOException
{ {
create(); create();
File file = getRealPath( path ); File file = getRealPath( path );
@@ -350,7 +321,7 @@ public class FileMount implements IWritableMount
@Nonnull @Nonnull
@Override @Override
public WritableByteChannel openChannelForAppend( @Nonnull String path ) throws IOException public WritableByteChannel openForAppend( @Nonnull String path ) throws IOException
{ {
if( !created() ) if( !created() )
{ {

View File

@@ -9,9 +9,6 @@ import dan200.computercraft.api.filesystem.IFileSystem;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel; import java.nio.channels.ReadableByteChannel;
import java.nio.channels.WritableByteChannel; import java.nio.channels.WritableByteChannel;
import java.util.Collections; import java.util.Collections;
@@ -55,7 +52,7 @@ public class FileSystemWrapperMount implements IFileSystem
@Nonnull @Nonnull
@Override @Override
public ReadableByteChannel openChannelForRead( @Nonnull String path ) throws IOException public ReadableByteChannel openForRead( @Nonnull String path ) throws IOException
{ {
try try
{ {
@@ -70,7 +67,7 @@ public class FileSystemWrapperMount implements IFileSystem
@Nonnull @Nonnull
@Override @Override
public WritableByteChannel openChannelForWrite( @Nonnull String path ) throws IOException public WritableByteChannel openForWrite( @Nonnull String path ) throws IOException
{ {
try try
{ {
@@ -84,7 +81,7 @@ public class FileSystemWrapperMount implements IFileSystem
@Nonnull @Nonnull
@Override @Override
public WritableByteChannel openChannelForAppend( @Nonnull String path ) throws IOException public WritableByteChannel openForAppend( @Nonnull String path ) throws IOException
{ {
try try
{ {
@@ -96,30 +93,6 @@ public class FileSystemWrapperMount implements IFileSystem
} }
} }
@Nonnull
@Override
@Deprecated
public InputStream openForRead( @Nonnull String path ) throws IOException
{
return Channels.newInputStream( openChannelForRead( path ) );
}
@Nonnull
@Override
@Deprecated
public OutputStream openForWrite( @Nonnull String path ) throws IOException
{
return Channels.newOutputStream( openChannelForWrite( path ) );
}
@Nonnull
@Override
@Deprecated
public OutputStream openForAppend( @Nonnull String path ) throws IOException
{
return Channels.newOutputStream( openChannelForAppend( path ) );
}
@Override @Override
public long getRemainingSpace() throws IOException public long getRemainingSpace() throws IOException
{ {

View File

@@ -184,15 +184,7 @@ public class JarMount implements IMount
@Nonnull @Nonnull
@Override @Override
@Deprecated public ReadableByteChannel openForRead( @Nonnull String path ) throws IOException
public InputStream openForRead( @Nonnull String path ) throws IOException
{
return Channels.newInputStream( openChannelForRead( path ) );
}
@Nonnull
@Override
public ReadableByteChannel openChannelForRead( @Nonnull String path ) throws IOException
{ {
FileEntry file = get( path ); FileEntry file = get( path );
if( file != null && !file.isDirectory() ) if( file != null && !file.isDirectory() )

View File

@@ -20,11 +20,11 @@ import java.util.OptionalLong;
class MountWrapper class MountWrapper
{ {
private String label; private final String label;
private String location; private final String location;
private IMount mount; private final IMount mount;
private IWritableMount writableMount; private final IWritableMount writableMount;
MountWrapper( String label, String location, IMount mount ) MountWrapper( String label, String location, IMount mount )
{ {
@@ -36,7 +36,9 @@ class MountWrapper
MountWrapper( String label, String location, IWritableMount mount ) MountWrapper( String label, String location, IWritableMount mount )
{ {
this( label, location, (IMount) mount ); this.label = label;
this.location = location;
this.mount = mount;
writableMount = mount; writableMount = mount;
} }
@@ -154,7 +156,7 @@ class MountWrapper
{ {
if( mount.exists( path ) && !mount.isDirectory( path ) ) if( mount.exists( path ) && !mount.isDirectory( path ) )
{ {
return mount.openChannelForRead( path ); return mount.openForRead( path );
} }
else else
{ {
@@ -232,7 +234,7 @@ class MountWrapper
writableMount.makeDirectory( dir ); writableMount.makeDirectory( dir );
} }
} }
return writableMount.openChannelForWrite( path ); return writableMount.openForWrite( path );
} }
} }
catch( AccessDeniedException e ) catch( AccessDeniedException e )
@@ -262,7 +264,7 @@ class MountWrapper
writableMount.makeDirectory( dir ); writableMount.makeDirectory( dir );
} }
} }
return writableMount.openChannelForWrite( path ); return writableMount.openForWrite( path );
} }
else if( mount.isDirectory( path ) ) else if( mount.isDirectory( path ) )
{ {
@@ -270,7 +272,7 @@ class MountWrapper
} }
else else
{ {
return writableMount.openChannelForAppend( path ); return writableMount.openForAppend( path );
} }
} }
catch( AccessDeniedException e ) catch( AccessDeniedException e )

View File

@@ -223,15 +223,7 @@ public final class ResourceMount implements IMount
@Nonnull @Nonnull
@Override @Override
@Deprecated public ReadableByteChannel openForRead( @Nonnull String path ) throws IOException
public InputStream openForRead( @Nonnull String path ) throws IOException
{
return Channels.newInputStream( openChannelForRead( path ) );
}
@Nonnull
@Override
public ReadableByteChannel openChannelForRead( @Nonnull String path ) throws IOException
{ {
FileEntry file = get( path ); FileEntry file = get( path );
if( file != null && !file.isDirectory() ) if( file != null && !file.isDirectory() )

View File

@@ -9,7 +9,6 @@ import dan200.computercraft.api.filesystem.IMount;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.nio.channels.ReadableByteChannel; import java.nio.channels.ReadableByteChannel;
import java.nio.file.attribute.BasicFileAttributes; import java.nio.file.attribute.BasicFileAttributes;
import java.util.List; import java.util.List;
@@ -51,19 +50,11 @@ public class SubMount implements IMount
@Nonnull @Nonnull
@Override @Override
@Deprecated public ReadableByteChannel openForRead( @Nonnull String path ) throws IOException
public InputStream openForRead( @Nonnull String path ) throws IOException
{ {
return parent.openForRead( getFullPath( path ) ); return parent.openForRead( getFullPath( path ) );
} }
@Nonnull
@Override
public ReadableByteChannel openChannelForRead( @Nonnull String path ) throws IOException
{
return parent.openChannelForRead( getFullPath( path ) );
}
@Nonnull @Nonnull
@Override @Override
public BasicFileAttributes getAttributes( @Nonnull String path ) throws IOException public BasicFileAttributes getAttributes( @Nonnull String path ) throws IOException

View File

@@ -312,19 +312,6 @@ public class Terminal
return null; return null;
} }
/**
* Determine whether this terminal has changed.
*
* @return If this terminal is dirty.
* @deprecated All {@code *Changed()} methods are deprecated: one should pass in a callback
* instead.
*/
@Deprecated
public final boolean getChanged()
{
return m_changed;
}
public final void setChanged() public final void setChanged()
{ {
m_changed = true; m_changed = true;

View File

@@ -14,9 +14,10 @@ import net.minecraft.data.DataGenerator;
import net.minecraft.data.DirectoryCache; import net.minecraft.data.DirectoryCache;
import net.minecraft.data.IDataProvider; import net.minecraft.data.IDataProvider;
import net.minecraft.util.ResourceLocation; import net.minecraft.util.ResourceLocation;
import net.minecraft.world.storage.loot.LootParameterSets;
import net.minecraft.world.storage.loot.LootTable; import net.minecraft.world.storage.loot.LootTable;
import net.minecraft.world.storage.loot.LootTableManager; import net.minecraft.world.storage.loot.LootTableManager;
import net.minecraft.world.storage.loot.ValidationResults; import net.minecraft.world.storage.loot.ValidationTracker;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import java.io.IOException; import java.io.IOException;
@@ -42,17 +43,17 @@ public abstract class LootTableProvider implements IDataProvider
@Override @Override
public void act( @Nonnull DirectoryCache cache ) public void act( @Nonnull DirectoryCache cache )
{ {
ValidationResults validation = new ValidationResults();
Map<ResourceLocation, LootTable> tables = new HashMap<>(); Map<ResourceLocation, LootTable> tables = new HashMap<>();
ValidationTracker validation = new ValidationTracker( LootParameterSets.GENERIC, x -> null, tables::get );
registerLoot( ( id, table ) -> { registerLoot( ( id, table ) -> {
if( tables.containsKey( id ) ) validation.addProblem( "Duplicate loot tables for " + id ); if( tables.containsKey( id ) ) validation.func_227530_a_( "Duplicate loot tables for " + id );
tables.put( id, table ); tables.put( id, table );
} ); } );
tables.forEach( ( key, value ) -> LootTableManager.func_215302_a( validation, key, value, tables::get ) ); tables.forEach( ( key, value ) -> LootTableManager.func_227508_a_( validation, key, value ) );
Multimap<String, String> problems = validation.getProblems(); Multimap<String, String> problems = validation.func_227527_a_();
if( !problems.isEmpty() ) if( !problems.isEmpty() )
{ {
problems.forEach( ( child, problem ) -> problems.forEach( ( child, problem ) ->

View File

@@ -6,12 +6,13 @@
package dan200.computercraft.shared; package dan200.computercraft.shared;
import com.electronwill.nightconfig.core.CommentedConfig; import com.electronwill.nightconfig.core.CommentedConfig;
import com.electronwill.nightconfig.core.UnmodifiableConfig;
import com.electronwill.nightconfig.core.file.CommentedFileConfig; import com.electronwill.nightconfig.core.file.CommentedFileConfig;
import com.google.common.base.CaseFormat; import com.google.common.base.CaseFormat;
import com.google.common.base.Converter; import com.google.common.base.Converter;
import dan200.computercraft.ComputerCraft; import dan200.computercraft.ComputerCraft;
import dan200.computercraft.api.turtle.event.TurtleAction; import dan200.computercraft.api.turtle.event.TurtleAction;
import dan200.computercraft.core.apis.AddressPredicate; import dan200.computercraft.core.apis.http.AddressRule;
import dan200.computercraft.core.apis.http.websocket.Websocket; import dan200.computercraft.core.apis.http.websocket.Websocket;
import net.minecraftforge.common.ForgeConfigSpec; import net.minecraftforge.common.ForgeConfigSpec;
import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.eventbus.api.SubscribeEvent;
@@ -19,13 +20,14 @@ import net.minecraftforge.fml.ModLoadingContext;
import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.config.ModConfig; import net.minecraftforge.fml.config.ModConfig;
import java.util.Arrays; import javax.annotation.Nullable;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static dan200.computercraft.ComputerCraft.DEFAULT_HTTP_BLACKLIST;
import static dan200.computercraft.ComputerCraft.DEFAULT_HTTP_WHITELIST;
import static net.minecraftforge.common.ForgeConfigSpec.Builder; import static net.minecraftforge.common.ForgeConfigSpec.Builder;
import static net.minecraftforge.common.ForgeConfigSpec.ConfigValue; import static net.minecraftforge.common.ForgeConfigSpec.ConfigValue;
@@ -50,8 +52,7 @@ public final class Config
private static final ConfigValue<Boolean> httpEnabled; private static final ConfigValue<Boolean> httpEnabled;
private static final ConfigValue<Boolean> httpWebsocketEnabled; private static final ConfigValue<Boolean> httpWebsocketEnabled;
private static final ConfigValue<List<? extends String>> httpWhitelist; private static final ConfigValue<List<? extends UnmodifiableConfig>> httpRules;
private static final ConfigValue<List<? extends String>> httpBlacklist;
private static final ConfigValue<Integer> httpTimeout; private static final ConfigValue<Integer> httpTimeout;
private static final ConfigValue<Integer> httpMaxRequests; private static final ConfigValue<Integer> httpMaxRequests;
@@ -151,25 +152,25 @@ public final class Config
builder.push( "http" ); builder.push( "http" );
httpEnabled = builder httpEnabled = builder
.comment( "Enable the \"http\" API on Computers (see \"http_whitelist\" and \"http_blacklist\" for more " + .comment( "Enable the \"http\" API on Computers (see \"rules\" for more fine grained control than this)." )
"fine grained control than this)" ) .define( "enabled", ComputerCraft.httpEnabled );
.define( "enabled", ComputerCraft.http_enable );
httpWebsocketEnabled = builder httpWebsocketEnabled = builder
.comment( "Enable use of http websockets. This requires the \"http_enable\" option to also be true." ) .comment( "Enable use of http websockets. This requires the \"http_enable\" option to also be true." )
.define( "websocket_enabled", ComputerCraft.http_websocket_enable ); .define( "websocket_enabled", ComputerCraft.httpWebsocketEnabled );
httpWhitelist = builder httpRules = builder
.comment( "A list of wildcards for domains or IP ranges that can be accessed through the \"http\" API on Computers.\n" + .comment( "A list of rules which control which domains or IPs are allowed through the \"http\" API on computers.\n" +
"Set this to \"*\" to access to the entire internet. Example: \"*.pastebin.com\" will restrict access to just subdomains of pastebin.com.\n" + "Each rule is an item with a 'host' to match against, and an action. " +
"You can use domain names (\"pastebin.com\"), wilcards (\"*.pastebin.com\") or CIDR notation (\"127.0.0.0/8\")." ) "The host may be a domain name (\"pastebin.com\"),\n" +
.defineList( "whitelist", Arrays.asList( DEFAULT_HTTP_WHITELIST ), x -> true ); "wildcard (\"*.pastebin.com\") or CIDR notation (\"127.0.0.0/8\"). 'action' maybe 'allow' or 'block'. If no rules" +
"match, the domain will be blocked." )
httpBlacklist = builder .defineList( "rules",
.comment( "A list of wildcards for domains or IP ranges that cannot be accessed through the \"http\" API on Computers.\n" + Stream.concat(
"If this is empty then all whitelisted domains will be accessible. Example: \"*.github.com\" will block access to all subdomains of github.com.\n" + Stream.of( ComputerCraft.DEFAULT_HTTP_DENY ).map( x -> makeRule( x, "deny" ) ),
"You can use domain names (\"pastebin.com\"), wilcards (\"*.pastebin.com\") or CIDR notation (\"127.0.0.0/8\")." ) Stream.of( ComputerCraft.DEFAULT_HTTP_ALLOW ).map( x -> makeRule( x, "allow" ) )
.defineList( "blacklist", Arrays.asList( DEFAULT_HTTP_BLACKLIST ), x -> true ); ).collect( Collectors.toList() ),
x -> x instanceof UnmodifiableConfig && parseRule( (UnmodifiableConfig) x ) != null );
httpTimeout = builder httpTimeout = builder
.comment( "The period of time (in milliseconds) to wait before a HTTP request times out. Set to 0 for unlimited." ) .comment( "The period of time (in milliseconds) to wait before a HTTP request times out. Set to 0 for unlimited." )
@@ -286,10 +287,10 @@ public final class Config
ComputerCraft.maxMainComputerTime = TimeUnit.MILLISECONDS.toNanos( maxMainComputerTime.get() ); ComputerCraft.maxMainComputerTime = TimeUnit.MILLISECONDS.toNanos( maxMainComputerTime.get() );
// HTTP // HTTP
ComputerCraft.http_enable = httpEnabled.get(); ComputerCraft.httpEnabled = httpEnabled.get();
ComputerCraft.http_websocket_enable = httpWebsocketEnabled.get(); ComputerCraft.httpWebsocketEnabled = httpWebsocketEnabled.get();
ComputerCraft.http_whitelist = new AddressPredicate( httpWhitelist.get() ); ComputerCraft.httpRules = Collections.unmodifiableList( httpRules.get().stream()
ComputerCraft.http_blacklist = new AddressPredicate( httpBlacklist.get() ); .map( Config::parseRule ).filter( Objects::nonNull ).collect( Collectors.toList() ) );
ComputerCraft.httpTimeout = httpTimeout.get(); ComputerCraft.httpTimeout = httpTimeout.get();
ComputerCraft.httpMaxRequests = httpMaxRequests.get(); ComputerCraft.httpMaxRequests = httpMaxRequests.get();
@@ -324,7 +325,7 @@ public final class Config
} }
@SubscribeEvent @SubscribeEvent
public static void sync( ModConfig.ConfigReloading event ) public static void sync( ModConfig.Reloading event )
{ {
// Ensure file configs are reloaded. Forge should probably do this, so worth checking in the future. // Ensure file configs are reloaded. Forge should probably do this, so worth checking in the future.
CommentedConfig config = event.getConfig().getConfigData(); CommentedConfig config = event.getConfig().getConfigData();
@@ -346,4 +347,28 @@ public final class Config
return null; return null;
} }
} }
private static UnmodifiableConfig makeRule( String host, String action )
{
com.electronwill.nightconfig.core.Config config = com.electronwill.nightconfig.core.Config.inMemory();
config.add( "host", host );
config.add( "action", action );
return config;
}
@Nullable
private static AddressRule parseRule( UnmodifiableConfig builder )
{
Object hostObj = builder.get( "host" );
Object actionObj = builder.get( "action" );
if( !(hostObj instanceof String) || !(actionObj instanceof String) ) return null;
String host = (String) hostObj, action = (String) actionObj;
for( AddressRule.Action candiate : AddressRule.Action.values() )
{
if( candiate.name().equalsIgnoreCase( action ) ) return AddressRule.parse( host, candiate );
}
return null;
}
} }

View File

@@ -84,17 +84,17 @@ public final class Registry
// Computers // Computers
ComputerCraft.Blocks.computerNormal = new BlockComputer( ComputerCraft.Blocks.computerNormal = new BlockComputer(
Block.Properties.create( Material.ROCK ).hardnessAndResistance( 2.0f ), Block.Properties.create( Material.ROCK ).hardnessAndResistance( 2.0f ),
ComputerFamily.Normal, TileComputer.FACTORY_NORMAL ComputerFamily.NORMAL, TileComputer.FACTORY_NORMAL
); );
ComputerCraft.Blocks.computerAdvanced = new BlockComputer( ComputerCraft.Blocks.computerAdvanced = new BlockComputer(
Block.Properties.create( Material.ROCK ).hardnessAndResistance( 2.0f ), Block.Properties.create( Material.ROCK ).hardnessAndResistance( 2.0f ),
ComputerFamily.Advanced, TileComputer.FACTORY_ADVANCED ComputerFamily.ADVANCED, TileComputer.FACTORY_ADVANCED
); );
ComputerCraft.Blocks.computerCommand = new BlockComputer( ComputerCraft.Blocks.computerCommand = new BlockComputer(
Block.Properties.create( Material.ROCK ).hardnessAndResistance( -1, 6000000.0F ), Block.Properties.create( Material.ROCK ).hardnessAndResistance( -1, 6000000.0F ),
ComputerFamily.Command, TileCommandComputer.FACTORY ComputerFamily.COMMAND, TileCommandComputer.FACTORY
); );
registry.registerAll( registry.registerAll(
@@ -106,12 +106,12 @@ public final class Registry
// Turtles // Turtles
ComputerCraft.Blocks.turtleNormal = new BlockTurtle( ComputerCraft.Blocks.turtleNormal = new BlockTurtle(
Block.Properties.create( Material.ROCK ).hardnessAndResistance( 2.5f ), Block.Properties.create( Material.ROCK ).hardnessAndResistance( 2.5f ),
ComputerFamily.Normal, TileTurtle.FACTORY_NORMAL ComputerFamily.NORMAL, TileTurtle.FACTORY_NORMAL
); );
ComputerCraft.Blocks.turtleAdvanced = new BlockTurtle( ComputerCraft.Blocks.turtleAdvanced = new BlockTurtle(
Block.Properties.create( Material.ROCK ).hardnessAndResistance( 2.5f ), Block.Properties.create( Material.ROCK ).hardnessAndResistance( 2.5f ),
ComputerFamily.Advanced, TileTurtle.FACTORY_ADVANCED ComputerFamily.ADVANCED, TileTurtle.FACTORY_ADVANCED
); );
registry.registerAll( registry.registerAll(
@@ -234,8 +234,8 @@ public final class Registry
); );
// Pocket computer // Pocket computer
ComputerCraft.Items.pocketComputerNormal = new ItemPocketComputer( defaultItem().maxStackSize( 1 ), ComputerFamily.Normal ); ComputerCraft.Items.pocketComputerNormal = new ItemPocketComputer( defaultItem().maxStackSize( 1 ), ComputerFamily.NORMAL );
ComputerCraft.Items.pocketComputerAdvanced = new ItemPocketComputer( defaultItem().maxStackSize( 1 ), ComputerFamily.Advanced ); ComputerCraft.Items.pocketComputerAdvanced = new ItemPocketComputer( defaultItem().maxStackSize( 1 ), ComputerFamily.ADVANCED );
registry.registerAll( registry.registerAll(
ComputerCraft.Items.pocketComputerNormal.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "pocket_computer_normal" ) ), ComputerCraft.Items.pocketComputerNormal.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "pocket_computer_normal" ) ),

View File

@@ -205,7 +205,7 @@ public final class CommandComputerCraft
int queued = 0; int queued = 0;
for( ServerComputer computer : computers ) for( ServerComputer computer : computers )
{ {
if( computer.getFamily() == ComputerFamily.Command && computer.isOn() ) if( computer.getFamily() == ComputerFamily.COMMAND && computer.isOn() )
{ {
computer.queueEvent( "computer_command", rest ); computer.queueEvent( "computer_command", rest );
queued++; queued++;

View File

@@ -11,12 +11,14 @@ import net.minecraft.block.BlockState;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntity;
import net.minecraft.tileentity.TileEntityType; import net.minecraft.tileentity.TileEntityType;
import net.minecraft.util.ActionResultType;
import net.minecraft.util.Hand; import net.minecraft.util.Hand;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.BlockRayTraceResult; import net.minecraft.util.math.BlockRayTraceResult;
import net.minecraft.world.IBlockReader; import net.minecraft.world.IBlockReader;
import net.minecraft.world.IWorldReader; import net.minecraft.world.IWorldReader;
import net.minecraft.world.World; import net.minecraft.world.World;
import net.minecraft.world.server.ServerWorld;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@@ -45,12 +47,13 @@ public abstract class BlockGeneric extends Block
if( tile instanceof TileGeneric ) ((TileGeneric) tile).destroy(); if( tile instanceof TileGeneric ) ((TileGeneric) tile).destroy();
} }
@Nonnull
@Override @Override
@Deprecated @Deprecated
public final boolean onBlockActivated( BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockRayTraceResult hit ) public final ActionResultType onBlockActivated( BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockRayTraceResult hit )
{ {
TileEntity tile = world.getTileEntity( pos ); TileEntity tile = world.getTileEntity( pos );
return tile instanceof TileGeneric && ((TileGeneric) tile).onActivate( player, hand, hit ); return tile instanceof TileGeneric ? ((TileGeneric) tile).onActivate( player, hand, hit ) : ActionResultType.PASS;
} }
@Override @Override
@@ -70,7 +73,7 @@ public abstract class BlockGeneric extends Block
@Override @Override
@Deprecated @Deprecated
public void tick( BlockState state, World world, BlockPos pos, Random rand ) public void tick( BlockState state, ServerWorld world, BlockPos pos, Random rand )
{ {
TileEntity te = world.getTileEntity( pos ); TileEntity te = world.getTileEntity( pos );
if( te instanceof TileGeneric ) ((TileGeneric) te).blockTick(); if( te instanceof TileGeneric ) ((TileGeneric) te).blockTick();

View File

@@ -12,6 +12,7 @@ import net.minecraft.network.NetworkManager;
import net.minecraft.network.play.server.SUpdateTileEntityPacket; import net.minecraft.network.play.server.SUpdateTileEntityPacket;
import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntity;
import net.minecraft.tileentity.TileEntityType; import net.minecraft.tileentity.TileEntityType;
import net.minecraft.util.ActionResultType;
import net.minecraft.util.Hand; import net.minecraft.util.Hand;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.BlockRayTraceResult; import net.minecraft.util.math.BlockRayTraceResult;
@@ -37,9 +38,10 @@ public abstract class TileGeneric extends TileEntity
getWorld().notifyBlockUpdate( pos, state, state, 3 ); getWorld().notifyBlockUpdate( pos, state, state, 3 );
} }
public boolean onActivate( PlayerEntity player, Hand hand, BlockRayTraceResult hit ) @Nonnull
public ActionResultType onActivate( PlayerEntity player, Hand hand, BlockRayTraceResult hit )
{ {
return false; return ActionResultType.PASS;
} }
public void onNeighbourChange( @Nonnull BlockPos neighbour ) public void onNeighbourChange( @Nonnull BlockPos neighbour )

View File

@@ -32,7 +32,7 @@ public class TileCommandComputer extends TileComputer
{ {
public static final NamedTileEntityType<TileCommandComputer> FACTORY = NamedTileEntityType.create( public static final NamedTileEntityType<TileCommandComputer> FACTORY = NamedTileEntityType.create(
new ResourceLocation( ComputerCraft.MOD_ID, "command_computer" ), new ResourceLocation( ComputerCraft.MOD_ID, "command_computer" ),
f -> new TileCommandComputer( ComputerFamily.Command, f ) f -> new TileCommandComputer( ComputerFamily.COMMAND, f )
); );
public class CommandReceiver implements ICommandSource public class CommandReceiver implements ICommandSource

View File

@@ -27,12 +27,12 @@ public class TileComputer extends TileComputerBase
{ {
public static final NamedTileEntityType<TileComputer> FACTORY_NORMAL = NamedTileEntityType.create( public static final NamedTileEntityType<TileComputer> FACTORY_NORMAL = NamedTileEntityType.create(
new ResourceLocation( ComputerCraft.MOD_ID, "computer_normal" ), new ResourceLocation( ComputerCraft.MOD_ID, "computer_normal" ),
f -> new TileComputer( ComputerFamily.Normal, f ) f -> new TileComputer( ComputerFamily.NORMAL, f )
); );
public static final NamedTileEntityType<TileComputer> FACTORY_ADVANCED = NamedTileEntityType.create( public static final NamedTileEntityType<TileComputer> FACTORY_ADVANCED = NamedTileEntityType.create(
new ResourceLocation( ComputerCraft.MOD_ID, "computer_advanced" ), new ResourceLocation( ComputerCraft.MOD_ID, "computer_advanced" ),
f -> new TileComputer( ComputerFamily.Advanced, f ) f -> new TileComputer( ComputerFamily.ADVANCED, f )
); );
private ComputerProxy m_proxy; private ComputerProxy m_proxy;

View File

@@ -30,6 +30,7 @@ import net.minecraft.item.Items;
import net.minecraft.nbt.CompoundNBT; import net.minecraft.nbt.CompoundNBT;
import net.minecraft.tileentity.ITickableTileEntity; import net.minecraft.tileentity.ITickableTileEntity;
import net.minecraft.tileentity.TileEntityType; import net.minecraft.tileentity.TileEntityType;
import net.minecraft.util.ActionResultType;
import net.minecraft.util.Direction; import net.minecraft.util.Direction;
import net.minecraft.util.Hand; import net.minecraft.util.Hand;
import net.minecraft.util.INameable; import net.minecraft.util.INameable;
@@ -102,8 +103,9 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT
return false; return false;
} }
@Nonnull
@Override @Override
public boolean onActivate( PlayerEntity player, Hand hand, BlockRayTraceResult hit ) public ActionResultType onActivate( PlayerEntity player, Hand hand, BlockRayTraceResult hit )
{ {
ItemStack currentItem = player.getHeldItem( hand ); ItemStack currentItem = player.getHeldItem( hand );
if( !currentItem.isEmpty() && currentItem.getItem() == Items.NAME_TAG && canNameWithTag( player ) && currentItem.hasDisplayName() ) if( !currentItem.isEmpty() && currentItem.getItem() == Items.NAME_TAG && canNameWithTag( player ) && currentItem.hasDisplayName() )
@@ -114,9 +116,9 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT
setLabel( currentItem.getDisplayName().getString() ); setLabel( currentItem.getDisplayName().getString() );
currentItem.shrink( 1 ); currentItem.shrink( 1 );
} }
return true; return ActionResultType.SUCCESS;
} }
else if( !player.isSneaking() ) else if( !player.isCrouching() )
{ {
// Regular right click to activate computer // Regular right click to activate computer
if( !getWorld().isRemote && isUsable( player, false ) ) if( !getWorld().isRemote && isUsable( player, false ) )
@@ -124,9 +126,9 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT
createServerComputer().turnOn(); createServerComputer().turnOn();
new ComputerContainerData( createServerComputer() ).open( player, this ); new ComputerContainerData( createServerComputer() ).open( player, this );
} }
return true; return ActionResultType.SUCCESS;
} }
return false; return ActionResultType.PASS;
} }
@Override @Override

View File

@@ -7,7 +7,7 @@ package dan200.computercraft.shared.computer.core;
public enum ComputerFamily public enum ComputerFamily
{ {
Normal, NORMAL,
Advanced, ADVANCED,
Command COMMAND
} }

View File

@@ -50,7 +50,7 @@ public class ServerComputer extends ServerTerminal implements IComputer, IComput
public ServerComputer( World world, int computerID, String label, int instanceID, ComputerFamily family, int terminalWidth, int terminalHeight ) public ServerComputer( World world, int computerID, String label, int instanceID, ComputerFamily family, int terminalWidth, int terminalHeight )
{ {
super( family != ComputerFamily.Normal, terminalWidth, terminalHeight ); super( family != ComputerFamily.NORMAL, terminalWidth, terminalHeight );
m_instanceID = instanceID; m_instanceID = instanceID;
m_world = world; m_world = world;

View File

@@ -48,7 +48,7 @@ public class ContainerViewComputer extends ContainerComputerBase implements ICon
} }
// If we're a command computer then ensure we're in creative // If we're a command computer then ensure we're in creative
if( computer.getFamily() == ComputerFamily.Command ) if( computer.getFamily() == ComputerFamily.COMMAND )
{ {
MinecraftServer server = player.getServer(); MinecraftServer server = player.getServer();
if( server == null || !server.isCommandBlockEnabled() ) if( server == null || !server.isCommandBlockEnabled() )

View File

@@ -29,11 +29,11 @@ public final class ComputerItemFactory
{ {
switch( family ) switch( family )
{ {
case Normal: case NORMAL:
return ComputerCraft.Items.computerNormal.create( id, label ); return ComputerCraft.Items.computerNormal.create( id, label );
case Advanced: case ADVANCED:
return ComputerCraft.Items.computerAdvanced.create( id, label ); return ComputerCraft.Items.computerAdvanced.create( id, label );
case Command: case COMMAND:
return ComputerCraft.Items.computerCommand.create( id, label ); return ComputerCraft.Items.computerCommand.create( id, label );
default: default:
return ItemStack.EMPTY; return ItemStack.EMPTY;

View File

@@ -80,7 +80,7 @@ public abstract class ItemComputerBase extends BlockItem implements IComputerIte
public IMount createDataMount( @Nonnull ItemStack stack, @Nonnull World world ) public IMount createDataMount( @Nonnull ItemStack stack, @Nonnull World world )
{ {
ComputerFamily family = getFamily(); ComputerFamily family = getFamily();
if( family != ComputerFamily.Command ) if( family != ComputerFamily.COMMAND )
{ {
int id = getComputerID( stack ); int id = getComputerID( stack );
if( id >= 0 ) if( id >= 0 )

View File

@@ -116,8 +116,8 @@ public class JEIComputerCraft implements IModPlugin
StringBuilder name = new StringBuilder(); StringBuilder name = new StringBuilder();
// Add left and right upgrades to the identifier // Add left and right upgrades to the identifier
ITurtleUpgrade left = turtle.getUpgrade( stack, TurtleSide.Left ); ITurtleUpgrade left = turtle.getUpgrade( stack, TurtleSide.LEFT );
ITurtleUpgrade right = turtle.getUpgrade( stack, TurtleSide.Right ); ITurtleUpgrade right = turtle.getUpgrade( stack, TurtleSide.RIGHT );
if( left != null ) name.append( left.getUpgradeID() ); if( left != null ) name.append( left.getUpgradeID() );
if( left != null && right != null ) name.append( '|' ); if( left != null && right != null ) name.append( '|' );
if( right != null ) name.append( right.getUpgradeID() ); if( right != null ) name.append( right.getUpgradeID() );

View File

@@ -37,7 +37,7 @@ import static net.minecraft.util.NonNullList.from;
class RecipeResolver implements IRecipeManagerPlugin class RecipeResolver implements IRecipeManagerPlugin
{ {
static final ComputerFamily[] MAIN_FAMILIES = new ComputerFamily[] { ComputerFamily.Normal, ComputerFamily.Advanced }; static final ComputerFamily[] MAIN_FAMILIES = new ComputerFamily[] { ComputerFamily.NORMAL, ComputerFamily.ADVANCED };
private final Map<Item, List<UpgradeInfo>> upgradeItemLookup = new HashMap<>(); private final Map<Item, List<UpgradeInfo>> upgradeItemLookup = new HashMap<>();
private final List<UpgradeInfo> pocketUpgrades = new ArrayList<>(); private final List<UpgradeInfo> pocketUpgrades = new ArrayList<>();
@@ -150,8 +150,8 @@ class RecipeResolver implements IRecipeManagerPlugin
{ {
// Suggest possible upgrades which can be applied to this turtle // Suggest possible upgrades which can be applied to this turtle
ITurtleItem item = (ITurtleItem) stack.getItem(); ITurtleItem item = (ITurtleItem) stack.getItem();
ITurtleUpgrade left = item.getUpgrade( stack, TurtleSide.Left ); ITurtleUpgrade left = item.getUpgrade( stack, TurtleSide.LEFT );
ITurtleUpgrade right = item.getUpgrade( stack, TurtleSide.Right ); ITurtleUpgrade right = item.getUpgrade( stack, TurtleSide.RIGHT );
if( left != null && right != null ) return Collections.emptyList(); if( left != null && right != null ) return Collections.emptyList();
List<Shaped> recipes = new ArrayList<>(); List<Shaped> recipes = new ArrayList<>();
@@ -231,8 +231,8 @@ class RecipeResolver implements IRecipeManagerPlugin
ITurtleItem item = (ITurtleItem) stack.getItem(); ITurtleItem item = (ITurtleItem) stack.getItem();
List<Shaped> recipes = new ArrayList<>( 0 ); List<Shaped> recipes = new ArrayList<>( 0 );
ITurtleUpgrade left = item.getUpgrade( stack, TurtleSide.Left ); ITurtleUpgrade left = item.getUpgrade( stack, TurtleSide.LEFT );
ITurtleUpgrade right = item.getUpgrade( stack, TurtleSide.Right ); ITurtleUpgrade right = item.getUpgrade( stack, TurtleSide.RIGHT );
// The turtle is facing towards us, so upgrades on the left are actually crafted on the right. // The turtle is facing towards us, so upgrades on the left are actually crafted on the right.
if( left != null ) if( left != null )

View File

@@ -126,6 +126,6 @@ public class ItemDisk extends Item implements IMedia, IColouredItem
public int getColour( @Nonnull ItemStack stack ) public int getColour( @Nonnull ItemStack stack )
{ {
int colour = IColouredItem.getColourBasic( stack ); int colour = IColouredItem.getColourBasic( stack );
return colour == -1 ? Colour.White.getHex() : colour; return colour == -1 ? Colour.WHITE.getHex() : colour;
} }
} }

View File

@@ -134,6 +134,6 @@ public class ItemTreasureDisk extends Item implements IMedia
public static int getColour( @Nonnull ItemStack stack ) public static int getColour( @Nonnull ItemStack stack )
{ {
CompoundNBT nbt = stack.getTag(); CompoundNBT nbt = stack.getTag();
return nbt != null && nbt.contains( NBT_COLOUR ) ? nbt.getInt( NBT_COLOUR ) : Colour.Blue.getHex(); return nbt != null && nbt.contains( NBT_COLOUR ) ? nbt.getInt( NBT_COLOUR ) : Colour.BLUE.getHex();
} }
} }

View File

@@ -87,7 +87,7 @@ public class DiskRecipe extends SpecialRecipe
} }
} }
return ItemDisk.createFromIDAndColour( -1, null, tracker.hasColour() ? tracker.getColour() : Colour.Blue.getHex() ); return ItemDisk.createFromIDAndColour( -1, null, tracker.hasColour() ? tracker.getColour() : Colour.BLUE.getHex() );
} }
@Override @Override
@@ -100,7 +100,7 @@ public class DiskRecipe extends SpecialRecipe
@Override @Override
public ItemStack getRecipeOutput() public ItemStack getRecipeOutput()
{ {
return ItemDisk.createFromIDAndColour( -1, null, Colour.Blue.getHex() ); return ItemDisk.createFromIDAndColour( -1, null, Colour.BLUE.getHex() );
} }
@Nonnull @Nonnull

View File

@@ -76,12 +76,10 @@ public final class NetworkHandler
{ {
for( ServerPlayerEntity player : ServerLifecycleHooks.getCurrentServer().getPlayerList().getPlayers() ) for( ServerPlayerEntity player : ServerLifecycleHooks.getCurrentServer().getPlayerList().getPlayers() )
{ {
if( player.getEntityWorld() != world ) continue; if( player.getEntityWorld() == world && player.getDistanceSq( pos ) < range * range )
{
double x = pos.x - player.posX; sendToPlayer( player, packet );
double y = pos.y - player.posY; }
double z = pos.z - player.posZ;
if( x * x + y * y + z * z < range * range ) sendToPlayer( player, packet );
} }
} }

View File

@@ -99,26 +99,27 @@ public final class TileDiskDrive extends TileGeneric implements DefaultInventory
} }
} }
@Nonnull
@Override @Override
public boolean onActivate( PlayerEntity player, Hand hand, BlockRayTraceResult hit ) public ActionResultType onActivate( PlayerEntity player, Hand hand, BlockRayTraceResult hit )
{ {
if( player.isSneaking() ) if( player.isCrouching() )
{ {
// Try to put a disk into the drive // Try to put a disk into the drive
ItemStack disk = player.getHeldItem( hand ); ItemStack disk = player.getHeldItem( hand );
if( disk.isEmpty() ) return false; if( disk.isEmpty() ) return ActionResultType.PASS;
if( !getWorld().isRemote && getStackInSlot( 0 ).isEmpty() && MediaProviders.get( disk ) != null ) if( !getWorld().isRemote && getStackInSlot( 0 ).isEmpty() && MediaProviders.get( disk ) != null )
{ {
setDiskStack( disk ); setDiskStack( disk );
player.setHeldItem( hand, ItemStack.EMPTY ); player.setHeldItem( hand, ItemStack.EMPTY );
} }
return true; return ActionResultType.SUCCESS;
} }
else else
{ {
// Open the GUI // Open the GUI
if( !getWorld().isRemote ) NetworkHooks.openGui( (ServerPlayerEntity) player, this ); if( !getWorld().isRemote ) NetworkHooks.openGui( (ServerPlayerEntity) player, this );
return true; return ActionResultType.SUCCESS;
} }
} }

View File

@@ -250,11 +250,4 @@ public class BlockCable extends BlockGeneric implements IWaterLoggable
.with( WEST, false ).with( UP, false ).with( DOWN, false ); .with( WEST, false ).with( UP, false ).with( DOWN, false );
} }
} }
@Override
@Deprecated
public boolean hasCustomBreakingProgress( BlockState state )
{
return true;
}
} }

View File

@@ -24,6 +24,7 @@ import net.minecraft.block.BlockState;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundNBT; import net.minecraft.nbt.CompoundNBT;
import net.minecraft.util.ActionResultType;
import net.minecraft.util.Direction; import net.minecraft.util.Direction;
import net.minecraft.util.Hand; import net.minecraft.util.Hand;
import net.minecraft.util.ResourceLocation; import net.minecraft.util.ResourceLocation;
@@ -238,12 +239,14 @@ public class TileCable extends TileGeneric implements IPeripheralTile
} }
} }
@Nonnull
@Override @Override
public boolean onActivate( PlayerEntity player, Hand hand, BlockRayTraceResult hit ) public ActionResultType onActivate( PlayerEntity player, Hand hand, BlockRayTraceResult hit )
{ {
if( !canAttachPeripheral() || player.isSneaking() ) return false; if( player.isCrouching() ) return ActionResultType.PASS;
if( !canAttachPeripheral() ) return ActionResultType.FAIL;
if( getWorld().isRemote ) return true; if( getWorld().isRemote ) return ActionResultType.SUCCESS;
String oldName = m_peripheral.getConnectedName(); String oldName = m_peripheral.getConnectedName();
togglePeripheralAccess(); togglePeripheralAccess();
@@ -262,7 +265,7 @@ public class TileCable extends TileGeneric implements IPeripheralTile
} }
} }
return true; return ActionResultType.SUCCESS;
} }
@Override @Override

View File

@@ -22,6 +22,7 @@ import dan200.computercraft.shared.wired.CapabilityWiredElement;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.nbt.CompoundNBT; import net.minecraft.nbt.CompoundNBT;
import net.minecraft.util.ActionResultType;
import net.minecraft.util.Direction; import net.minecraft.util.Direction;
import net.minecraft.util.Hand; import net.minecraft.util.Hand;
import net.minecraft.util.ResourceLocation; import net.minecraft.util.ResourceLocation;
@@ -184,10 +185,11 @@ public class TileWiredModemFull extends TileGeneric implements IPeripheralTile
} }
} }
@Nonnull
@Override @Override
public boolean onActivate( PlayerEntity player, Hand hand, BlockRayTraceResult hit ) public ActionResultType onActivate( PlayerEntity player, Hand hand, BlockRayTraceResult hit )
{ {
if( getWorld().isRemote ) return true; if( getWorld().isRemote ) return ActionResultType.SUCCESS;
// On server, we interacted if a peripheral was found // On server, we interacted if a peripheral was found
Set<String> oldPeriphNames = getConnectedPeripheralNames(); Set<String> oldPeriphNames = getConnectedPeripheralNames();
@@ -200,7 +202,7 @@ public class TileWiredModemFull extends TileGeneric implements IPeripheralTile
sendPeripheralChanges( player, "chat.computercraft.wired_modem.peripheral_connected", periphNames ); sendPeripheralChanges( player, "chat.computercraft.wired_modem.peripheral_connected", periphNames );
} }
return true; return ActionResultType.SUCCESS;
} }
private static void sendPeripheralChanges( PlayerEntity player, String kind, Collection<String> peripherals ) private static void sendPeripheralChanges( PlayerEntity player, String kind, Collection<String> peripherals )

View File

@@ -374,7 +374,7 @@ public abstract class WiredModemPeripheral extends ModemPeripheral implements IW
m_computer.queueEvent( event, arguments ); m_computer.queueEvent( event, arguments );
} }
@Nullable @Nonnull
@Override @Override
public IWorkMonitor getMainThreadMonitor() public IWorkMonitor getMainThreadMonitor()
{ {

View File

@@ -18,12 +18,10 @@ import net.minecraft.state.EnumProperty;
import net.minecraft.state.StateContainer; import net.minecraft.state.StateContainer;
import net.minecraft.state.properties.BlockStateProperties; import net.minecraft.state.properties.BlockStateProperties;
import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.BlockRenderLayer;
import net.minecraft.util.Direction; import net.minecraft.util.Direction;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World; import net.minecraft.world.World;
import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
public class BlockMonitor extends BlockGeneric public class BlockMonitor extends BlockGeneric
@@ -38,28 +36,13 @@ public class BlockMonitor extends BlockGeneric
public BlockMonitor( Properties settings, NamedTileEntityType<? extends TileGeneric> type ) public BlockMonitor( Properties settings, NamedTileEntityType<? extends TileGeneric> type )
{ {
super( settings, type ); super( settings, type );
// TODO: Test underwater - do we need isSolid at all?
setDefaultState( getStateContainer().getBaseState() setDefaultState( getStateContainer().getBaseState()
.with( ORIENTATION, Direction.NORTH ) .with( ORIENTATION, Direction.NORTH )
.with( FACING, Direction.NORTH ) .with( FACING, Direction.NORTH )
.with( STATE, MonitorEdgeState.NONE ) ); .with( STATE, MonitorEdgeState.NONE ) );
} }
@Nonnull
@Override
public BlockRenderLayer getRenderLayer()
{
// We use the CUTOUT layer, as otherwise monitor rendering will cause flickering.
return BlockRenderLayer.CUTOUT;
}
@Override
@Deprecated
public boolean isSolid( BlockState state )
{
// We override isSolid, as our overriding of getRenderLayer means that it would otherwise return false.
return true;
}
@Override @Override
protected void fillStateContainer( StateContainer.Builder<Block, BlockState> builder ) protected void fillStateContainer( StateContainer.Builder<Block, BlockState> builder )
{ {

View File

@@ -54,7 +54,7 @@ public final class ClientMonitor extends ClientTerminal
if( buffer != null ) return false; if( buffer != null ) return false;
deleteBuffers(); deleteBuffers();
buffer = new VertexBuffer( FixedWidthFontRenderer.POSITION_COLOR_TEX ); buffer = new VertexBuffer( FixedWidthFontRenderer.TYPE.getVertexFormat() );
addMonitor(); addMonitor();
return true; return true;
@@ -75,7 +75,7 @@ public final class ClientMonitor extends ClientTerminal
{ {
if( buffer != null ) if( buffer != null )
{ {
buffer.deleteGlBuffers(); buffer.close();
buffer = null; buffer = null;
} }
} }

View File

@@ -6,7 +6,6 @@
package dan200.computercraft.shared.peripheral.monitor; package dan200.computercraft.shared.peripheral.monitor;
import com.mojang.blaze3d.platform.GLX;
import dan200.computercraft.ComputerCraft; import dan200.computercraft.ComputerCraft;
import dan200.computercraft.client.render.TileEntityMonitorRenderer; import dan200.computercraft.client.render.TileEntityMonitorRenderer;
@@ -73,22 +72,7 @@ public enum MonitorRenderer
public static MonitorRenderer current() public static MonitorRenderer current()
{ {
MonitorRenderer current = ComputerCraft.monitorRenderer; MonitorRenderer current = ComputerCraft.monitorRenderer;
switch( current ) return current == MonitorRenderer.BEST ? best() : current;
{
case BEST:
return best();
case VBO:
if( !GLX.useVbo() )
{
ComputerCraft.log.warn( "VBOs are not supported on your graphics card. Falling back to default." );
ComputerCraft.monitorRenderer = BEST;
return best();
}
return VBO;
default:
return current;
}
} }
private static MonitorRenderer best() private static MonitorRenderer best()

View File

@@ -18,9 +18,11 @@ import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.nbt.CompoundNBT; import net.minecraft.nbt.CompoundNBT;
import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntity;
import net.minecraft.tileentity.TileEntityType; import net.minecraft.tileentity.TileEntityType;
import net.minecraft.util.ActionResultType;
import net.minecraft.util.Direction; import net.minecraft.util.Direction;
import net.minecraft.util.Hand; import net.minecraft.util.Hand;
import net.minecraft.util.ResourceLocation; import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.BlockRayTraceResult; import net.minecraft.util.math.BlockRayTraceResult;
import net.minecraft.world.World; import net.minecraft.world.World;
@@ -104,10 +106,11 @@ public class TileMonitor extends TileGeneric implements IPeripheralTile
if( m_clientMonitor != null && m_xIndex == 0 && m_yIndex == 0 ) m_clientMonitor.destroy(); if( m_clientMonitor != null && m_xIndex == 0 && m_yIndex == 0 ) m_clientMonitor.destroy();
} }
@Nonnull
@Override @Override
public boolean onActivate( PlayerEntity player, Hand hand, BlockRayTraceResult hit ) public ActionResultType onActivate( PlayerEntity player, Hand hand, BlockRayTraceResult hit )
{ {
if( !player.isSneaking() && getFront() == hit.getFace() ) if( !player.isCrouching() && getFront() == hit.getFace() )
{ {
if( !getWorld().isRemote ) if( !getWorld().isRemote )
{ {
@@ -117,10 +120,10 @@ public class TileMonitor extends TileGeneric implements IPeripheralTile
(float) (hit.getHitVec().z - hit.getPos().getZ()) (float) (hit.getHitVec().z - hit.getPos().getZ())
); );
} }
return true; return ActionResultType.SUCCESS;
} }
return false; return ActionResultType.PASS;
} }
@Nonnull @Nonnull
@@ -651,13 +654,12 @@ public class TileMonitor extends TileGeneric implements IPeripheralTile
m_computers.remove( computer ); m_computers.remove( computer );
} }
/*
@Nonnull @Nonnull
@Override @Override
public AxisAlignedBB getRenderBoundingBox() public AxisAlignedBB getRenderBoundingBox()
{ {
TileMonitor start = getNeighbour( 0, 0 ); TileMonitor start = getNeighbour( 0, 0 );
TileMonitor end = getNeighbour( width - 1, height - 1 ); TileMonitor end = getNeighbour( m_width - 1, m_height - 1 );
if( start != null && end != null ) if( start != null && end != null )
{ {
BlockPos startPos = start.getPos(); BlockPos startPos = start.getPos();
@@ -676,5 +678,4 @@ public class TileMonitor extends TileGeneric implements IPeripheralTile
return new AxisAlignedBB( pos.getX(), pos.getY(), pos.getZ(), pos.getX() + 1, pos.getY() + 1, pos.getZ() + 1 ); return new AxisAlignedBB( pos.getX(), pos.getY(), pos.getZ(), pos.getX() + 1, pos.getY() + 1, pos.getZ() + 1 );
} }
} }
*/
} }

View File

@@ -25,8 +25,8 @@ import net.minecraft.inventory.container.INamedContainerProvider;
import net.minecraft.item.*; import net.minecraft.item.*;
import net.minecraft.nbt.CompoundNBT; import net.minecraft.nbt.CompoundNBT;
import net.minecraft.util.*; import net.minecraft.util.*;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.BlockRayTraceResult; import net.minecraft.util.math.BlockRayTraceResult;
import net.minecraft.util.math.Vec3d;
import net.minecraft.util.text.ITextComponent; import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.text.TranslationTextComponent; import net.minecraft.util.text.TranslationTextComponent;
import net.minecraftforge.common.capabilities.Capability; import net.minecraftforge.common.capabilities.Capability;
@@ -94,13 +94,14 @@ public final class TilePrinter extends TileGeneric implements DefaultSidedInvent
} }
} }
@Nonnull
@Override @Override
public boolean onActivate( PlayerEntity player, Hand hand, BlockRayTraceResult hit ) public ActionResultType onActivate( PlayerEntity player, Hand hand, BlockRayTraceResult hit )
{ {
if( player.isSneaking() ) return false; if( player.isCrouching() ) return ActionResultType.PASS;
if( !getWorld().isRemote ) NetworkHooks.openGui( (ServerPlayerEntity) player, this ); if( !getWorld().isRemote ) NetworkHooks.openGui( (ServerPlayerEntity) player, this );
return true; return ActionResultType.SUCCESS;
} }
@Override @Override
@@ -424,11 +425,7 @@ public final class TilePrinter extends TileGeneric implements DefaultSidedInvent
setInventorySlotContents( i, ItemStack.EMPTY ); setInventorySlotContents( i, ItemStack.EMPTY );
// Spawn the item in the world // Spawn the item in the world
BlockPos pos = getPos(); WorldUtil.dropItemStack( stack, getWorld(), new Vec3d( getPos() ).add( 0.5, 0.75, 0.5 ) );
double x = pos.getX() + 0.5;
double y = pos.getY() + 0.75;
double z = pos.getZ() + 0.5;
WorldUtil.dropItemStack( stack, getWorld(), x, y, z );
} }
} }
} }

View File

@@ -80,7 +80,7 @@ public class PocketAPI implements ILuaAPI
stack = InventoryUtil.storeItems( stack, new PlayerMainInvWrapper( inventory ), inventory.currentItem ); stack = InventoryUtil.storeItems( stack, new PlayerMainInvWrapper( inventory ), inventory.currentItem );
if( !stack.isEmpty() ) if( !stack.isEmpty() )
{ {
WorldUtil.dropItemStack( stack, player.getEntityWorld(), player.posX, player.posY, player.posZ ); WorldUtil.dropItemStack( stack, player.getEntityWorld(), player.getPositionVec() );
} }
} }
} }
@@ -111,7 +111,7 @@ public class PocketAPI implements ILuaAPI
stack = InventoryUtil.storeItems( stack, new PlayerMainInvWrapper( inventory ), inventory.currentItem ); stack = InventoryUtil.storeItems( stack, new PlayerMainInvWrapper( inventory ), inventory.currentItem );
if( stack.isEmpty() ) if( stack.isEmpty() )
{ {
WorldUtil.dropItemStack( stack, player.getEntityWorld(), player.posX, player.posY, player.posZ ); WorldUtil.dropItemStack( stack, player.getEntityWorld(), player.getPositionVec() );
} }
} }

View File

@@ -21,9 +21,9 @@ public final class PocketComputerItemFactory
{ {
switch( family ) switch( family )
{ {
case Normal: case NORMAL:
return ComputerCraft.Items.pocketComputerNormal.create( id, label, colour, upgrade ); return ComputerCraft.Items.pocketComputerNormal.create( id, label, colour, upgrade );
case Advanced: case ADVANCED:
return ComputerCraft.Items.pocketComputerAdvanced.create( id, label, colour, upgrade ); return ComputerCraft.Items.pocketComputerAdvanced.create( id, label, colour, upgrade );
default: default:
return ItemStack.EMPTY; return ItemStack.EMPTY;

View File

@@ -37,7 +37,7 @@ public final class PocketComputerUpgradeRecipe extends SpecialRecipe
@Override @Override
public ItemStack getRecipeOutput() public ItemStack getRecipeOutput()
{ {
return PocketComputerItemFactory.create( -1, null, -1, ComputerFamily.Normal, null ); return PocketComputerItemFactory.create( -1, null, -1, ComputerFamily.NORMAL, null );
} }
@Override @Override

View File

@@ -11,7 +11,6 @@ import dan200.computercraft.api.media.IMedia;
import dan200.computercraft.api.peripheral.IPeripheralTile; import dan200.computercraft.api.peripheral.IPeripheralTile;
import dan200.computercraft.core.computer.MainThread; import dan200.computercraft.core.computer.MainThread;
import dan200.computercraft.core.tracking.Tracking; import dan200.computercraft.core.tracking.Tracking;
import dan200.computercraft.shared.Config;
import dan200.computercraft.shared.command.CommandComputerCraft; import dan200.computercraft.shared.command.CommandComputerCraft;
import dan200.computercraft.shared.command.arguments.ArgumentSerializers; import dan200.computercraft.shared.command.arguments.ArgumentSerializers;
import dan200.computercraft.shared.common.DefaultBundledRedstoneProvider; import dan200.computercraft.shared.common.DefaultBundledRedstoneProvider;
@@ -36,7 +35,6 @@ import net.minecraft.world.storage.loot.conditions.LootConditionManager;
import net.minecraftforge.event.TickEvent; import net.minecraftforge.event.TickEvent;
import net.minecraftforge.event.entity.player.PlayerContainerEvent; import net.minecraftforge.event.entity.player.PlayerContainerEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.client.event.ConfigChangedEvent;
import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent; import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent;
import net.minecraftforge.fml.event.server.FMLServerStartedEvent; import net.minecraftforge.fml.event.server.FMLServerStartedEvent;
@@ -133,12 +131,6 @@ public final class ComputerCraftProxyCommon
} }
} }
@SubscribeEvent
public static void onConfigChanged( ConfigChangedEvent.OnConfigChangedEvent event )
{
if( event.getModID().equals( ComputerCraft.MOD_ID ) ) Config.sync();
}
@SubscribeEvent @SubscribeEvent
public static void onContainerOpen( PlayerContainerEvent.Open event ) public static void onContainerOpen( PlayerContainerEvent.Open event )
{ {

View File

@@ -133,11 +133,11 @@ public class TurtleAPI implements ILuaAPI
} }
else if( side.equalsIgnoreCase( "left" ) ) else if( side.equalsIgnoreCase( "left" ) )
{ {
return TurtleSide.Left; return TurtleSide.LEFT;
} }
else if( side.equalsIgnoreCase( "right" ) ) else if( side.equalsIgnoreCase( "right" ) )
{ {
return TurtleSide.Right; return TurtleSide.RIGHT;
} }
else else
{ {
@@ -152,58 +152,58 @@ public class TurtleAPI implements ILuaAPI
{ {
case 0: // forward case 0: // forward
m_environment.addTrackingChange( TrackingField.TURTLE_OPS ); m_environment.addTrackingChange( TrackingField.TURTLE_OPS );
return tryCommand( context, new TurtleMoveCommand( MoveDirection.Forward ) ); return tryCommand( context, new TurtleMoveCommand( MoveDirection.FORWARD ) );
case 1: // back case 1: // back
m_environment.addTrackingChange( TrackingField.TURTLE_OPS ); m_environment.addTrackingChange( TrackingField.TURTLE_OPS );
return tryCommand( context, new TurtleMoveCommand( MoveDirection.Back ) ); return tryCommand( context, new TurtleMoveCommand( MoveDirection.BACK ) );
case 2: // up case 2: // up
m_environment.addTrackingChange( TrackingField.TURTLE_OPS ); m_environment.addTrackingChange( TrackingField.TURTLE_OPS );
return tryCommand( context, new TurtleMoveCommand( MoveDirection.Up ) ); return tryCommand( context, new TurtleMoveCommand( MoveDirection.UP ) );
case 3: // down case 3: // down
m_environment.addTrackingChange( TrackingField.TURTLE_OPS ); m_environment.addTrackingChange( TrackingField.TURTLE_OPS );
return tryCommand( context, new TurtleMoveCommand( MoveDirection.Down ) ); return tryCommand( context, new TurtleMoveCommand( MoveDirection.DOWN ) );
case 4: // turnLeft case 4: // turnLeft
m_environment.addTrackingChange( TrackingField.TURTLE_OPS ); m_environment.addTrackingChange( TrackingField.TURTLE_OPS );
return tryCommand( context, new TurtleTurnCommand( TurnDirection.Left ) ); return tryCommand( context, new TurtleTurnCommand( TurnDirection.LEFT ) );
case 5: // turnRight case 5: // turnRight
m_environment.addTrackingChange( TrackingField.TURTLE_OPS ); m_environment.addTrackingChange( TrackingField.TURTLE_OPS );
return tryCommand( context, new TurtleTurnCommand( TurnDirection.Right ) ); return tryCommand( context, new TurtleTurnCommand( TurnDirection.RIGHT ) );
case 6: case 6:
{ {
// dig // dig
TurtleSide side = parseSide( args, 0 ); TurtleSide side = parseSide( args, 0 );
m_environment.addTrackingChange( TrackingField.TURTLE_OPS ); m_environment.addTrackingChange( TrackingField.TURTLE_OPS );
return tryCommand( context, TurtleToolCommand.dig( InteractDirection.Forward, side ) ); return tryCommand( context, TurtleToolCommand.dig( InteractDirection.FORWARD, side ) );
} }
case 7: case 7:
{ {
// digUp // digUp
TurtleSide side = parseSide( args, 0 ); TurtleSide side = parseSide( args, 0 );
m_environment.addTrackingChange( TrackingField.TURTLE_OPS ); m_environment.addTrackingChange( TrackingField.TURTLE_OPS );
return tryCommand( context, TurtleToolCommand.dig( InteractDirection.Up, side ) ); return tryCommand( context, TurtleToolCommand.dig( InteractDirection.UP, side ) );
} }
case 8: case 8:
{ {
// digDown // digDown
TurtleSide side = parseSide( args, 0 ); TurtleSide side = parseSide( args, 0 );
m_environment.addTrackingChange( TrackingField.TURTLE_OPS ); m_environment.addTrackingChange( TrackingField.TURTLE_OPS );
return tryCommand( context, TurtleToolCommand.dig( InteractDirection.Down, side ) ); return tryCommand( context, TurtleToolCommand.dig( InteractDirection.DOWN, side ) );
} }
case 9: // place case 9: // place
m_environment.addTrackingChange( TrackingField.TURTLE_OPS ); m_environment.addTrackingChange( TrackingField.TURTLE_OPS );
return tryCommand( context, new TurtlePlaceCommand( InteractDirection.Forward, args ) ); return tryCommand( context, new TurtlePlaceCommand( InteractDirection.FORWARD, args ) );
case 10: // placeUp case 10: // placeUp
m_environment.addTrackingChange( TrackingField.TURTLE_OPS ); m_environment.addTrackingChange( TrackingField.TURTLE_OPS );
return tryCommand( context, new TurtlePlaceCommand( InteractDirection.Up, args ) ); return tryCommand( context, new TurtlePlaceCommand( InteractDirection.UP, args ) );
case 11: // placeDown case 11: // placeDown
m_environment.addTrackingChange( TrackingField.TURTLE_OPS ); m_environment.addTrackingChange( TrackingField.TURTLE_OPS );
return tryCommand( context, new TurtlePlaceCommand( InteractDirection.Down, args ) ); return tryCommand( context, new TurtlePlaceCommand( InteractDirection.DOWN, args ) );
case 12: case 12:
{ {
// drop // drop
int count = parseCount( args, 0 ); int count = parseCount( args, 0 );
m_environment.addTrackingChange( TrackingField.TURTLE_OPS ); m_environment.addTrackingChange( TrackingField.TURTLE_OPS );
return tryCommand( context, new TurtleDropCommand( InteractDirection.Forward, count ) ); return tryCommand( context, new TurtleDropCommand( InteractDirection.FORWARD, count ) );
} }
case 13: case 13:
{ {
@@ -229,72 +229,72 @@ public class TurtleAPI implements ILuaAPI
return new Object[] { stack.isEmpty() ? 64 : Math.min( stack.getMaxStackSize(), 64 ) - stack.getCount() }; return new Object[] { stack.isEmpty() ? 64 : Math.min( stack.getMaxStackSize(), 64 ) - stack.getCount() };
} }
case 16: // detect case 16: // detect
return tryCommand( context, new TurtleDetectCommand( InteractDirection.Forward ) ); return tryCommand( context, new TurtleDetectCommand( InteractDirection.FORWARD ) );
case 17: // detectUp case 17: // detectUp
return tryCommand( context, new TurtleDetectCommand( InteractDirection.Up ) ); return tryCommand( context, new TurtleDetectCommand( InteractDirection.UP ) );
case 18: // detectDown case 18: // detectDown
return tryCommand( context, new TurtleDetectCommand( InteractDirection.Down ) ); return tryCommand( context, new TurtleDetectCommand( InteractDirection.DOWN ) );
case 19: // compare case 19: // compare
return tryCommand( context, new TurtleCompareCommand( InteractDirection.Forward ) ); return tryCommand( context, new TurtleCompareCommand( InteractDirection.FORWARD ) );
case 20: // compareUp case 20: // compareUp
return tryCommand( context, new TurtleCompareCommand( InteractDirection.Up ) ); return tryCommand( context, new TurtleCompareCommand( InteractDirection.UP ) );
case 21: // compareDown case 21: // compareDown
return tryCommand( context, new TurtleCompareCommand( InteractDirection.Down ) ); return tryCommand( context, new TurtleCompareCommand( InteractDirection.DOWN ) );
case 22: case 22:
{ {
// attack // attack
TurtleSide side = parseSide( args, 0 ); TurtleSide side = parseSide( args, 0 );
m_environment.addTrackingChange( TrackingField.TURTLE_OPS ); m_environment.addTrackingChange( TrackingField.TURTLE_OPS );
return tryCommand( context, TurtleToolCommand.attack( InteractDirection.Forward, side ) ); return tryCommand( context, TurtleToolCommand.attack( InteractDirection.FORWARD, side ) );
} }
case 23: case 23:
{ {
// attackUp // attackUp
TurtleSide side = parseSide( args, 0 ); TurtleSide side = parseSide( args, 0 );
m_environment.addTrackingChange( TrackingField.TURTLE_OPS ); m_environment.addTrackingChange( TrackingField.TURTLE_OPS );
return tryCommand( context, TurtleToolCommand.attack( InteractDirection.Up, side ) ); return tryCommand( context, TurtleToolCommand.attack( InteractDirection.UP, side ) );
} }
case 24: case 24:
{ {
// attackDown // attackDown
TurtleSide side = parseSide( args, 0 ); TurtleSide side = parseSide( args, 0 );
m_environment.addTrackingChange( TrackingField.TURTLE_OPS ); m_environment.addTrackingChange( TrackingField.TURTLE_OPS );
return tryCommand( context, TurtleToolCommand.attack( InteractDirection.Down, side ) ); return tryCommand( context, TurtleToolCommand.attack( InteractDirection.DOWN, side ) );
} }
case 25: case 25:
{ {
// dropUp // dropUp
int count = parseCount( args, 0 ); int count = parseCount( args, 0 );
m_environment.addTrackingChange( TrackingField.TURTLE_OPS ); m_environment.addTrackingChange( TrackingField.TURTLE_OPS );
return tryCommand( context, new TurtleDropCommand( InteractDirection.Up, count ) ); return tryCommand( context, new TurtleDropCommand( InteractDirection.UP, count ) );
} }
case 26: case 26:
{ {
// dropDown // dropDown
int count = parseCount( args, 0 ); int count = parseCount( args, 0 );
m_environment.addTrackingChange( TrackingField.TURTLE_OPS ); m_environment.addTrackingChange( TrackingField.TURTLE_OPS );
return tryCommand( context, new TurtleDropCommand( InteractDirection.Down, count ) ); return tryCommand( context, new TurtleDropCommand( InteractDirection.DOWN, count ) );
} }
case 27: case 27:
{ {
// suck // suck
int count = parseCount( args, 0 ); int count = parseCount( args, 0 );
m_environment.addTrackingChange( TrackingField.TURTLE_OPS ); m_environment.addTrackingChange( TrackingField.TURTLE_OPS );
return tryCommand( context, new TurtleSuckCommand( InteractDirection.Forward, count ) ); return tryCommand( context, new TurtleSuckCommand( InteractDirection.FORWARD, count ) );
} }
case 28: case 28:
{ {
// suckUp // suckUp
int count = parseCount( args, 0 ); int count = parseCount( args, 0 );
m_environment.addTrackingChange( TrackingField.TURTLE_OPS ); m_environment.addTrackingChange( TrackingField.TURTLE_OPS );
return tryCommand( context, new TurtleSuckCommand( InteractDirection.Up, count ) ); return tryCommand( context, new TurtleSuckCommand( InteractDirection.UP, count ) );
} }
case 29: case 29:
{ {
// suckDown // suckDown
int count = parseCount( args, 0 ); int count = parseCount( args, 0 );
m_environment.addTrackingChange( TrackingField.TURTLE_OPS ); m_environment.addTrackingChange( TrackingField.TURTLE_OPS );
return tryCommand( context, new TurtleSuckCommand( InteractDirection.Down, count ) ); return tryCommand( context, new TurtleSuckCommand( InteractDirection.DOWN, count ) );
} }
case 30: // getFuelLevel case 30: // getFuelLevel
return new Object[] { m_turtle.isFuelNeeded() ? m_turtle.getFuelLevel() : "unlimited" }; return new Object[] { m_turtle.isFuelNeeded() ? m_turtle.getFuelLevel() : "unlimited" };
@@ -324,16 +324,16 @@ public class TurtleAPI implements ILuaAPI
return new Object[] { m_turtle.isFuelNeeded() ? m_turtle.getFuelLimit() : "unlimited" }; return new Object[] { m_turtle.isFuelNeeded() ? m_turtle.getFuelLimit() : "unlimited" };
case 36: // equipLeft case 36: // equipLeft
m_environment.addTrackingChange( TrackingField.TURTLE_OPS ); m_environment.addTrackingChange( TrackingField.TURTLE_OPS );
return tryCommand( context, new TurtleEquipCommand( TurtleSide.Left ) ); return tryCommand( context, new TurtleEquipCommand( TurtleSide.LEFT ) );
case 37: // equipRight case 37: // equipRight
m_environment.addTrackingChange( TrackingField.TURTLE_OPS ); m_environment.addTrackingChange( TrackingField.TURTLE_OPS );
return tryCommand( context, new TurtleEquipCommand( TurtleSide.Right ) ); return tryCommand( context, new TurtleEquipCommand( TurtleSide.RIGHT ) );
case 38: // inspect case 38: // inspect
return tryCommand( context, new TurtleInspectCommand( InteractDirection.Forward ) ); return tryCommand( context, new TurtleInspectCommand( InteractDirection.FORWARD ) );
case 39: // inspectUp case 39: // inspectUp
return tryCommand( context, new TurtleInspectCommand( InteractDirection.Up ) ); return tryCommand( context, new TurtleInspectCommand( InteractDirection.UP ) );
case 40: // inspectDown case 40: // inspectDown
return tryCommand( context, new TurtleInspectCommand( InteractDirection.Down ) ); return tryCommand( context, new TurtleInspectCommand( InteractDirection.DOWN ) );
case 41: // getItemDetail case 41: // getItemDetail
{ {
// FIXME: There's a race condition here if the stack is being modified (mutating NBT, etc...) // FIXME: There's a race condition here if the stack is being modified (mutating NBT, etc...)

View File

@@ -152,7 +152,7 @@ public class BlockTurtle extends BlockComputerBase<TileTurtle> implements IWater
@Override @Override
public float getExplosionResistance( BlockState state, IWorldReader world, BlockPos pos, @Nullable Entity exploder, Explosion explosion ) public float getExplosionResistance( BlockState state, IWorldReader world, BlockPos pos, @Nullable Entity exploder, Explosion explosion )
{ {
if( getFamily() == ComputerFamily.Advanced || exploder instanceof LivingEntity || exploder instanceof DamagingProjectileEntity ) if( getFamily() == ComputerFamily.ADVANCED || exploder instanceof LivingEntity || exploder instanceof DamagingProjectileEntity )
{ {
return 2000; return 2000;
} }

View File

@@ -33,10 +33,7 @@ import net.minecraft.item.Items;
import net.minecraft.nbt.CompoundNBT; import net.minecraft.nbt.CompoundNBT;
import net.minecraft.nbt.ListNBT; import net.minecraft.nbt.ListNBT;
import net.minecraft.tileentity.TileEntityType; import net.minecraft.tileentity.TileEntityType;
import net.minecraft.util.Direction; import net.minecraft.util.*;
import net.minecraft.util.Hand;
import net.minecraft.util.NonNullList;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.BlockRayTraceResult; import net.minecraft.util.math.BlockRayTraceResult;
import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3d;
@@ -60,12 +57,12 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default
public static final NamedTileEntityType<TileTurtle> FACTORY_NORMAL = NamedTileEntityType.create( public static final NamedTileEntityType<TileTurtle> FACTORY_NORMAL = NamedTileEntityType.create(
new ResourceLocation( ComputerCraft.MOD_ID, "turtle_normal" ), new ResourceLocation( ComputerCraft.MOD_ID, "turtle_normal" ),
type -> new TileTurtle( type, ComputerFamily.Normal ) type -> new TileTurtle( type, ComputerFamily.NORMAL )
); );
public static final NamedTileEntityType<TileTurtle> FACTORY_ADVANCED = NamedTileEntityType.create( public static final NamedTileEntityType<TileTurtle> FACTORY_ADVANCED = NamedTileEntityType.create(
new ResourceLocation( ComputerCraft.MOD_ID, "turtle_advanced" ), new ResourceLocation( ComputerCraft.MOD_ID, "turtle_advanced" ),
type -> new TileTurtle( type, ComputerFamily.Advanced ) type -> new TileTurtle( type, ComputerFamily.ADVANCED )
); );
enum MoveState enum MoveState
@@ -164,8 +161,9 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default
} }
} }
@Nonnull
@Override @Override
public boolean onActivate( PlayerEntity player, Hand hand, BlockRayTraceResult hit ) public ActionResultType onActivate( PlayerEntity player, Hand hand, BlockRayTraceResult hit )
{ {
// Apply dye // Apply dye
ItemStack currentItem = player.getHeldItem( hand ); ItemStack currentItem = player.getHeldItem( hand );
@@ -186,7 +184,7 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default
} }
} }
} }
return true; return ActionResultType.SUCCESS;
} }
else if( currentItem.getItem() == Items.WATER_BUCKET && m_brain.getColour() != -1 ) else if( currentItem.getItem() == Items.WATER_BUCKET && m_brain.getColour() != -1 )
{ {
@@ -203,7 +201,7 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default
} }
} }
} }
return true; return ActionResultType.SUCCESS;
} }
} }
@@ -528,10 +526,10 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default
switch( side ) switch( side )
{ {
case RIGHT: case RIGHT:
upgrade = getUpgrade( TurtleSide.Right ); upgrade = getUpgrade( TurtleSide.RIGHT );
break; break;
case LEFT: case LEFT:
upgrade = getUpgrade( TurtleSide.Left ); upgrade = getUpgrade( TurtleSide.LEFT );
break; break;
default: default:
return false; return false;

View File

@@ -10,20 +10,20 @@ import net.minecraft.util.Direction;
public enum InteractDirection public enum InteractDirection
{ {
Forward, FORWARD,
Up, UP,
Down; DOWN;
public Direction toWorldDir( ITurtleAccess turtle ) public Direction toWorldDir( ITurtleAccess turtle )
{ {
switch( this ) switch( this )
{ {
case Forward: case FORWARD:
default: default:
return turtle.getDirection(); return turtle.getDirection();
case Up: case UP:
return Direction.UP; return Direction.UP;
case Down: case DOWN:
return Direction.DOWN; return Direction.DOWN;
} }
} }

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