1
0
mirror of https://github.com/SquidDev-CC/CC-Tweaked synced 2025-10-20 08:27:38 +00:00

Compare commits

..

1 Commits

Author SHA1 Message Date
SquidDev
6ac1c0e944 Basic network visualiser 2019-02-11 09:05:27 +00:00
77 changed files with 928 additions and 979 deletions

View File

@@ -6,10 +6,11 @@ about: Report some misbehaviour in the mod
<!-- <!--
## Before reporting ## Before reporting
- Search for the bug on the issue tracker. Make sure to look at closed issues too! - Search for the bug both here and [on the ComputerCraft issues page](https://github.com/dan200/ComputerCraft/issues?utf8=%E2%9C%93&q=is%3Aissue+)
- If possible, try to reproduce on vanilla ComputerCraft. If it still occurs, [report on the ComputerCraft repo](https://github.com/dan200/ComputerCraft/issues/new) instead.
--> -->
## Useful information to include: ## Useful information to include:
- Minecraft version - Minecraft version
- CC: Tweaked version - CC: Tweaked version
- Detailed reproduction steps: sometimes I can spot a bug pretty easily, but often it's much more obscure. The more information I have to help reproduce it, the quicker it'll get fixed. - Detailed reproduction steps!** Sometimes I can spot a bug pretty easily, but often it's much more obscure. Anything you can give which will help reproduce it means it'll get fixed quicker.

View File

@@ -6,9 +6,10 @@ about: Suggest an idea or improvement
<!-- <!--
## Before reporting ## Before reporting
- Search for the suggestion here. It's possible someone's suggested it before! - Search for the suggestion both here and [on the ComputerCraft issues page](https://github.com/dan200/ComputerCraft/issues?utf8=%E2%9C%93&q=is%3Aissue+). It's possible someone's suggested it before!
- Unless something is specific to CC:Tweaked, try to [suggest them on the ComputerCraft repo](https://github.com/dan200/ComputerCraft/issues/new). There's a lot more people watching it, so it allows the wider community to contribute.
--> -->
## Useful information to include: ## Useful information to include:
- Explanation of how the feature/change should work. - Explanation of how the feature/change chould work.
- Some rationale/use case for a feature. I'd like to keep CC:T as minimal as possible, so I like have a solid justification for each feature. - Some rationale/use case for a feature. I'd like to keep CC:T as minimal

9
.github/pull_request_template.md vendored Normal file
View File

@@ -0,0 +1,9 @@
<!--
Unless this feature is specific to CC:Tweaked, try to [target the original ComputerCraft repo](https://github.com/dan200/ComputerCraft/) instead. There's a lot more people watching it, so it allows the wider community to contribute.
-->
## Useful information to include:
- Brief explanation of the changes you've made.
- Rationale of why this change has been made/reasoning behind it.
The more information you can provide, the easier it is to review something now _and_ to see why a change was made, when the code needs updating in the future.

19
LICENSE-luaj Normal file
View File

@@ -0,0 +1,19 @@
Copyright (c) 2007 LuaJ. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@@ -1,35 +1,35 @@
# ![CC: Tweaked](logo.png) # ![CC: Tweaked](logo.png)
[![Build Status](https://travis-ci.org/SquidDev-CC/CC-Tweaked.svg?branch=master)](https://travis-ci.org/SquidDev-CC/CC-Tweaked) [![Build Status](https://travis-ci.org/SquidDev-CC/CC-Tweaked.svg?branch=master)](https://travis-ci.org/SquidDev-CC/CC-Tweaked)
CC: Tweaked is a fork of [ComputerCraft](https://github.com/dan200/ComputerCraft), adding programmable computers, CC: Tweaked is a fork of ComputerCraft which aims to provide earlier access to the more experimental and in-development
turtles and more to Minecraft. features of the mod. For a more stable experience, I recommend checking out the
[original mod](https://github.com/dan200/ComputerCraft).
## What? ## What?
ComputerCraft has always held a fond place in my heart: it's the mod which really got me into Minecraft, and it's the CC: Tweaked (or CC:T for short) does not aim to create a competing fork of ComputerCraft, nor am I planning to take it
mod which has kept me playing it for many years. However, development of the original mod has slowed, as the original in in a vastly different direction to the original mod. In fact, CC:T aims to be a nurturing ground for various
developers have had less time to work on the mod, and moved onto other projects and commitments. features, with a pull request against the original mod being the end goal.
CC:Tweaked (or CC:T for short) is an attempt to continue ComputerCraft's legacy. It's not intended to be a competitor CC:T also includes many pull requests from the community which have not yet been merged, offering a large number
to CC, nor do I want to take it in a vastly different direction to the original mod. Instead, CC:T focuses on making the of additional bug fixes and features over the original mod.
ComputerCraft experience as _solid_ as possible, ironing out any wrinkles that may have developed over time.
## Features ## Features
CC: Tweaked contains all the features of the latest version of ComputerCraft, as well as numerous fixes, performance CC: Tweaked contains all the features of the latest alpha, as well as numerous fixes, performance improvements and
improvements and several nifty additions. I'd recommend checking out [the releases page](https://github.com/SquidDev-CC/CC-Tweaked/releases) several additional features. I'd recommend checking out [the releases page](https://github.com/SquidDev-CC/CC-Tweaked/releases)
to see the full set of changes, but here's a couple of the more interesting additions: to see the full changes, but here's a couple of the more interesting changes:
- Improvements to the `http` library, including websockets, support for other HTTP methods (`PUT`, `DELETE`, etc...) - Replace LuaJ with Cobalt.
and configurable limits on HTTP usage. - Allow running multiple computers at the same time.
- Full-block wired modems, allowing one to wrap non-solid peripherals (such as turtles, or chests if Plethora is - Websocket support in the HTTP library.
installed). - Wired modems and cables act more like multiparts.
- Pocket computers can be held like maps, allowing you to view the screen without entering a GUI. - Add map-like rendering for pocket computers and printed pages/books.
- Printed pages and books can be placed in item frames and held like maps. - Adds the `/computercraft` command, offering various diagnostic tools for server owners. This allows operators to
- Several profiling and administration tools for server owners, via the `/computercraft` command. This allows operators track which computers are hogging resources, turn on and shutdown multiple computers at once and interact with
to track which computers are hogging resources, turn on and shutdown multiple computers at once and interact with
computers remotely. computers remotely.
- Closer emulation of standard Lua, adding the `debug` and `io` libraries. This also enables seeking within binary - Add full-block wired modems, allowing one to wrap non-solid peripherals (such as turtles, or chests if Plethora is
files, meaning you don't need to read large files into memory. installed).
- Allow running multiple computers on multiple threads, reducing latency on worlds with many computers. - Extended binary file handles. They support file seeking, and reading new lines, allowing full (and accurate)
emulation of the standard Lua `io` library.
## Relation to CCTweaks? ## Relation to CCTweaks?
This mod has nothing to do with CCTweaks, though there is no denying the name is a throwback to it. That being said, This mod has nothing to do with CCTweaks, though there is no denying the name is a throwback to it. That being said,
@@ -37,8 +37,10 @@ several features have been included, such as full block modems, the Cobalt runti
computers. computers.
## Contributing ## Contributing
Any contribution is welcome, be that using the mod, reporting bugs or contributing code. In order to start helping Any contribution is welcome, be that using the mod, reporting bugs or contributing code. If you do wish to contribute
develop CC:T, you'll need to follow these steps: code, do consider submitting it to the ComputerCraft repository first.
That being said, in order to start helping develop CC:T, you'll need to follow these steps:
- **Clone the repository:** `git clone https://github.com/SquidDev-CC/CC-Tweaked.git && cd CC-Tweaked` - **Clone the repository:** `git clone https://github.com/SquidDev-CC/CC-Tweaked.git && cd CC-Tweaked`
- **Setup Forge:** `./gradlew setupDecompWorkspace` - **Setup Forge:** `./gradlew setupDecompWorkspace`

View File

@@ -9,9 +9,7 @@ buildscript {
} }
} }
dependencies { dependencies {
classpath 'com.google.code.gson:gson:2.8.1'
classpath 'net.minecraftforge.gradle:ForgeGradle:2.3-SNAPSHOT' classpath 'net.minecraftforge.gradle:ForgeGradle:2.3-SNAPSHOT'
classpath 'net.sf.proguard:proguard-gradle:6.1.0beta1'
classpath 'org.ajoberstar.grgit:grgit-gradle:3.0.0' classpath 'org.ajoberstar.grgit:grgit-gradle:3.0.0'
} }
} }
@@ -25,17 +23,14 @@ apply plugin: 'org.ajoberstar.grgit'
apply plugin: 'maven-publish' apply plugin: 'maven-publish'
apply plugin: 'maven' apply plugin: 'maven'
def mc_version = "1.12.2" version = "1.80pr1.14"
def main_version = "1.81.1"
version = "${mc_version}-${main_version}"
group = "org.squiddev" group = "org.squiddev"
archivesBaseName = "cc-tweaked" archivesBaseName = "cc-tweaked"
minecraft { minecraft {
version = "${mc_version}-14.23.4.2749" version = "1.12.2-14.23.4.2749"
runDir = "run" runDir = "run"
replace '${version}', main_version replace '${version}', project.version
// the mappings can be changed at any time, and must be in the following format. // the mappings can be changed at any time, and must be in the following format.
// snapshot_YYYYMMDD snapshot are built nightly. // snapshot_YYYYMMDD snapshot are built nightly.
@@ -89,68 +84,20 @@ jar {
attributes('FMLAT': 'computercraft_at.cfg') attributes('FMLAT': 'computercraft_at.cfg')
} }
from (sourceSets.main.allSource) { into("docs", { from (javadoc.destinationDir) })
into("api", { from (sourceSets.main.allSource) {
include "dan200/computercraft/api/**/*.java" include "dan200/computercraft/api/**/*.java"
} }})
from configurations.shade.collect { it.isDirectory() ? it : zipTree(it) } from configurations.shade.collect { it.isDirectory() ? it : zipTree(it) }
} }
import java.nio.charset.StandardCharsets
import java.nio.file.*
import java.util.zip.*
import com.google.gson.GsonBuilder
import com.google.gson.JsonElement
import org.ajoberstar.grgit.Grgit import org.ajoberstar.grgit.Grgit
import proguard.gradle.ProGuardTask
task proguard(type: ProGuardTask, dependsOn: jar) {
description "Removes unused shadowed classes from the jar"
group "compact"
injars jar.archivePath
outjars "${jar.archivePath.absolutePath.replace(".jar", "")}-min.jar"
// Add the main runtime jar and all non-shadowed dependencies
libraryjars "${System.getProperty('java.home')}/lib/rt.jar"
doFirst {
sourceSets.main.compileClasspath
.filter { !it.name.contains("Cobalt") }
.each { libraryjars it }
}
// We want to avoid as much obfuscation as possible. We're only doing this to shrink code size.
dontobfuscate; dontoptimize; keepattributes; keepparameternames
// Proguard will remove directories by default, but that breaks JarMount.
keepdirectories 'assets/computercraft/lua**'
// Preserve ComputerCraft classes - we only want to strip shadowed files.
keep 'class dan200.computercraft.** { *; }'
// Preserve the constructors in Cobalt library class, as we init them via reflection
keepclassmembers 'class org.squiddev.cobalt.lib.** { <init>(...); }'
}
task proguardMove(dependsOn: proguard) {
description "Replace the original jar with the minified version"
group "compact"
doLast {
Files.move(
file("${jar.archivePath.absolutePath.replace(".jar", "")}-min.jar").toPath(),
file(jar.archivePath).toPath(),
StandardCopyOption.REPLACE_EXISTING
)
}
}
reobfJar.dependsOn proguardMove
processResources { processResources {
inputs.property "version", main_version inputs.property "version", project.version
inputs.property "mcversion", mc_version inputs.property "mcversion", project.minecraft.version
def hash = 'none' def hash = 'none'
Set<String> contributors = [] Set<String> contributors = []
@@ -171,9 +118,9 @@ processResources {
include 'mcmod.info' include 'mcmod.info'
include 'assets/computercraft/lua/rom/help/credits.txt' include 'assets/computercraft/lua/rom/help/credits.txt'
expand 'version': main_version, expand 'version':project.version,
'mcversion': mc_version, 'mcversion':project.minecraft.version,
'gitcontributors': contributors.sort(false, String.CASE_INSENSITIVE_ORDER).join('\n') 'gitcontributors':contributors.sort(false, String.CASE_INSENSITIVE_ORDER).join('\n')
} }
from(sourceSets.main.resources.srcDirs) { from(sourceSets.main.resources.srcDirs) {
@@ -182,53 +129,12 @@ processResources {
} }
} }
task compressJson(dependsOn: extractAnnotationsJar) {
group "compact"
description "Minifies all JSON files, stripping whitespace"
def jarPath = file(jar.archivePath)
def tempPath = File.createTempFile("input", ".jar", temporaryDir)
tempPath.deleteOnExit()
def gson = new GsonBuilder().create()
doLast {
// Copy over all files in the current jar to the new one, running json files from GSON. As pretty printing
// is turned off, they should be minified.
new ZipFile(jarPath).withCloseable { inJar ->
new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(tempPath))).withCloseable { outJar ->
inJar.entries().each { entry ->
if(entry.directory) {
outJar.putNextEntry(entry)
} else if(!entry.name.endsWith(".json")) {
outJar.putNextEntry(entry)
inJar.getInputStream(entry).withCloseable { outJar << it }
} else {
ZipEntry newEntry = new ZipEntry(entry.name)
newEntry.setTime(entry.time)
outJar.putNextEntry(newEntry)
def element = inJar.getInputStream(entry).withCloseable { gson.fromJson(it.newReader("UTF8"), JsonElement.class) }
outJar.write(gson.toJson(element).getBytes(StandardCharsets.UTF_8))
}
}
}
}
// And replace the original jar again
Files.move(tempPath.toPath(), jarPath.toPath(), StandardCopyOption.REPLACE_EXISTING)
}
}
assemble.dependsOn compressJson
curseforge { curseforge {
apiKey = project.hasProperty('curseForgeApiKey') ? project.curseForgeApiKey : '' apiKey = project.hasProperty('curseForgeApiKey') ? project.curseForgeApiKey : ''
project { project {
id = '282001' id = '282001'
releaseType = 'release' releaseType = 'beta'
changelog = "Release notes can be found on the GitHub repository (https://github.com/SquidDev-CC/CC-Tweaked/releases/tag/v${project.version})." changelog = "Release notes can be found on the GitHub repository (https://github.com/SquidDev-CC/CC-Tweaked/releases/tag/v${project.version})."
} }
} }

View File

@@ -13,14 +13,12 @@ import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.FontRenderer; import net.minecraft.client.gui.FontRenderer;
import net.minecraft.client.gui.GuiNewChat; import net.minecraft.client.gui.GuiNewChat;
import net.minecraft.client.gui.GuiUtilRenderComponents;
import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.MathHelper;
import net.minecraft.util.text.ITextComponent; import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.text.TextFormatting; import net.minecraft.util.text.TextFormatting;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.util.List;
public class ClientTableFormatter implements TableFormatter public class ClientTableFormatter implements TableFormatter
{ {
@@ -64,13 +62,7 @@ public class ClientTableFormatter implements TableFormatter
@Override @Override
public void writeLine( int id, ITextComponent component ) public void writeLine( int id, ITextComponent component )
{ {
Minecraft mc = Minecraft.getMinecraft(); Minecraft.getMinecraft().ingameGUI.getChatGUI().printChatMessageWithOptionalDeletion( component, id );
GuiNewChat chat = mc.ingameGUI.getChatGUI();
// Trim the text if it goes over the allowed length
int maxWidth = MathHelper.floor( chat.getChatWidth() / chat.getChatScale() );
List<ITextComponent> list = GuiUtilRenderComponents.splitText( component, maxWidth, mc.fontRenderer, false, false );
if( !list.isEmpty() ) chat.printChatMessageWithOptionalDeletion( list.get( 0 ), id );
} }
@Override @Override

View File

@@ -0,0 +1,188 @@
package dan200.computercraft.client.render;
import com.google.common.collect.Sets;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.api.network.wired.IWiredElement;
import dan200.computercraft.shared.wired.WiredNetwork;
import dan200.computercraft.shared.wired.WiredNode;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.FontRenderer;
import net.minecraft.client.renderer.BufferBuilder;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.entity.RenderManager;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.init.Items;
import net.minecraft.item.ItemStack;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World;
import net.minecraftforge.client.event.RenderWorldLastEvent;
import net.minecraftforge.fml.common.FMLCommonHandler;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import org.lwjgl.opengl.GL11;
import java.awt.*;
import java.util.Collection;
import java.util.Set;
/**
* This is a helper to render a network when testing.
*/
public final class RenderOverlayNetwork
{
private int ticksInGame;
private IWiredElement element;
@SubscribeEvent
public void onWorldRenderLast( RenderWorldLastEvent event )
{
++ticksInGame;
RayTraceResult result = Minecraft.getMinecraft().objectMouseOver;
if( result != null && result.typeOfHit == RayTraceResult.Type.BLOCK )
{
World clientWorld = Minecraft.getMinecraft().world;
World world = FMLCommonHandler.instance().getMinecraftServerInstance().getWorld( clientWorld.provider.getDimension() );
IWiredElement newElement = ComputerCraft.getWiredElementAt( world, result.getBlockPos(), result.sideHit );
if( newElement != null ) element = newElement;
}
if( element == null ) return;
Minecraft minecraft = Minecraft.getMinecraft();
ItemStack stack = minecraft.player.getHeldItemMainhand();
ItemStack otherStack = minecraft.player.getHeldItemOffhand();
if( stack.getItem() != Items.STICK && otherStack.getItem() != Items.STICK ) return;
GlStateManager.pushMatrix();
RenderManager renderManager = minecraft.getRenderManager();
GlStateManager.translate( -renderManager.viewerPosX, -renderManager.viewerPosY, -renderManager.viewerPosZ );
GlStateManager.disableDepth();
GlStateManager.disableTexture2D();
GlStateManager.enableBlend();
GlStateManager.blendFunc( GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA );
Set<Pair<IWiredElement>> connections = Sets.newHashSet();
WiredNetwork network = (WiredNetwork) element.getNode().getNetwork();
for( WiredNode node : network.getNodes() )
{
for( WiredNode other : node.getNeighbours() )
{
connections.add( new Pair<>( node.getElement(), other.getElement() ) );
}
}
renderNetworkConnections( connections, new Color( Color.HSBtoRGB( ticksInGame % 200 / 200F, 0.6F, 1F ) ), 1f );
GlStateManager.enableDepth();
GlStateManager.enableTexture2D();
GlStateManager.disableBlend();
GlStateManager.popMatrix();
}
private void renderNetworkConnections( Collection<Pair<IWiredElement>> data, Color color, float thickness )
{
renderConnections( data, color, 1.0f, thickness );
renderConnections( data, color, 64.0f / 255.0f, thickness * 3 );
}
private void renderConnections( Collection<Pair<IWiredElement>> connections, Color color, float alpha, float thickness )
{
Tessellator tessellator = Tessellator.getInstance();
BufferBuilder renderer = tessellator.getBuffer();
GlStateManager.pushMatrix();
GlStateManager.scale( 1, 1, 1 );
GlStateManager.color( color.getRed() / 255.0f, color.getGreen() / 255.0f, color.getBlue() / 255.0f, alpha );
GL11.glLineWidth( thickness );
renderer.begin( GL11.GL_LINES, DefaultVertexFormats.POSITION );
for( Pair<IWiredElement> connection : connections )
{
Vec3d a = connection.x.getPosition(), b = connection.y.getPosition();
renderer.pos( a.x, a.y, a.z ).endVertex();
renderer.pos( b.x, b.y, b.z ).endVertex();
}
tessellator.draw();
GlStateManager.popMatrix();
}
private void renderLabel( double x, double y, double z, String label )
{
RenderManager renderManager = Minecraft.getMinecraft().getRenderManager();
FontRenderer fontrenderer = renderManager.getFontRenderer();
if( fontrenderer == null ) return;
GlStateManager.pushMatrix();
GlStateManager.disableLighting();
float scale = 0.02666667f;
GlStateManager.translate( x, y, z );
GlStateManager.rotate( -renderManager.playerViewY, 0, 1, 0 );
GlStateManager.rotate( renderManager.playerViewX, 1, 0, 0 );
GlStateManager.scale( -scale, -scale, scale );
// Render label background
Tessellator tessellator = Tessellator.getInstance();
BufferBuilder renderer = tessellator.getBuffer();
int width = fontrenderer.getStringWidth( label );
int xOffset = width / 2;
GlStateManager.disableTexture2D();
GlStateManager.color( 0, 0, 0, 65 / 225.0f );
renderer.begin( GL11.GL_QUADS, DefaultVertexFormats.POSITION );
renderer.pos( -xOffset - 1, -1, 0 ).endVertex();
renderer.pos( -xOffset - 1, 8, 0 ).endVertex();
renderer.pos( xOffset + 1, 8, 0 ).endVertex();
renderer.pos( xOffset + 1, -1, 0 ).endVertex();
tessellator.draw();
GlStateManager.enableTexture2D();
// Render label
fontrenderer.drawString( label, -width / 2, 0, 0xFFFFFFFF );
GlStateManager.enableLighting();
GlStateManager.popMatrix();
}
private static class Pair<T>
{
public final T x;
public final T y;
public Pair( T right, T y )
{
this.x = right;
this.y = y;
}
@Override
public boolean equals( Object o )
{
if( this == o ) return true;
if( o == null || getClass() != o.getClass() ) return false;
Pair<?> p = (Pair<?>) o;
return (x.equals( p.x ) && y.equals( p.y ))
|| (x.equals( p.y ) && y.equals( p.x ));
}
@Override
public int hashCode()
{
return x.hashCode() ^ y.hashCode();
}
}
}

View File

@@ -40,7 +40,7 @@ import java.util.List;
public class TileEntityTurtleRenderer extends TileEntitySpecialRenderer<TileTurtle> public class TileEntityTurtleRenderer extends TileEntitySpecialRenderer<TileTurtle>
{ {
private static final ModelResourceLocation NORMAL_TURTLE_MODEL = new ModelResourceLocation( "computercraft:turtle", "inventory" ); private static final ModelResourceLocation NORMAL_TURTLE_MODEL = new ModelResourceLocation( "computercraft:turtle", "inventory" );
private static final ModelResourceLocation ADVANCED_TURTLE_MODEL = new ModelResourceLocation( "computercraft:turtle_advanced", "inventory" ); private static final ModelResourceLocation ADVANCED_TURTLE_MODEL = new ModelResourceLocation( "computercraft:advanced_turtle", "inventory" );
private static final ModelResourceLocation COLOUR_TURTLE_MODEL = new ModelResourceLocation( "computercraft:turtle_white", "inventory" ); private static final ModelResourceLocation COLOUR_TURTLE_MODEL = new ModelResourceLocation( "computercraft:turtle_white", "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" );

View File

@@ -14,32 +14,20 @@ import dan200.computercraft.core.filesystem.FileSystem;
import dan200.computercraft.core.terminal.Terminal; import dan200.computercraft.core.terminal.Terminal;
import dan200.computercraft.core.tracking.TrackingField; import dan200.computercraft.core.tracking.TrackingField;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public interface IAPIEnvironment extends IComputerOwned public interface IAPIEnvironment extends IComputerOwned
{ {
String[] SIDE_NAMES = new String[] {
"bottom", "top", "back", "front", "right", "left",
};
int SIDE_COUNT = 6;
interface IPeripheralChangeListener interface IPeripheralChangeListener
{ {
void onPeripheralChanged( int side, @Nullable IPeripheral newPeripheral ); void onPeripheralChanged( int side, IPeripheral newPeripheral );
} }
@Nonnull
@Override @Override
Computer getComputer(); Computer getComputer();
int getComputerID(); int getComputerID();
@Nonnull
IComputerEnvironment getComputerEnvironment(); IComputerEnvironment getComputerEnvironment();
@Nonnull
Terminal getTerminal(); Terminal getTerminal();
FileSystem getFileSystem(); FileSystem getFileSystem();
@@ -62,18 +50,17 @@ public interface IAPIEnvironment extends IComputerOwned
int getBundledInput( int side ); int getBundledInput( int side );
void setPeripheralChangeListener( @Nullable IPeripheralChangeListener listener ); void setPeripheralChangeListener( IPeripheralChangeListener listener );
@Nullable
IPeripheral getPeripheral( int side ); IPeripheral getPeripheral( int side );
String getLabel(); String getLabel();
void setLabel( @Nullable String label ); void setLabel( String label );
void addTrackingChange( @Nonnull TrackingField field, long change ); void addTrackingChange( TrackingField field, long change );
default void addTrackingChange( @Nonnull TrackingField field ) default void addTrackingChange( TrackingField field )
{ {
addTrackingChange( field, 1 ); addTrackingChange( field, 1 );
} }

View File

@@ -278,13 +278,13 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange
}, null ); }, null );
// Queue a detachment event // Queue a detachment event
m_environment.queueEvent( "peripheral_detach", new Object[] { IAPIEnvironment.SIDE_NAMES[side] } ); m_environment.queueEvent( "peripheral_detach", new Object[] { Computer.s_sideNames[side] } );
} }
// Assign the new peripheral // Assign the new peripheral
if( newPeripheral != null ) if( newPeripheral != null )
{ {
m_peripherals[side] = new PeripheralWrapper( newPeripheral, IAPIEnvironment.SIDE_NAMES[side] ); m_peripherals[side] = new PeripheralWrapper( newPeripheral, Computer.s_sideNames[side] );
} }
else else
{ {
@@ -317,7 +317,7 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange
}, null ); }, null );
// Queue an attachment event // Queue an attachment event
m_environment.queueEvent( "peripheral", new Object[] { IAPIEnvironment.SIDE_NAMES[side] } ); m_environment.queueEvent( "peripheral", new Object[] { Computer.s_sideNames[side] } );
} }
} }
} }
@@ -483,9 +483,9 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange
private int parseSide( Object[] args ) throws LuaException private int parseSide( Object[] args ) throws LuaException
{ {
String side = getString( args, 0 ); String side = getString( args, 0 );
for( int n = 0; n < IAPIEnvironment.SIDE_NAMES.length; n++ ) for( int n = 0; n < Computer.s_sideNames.length; n++ )
{ {
if( side.equals( IAPIEnvironment.SIDE_NAMES[n] ) ) if( side.equals( Computer.s_sideNames[n] ) )
{ {
return n; return n;
} }

View File

@@ -9,6 +9,7 @@ package dan200.computercraft.core.apis;
import dan200.computercraft.api.lua.ILuaAPI; 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.core.computer.Computer;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import java.util.HashMap; import java.util.HashMap;
@@ -64,9 +65,9 @@ public class RedstoneAPI implements ILuaAPI
{ {
// getSides // getSides
Map<Object, Object> table = new HashMap<>(); Map<Object, Object> table = new HashMap<>();
for( int i = 0; i < IAPIEnvironment.SIDE_NAMES.length; i++ ) for( int i = 0; i < Computer.s_sideNames.length; i++ )
{ {
table.put( i + 1, IAPIEnvironment.SIDE_NAMES[i] ); table.put( i + 1, Computer.s_sideNames[i] );
} }
return new Object[] { table }; return new Object[] { table };
} }
@@ -155,9 +156,9 @@ public class RedstoneAPI implements ILuaAPI
private int parseSide( Object[] args ) throws LuaException private int parseSide( Object[] args ) throws LuaException
{ {
String side = getString( args, 0 ); String side = getString( args, 0 );
for( int n = 0; n < IAPIEnvironment.SIDE_NAMES.length; n++ ) for( int n = 0; n < Computer.s_sideNames.length; n++ )
{ {
if( side.equals( IAPIEnvironment.SIDE_NAMES[n] ) ) if( side.equals( Computer.s_sideNames[n] ) )
{ {
return n; return n;
} }

View File

@@ -11,7 +11,6 @@ import dan200.computercraft.api.lua.ILuaContext;
import dan200.computercraft.api.lua.LuaException; import dan200.computercraft.api.lua.LuaException;
import dan200.computercraft.core.computer.IComputerEnvironment; import dan200.computercraft.core.computer.IComputerEnvironment;
import dan200.computercraft.core.terminal.Terminal; import dan200.computercraft.core.terminal.Terminal;
import dan200.computercraft.shared.util.Colour;
import dan200.computercraft.shared.util.Palette; import dan200.computercraft.shared.util.Palette;
import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.ArrayUtils;
@@ -66,8 +65,6 @@ public class TermAPI implements ILuaAPI
"setPaletteColor", "setPaletteColor",
"getPaletteColour", "getPaletteColour",
"getPaletteColor", "getPaletteColor",
"nativePaletteColour",
"nativePaletteColor",
"getCursorBlink", "getCursorBlink",
}; };
} }
@@ -292,19 +289,6 @@ public class TermAPI implements ILuaAPI
return null; return null;
} }
case 23: case 23:
case 24:
{
// nativePaletteColour/nativePaletteColor
int colour = 15 - parseColour( args );
Colour c = Colour.fromInt( colour );
float[] rgb = c.getRGB();
Object[] rgbObj = new Object[rgb.length];
for( int i = 0; i < rgbObj.length; ++i ) rgbObj[i] = rgb[i];
return rgbObj;
}
case 25:
// getCursorBlink // getCursorBlink
return new Object[] { m_terminal.getCursorBlink() }; return new Object[] { m_terminal.getCursorBlink() };
default: default:

View File

@@ -169,42 +169,27 @@ public class BinaryReadableHandle extends HandleGeneric
{ {
ByteArrayOutputStream stream = new ByteArrayOutputStream(); ByteArrayOutputStream stream = new ByteArrayOutputStream();
boolean readAnything = false, readRc = false; boolean readAnything = false;
while( true ) while( true )
{ {
single.clear(); single.clear();
int read = m_reader.read( single ); int r = m_reader.read( single );
if( read <= 0 ) if( r == -1 ) break;
{
// Nothing else to read, and we saw no \n. Return the array. If we saw a \r, then add it
// back.
if( readRc ) stream.write( '\r' );
return readAnything ? new Object[] { stream.toByteArray() } : null;
}
readAnything = true; readAnything = true;
byte b = single.get( 0 );
byte chr = single.get( 0 ); if( b == '\n' )
if( chr == '\n' )
{ {
if( withTrailing ) if( withTrailing ) stream.write( b );
{ break;
if( readRc ) stream.write( '\r' );
stream.write( chr );
}
return new Object[] { stream.toByteArray() };
} }
else else
{ {
// We want to skip \r\n, but obviously need to include cases where \r is not followed by \n. stream.write( b );
// Note, this behaviour is non-standard compliant (strictly speaking we should have no
// special logic for \r), but we preserve compatibility with EncodedReadableHandle and
// previous behaviour of the io library.
if( readRc ) stream.write( '\r' );
readRc = chr == '\r';
if( !readRc ) stream.write( chr );
} }
} }
return readAnything ? new Object[] { stream.toByteArray() } : null;
} }
catch( IOException e ) catch( IOException e )
{ {

View File

@@ -83,11 +83,6 @@ public class WebsocketHandler extends SimpleChannelInboundHandler<Object>
CloseWebSocketFrame closeFrame = (CloseWebSocketFrame) frame; CloseWebSocketFrame closeFrame = (CloseWebSocketFrame) frame;
websocket.close( closeFrame.statusCode(), closeFrame.reasonText() ); websocket.close( closeFrame.statusCode(), closeFrame.reasonText() );
} }
else if( frame instanceof PingWebSocketFrame )
{
frame.content().retain();
ctx.channel().writeAndFlush( new PongWebSocketFrame( frame.content() ) );
}
} }
@Override @Override
@@ -113,13 +108,6 @@ public class WebsocketHandler extends SimpleChannelInboundHandler<Object>
message = "Could not connect"; message = "Could not connect";
} }
if( handshaker.isHandshakeComplete() ) websocket.failure( message );
{
websocket.close( -1, message );
}
else
{
websocket.failure( message );
}
} }
} }

View File

@@ -1,68 +0,0 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.core.computer;
import dan200.computercraft.api.lua.ILuaAPI;
import dan200.computercraft.api.lua.ILuaContext;
import dan200.computercraft.api.lua.LuaException;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/**
* A wrapper for {@link ILuaAPI}s which cleans up after a {@link ComputerSystem} when the computer is shutdown.
*/
public class ApiWrapper implements ILuaAPI
{
private final ILuaAPI delegate;
private final ComputerSystem system;
ApiWrapper( ILuaAPI delegate, ComputerSystem system )
{
this.delegate = delegate;
this.system = system;
}
@Override
public String[] getNames()
{
return delegate.getNames();
}
@Override
public void startup()
{
delegate.startup();
}
@Override
public void update()
{
delegate.update();
}
@Override
public void shutdown()
{
delegate.shutdown();
system.unmountAll();
}
@Nonnull
@Override
public String[] getMethodNames()
{
return delegate.getMethodNames();
}
@Nullable
@Override
public Object[] callMethod( @Nonnull ILuaContext context, int method, @Nonnull Object[] arguments ) throws LuaException, InterruptedException
{
return delegate.callMethod( context, method, arguments );
}
}

View File

@@ -8,10 +8,11 @@ package dan200.computercraft.core.computer;
import com.google.common.base.Objects; import com.google.common.base.Objects;
import dan200.computercraft.ComputerCraft; import dan200.computercraft.ComputerCraft;
import dan200.computercraft.api.filesystem.IFileSystem;
import dan200.computercraft.api.filesystem.IMount; import dan200.computercraft.api.filesystem.IMount;
import dan200.computercraft.api.filesystem.IWritableMount; import dan200.computercraft.api.filesystem.IWritableMount;
import dan200.computercraft.api.lua.ILuaAPI; import dan200.computercraft.api.lua.ILuaAPI;
import dan200.computercraft.api.lua.ILuaAPIFactory; import dan200.computercraft.api.lua.*;
import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.api.peripheral.IPeripheral;
import dan200.computercraft.core.apis.*; import dan200.computercraft.core.apis.*;
import dan200.computercraft.core.filesystem.FileSystem; import dan200.computercraft.core.filesystem.FileSystem;
@@ -19,7 +20,11 @@ import dan200.computercraft.core.filesystem.FileSystemException;
import dan200.computercraft.core.lua.CobaltLuaMachine; import dan200.computercraft.core.lua.CobaltLuaMachine;
import dan200.computercraft.core.lua.ILuaMachine; import dan200.computercraft.core.lua.ILuaMachine;
import dan200.computercraft.core.terminal.Terminal; import dan200.computercraft.core.terminal.Terminal;
import dan200.computercraft.core.tracking.Tracking;
import dan200.computercraft.core.tracking.TrackingField;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.util.ArrayList; import java.util.ArrayList;
@@ -27,6 +32,10 @@ import java.util.List;
public class Computer public class Computer
{ {
public static final String[] s_sideNames = new String[] {
"bottom", "top", "back", "front", "right", "left",
};
private enum State private enum State
{ {
Off, Off,
@@ -35,81 +44,319 @@ public class Computer
Stopping, Stopping,
} }
private static IMount s_romMount = null; private static class APIEnvironment implements IAPIEnvironment
private int m_id;
private String m_label = null;
private final IComputerEnvironment m_environment;
private int m_ticksSinceStart = -1;
private boolean m_startRequested = false;
private State m_state = State.Off;
private boolean m_blinking = false;
private ILuaMachine m_machine = null;
private final List<ILuaAPI> m_apis = new ArrayList<>();
private final Environment m_internalEnvironment = new Environment( this );
private final Terminal m_terminal;
private FileSystem m_fileSystem = null;
private IWritableMount m_rootMount = null;
private boolean m_externalOutputChanged;
public Computer( IComputerEnvironment environment, Terminal terminal, int id )
{ {
m_id = id; private Computer m_computer;
m_environment = environment; private IAPIEnvironment.IPeripheralChangeListener m_peripheralListener;
m_terminal = terminal;
// Ensure the computer thread is running as required. public APIEnvironment( Computer computer )
ComputerThread.start();
// Add all default APIs to the loaded list.
m_apis.add( new TermAPI( m_internalEnvironment ) );
m_apis.add( new RedstoneAPI( m_internalEnvironment ) );
m_apis.add( new FSAPI( m_internalEnvironment ) );
m_apis.add( new PeripheralAPI( m_internalEnvironment ) );
m_apis.add( new OSAPI( m_internalEnvironment ) );
if( ComputerCraft.http_enable ) m_apis.add( new HTTPAPI( m_internalEnvironment ) );
// Load in the API registered APIs.
for( ILuaAPIFactory factory : ApiFactories.getAll() )
{ {
ComputerSystem system = new ComputerSystem( m_internalEnvironment ); m_computer = computer;
ILuaAPI api = factory.create( system ); m_peripheralListener = null;
if( api != null ) m_apis.add( new ApiWrapper( api, system ) ); }
@Override
public Computer getComputer()
{
return m_computer;
}
@Override
public int getComputerID()
{
return m_computer.assignID();
}
@Override
public IComputerEnvironment getComputerEnvironment()
{
return m_computer.m_environment;
}
@Override
public Terminal getTerminal()
{
return m_computer.m_terminal;
}
@Override
public FileSystem getFileSystem()
{
return m_computer.m_fileSystem;
}
@Override
public void shutdown()
{
m_computer.shutdown();
}
@Override
public void reboot()
{
m_computer.reboot();
}
@Override
public void queueEvent( String event, Object[] args )
{
m_computer.queueEvent( event, args );
}
@Override
public void setOutput( int side, int output )
{
m_computer.setRedstoneOutput( side, output );
}
@Override
public int getOutput( int side )
{
return m_computer.getInternalRedstoneOutput( side );
}
@Override
public int getInput( int side )
{
return m_computer.getRedstoneInput( side );
}
@Override
public void setBundledOutput( int side, int output )
{
m_computer.setBundledRedstoneOutput( side, output );
}
@Override
public int getBundledOutput( int side )
{
return m_computer.getInternalBundledRedstoneOutput( side );
}
@Override
public int getBundledInput( int side )
{
return m_computer.getBundledRedstoneInput( side );
}
@Override
public IPeripheral getPeripheral( int side )
{
synchronized( m_computer.m_peripherals )
{
return m_computer.m_peripherals[side];
}
}
@Override
public void setPeripheralChangeListener( IPeripheralChangeListener listener )
{
synchronized( m_computer.m_peripherals )
{
m_peripheralListener = listener;
}
}
@Override
public String getLabel()
{
return m_computer.getLabel();
}
@Override
public void setLabel( String label )
{
m_computer.setLabel( label );
}
@Override
public void addTrackingChange( TrackingField field, long change )
{
Tracking.addValue( m_computer, field, change );
}
public void onPeripheralChanged( int side, IPeripheral peripheral )
{
synchronized( m_computer.m_peripherals )
{
if( m_peripheralListener != null )
{
m_peripheralListener.onPeripheralChanged( side, peripheral );
}
}
} }
} }
IComputerEnvironment getComputerEnvironment() private static class ComputerSystem extends ComputerAccess implements IComputerSystem
{ {
return m_environment; private final IAPIEnvironment m_environment;
private ComputerSystem( IAPIEnvironment m_environment )
{
super( m_environment );
this.m_environment = m_environment;
}
@Nonnull
@Override
public String getAttachmentName()
{
return "computer";
}
@Nullable
@Override
public IFileSystem getFileSystem()
{
FileSystem fs = m_environment.getFileSystem();
return fs == null ? null : fs.getMountWrapper();
}
@Nullable
@Override
public String getLabel()
{
return m_environment.getLabel();
}
} }
FileSystem getFileSystem() private static class APIWrapper implements ILuaAPI
{ {
return m_fileSystem; private final ILuaAPI delegate;
private final ComputerSystem system;
private APIWrapper( ILuaAPI delegate, ComputerSystem system )
{
this.delegate = delegate;
this.system = system;
}
@Override
public String[] getNames()
{
return delegate.getNames();
}
@Override
public void startup()
{
delegate.startup();
}
@Override
public void update()
{
delegate.update();
}
@Override
public void shutdown()
{
delegate.shutdown();
system.unmountAll();
}
@Nonnull
@Override
public String[] getMethodNames()
{
return delegate.getMethodNames();
}
@Nullable
@Override
public Object[] callMethod( @Nonnull ILuaContext context, int method, @Nonnull Object[] arguments ) throws LuaException, InterruptedException
{
return delegate.callMethod( context, method, arguments );
}
} }
Terminal getTerminal() private static IMount s_romMount = null;
{
return m_terminal;
}
public Environment getEnvironment() private int m_id;
private String m_label;
private final IComputerEnvironment m_environment;
private int m_ticksSinceStart;
private boolean m_startRequested;
private State m_state;
private boolean m_blinking;
private ILuaMachine m_machine;
private final List<ILuaAPI> m_apis;
private final APIEnvironment m_apiEnvironment;
private final Terminal m_terminal;
private FileSystem m_fileSystem;
private IWritableMount m_rootMount;
private final int[] m_internalOutput;
private final int[] m_internalBundledOutput;
private boolean m_internalOutputChanged;
private final int[] m_externalOutput;
private final int[] m_externalBundledOutput;
private boolean m_externalOutputChanged;
private final int[] m_input;
private final int[] m_bundledInput;
private boolean m_inputChanged;
private final IPeripheral[] m_peripherals;
public Computer( IComputerEnvironment environment, Terminal terminal, int id )
{ {
return m_internalEnvironment; ComputerThread.start();
m_id = id;
m_label = null;
m_environment = environment;
m_ticksSinceStart = -1;
m_startRequested = false;
m_state = State.Off;
m_blinking = false;
m_terminal = terminal;
m_fileSystem = null;
m_machine = null;
m_apis = new ArrayList<>();
m_apiEnvironment = new APIEnvironment( this );
m_internalOutput = new int[6];
m_internalBundledOutput = new int[6];
m_internalOutputChanged = true;
m_externalOutput = new int[6];
m_externalBundledOutput = new int[6];
m_externalOutputChanged = true;
m_input = new int[6];
m_bundledInput = new int[6];
m_inputChanged = false;
m_peripherals = new IPeripheral[6];
for( int i = 0; i < 6; i++ )
{
m_peripherals[i] = null;
}
m_rootMount = null;
createAPIs();
} }
public IAPIEnvironment getAPIEnvironment() public IAPIEnvironment getAPIEnvironment()
{ {
return m_internalEnvironment; return m_apiEnvironment;
} }
public void turnOn() public void turnOn()
{ {
if( m_state == State.Off ) m_startRequested = true; if( m_state == State.Off )
{
m_startRequested = true;
}
} }
public void shutdown() public void shutdown()
@@ -150,7 +397,10 @@ public class Computer
public void unload() public void unload()
{ {
stopComputer( false ); synchronized( this )
{
stopComputer( false );
}
} }
public int getID() public int getID()
@@ -186,7 +436,7 @@ public class Computer
} }
} }
public void advance() public void advance( double _dt )
{ {
synchronized( this ) synchronized( this )
{ {
@@ -203,27 +453,67 @@ public class Computer
if( m_state == State.Running ) if( m_state == State.Running )
{ {
// Update the environment's internal state. // Fire the redstone event if our redstone input has changed
m_internalEnvironment.update(); synchronized( m_input )
{
if( m_inputChanged )
{
queueEvent( "redstone", null );
m_inputChanged = false;
}
}
// Advance our APIs // Advance our APIs
for( ILuaAPI api : m_apis ) api.update(); synchronized( m_apis )
{
for( ILuaAPI api : m_apis )
{
api.update();
}
}
} }
} }
// Prepare to propagate the environment's output to the world. // Set outputchanged if the internal redstone has changed
if( m_internalEnvironment.updateOutput() ) m_externalOutputChanged = true; synchronized( m_internalOutput )
// Set output changed if the terminal has changed from blinking to not
boolean blinking =
m_terminal.getCursorBlink() &&
m_terminal.getCursorX() >= 0 && m_terminal.getCursorX() < m_terminal.getWidth() &&
m_terminal.getCursorY() >= 0 && m_terminal.getCursorY() < m_terminal.getHeight();
if( blinking != m_blinking )
{ {
m_blinking = blinking; if( m_internalOutputChanged )
m_externalOutputChanged = true; {
boolean changed = false;
for( int i = 0; i < 6; i++ )
{
if( m_externalOutput[i] != m_internalOutput[i] )
{
m_externalOutput[i] = m_internalOutput[i];
changed = true;
}
if( m_externalBundledOutput[i] != m_internalBundledOutput[i] )
{
m_externalBundledOutput[i] = m_internalBundledOutput[i];
changed = true;
}
}
m_internalOutputChanged = false;
if( changed )
{
m_externalOutputChanged = true;
}
}
}
// Set outputchanged if the terminal has changed from blinking to not
synchronized( m_terminal )
{
boolean blinking =
m_terminal.getCursorBlink() &&
m_terminal.getCursorX() >= 0 && m_terminal.getCursorX() < m_terminal.getWidth() &&
m_terminal.getCursorY() >= 0 && m_terminal.getCursorY() < m_terminal.getHeight();
if( blinking != m_blinking )
{
m_blinking = blinking;
m_externalOutputChanged = true;
}
} }
} }
@@ -239,7 +529,10 @@ public class Computer
public boolean isBlinking() public boolean isBlinking()
{ {
return isOn() && m_blinking; synchronized( m_terminal )
{
return isOn() && m_blinking;
}
} }
public IWritableMount getRootMount() public IWritableMount getRootMount()
@@ -260,7 +553,10 @@ public class Computer
try try
{ {
m_fileSystem = new FileSystem( "hdd", getRootMount() ); m_fileSystem = new FileSystem( "hdd", getRootMount() );
if( s_romMount == null ) s_romMount = m_environment.createResourceMount( "computercraft", "lua/rom" ); if( s_romMount == null )
{
s_romMount = m_environment.createResourceMount( "computercraft", "lua/rom" );
}
if( s_romMount != null ) if( s_romMount != null )
{ {
m_fileSystem.mount( "rom", "rom", s_romMount ); m_fileSystem.mount( "rom", "rom", s_romMount );
@@ -275,6 +571,104 @@ public class Computer
} }
} }
// Redstone
public int getRedstoneOutput( int side )
{
synchronized( m_internalOutput )
{
return isOn() ? m_externalOutput[side] : 0;
}
}
private int getInternalRedstoneOutput( int side )
{
synchronized( m_internalOutput )
{
return isOn() ? m_internalOutput[side] : 0;
}
}
private void setRedstoneOutput( int side, int level )
{
synchronized( m_internalOutput )
{
if( m_internalOutput[side] != level )
{
m_internalOutput[side] = level;
m_internalOutputChanged = true;
}
}
}
public void setRedstoneInput( int side, int level )
{
synchronized( m_input )
{
if( m_input[side] != level )
{
m_input[side] = level;
m_inputChanged = true;
}
}
}
private int getRedstoneInput( int side )
{
synchronized( m_input )
{
return m_input[side];
}
}
public int getBundledRedstoneOutput( int side )
{
synchronized( m_internalOutput )
{
return isOn() ? m_externalBundledOutput[side] : 0;
}
}
private int getInternalBundledRedstoneOutput( int side )
{
synchronized( m_internalOutput )
{
return isOn() ? m_internalBundledOutput[side] : 0;
}
}
private void setBundledRedstoneOutput( int side, int combination )
{
synchronized( m_internalOutput )
{
if( m_internalBundledOutput[side] != combination )
{
m_internalBundledOutput[side] = combination;
m_internalOutputChanged = true;
}
}
}
public void setBundledRedstoneInput( int side, int combination )
{
synchronized( m_input )
{
if( m_bundledInput[side] != combination )
{
m_bundledInput[side] = combination;
m_inputChanged = true;
}
}
}
private int getBundledRedstoneInput( int side )
{
synchronized( m_input )
{
return m_bundledInput[side];
}
}
// Peripherals // Peripherals
public void addAPI( ILuaAPI api ) public void addAPI( ILuaAPI api )
@@ -282,8 +676,57 @@ public class Computer
m_apis.add( api ); m_apis.add( api );
} }
@SuppressWarnings( "deprecation" )
public void addAPI( dan200.computercraft.core.apis.ILuaAPI api )
{
addAPI( (ILuaAPI) api );
}
public void setPeripheral( int side, IPeripheral peripheral )
{
synchronized( m_peripherals )
{
IPeripheral existing = m_peripherals[side];
if( (existing == null && peripheral != null) ||
(existing != null && peripheral == null) ||
(existing != null && !existing.equals( peripheral )) )
{
m_peripherals[side] = peripheral;
m_apiEnvironment.onPeripheralChanged( side, peripheral );
}
}
}
public IPeripheral getPeripheral( int side )
{
synchronized( m_peripherals )
{
return m_peripherals[side];
}
}
// Lua // Lua
private void createAPIs()
{
m_apis.add( new TermAPI( m_apiEnvironment ) );
m_apis.add( new RedstoneAPI( m_apiEnvironment ) );
m_apis.add( new FSAPI( m_apiEnvironment ) );
m_apis.add( new PeripheralAPI( m_apiEnvironment ) );
m_apis.add( new OSAPI( m_apiEnvironment ) );
if( ComputerCraft.http_enable )
{
m_apis.add( new HTTPAPI( m_apiEnvironment ) );
}
for( ILuaAPIFactory factory : ApiFactories.getAll() )
{
ComputerSystem system = new ComputerSystem( m_apiEnvironment );
ILuaAPI api = factory.create( system );
if( api != null ) m_apis.add( api );
}
}
private void initLua() private void initLua()
{ {
// Create the lua machine // Create the lua machine
@@ -381,7 +824,10 @@ public class Computer
} }
// Init terminal // Init terminal
m_terminal.reset(); synchronized( m_terminal )
{
m_terminal.reset();
}
// Init filesystem // Init filesystem
if( !initFileSystem() ) if( !initFileSystem() )
@@ -474,7 +920,10 @@ public class Computer
if( m_machine != null ) if( m_machine != null )
{ {
m_terminal.reset(); synchronized( m_terminal )
{
m_terminal.reset();
}
synchronized( m_machine ) synchronized( m_machine )
{ {
@@ -484,7 +933,15 @@ public class Computer
} }
// Reset redstone output // Reset redstone output
m_internalEnvironment.resetOutput(); synchronized( m_internalOutput )
{
for( int i = 0; i < 6; i++ )
{
m_internalOutput[i] = 0;
m_internalBundledOutput[i] = 0;
}
m_internalOutputChanged = true;
}
m_state = State.Off; m_state = State.Off;
m_externalOutputChanged = true; m_externalOutputChanged = true;
@@ -545,31 +1002,4 @@ public class Computer
ComputerThread.queueTask( task, computer ); ComputerThread.queueTask( task, computer );
} }
@Deprecated
public IPeripheral getPeripheral( int side )
{
return m_internalEnvironment.getPeripheral( side );
}
@Deprecated
public void setPeripheral( int side, IPeripheral peripheral )
{
m_internalEnvironment.setPeripheral( side, peripheral );
}
@Deprecated
public void addAPI( dan200.computercraft.core.apis.ILuaAPI api )
{
addAPI( (ILuaAPI) api );
}
@Deprecated
@SuppressWarnings( "unused" )
public void advance( double dt )
{
advance();
}
public static final String[] s_sideNames = IAPIEnvironment.SIDE_NAMES;
} }

View File

@@ -1,58 +0,0 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.core.computer;
import dan200.computercraft.api.filesystem.IFileSystem;
import dan200.computercraft.api.lua.IComputerSystem;
import dan200.computercraft.api.lua.ILuaAPIFactory;
import dan200.computercraft.api.peripheral.IComputerAccess;
import dan200.computercraft.core.apis.ComputerAccess;
import dan200.computercraft.core.apis.IAPIEnvironment;
import dan200.computercraft.core.filesystem.FileSystem;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/**
* Implementation of {@link IComputerAccess}/{@link IComputerSystem} for external APIs.
*
* @see dan200.computercraft.api.ComputerCraftAPI#registerAPIFactory(ILuaAPIFactory)
* @see ILuaAPIFactory
* @see ApiWrapper
*/
public class ComputerSystem extends ComputerAccess implements IComputerSystem
{
private final IAPIEnvironment m_environment;
ComputerSystem( IAPIEnvironment m_environment )
{
super( m_environment );
this.m_environment = m_environment;
}
@Nonnull
@Override
public String getAttachmentName()
{
return "computer";
}
@Nullable
@Override
public IFileSystem getFileSystem()
{
FileSystem fs = m_environment.getFileSystem();
return fs == null ? null : fs.getMountWrapper();
}
@Nullable
@Override
public String getLabel()
{
return m_environment.getLabel();
}
}

View File

@@ -1,306 +0,0 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.core.computer;
import dan200.computercraft.api.peripheral.IPeripheral;
import dan200.computercraft.core.apis.IAPIEnvironment;
import dan200.computercraft.core.filesystem.FileSystem;
import dan200.computercraft.core.terminal.Terminal;
import dan200.computercraft.core.tracking.Tracking;
import dan200.computercraft.core.tracking.TrackingField;
import javax.annotation.Nonnull;
import java.util.Arrays;
/**
* Represents the "environment" that a {@link Computer} exists in.
*
* This handles storing and updating of peripherals and redstone.
*
* <h2>Redstone</h2>
* We holds three kinds of arrays for redstone, in normal and bundled versions:
* <ul>
* <li>{@link #internalOutput} is the redstone output which the computer has currently set. This is read on both
* threads, and written on the computer thread.</li>
* <li>{@link #externalOutput} is the redstone output currently propagated to the world. This is only read and written
* on the main thread.</li>
* <li>{@link #input} is the redstone input from external sources. This is read on both threads, and written on the main
* thread.</li>
* </ul>
*
* <h2>Peripheral</h2>
* We also keep track of peripherals. These are read on both threads, and only written on the main thread.
*/
public final class Environment implements IAPIEnvironment
{
private final Computer computer;
private boolean internalOutputChanged = false;
private final int[] internalOutput = new int[SIDE_COUNT];
private final int[] internalBundledOutput = new int[SIDE_COUNT];
private final int[] externalOutput = new int[SIDE_COUNT];
private final int[] externalBundledOutput = new int[SIDE_COUNT];
private boolean inputChanged = false;
private final int[] input = new int[SIDE_COUNT];
private final int[] bundledInput = new int[SIDE_COUNT];
private final IPeripheral[] peripherals = new IPeripheral[SIDE_COUNT];
private IPeripheralChangeListener peripheralListener = null;
Environment( Computer computer )
{
this.computer = computer;
}
@Nonnull
@Override
public Computer getComputer()
{
return computer;
}
@Override
public int getComputerID()
{
return computer.assignID();
}
@Nonnull
@Override
public IComputerEnvironment getComputerEnvironment()
{
return computer.getComputerEnvironment();
}
@Nonnull
@Override
public Terminal getTerminal()
{
return computer.getTerminal();
}
@Override
public FileSystem getFileSystem()
{
return computer.getFileSystem();
}
@Override
public void shutdown()
{
computer.shutdown();
}
@Override
public void reboot()
{
computer.reboot();
}
@Override
public void queueEvent( String event, Object[] args )
{
computer.queueEvent( event, args );
}
@Override
public int getInput( int side )
{
return input[side];
}
@Override
public int getBundledInput( int side )
{
return bundledInput[side];
}
@Override
public void setOutput( int side, int output )
{
synchronized( internalOutput )
{
if( internalOutput[side] != output )
{
internalOutput[side] = output;
internalOutputChanged = true;
}
}
}
@Override
public int getOutput( int side )
{
synchronized( internalOutput )
{
return computer.isOn() ? internalOutput[side] : 0;
}
}
@Override
public void setBundledOutput( int side, int output )
{
synchronized( internalOutput )
{
if( internalBundledOutput[side] != output )
{
internalBundledOutput[side] = output;
internalOutputChanged = true;
}
}
}
@Override
public int getBundledOutput( int side )
{
synchronized( internalOutput )
{
return computer.isOn() ? internalBundledOutput[side] : 0;
}
}
public int getExternalRedstoneOutput( int side )
{
return computer.isOn() ? externalOutput[side] : 0;
}
public int getExternalBundledRedstoneOutput( int side )
{
return computer.isOn() ? externalBundledOutput[side] : 0;
}
public void setRedstoneInput( int side, int level )
{
if( input[side] != level )
{
input[side] = level;
inputChanged = true;
}
}
public void setBundledRedstoneInput( int side, int combination )
{
if( bundledInput[side] != combination )
{
bundledInput[side] = combination;
inputChanged = true;
}
}
/**
* Called on the main thread to update the internal state of the computer.
*
* This just queues a {@code redstone} event if the input has changed.
*/
void update()
{
if( inputChanged )
{
inputChanged = false;
queueEvent( "redstone", null );
}
}
/**
* Called on the main thread to propagate the internal outputs to the external ones.
*
* @return If the outputs have changed.
*/
boolean updateOutput()
{
// Set outputchanged if the internal redstone has changed
synchronized( internalOutput )
{
if( !internalOutputChanged ) return false;
boolean changed = false;
for( int i = 0; i < SIDE_COUNT; i++ )
{
if( externalOutput[i] != internalOutput[i] )
{
externalOutput[i] = internalOutput[i];
changed = true;
}
if( externalBundledOutput[i] != internalBundledOutput[i] )
{
externalBundledOutput[i] = internalBundledOutput[i];
changed = true;
}
}
internalOutputChanged = false;
return changed;
}
}
void resetOutput()
{
// Reset redstone output
synchronized( internalOutput )
{
Arrays.fill( internalOutput, 0 );
Arrays.fill( internalBundledOutput, 0 );
internalOutputChanged = true;
}
}
@Override
public IPeripheral getPeripheral( int side )
{
synchronized( peripherals )
{
return peripherals[side];
}
}
public void setPeripheral( int side, IPeripheral peripheral )
{
synchronized( peripherals )
{
IPeripheral existing = peripherals[side];
if( (existing == null && peripheral != null) ||
(existing != null && peripheral == null) ||
(existing != null && !existing.equals( peripheral )) )
{
peripherals[side] = peripheral;
if( peripheralListener != null ) peripheralListener.onPeripheralChanged( side, peripheral );
}
}
}
@Override
public void setPeripheralChangeListener( IPeripheralChangeListener listener )
{
synchronized( peripherals )
{
peripheralListener = listener;
}
}
@Override
public String getLabel()
{
return computer.getLabel();
}
@Override
public void setLabel( String label )
{
computer.setLabel( label );
}
@Override
public void addTrackingChange( @Nonnull TrackingField field, long change )
{
Tracking.addValue( computer, field, change );
}
}

View File

@@ -9,7 +9,6 @@ package dan200.computercraft.shared.command;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
import dan200.computercraft.ComputerCraft; import dan200.computercraft.ComputerCraft;
import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.api.peripheral.IPeripheral;
import dan200.computercraft.core.apis.IAPIEnvironment;
import dan200.computercraft.core.computer.Computer; import dan200.computercraft.core.computer.Computer;
import dan200.computercraft.core.tracking.ComputerTracker; import dan200.computercraft.core.tracking.ComputerTracker;
import dan200.computercraft.core.tracking.Tracking; import dan200.computercraft.core.tracking.Tracking;
@@ -127,7 +126,7 @@ public final class CommandComputerCraft extends CommandDelegate
IPeripheral peripheral = computer.getPeripheral( i ); IPeripheral peripheral = computer.getPeripheral( i );
if( peripheral != null ) if( peripheral != null )
{ {
table.row( header( "Peripheral " + IAPIEnvironment.SIDE_NAMES[i] ), text( peripheral.getType() ) ); table.row( header( "Peripheral " + Computer.s_sideNames[i] ), text( peripheral.getType() ) );
} }
} }

View File

@@ -101,11 +101,6 @@ public class TableBuilder
return additional; return additional;
} }
public void setAdditional( int additional )
{
this.additional = additional;
}
/** /**
* Trim this table to a given height * Trim this table to a given height
* *
@@ -115,8 +110,8 @@ public class TableBuilder
{ {
if( rows.size() > height ) if( rows.size() > height )
{ {
additional += rows.size() - height - 1; additional += rows.size() - height;
rows.subList( height - 1, rows.size() ).clear(); rows.subList( height, rows.size() ).clear();
} }
} }

View File

@@ -74,6 +74,8 @@ public interface TableFormatter
int totalWidth = (columns - 1) * getWidth( SEPARATOR ); int totalWidth = (columns - 1) * getWidth( SEPARATOR );
for( int x : maxWidths ) totalWidth += x; for( int x : maxWidths ) totalWidth += x;
// TODO: Limit the widths of some entries if totalWidth > maxWidth
if( headers != null ) if( headers != null )
{ {
TextComponentString line = new TextComponentString( "" ); TextComponentString line = new TextComponentString( "" );

View File

@@ -51,11 +51,15 @@ public abstract class BlockGeneric extends Block implements ITileEntityProvider
@Override @Override
@Deprecated @Deprecated
@SuppressWarnings( "deprecation" )
public final void neighborChanged( IBlockState state, World world, BlockPos pos, Block block, BlockPos neighbour ) public final void neighborChanged( IBlockState state, World world, BlockPos pos, Block block, BlockPos neighbour )
{ {
TileEntity tile = world.getTileEntity( pos ); TileEntity tile = world.getTileEntity( pos );
if( tile instanceof TileGeneric ) ((TileGeneric) tile).onNeighbourChange( neighbour ); if( tile instanceof TileGeneric )
{
TileGeneric generic = (TileGeneric) tile;
generic.onNeighbourChange();
generic.onNeighbourChange( neighbour );
}
} }
@Override @Override

View File

@@ -63,10 +63,8 @@ public abstract class TileGeneric extends TileEntity
{ {
} }
@SuppressWarnings( "deprecation" )
public void onNeighbourChange( @Nonnull BlockPos neighbour ) public void onNeighbourChange( @Nonnull BlockPos neighbour )
{ {
onNeighbourChange();
} }
public void onNeighbourTileEntityChange( @Nonnull BlockPos neighbour ) public void onNeighbourTileEntityChange( @Nonnull BlockPos neighbour )

View File

@@ -105,7 +105,7 @@ public class ServerComputer extends ServerTerminal implements IComputer, IComput
public void update() public void update()
{ {
super.update(); super.update();
m_computer.advance(); m_computer.advance( 0.05 );
m_changedLastFrame = m_computer.pollAndResetChanged() || m_changed; m_changedLastFrame = m_computer.pollAndResetChanged() || m_changed;
m_changed = false; m_changed = false;
@@ -283,22 +283,22 @@ public class ServerComputer extends ServerTerminal implements IComputer, IComput
public int getRedstoneOutput( int side ) public int getRedstoneOutput( int side )
{ {
return m_computer.getEnvironment().getExternalRedstoneOutput( side ); return m_computer.getRedstoneOutput( side );
} }
public void setRedstoneInput( int side, int level ) public void setRedstoneInput( int side, int level )
{ {
m_computer.getEnvironment().setRedstoneInput( side, level ); m_computer.setRedstoneInput( side, level );
} }
public int getBundledRedstoneOutput( int side ) public int getBundledRedstoneOutput( int side )
{ {
return m_computer.getEnvironment().getExternalBundledRedstoneOutput( side ); return m_computer.getBundledRedstoneOutput( side );
} }
public void setBundledRedstoneInput( int side, int combination ) public void setBundledRedstoneInput( int side, int combination )
{ {
m_computer.getEnvironment().setBundledRedstoneInput( side, combination ); m_computer.setBundledRedstoneInput( side, combination );
} }
public void addAPI( ILuaAPI api ) public void addAPI( ILuaAPI api )
@@ -306,7 +306,7 @@ public class ServerComputer extends ServerTerminal implements IComputer, IComput
m_computer.addAPI( api ); m_computer.addAPI( api );
} }
@Deprecated @SuppressWarnings( "deprecation" )
public void addAPI( dan200.computercraft.core.apis.ILuaAPI api ) public void addAPI( dan200.computercraft.core.apis.ILuaAPI api )
{ {
m_computer.addAPI( api ); m_computer.addAPI( api );
@@ -314,12 +314,12 @@ public class ServerComputer extends ServerTerminal implements IComputer, IComput
public void setPeripheral( int side, IPeripheral peripheral ) public void setPeripheral( int side, IPeripheral peripheral )
{ {
m_computer.getEnvironment().setPeripheral( side, peripheral ); m_computer.setPeripheral( side, peripheral );
} }
public IPeripheral getPeripheral( int side ) public IPeripheral getPeripheral( int side )
{ {
return m_computer.getEnvironment().getPeripheral( side ); return m_computer.getPeripheral( side );
} }
public void setLabel( String label ) public void setLabel( String label )

View File

@@ -43,10 +43,7 @@ final class BundledCapabilityProvider implements ICapabilityProvider
if( capability == CAPABILITY_RECEIVER ) if( capability == CAPABILITY_RECEIVER )
{ {
IBundledReceiver receiver = this.receiver; IBundledReceiver receiver = this.receiver;
if( receiver == null ) if( receiver == null ) receiver = this.receiver = tile::onNeighbourChange;
{
receiver = this.receiver = () -> tile.onNeighbourChange( tile.getPos().offset( side ) );
}
return CAPABILITY_RECEIVER.cast( receiver ); return CAPABILITY_RECEIVER.cast( receiver );
} }

View File

@@ -48,8 +48,6 @@ public class ChatTableClientMessage implements NetworkMessage
{ {
for( ITextComponent column : row ) buf.writeTextComponent( column ); for( ITextComponent column : row ) buf.writeTextComponent( column );
} }
buf.writeVarInt( table.getAdditional() );
} }
@Override @Override
@@ -76,8 +74,6 @@ public class ChatTableClientMessage implements NetworkMessage
for( int j = 0; j < columns; j++ ) row[j] = NBTUtil.readTextComponent( buf ); for( int j = 0; j < columns; j++ ) row[j] = NBTUtil.readTextComponent( buf );
table.row( row ); table.row( row );
} }
table.setAdditional( buf.readVarInt() );
this.table = table; this.table = table;
} }

View File

@@ -25,7 +25,6 @@ public abstract class TileWirelessModemBase extends TileGeneric implements IPeri
protected TileWirelessModemBase( boolean advanced ) protected TileWirelessModemBase( boolean advanced )
{ {
this.advanced = advanced; this.advanced = advanced;
this.modem = new Peripheral( this ); // Needs to be initialised after advanced
} }
private static class Peripheral extends WirelessModemPeripheral private static class Peripheral extends WirelessModemPeripheral
@@ -63,7 +62,7 @@ public abstract class TileWirelessModemBase extends TileGeneric implements IPeri
private final boolean advanced; private final boolean advanced;
private boolean hasModemDirection = false; private boolean hasModemDirection = false;
private EnumFacing modemDirection = EnumFacing.DOWN; private EnumFacing modemDirection = EnumFacing.DOWN;
private final ModemPeripheral modem; private final ModemPeripheral modem = new Peripheral( this );
private boolean destroyed = false; private boolean destroyed = false;
private boolean on = false; private boolean on = false;

View File

@@ -13,6 +13,7 @@ import dan200.computercraft.shared.media.items.ItemPrintout;
import dan200.computercraft.shared.peripheral.PeripheralType; import dan200.computercraft.shared.peripheral.PeripheralType;
import dan200.computercraft.shared.peripheral.common.TilePeripheralBase; import dan200.computercraft.shared.peripheral.common.TilePeripheralBase;
import dan200.computercraft.shared.util.DefaultSidedInventory; import dan200.computercraft.shared.util.DefaultSidedInventory;
import dan200.computercraft.shared.util.InventoryUtil;
import dan200.computercraft.shared.util.WorldUtil; import dan200.computercraft.shared.util.WorldUtil;
import net.minecraft.block.state.IBlockState; import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayer;
@@ -261,23 +262,6 @@ public class TilePrinter extends TilePeripheralBase implements DefaultSidedInven
} }
} }
@Override
public boolean isItemValidForSlot( int slot, @Nonnull ItemStack stack )
{
if( slot == 0 )
{
return isInk( stack );
}
else if( slot >= topSlots[0] && slot <= topSlots[topSlots.length - 1] )
{
return isPaper( stack );
}
else
{
return false;
}
}
@Override @Override
public boolean hasCustomName() public boolean hasCustomName()
{ {
@@ -409,15 +393,15 @@ public class TilePrinter extends TilePeripheralBase implements DefaultSidedInven
} }
} }
private static boolean isInk( @Nonnull ItemStack stack ) private boolean isInk( @Nonnull ItemStack stack )
{ {
return stack.getItem() == Items.DYE; return (stack.getItem() == Items.DYE);
} }
private static boolean isPaper( @Nonnull ItemStack stack ) private boolean isPaper( @Nonnull ItemStack stack )
{ {
Item item = stack.getItem(); Item item = stack.getItem();
return item == Items.PAPER || (item instanceof ItemPrintout && ItemPrintout.getType( stack ) == ItemPrintout.Type.Single); return (item == Items.PAPER || (item instanceof ItemPrintout && ItemPrintout.getType( stack ) == ItemPrintout.Type.Single));
} }
private boolean canInputPage() private boolean canInputPage()
@@ -509,14 +493,11 @@ public class TilePrinter extends TilePeripheralBase implements DefaultSidedInven
ItemStack stack = ItemPrintout.createSingleFromTitleAndText( m_pageTitle, lines, colours ); ItemStack stack = ItemPrintout.createSingleFromTitleAndText( m_pageTitle, lines, colours );
synchronized( m_inventory ) synchronized( m_inventory )
{ {
for( int slot : bottomSlots ) ItemStack remainder = InventoryUtil.storeItems( stack, m_itemHandlerAll, 7, 6, 7 );
if( remainder.isEmpty() )
{ {
if( m_inventory.get( slot ).isEmpty() ) m_printing = false;
{ return true;
m_inventory.set( slot, stack );
m_printing = false;
return true;
}
} }
} }
return false; return false;

View File

@@ -80,7 +80,7 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default
m_inventory = NonNullList.withSize( INVENTORY_SIZE, ItemStack.EMPTY ); m_inventory = NonNullList.withSize( INVENTORY_SIZE, ItemStack.EMPTY );
m_previousInventory = NonNullList.withSize( INVENTORY_SIZE, ItemStack.EMPTY ); m_previousInventory = NonNullList.withSize( INVENTORY_SIZE, ItemStack.EMPTY );
m_inventoryChanged = false; m_inventoryChanged = false;
m_brain = new TurtleBrain( this ); m_brain = createBrain();
m_moveState = MoveState.NOT_MOVED; m_moveState = MoveState.NOT_MOVED;
m_family = family; m_family = family;
} }
@@ -90,12 +90,21 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default
return m_moveState == MoveState.MOVED; return m_moveState == MoveState.MOVED;
} }
@Override protected TurtleBrain createBrain()
protected ServerComputer createComputer( int instanceID, int id ) {
return new TurtleBrain( this );
}
protected final ServerComputer createComputer( int instanceID, int id, int termWidth, int termHeight )
{ {
ServerComputer computer = new ServerComputer( ServerComputer computer = new ServerComputer(
getWorld(), id, m_label, instanceID, getFamily(), getWorld(),
ComputerCraft.terminalWidth_turtle, ComputerCraft.terminalHeight_turtle id,
m_label,
instanceID,
getFamily(),
termWidth,
termHeight
); );
computer.setPosition( getPos() ); computer.setPosition( getPos() );
computer.addAPI( new TurtleAPI( computer.getAPIEnvironment(), getAccess() ) ); computer.addAPI( new TurtleAPI( computer.getAPIEnvironment(), getAccess() ) );
@@ -103,6 +112,12 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default
return computer; return computer;
} }
@Override
protected ServerComputer createComputer( int instanceID, int id )
{
return createComputer( instanceID, id, ComputerCraft.terminalWidth_turtle, ComputerCraft.terminalHeight_turtle );
}
@Override @Override
public ComputerProxy createProxy() public ComputerProxy createProxy()
{ {

View File

@@ -54,7 +54,7 @@ public class TurtleBrain implements ITurtleAccess
private int m_commandsIssued = 0; private int m_commandsIssued = 0;
private Map<TurtleSide, ITurtleUpgrade> m_upgrades = new EnumMap<>( TurtleSide.class ); private Map<TurtleSide, ITurtleUpgrade> m_upgrades = new EnumMap<>( TurtleSide.class );
private Map<TurtleSide, IPeripheral> peripherals = new EnumMap<>( TurtleSide.class ); private Map<TurtleSide, IPeripheral> m_peripherals = new EnumMap<>( TurtleSide.class );
private Map<TurtleSide, NBTTagCompound> m_upgradeNBTData = new EnumMap<>( TurtleSide.class ); private Map<TurtleSide, NBTTagCompound> m_upgradeNBTData = new EnumMap<>( TurtleSide.class );
private int m_selectedSlot = 0; private int m_selectedSlot = 0;
@@ -824,9 +824,9 @@ public class TurtleBrain implements ITurtleAccess
@Override @Override
public IPeripheral getPeripheral( @Nonnull TurtleSide side ) public IPeripheral getPeripheral( @Nonnull TurtleSide side )
{ {
if( peripherals.containsKey( side ) ) if( m_peripherals.containsKey( side ) )
{ {
return peripherals.get( side ); return m_peripherals.get( side );
} }
return null; return null;
} }
@@ -924,9 +924,13 @@ public class TurtleBrain implements ITurtleAccess
} }
} }
private void updatePeripherals( ServerComputer serverComputer ) public void updatePeripherals( ServerComputer serverComputer )
{ {
if( serverComputer == null ) return; if( serverComputer == null )
{
// Nothing to do
return;
}
// Update peripherals // Update peripherals
for( TurtleSide side : TurtleSide.values() ) for( TurtleSide side : TurtleSide.values() )
@@ -938,20 +942,26 @@ public class TurtleBrain implements ITurtleAccess
peripheral = upgrade.createPeripheral( this, side ); peripheral = upgrade.createPeripheral( this, side );
} }
IPeripheral existing = peripherals.get( side ); int dir = toDirection( side );
if( existing == peripheral || (existing != null && peripheral != null && existing.equals( peripheral )) ) if( peripheral != null )
{ {
// If the peripheral is the same, just use that. if( !m_peripherals.containsKey( side ) )
peripheral = existing; {
serverComputer.setPeripheral( dir, peripheral );
m_peripherals.put( side, peripheral );
}
else if( !m_peripherals.get( side ).equals( peripheral ) )
{
serverComputer.setPeripheral( dir, peripheral );
m_peripherals.remove( side );
m_peripherals.put( side, peripheral );
}
} }
else else if( m_peripherals.containsKey( side ) )
{ {
// Otherwise update our map serverComputer.setPeripheral( dir, null );
peripherals.put( side, peripheral ); m_peripherals.remove( side );
} }
// Always update the computer: it may not be the same computer as before!
serverComputer.setPeripheral( toDirection( side ), peripheral );
} }
} }

View File

@@ -1,25 +0,0 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.shared.util;
import net.minecraft.inventory.IInventory;
import net.minecraft.inventory.Slot;
import net.minecraft.item.ItemStack;
public class ValidatingSlot extends Slot
{
public ValidatingSlot( IInventory inventoryIn, int index, int xPosition, int yPosition )
{
super( inventoryIn, index, xPosition, yPosition );
}
@Override
public boolean isItemValid( ItemStack stack )
{
return true; // inventory.isItemValidForSlot( slotNumber, stack );
}
}

View File

@@ -48,39 +48,22 @@ function test( colors, color )
if type( color ) ~= "number" then if type( color ) ~= "number" then
error( "bad argument #2 (expected number, got " .. type( color ) .. ")", 2 ) error( "bad argument #2 (expected number, got " .. type( color ) .. ")", 2 )
end end
return bit32.band(colors, color) == color return ((bit32.band(colors, color)) == color)
end
function packRGB( r, g, b )
if type( r ) ~= "number" then
error( "bad argument #1 (expected number, got " .. type( r ) .. ")", 2 )
end
if type( g ) ~= "number" then
error( "bad argument #2 (expected number, got " .. type( g ) .. ")", 2 )
end
if type( b ) ~= "number" then
error( "bad argument #3 (expected number, got " .. type( b ) .. ")", 2 )
end
return
bit32.band( r * 255, 0xFF ) * 2^16 +
bit32.band( g * 255, 0xFF ) * 2^8 +
bit32.band( b * 255, 0xFF )
end
function unpackRGB( rgb )
if type( rgb ) ~= "number" then
error( "bad argument #1 (expected number, got " .. type( rgb ) .. ")", 2 )
end
return
bit32.band( bit32.rshift( rgb, 16 ), 0xFF ) / 255,
bit32.band( bit32.rshift( rgb, 8 ), 0xFF ) / 255,
bit32.band( rgb, 0xFF ) / 255
end end
function rgb8( r, g, b ) function rgb8( r, g, b )
if g == nil and b == nil then if type( r ) ~= "number" then
return unpackRGB( r ) error( "bad argument #1 (expected number, got " .. type( r ) .. ")", 2 )
else elseif type(r) == "number" and g == nil and b == nil then
return packRGB( r, g, b ) return bit32.band( bit32.rshift( r, 16 ), 0xFF ) / 255, bit32.band( bit32.rshift( r, 8 ), 0xFF ) / 255, bit32.band( r, 0xFF ) / 255
elseif type(r) == "number" and type(g) == "number" and type(b) == "number" then
return
bit32.lshift( bit32.band(r * 255, 0xFF), 16 ) +
bit32.lshift( bit32.band(g * 255, 0xFF), 8 ) +
bit32.band(b * 255, 0xFF)
elseif type( g ) ~= "number" then
error( "bad argument #2 (expected number, got " .. type( g ) .. ")", 2 )
elseif type( b ) ~= "number" then
error( "bad argument #3 (expected number, got " .. type( b ) .. ")", 2 )
end end
end end

View File

@@ -42,16 +42,11 @@ term.native = function()
return native return native
end end
-- Some methods shouldn't go through redirects, so we move them to the main
-- term API.
for _, method in ipairs { "nativePaletteColor", "nativePaletteColour"} do
term[method] = native[method]
native[method] = nil
end
for k,v in pairs( native ) do for k,v in pairs( native ) do
if type( k ) == "string" and type( v ) == "function" and term[k] == nil then if type( k ) == "string" and type( v ) == "function" then
term[k] = wrap( k ) if term[k] == nil then
term[k] = wrap( k )
end
end end
end end

View File

@@ -298,7 +298,7 @@ function create( parent, nX, nY, nWidth, nHeight, bStartVisible )
local tCol local tCol
if type(r) == "number" and g == nil and b == nil then if type(r) == "number" and g == nil and b == nil then
tCol = { colours.unpackRGB( r ) } tCol = { colours.rgb8( r ) }
tPalette[ colour ] = tCol tPalette[ colour ] = tCol
else else
if type( r ) ~= "number" then error( "bad argument #2 (expected number, got " .. type( r ) .. ")", 2 ) end if type( r ) ~= "number" then error( "bad argument #2 (expected number, got " .. type( r ) .. ")", 2 ) end

View File

@@ -8,8 +8,6 @@ local nCurrentProcess = nil
local nRunningProcess = nil local nRunningProcess = nil
local bShowMenu = false local bShowMenu = false
local bWindowsResized = false local bWindowsResized = false
local nScrollPos = 1
local bScrollRight = false
local function selectProcess( n ) local function selectProcess( n )
if nCurrentProcess ~= n then if nCurrentProcess ~= n then
@@ -88,9 +86,6 @@ local function cullProcess( nProcess )
selectProcess( 1 ) selectProcess( 1 )
end end
end end
if nScrollPos ~= 1 then
nScrollPos = nScrollPos - 1
end
return true return true
end end
return false return false
@@ -120,15 +115,7 @@ local function redrawMenu()
parentTerm.setCursorPos( 1, 1 ) parentTerm.setCursorPos( 1, 1 )
parentTerm.setBackgroundColor( menuOtherBgColor ) parentTerm.setBackgroundColor( menuOtherBgColor )
parentTerm.clearLine() parentTerm.clearLine()
local nCharCount = 0 for n=1,#tProcesses do
local nSize = parentTerm.getSize()
if nScrollPos ~= 1 then
parentTerm.setTextColor( menuOtherTextColor )
parentTerm.setBackgroundColor( menuOtherBgColor )
parentTerm.write( "<" )
nCharCount = 1
end
for n=nScrollPos,#tProcesses do
if n == nCurrentProcess then if n == nCurrentProcess then
parentTerm.setTextColor( menuMainTextColor ) parentTerm.setTextColor( menuMainTextColor )
parentTerm.setBackgroundColor( menuMainBgColor ) parentTerm.setBackgroundColor( menuMainBgColor )
@@ -137,16 +124,6 @@ local function redrawMenu()
parentTerm.setBackgroundColor( menuOtherBgColor ) parentTerm.setBackgroundColor( menuOtherBgColor )
end end
parentTerm.write( " " .. tProcesses[n].sTitle .. " " ) parentTerm.write( " " .. tProcesses[n].sTitle .. " " )
nCharCount = nCharCount + #tProcesses[n].sTitle + 2
end
if nCharCount > nSize then
parentTerm.setTextColor( menuOtherTextColor )
parentTerm.setBackgroundColor( menuOtherBgColor )
parentTerm.setCursorPos( nSize, 1 )
parentTerm.write( ">" )
bScrollRight = true
else
bScrollRight = false
end end
-- Put the cursor back where it should be -- Put the cursor back where it should be
@@ -285,26 +262,15 @@ while #tProcesses > 0 do
local button, x, y = tEventData[2], tEventData[3], tEventData[4] local button, x, y = tEventData[2], tEventData[3], tEventData[4]
if bShowMenu and y == 1 then if bShowMenu and y == 1 then
-- Switch process -- Switch process
if x == 1 and nScrollPos ~= 1 then local tabStart = 1
nScrollPos = nScrollPos - 1 for n=1,#tProcesses do
redrawMenu() local tabEnd = tabStart + string.len( tProcesses[n].sTitle ) + 1
elseif bScrollRight and x == term.getSize() then if x >= tabStart and x <= tabEnd then
nScrollPos = nScrollPos + 1 selectProcess( n )
redrawMenu() redrawMenu()
else break
local tabStart = 1
if nScrollPos ~= 1 then
tabStart = 2
end
for n=nScrollPos,#tProcesses do
local tabEnd = tabStart + string.len( tProcesses[n].sTitle ) + 1
if x >= tabStart and x <= tabEnd then
selectProcess( n )
redrawMenu()
break
end
tabStart = tabEnd + 1
end end
tabStart = tabEnd + 1
end end
else else
-- Passthrough to current process -- Passthrough to current process
@@ -318,15 +284,7 @@ while #tProcesses > 0 do
elseif sEvent == "mouse_drag" or sEvent == "mouse_up" or sEvent == "mouse_scroll" then elseif sEvent == "mouse_drag" or sEvent == "mouse_up" or sEvent == "mouse_scroll" then
-- Other mouse event -- Other mouse event
local p1, x, y = tEventData[2], tEventData[3], tEventData[4] local p1, x, y = tEventData[2], tEventData[3], tEventData[4]
if bShowMenu and sEvent == "mouse_scroll" and y == 1 then if not (bShowMenu and y == 1) then
if p1 == -1 and nScrollPos ~= 1 then
nScrollPos = nScrollPos - 1
redrawMenu()
elseif bScrollRight and p1 == 1 then
nScrollPos = nScrollPos + 1
redrawMenu()
end
elseif not (bShowMenu and y == 1) then
-- Passthrough to current process -- Passthrough to current process
resumeProcess( nCurrentProcess, sEvent, p1, x, (bShowMenu and y-1) or y ) resumeProcess( nCurrentProcess, sEvent, p1, x, (bShowMenu and y-1) or y )
if cullProcess( nCurrentProcess ) then if cullProcess( nCurrentProcess ) then

Binary file not shown.

Before

Width:  |  Height:  |  Size: 190 B

After

Width:  |  Height:  |  Size: 230 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 181 B

After

Width:  |  Height:  |  Size: 222 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 641 B

After

Width:  |  Height:  |  Size: 643 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 205 B

After

Width:  |  Height:  |  Size: 312 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 296 B

After

Width:  |  Height:  |  Size: 332 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 294 B

After

Width:  |  Height:  |  Size: 333 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 179 B

After

Width:  |  Height:  |  Size: 273 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 237 B

After

Width:  |  Height:  |  Size: 381 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 267 B

After

Width:  |  Height:  |  Size: 273 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 224 B

After

Width:  |  Height:  |  Size: 259 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 248 B

After

Width:  |  Height:  |  Size: 250 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 234 B

After

Width:  |  Height:  |  Size: 258 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 235 B

After

Width:  |  Height:  |  Size: 263 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 179 B

After

Width:  |  Height:  |  Size: 222 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 221 B

After

Width:  |  Height:  |  Size: 266 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 224 B

After

Width:  |  Height:  |  Size: 261 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 302 B

After

Width:  |  Height:  |  Size: 337 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 294 B

After

Width:  |  Height:  |  Size: 619 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 241 B

After

Width:  |  Height:  |  Size: 254 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 282 B

After

Width:  |  Height:  |  Size: 316 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 239 B

After

Width:  |  Height:  |  Size: 253 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 235 B

After

Width:  |  Height:  |  Size: 259 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 426 B

After

Width:  |  Height:  |  Size: 974 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 436 B

After

Width:  |  Height:  |  Size: 989 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 430 B

After

Width:  |  Height:  |  Size: 992 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 490 B

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 223 B

After

Width:  |  Height:  |  Size: 241 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 200 B

After

Width:  |  Height:  |  Size: 211 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 260 B

After

Width:  |  Height:  |  Size: 299 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 200 B

After

Width:  |  Height:  |  Size: 212 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 516 B

After

Width:  |  Height:  |  Size: 638 B

View File

@@ -10,10 +10,9 @@ import dan200.computercraft.api.lua.LuaException;
import dan200.computercraft.core.apis.ObjectWrapper; import dan200.computercraft.core.apis.ObjectWrapper;
import org.junit.Test; import org.junit.Test;
import java.nio.charset.StandardCharsets;
import java.util.Arrays; import java.util.Arrays;
import static org.junit.Assert.*; import static org.junit.Assert.assertEquals;
public class BinaryReadableHandleTest public class BinaryReadableHandleTest
{ {
@@ -60,24 +59,6 @@ public class BinaryReadableHandleTest
assertEquals( 1000, wrapper.<byte[]>callOf( "read", 11000 ).length ); assertEquals( 1000, wrapper.<byte[]>callOf( "read", 11000 ).length );
} }
@Test
public void testReadLine() throws LuaException
{
ObjectWrapper wrapper = new ObjectWrapper( new BinaryReadableHandle( new ArrayByteChannel( "hello\r\nworld\r!".getBytes( StandardCharsets.UTF_8 ) ) ) );
assertArrayEquals( "hello".getBytes( StandardCharsets.UTF_8 ), wrapper.callOf( "readLine" ) );
assertArrayEquals( "world\r!".getBytes( StandardCharsets.UTF_8 ), wrapper.callOf( "readLine" ) );
assertNull( wrapper.call( "readLine" ) );
}
@Test
public void testReadLineTrailing() throws LuaException
{
ObjectWrapper wrapper = new ObjectWrapper( new BinaryReadableHandle( new ArrayByteChannel( "hello\r\nworld\r!".getBytes( StandardCharsets.UTF_8 ) ) ) );
assertArrayEquals( "hello\r\n".getBytes( StandardCharsets.UTF_8 ), wrapper.callOf( "readLine", true ) );
assertArrayEquals( "world\r!".getBytes( StandardCharsets.UTF_8 ), wrapper.callOf( "readLine", true ) );
assertNull( wrapper.call( "readLine", true ) );
}
private static ObjectWrapper fromLength( int length ) private static ObjectWrapper fromLength( int length )
{ {
byte[] input = new byte[length]; byte[] input = new byte[length];