1
0
mirror of https://github.com/SquidDev-CC/CC-Tweaked synced 2025-11-01 06:03:00 +00:00

Compare commits

...

30 Commits

Author SHA1 Message Date
SquidDev
a4cd1fe77d Stop releasing betas by default
Things just got serious I guess??
2019-02-23 10:35:15 +00:00
Wilma456 (Jakob0815)
4145914024 Make Multishell Scrollable (#123)
You can now Scroll through the program list, if the list bigger than your
screen.
2019-02-21 16:00:13 +00:00
SquidDev
6bd11a5e4a Fix the other instance of the neighbour deprecation warning 2019-02-20 18:37:22 +00:00
SquidDev
46fa798797 Several minor improvements
- Restrict what items can be inserted into printers. They're now closer
   to brewing stands or furnaces: nothing can go in the output slot,
   only ink in the ink slot, and only paper in the paper slot.
 - Fix build.gradle using the wrong version
 - Trim the width of tables to fit when displaying on the client. Closes
   #45. Note, our solution isn't perfect, as it will wordwrap too, but
   it's adaquate for now.
2019-02-20 09:48:16 +00:00
SquidDev
70a226207e Update README and versioning (#121)
- Reword elements of the README, mostly changing the elements about
   vanilla ComputerCraft.
 - Change versioning scheme: we'll now do 1.x.y, with 1.81.0 being the
   next version.
 - Include MC version in the file name
 - Stop bundling javadoc with the jar. We'll look into hosting this on
   squiddev.cc if really needed.
 - Remove the LuaJ license from the root - we no longer bundle the
   sources, so it's not needed here.

I realise this change looks a little dodgey on its own, so see #113 for
the full rationale.
2019-02-19 14:49:13 +00:00
SquidDev
257a35f3ed Merge pull request #120 from SquidDev-CC/feature/palette-improvements
Minor palette improvements
2019-02-19 10:59:35 +00:00
Lignum
af01b9514b Split colours.rgb8 into colours.packRGB and colours.unpackRGB 2019-02-19 09:51:01 +00:00
Lignum
070fd1f2ff Add term.nativePaletteColo(u)r 2019-02-19 09:50:57 +00:00
SquidDev
fb59da2b06 Update GitHub templates, removing CC repo links
See #113
2019-02-18 23:35:50 +00:00
SquidDev
11e4d0de82 Fix turtle peripherals becoming desynced
When a turtle was unloaded but not actually disposed of, the
m_peripheral map hangs around. As a result, when creating a new
ServerComputer, the peripherals aren't considered changed and so they're
never attached.

Fixes #50.

Also fix that blumin' deprecated method which has been around for a wee
while now.
2019-02-18 23:28:51 +00:00
SquidDev
e46ab1e267 Revert some image optimisations 2019-02-18 22:58:39 +00:00
SquidDev
d6e0f368df Handle managing computer inputs/outputs separatly
The Computer class currently has several resposiblities such as storing
id/label, managing redstone/peirpherals, handling management of the
computer (on/off/events) and updating the output.

In order to simplify this a little bit, we move our IAPIEnvironment
implementation into a separate file, and store all "world state"
(redstone + peripherals) in there. While we still need to have some
level of updating them within the main Computer instance, it's
substantially simpler.
2019-02-17 19:48:52 +00:00
SquidDev
9f2884bc0f Several minor improvments to websockets
- Fire close events instead of failure when open websockets error.
 - Handle ping events. I thought I was doing this already, but this
   requires a WebsocketProtocolHandler. Fixes #118
2019-02-17 19:36:18 +00:00
SquidDev
18d468e887 Fix building from a fresh setup
We were attempting to resolve the Forge jars before they had been
generated, which meant the build failed.
2019-02-16 16:01:47 +00:00
SquidDev
63f6735bb8 Attempt to reduce jar size a little
- Run optipng on all our images. This has very little effect on most of
   them (as they're all so small anyway), but has resulted in a 50%
   reduction in some cases.
 - Run Proguard on our shadowed dependencies (Cobalt).
 - Minify our JSON files, stripping all whitespace. This is mostly
   useful for FML's annotation cache, as that's a massive file, but
   still a semi-useful optimisation to make.

This has helped reduce the jar by about 110kb, which isn't much but
still feels somewhat worth it.
2019-02-14 10:53:18 +00:00
SquidDev
ab6f0ccd16 Fix advanced modems not actually being advanced
We were constructing the peripheral before the advanced property had
been set, thus it was always false. Yay for Java.

Closes #111
2019-02-12 18:11:04 +00:00
SquidDev
ae0f093e73 Strip \r from .readLine on binary handles
Note, this is technically inconsistent with the spec. However, we'll use
this method for now in order to remain backwards compatible.

Fixes #109.
2019-02-11 16:58:43 +00:00
SquidDev
e5f988e3fe Fix missing advanced turtle model when rendering
I'm not even sure how I missed this when testing.
2019-02-11 16:38:33 +00:00
SquidDev
12e82afad2 Bump Cobalt version to enable single-threading
The latest version of Cobalt has several major changes, which I'm
looking forward to taking advantage of in the coming months:

 - The Lua interpreter has been split up from the actual LuaClosure
   instance. It now runs multiple functions within one loop, handling
   pushing/popping and resuming method calls correctly.

   This means we have a theoretically infinite call depth, as we're no
   longer bounded by Java's stack size. In reality, this is limited to
   32767 (Short.MAX_VALUE), as that's a mostly equivalent to the limits
   PUC Lua exposes.

 - The stack is no longer unwound in the event of errors. This both
   simplifies error handling (not that CC:T needs to care about that)
   but also means one can call debug.traceback on a now-dead coroutine
   (which is more useful for debugging than using xpcall).

 - Most significantly, coroutines are no longer each run on a dedicated
   thread. Instead, yielding or resuming throws an exception to unwind
   the Java stack and switches to a different coroutine.

   In order to preserve compatability with CC's assumption about LuaJ's
   threading model (namely that yielding blocks the thread), we also
   provide a yieldBlock method (which CC:T consumes). This suspends the
   current thread and switches execution to a new thread (see
   SquidDev/Cobalt@b5ddf164f1 for more
   details). While this does mean we need to use more than 1 thread,
   it's still /substantially/ less than would otherwise be needed.

We've been running these changes on SwitchCraft for a few days now and
haven't seen any issues. One nice thing to observe is that the number of
CC thread has gone down from ~1.9k to ~100 (of those, ~70 are dedicated
to running coroutines). Similarly, the server has gone from generating
~15k threads over its lifetime, to ~3k. While this is still a lot, it's
a substantial improvement.
2019-02-10 22:02:30 +00:00
SquidDev
6c2db93cbd Register item colour handlers on the event instead
Another step on my misguided quest to get rid of proxies
2019-02-10 09:55:06 +00:00
SquidDev
d5edbe700b Load turtle item models using a model loader
This is far more elegant than our weird method of baking things and
manually inserting them into the model map. Also means we no longer need
the whole turtle_dynamic thing.
2019-02-10 09:45:15 +00:00
SquidDev
86ad43c3ab Fix peripheral direction not being set
We moved the direction call within the if block, but never actally
updated the condition! I'm on a roll of stupid bug fixes today, which
really isn't a good sign.
2019-02-07 23:07:49 +00:00
SquidDev
f450c0156b Recomment out a global
It's actually rather worrying this was exposed, you could cause some
serious issues with it.
2019-02-07 20:22:00 +00:00
SquidDev
8abcfcb4ac Track turtle commands as server tasks
They're basically an alternative version of issueMainThreadTask anyway.
2019-01-30 20:43:08 +00:00
SquidDev
f3cace1d03 Allow building without a git repository
Closes #102
2019-01-28 14:05:53 +00:00
SquidDev
e1e5e898ab Make monitors use a concurrent map instead of a synchronized
We didn't lock when iterating on the main-thread, so it wasn't actually
thread-safe anyway!
2019-01-25 22:59:01 +00:00
SquidDev
3aa3852ff6 Some further improvements to BlockGeneric
- Only have computers implement custom block drop logic: everything
   else only drops in creative mode.
 - Fix redstone inputs not being received correctly. Introduced in
   8b86a954ee, yes I'm a silly billy.
 - Only update the neighbour which changed.
2019-01-25 22:03:44 +00:00
SquidDev
709a6329c7 Fix all wireless modem blocks being advanced 2019-01-25 00:12:49 +00:00
SquidDev
c9f05a2939 Make require a little more consistent with Lua 5.1
- Error messages are indented correctly
 - The module's name is passed as the first argument to modules
 - Make error messages match Lua's
2019-01-23 18:50:17 +00:00
Devilholk
e41377f862 Handle connection errors on websockets 2019-01-22 11:11:25 +00:00
102 changed files with 1464 additions and 1388 deletions

View File

@@ -6,11 +6,10 @@ about: Report some misbehaviour in the mod
<!--
## Before reporting
- 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.
- Search for the bug on the issue tracker. Make sure to look at closed issues too!
-->
## Useful information to include:
- Minecraft version
- CC: Tweaked version
- 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.
- 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.

View File

@@ -6,10 +6,9 @@ about: Suggest an idea or improvement
<!--
## Before reporting
- 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.
- Search for the suggestion here. It's possible someone's suggested it before!
-->
## Useful information to include:
- Explanation of how the feature/change chould work.
- Some rationale/use case for a feature. I'd like to keep CC:T as minimal
- Explanation of how the feature/change should 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.

View File

@@ -1,9 +0,0 @@
<!--
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.

View File

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

View File

@@ -9,8 +9,10 @@ buildscript {
}
}
dependencies {
classpath 'com.google.code.gson:gson:2.8.1'
classpath 'net.minecraftforge.gradle:ForgeGradle:2.3-SNAPSHOT'
classpath 'org.ajoberstar:gradle-git:1.6.0'
classpath 'net.sf.proguard:proguard-gradle:6.1.0beta1'
classpath 'org.ajoberstar.grgit:grgit-gradle:3.0.0'
}
}
@@ -23,12 +25,14 @@ apply plugin: 'org.ajoberstar.grgit'
apply plugin: 'maven-publish'
apply plugin: 'maven'
version = "1.80pr1.14"
def mc_version = "1.12.2"
version = "1.81.0"
group = "org.squiddev"
archivesBaseName = "cc-tweaked"
archivesBaseName = "cc-tweaked-${mc_version}"
minecraft {
version = "1.12.2-14.23.4.2749"
version = "${mc_version}-14.23.4.2749"
runDir = "run"
replace '${version}', project.version
@@ -48,7 +52,7 @@ repositories {
}
maven {
name = "squiddev"
url = "https://dl.bintray.com/squiddev/maven"
url = "https://squiddev.cc/maven"
}
ivy { artifactPattern "https://asie.pl/files/mods/Charset/LibOnly/[module]-[revision](-[classifier]).[ext]" }
@@ -66,7 +70,7 @@ dependencies {
runtime "mezz.jei:jei_1.12.2:4.8.5.159"
shade 'org.squiddev:Cobalt:0.4.0'
shade 'org.squiddev:Cobalt:0.5.0-SNAPSHOT'
testCompile 'junit:junit:4.11'
@@ -84,39 +88,91 @@ jar {
attributes('FMLAT': 'computercraft_at.cfg')
}
into("docs", { from (javadoc.destinationDir) })
into("api", { from (sourceSets.main.allSource) {
from (sourceSets.main.allSource) {
include "dan200/computercraft/api/**/*.java"
}})
}
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 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 {
inputs.property "version", project.version
inputs.property "mcversion", project.minecraft.version
inputs.property "mcversion", mc_version
def grgit = Grgit.open(dir: '.')
inputs.property "commithash", grgit.head().id
def blacklist = ['GitHub', 'dan200', 'Daniel Ratcliffe']
def hash = 'none'
Set<String> contributors = []
try {
def grgit = Grgit.open(dir: '.')
hash = grgit.head().id
grgit.log().each {
if (!blacklist.contains(it.author.name)) contributors.add(it.author.name)
if (!blacklist.contains(it.committer.name)) contributors.add(it.committer.name)
}
def blacklist = ['GitHub', 'dan200', 'Daniel Ratcliffe']
grgit.log().each {
if (!blacklist.contains(it.author.name)) contributors.add(it.author.name)
if (!blacklist.contains(it.committer.name)) contributors.add(it.committer.name)
}
} catch(Exception ignored) { }
inputs.property "commithash", hash
from(sourceSets.main.resources.srcDirs) {
include 'mcmod.info'
include 'assets/computercraft/lua/rom/help/credits.txt'
expand 'version':project.version,
'mcversion':project.minecraft.version,
'gitcontributors':contributors.sort(false, String.CASE_INSENSITIVE_ORDER).join('\n')
expand 'version': project.version,
'mcversion': mc_version,
'gitcontributors': contributors.sort(false, String.CASE_INSENSITIVE_ORDER).join('\n')
}
from(sourceSets.main.resources.srcDirs) {
@@ -125,12 +181,53 @@ 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 {
apiKey = project.hasProperty('curseForgeApiKey') ? project.curseForgeApiKey : ''
project {
id = '282001'
releaseType = 'beta'
releaseType = 'release'
changelog = "Release notes can be found on the GitHub repository (https://github.com/SquidDev-CC/CC-Tweaked/releases/tag/v${project.version})."
}
}

View File

@@ -235,7 +235,8 @@ public class ComputerCraft
}
@Deprecated
public static class Upgrades {
public static class Upgrades
{
public static TurtleModem advancedModem;
}

View File

@@ -7,6 +7,10 @@
package dan200.computercraft.client;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.client.render.TurtleModelLoader;
import dan200.computercraft.shared.media.items.ItemDiskLegacy;
import dan200.computercraft.shared.turtle.items.ItemTurtleBase;
import dan200.computercraft.shared.util.Colour;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.ItemMeshDefinition;
import net.minecraft.client.renderer.block.model.IBakedModel;
@@ -17,6 +21,7 @@ import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.client.event.ColorHandlerEvent;
import net.minecraftforge.client.event.ModelBakeEvent;
import net.minecraftforge.client.event.ModelRegistryEvent;
import net.minecraftforge.client.event.TextureStitchEvent;
@@ -35,7 +40,7 @@ import javax.annotation.Nonnull;
@Mod.EventBusSubscriber( modid = ComputerCraft.MOD_ID, value = Side.CLIENT )
public class ClientRegistry
{
private static final String[] TURTLE_UPGRADES = {
private static final String[] EXTRA_MODELS = {
"turtle_modem_off_left",
"turtle_modem_on_left",
"turtle_modem_off_right",
@@ -48,11 +53,16 @@ public class ClientRegistry
"advanced_turtle_modem_on_right",
"turtle_speaker_upgrade_left",
"turtle_speaker_upgrade_right",
"turtle_white",
"turtle_elf_overlay",
};
@SubscribeEvent
public static void registerModels( ModelRegistryEvent event )
{
ModelLoaderRegistry.registerLoader( TurtleModelLoader.INSTANCE );
// Register item models
registerUniversalItemModel( ComputerCraft.Items.computer, "computer" );
registerItemModel( ComputerCraft.Items.commandComputer, 0, "command_computer" );
@@ -79,35 +89,70 @@ public class ClientRegistry
registerItemModel( ComputerCraft.Items.printout, 1, "pages" );
registerItemModel( ComputerCraft.Items.printout, 2, "book" );
String[] extraTurtleModels = new String[] { "turtle", "turtle_advanced", "turtle_white", "turtle_elf_overlay" };
registerUniversalItemModel( ComputerCraft.Items.turtle, "turtle_dynamic", extraTurtleModels );
registerUniversalItemModel( ComputerCraft.Items.turtleExpanded, "turtle_dynamic", extraTurtleModels );
registerUniversalItemModel( ComputerCraft.Items.turtleAdvanced, "turtle_dynamic", extraTurtleModels );
registerUniversalItemModel( ComputerCraft.Items.turtle, "turtle" );
registerUniversalItemModel( ComputerCraft.Items.turtleExpanded, "turtle" );
registerUniversalItemModel( ComputerCraft.Items.turtleAdvanced, "turtle_advanced" );
}
@SubscribeEvent
public static void onTextureStitchEvent( TextureStitchEvent.Pre event )
{
// Load all textures for upgrades
// Load all textures for the extra models
TextureMap map = event.getMap();
for( String upgrade : TURTLE_UPGRADES )
for( String upgrade : EXTRA_MODELS )
{
IModel model = ModelLoaderRegistry.getModelOrMissing( new ResourceLocation( "computercraft", "block/" + upgrade ) );
for( ResourceLocation texture : model.getTextures() )
{
map.registerSprite( texture );
}
for( ResourceLocation texture : model.getTextures() ) map.registerSprite( texture );
}
}
@SubscribeEvent
public static void onModelBakeEvent( ModelBakeEvent event )
{
// Load all upgrade models
for( String upgrade : TURTLE_UPGRADES )
{
loadBlockModel( event, upgrade );
}
// Load all extra models
for( String model : EXTRA_MODELS ) loadBlockModel( event, model );
}
@SubscribeEvent
public static void onItemColours( ColorHandlerEvent.Item event )
{
event.getItemColors().registerItemColorHandler(
( stack, layer ) -> layer == 0 ? 0xFFFFFF : ((ItemDiskLegacy) stack.getItem()).getColour( stack ),
ComputerCraft.Items.disk, ComputerCraft.Items.diskExpanded
);
event.getItemColors().registerItemColorHandler( ( stack, layer ) -> {
switch( layer )
{
case 0:
default:
return 0xFFFFFF;
case 1:
{
// Frame colour
int colour = ComputerCraft.Items.pocketComputer.getColour( stack );
return colour == -1 ? 0xFFFFFF : colour;
}
case 2:
{
// Light colour
int colour = ComputerCraft.Items.pocketComputer.getLightState( stack );
return colour == -1 ? Colour.Black.getHex() : colour;
}
}
}, ComputerCraft.Items.pocketComputer );
// Setup turtle colours
event.getItemColors().registerItemColorHandler( ( stack, tintIndex ) -> {
if( tintIndex == 0 )
{
ItemTurtleBase turtle = (ItemTurtleBase) stack.getItem();
int colour = turtle.getColour( stack );
if( colour != -1 ) return colour;
}
return 0xFFFFFF;
}, ComputerCraft.Blocks.turtle, ComputerCraft.Blocks.turtleExpanded, ComputerCraft.Blocks.turtleAdvanced );
}
private static void registerItemModel( Item item, int damage, String name )
@@ -118,18 +163,10 @@ public class ClientRegistry
ModelLoader.setCustomModelResourceLocation( item, damage, res );
}
private static void registerUniversalItemModel( Item item, String mainModel, String... extraModels )
private static void registerUniversalItemModel( Item item, String mainModel )
{
ResourceLocation mainLocation = new ResourceLocation( ComputerCraft.MOD_ID, mainModel );
ResourceLocation[] modelLocations = new ResourceLocation[extraModels.length + 1];
modelLocations[0] = mainLocation;
for( int i = 0; i < extraModels.length; i++ )
{
modelLocations[i + 1] = new ResourceLocation( ComputerCraft.MOD_ID, extraModels[i] );
}
ModelBakery.registerItemVariants( item, modelLocations );
ModelBakery.registerItemVariants( item, mainLocation );
final ModelResourceLocation mainModelLocation = new ModelResourceLocation( mainLocation, "inventory" );
ModelLoader.setCustomMeshDefinition( item, new ItemMeshDefinition()

View File

@@ -13,12 +13,14 @@ import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.FontRenderer;
import net.minecraft.client.gui.GuiNewChat;
import net.minecraft.client.gui.GuiUtilRenderComponents;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.text.TextFormatting;
import org.apache.commons.lang3.StringUtils;
import javax.annotation.Nullable;
import java.util.List;
public class ClientTableFormatter implements TableFormatter
{
@@ -62,7 +64,13 @@ public class ClientTableFormatter implements TableFormatter
@Override
public void writeLine( int id, ITextComponent component )
{
Minecraft.getMinecraft().ingameGUI.getChatGUI().printChatMessageWithOptionalDeletion( component, id );
Minecraft mc = Minecraft.getMinecraft();
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

View File

@@ -6,69 +6,19 @@
package dan200.computercraft.client.proxy;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.client.render.TileEntityTurtleRenderer;
import dan200.computercraft.client.render.TurtleSmartItemModel;
import dan200.computercraft.shared.proxy.CCTurtleProxyCommon;
import dan200.computercraft.shared.turtle.blocks.TileTurtle;
import dan200.computercraft.shared.turtle.items.ItemTurtleBase;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.block.model.ModelResourceLocation;
import net.minecraft.client.resources.IReloadableResourceManager;
import net.minecraft.client.resources.IResourceManager;
import net.minecraftforge.client.event.ModelBakeEvent;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.fml.client.registry.ClientRegistry;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
public class CCTurtleProxyClient extends CCTurtleProxyCommon
{
@Override
public void preInit()
{
super.preInit();
MinecraftForge.EVENT_BUS.register( new ForgeHandlers() );
}
@Override
public void init()
{
super.init();
// Setup turtle colours
Minecraft.getMinecraft().getItemColors().registerItemColorHandler( ( stack, tintIndex ) -> {
if( tintIndex == 0 )
{
ItemTurtleBase turtle = (ItemTurtleBase) stack.getItem();
int colour = turtle.getColour( stack );
if( colour != -1 ) return colour;
}
return 0xFFFFFF;
}, ComputerCraft.Blocks.turtle, ComputerCraft.Blocks.turtleExpanded, ComputerCraft.Blocks.turtleAdvanced );
// Setup renderers
ClientRegistry.bindTileEntitySpecialRenderer( TileTurtle.class, new TileEntityTurtleRenderer() );
}
public static class ForgeHandlers
{
private final TurtleSmartItemModel m_turtleSmartItemModel = new TurtleSmartItemModel();
ForgeHandlers()
{
IResourceManager resourceManager = Minecraft.getMinecraft().getResourceManager();
if( resourceManager instanceof IReloadableResourceManager )
{
((IReloadableResourceManager) resourceManager).registerReloadListener( m_turtleSmartItemModel );
}
}
@SubscribeEvent
public void onModelBakeEvent( ModelBakeEvent event )
{
event.getModelRegistry().putObject( new ModelResourceLocation( "computercraft:turtle_dynamic", "inventory" ), m_turtleSmartItemModel );
}
}
}

View File

@@ -10,24 +10,16 @@ import dan200.computercraft.ComputerCraft;
import dan200.computercraft.client.render.TileEntityCableRenderer;
import dan200.computercraft.client.render.TileEntityMonitorRenderer;
import dan200.computercraft.shared.command.CommandCopy;
import dan200.computercraft.shared.media.items.ItemDiskLegacy;
import dan200.computercraft.shared.peripheral.modem.wired.TileCable;
import dan200.computercraft.shared.peripheral.monitor.ClientMonitor;
import dan200.computercraft.shared.peripheral.monitor.TileMonitor;
import dan200.computercraft.shared.proxy.ComputerCraftProxyCommon;
import dan200.computercraft.shared.util.Colour;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.color.IItemColor;
import net.minecraft.item.ItemStack;
import net.minecraftforge.client.ClientCommandHandler;
import net.minecraftforge.event.world.WorldEvent;
import net.minecraftforge.fml.client.registry.ClientRegistry;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import javax.annotation.Nonnull;
public class ComputerCraftProxyClient extends ComputerCraftProxyCommon
{
@@ -45,33 +37,6 @@ public class ComputerCraftProxyClient extends ComputerCraftProxyCommon
{
super.init();
Minecraft mc = Minecraft.getMinecraft();
// Setup
mc.getItemColors().registerItemColorHandler( new DiskColorHandler( ComputerCraft.Items.disk ), ComputerCraft.Items.disk );
mc.getItemColors().registerItemColorHandler( new DiskColorHandler( ComputerCraft.Items.diskExpanded ), ComputerCraft.Items.diskExpanded );
mc.getItemColors().registerItemColorHandler( ( stack, layer ) -> {
switch( layer )
{
case 0:
default:
return 0xFFFFFF;
case 1:
{
// Frame colour
int colour = ComputerCraft.Items.pocketComputer.getColour( stack );
return colour == -1 ? 0xFFFFFF : colour;
}
case 2:
{
// Light colour
int colour = ComputerCraft.Items.pocketComputer.getLightState( stack );
return colour == -1 ? Colour.Black.getHex() : colour;
}
}
}, ComputerCraft.Items.pocketComputer );
// Setup renderers
ClientRegistry.bindTileEntitySpecialRenderer( TileMonitor.class, new TileEntityMonitorRenderer() );
ClientRegistry.bindTileEntitySpecialRenderer( TileCable.class, new TileEntityCableRenderer() );
@@ -90,20 +55,5 @@ public class ComputerCraftProxyClient extends ComputerCraftProxyCommon
}
}
@SideOnly( Side.CLIENT )
private static class DiskColorHandler implements IItemColor
{
private final ItemDiskLegacy disk;
private DiskColorHandler( ItemDiskLegacy disk )
{
this.disk = disk;
}
@Override
public int colorMultiplier( @Nonnull ItemStack stack, int layer )
{
return layer == 0 ? 0xFFFFFF : disk.getColour( stack );
}
}
}

View File

@@ -14,23 +14,20 @@ import dan200.computercraft.shared.util.Holiday;
import dan200.computercraft.shared.util.HolidayUtil;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.FontRenderer;
import net.minecraft.client.renderer.BufferBuilder;
import net.minecraft.client.renderer.EntityRenderer;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.block.model.BakedQuad;
import net.minecraft.client.renderer.block.model.IBakedModel;
import net.minecraft.client.renderer.block.model.ModelManager;
import net.minecraft.client.renderer.block.model.ModelResourceLocation;
import net.minecraft.client.renderer.entity.RenderManager;
import net.minecraft.client.renderer.texture.TextureMap;
import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.client.renderer.vertex.VertexFormat;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.util.math.Vec3d;
import net.minecraftforge.client.ForgeHooksClient;
import net.minecraftforge.client.model.pipeline.LightUtil;
@@ -65,7 +62,7 @@ public class TileEntityTurtleRenderer extends TileEntitySpecialRenderer<TileTurt
}
}
public static ModelResourceLocation getTurtleOverlayModel( ComputerFamily family, ResourceLocation overlay, boolean christmas )
public static ModelResourceLocation getTurtleOverlayModel( ResourceLocation overlay, boolean christmas )
{
if( overlay != null )
{
@@ -83,6 +80,19 @@ public class TileEntityTurtleRenderer extends TileEntitySpecialRenderer<TileTurt
private void renderTurtleAt( TileTurtle turtle, double posX, double posY, double posZ, float f, int i )
{
// Render the label
String label = turtle.createProxy().getLabel();
if( label != null && rendererDispatcher.cameraHitResult != null && turtle.getPos().equals( rendererDispatcher.cameraHitResult.getBlockPos() ) )
{
setLightmapDisabled( true );
EntityRenderer.drawNameplate(
getFontRenderer(), label,
(float) posX + 0.5F, (float) posY + 1.2F, (float) posZ + 0.5F, 0,
rendererDispatcher.entityYaw, rendererDispatcher.entityPitch, false, false
);
setLightmapDisabled( false );
}
IBlockState state = turtle.getWorld().getBlockState( turtle.getPos() );
GlStateManager.pushMatrix();
try
@@ -94,13 +104,6 @@ public class TileEntityTurtleRenderer extends TileEntitySpecialRenderer<TileTurt
yaw = turtle.getRenderYaw( f );
GlStateManager.translate( posX + offset.x, posY + offset.y, posZ + offset.z );
// Render the label
String label = turtle.createProxy().getLabel();
if( label != null )
{
renderLabel( turtle.getAccess().getPosition(), label );
}
// Render the turtle
GlStateManager.translate( 0.5f, 0.5f, 0.5f );
GlStateManager.rotate( 180.0f - yaw, 0.0f, 1.0f, 0.0f );
@@ -123,7 +126,6 @@ public class TileEntityTurtleRenderer extends TileEntitySpecialRenderer<TileTurt
// Render the overlay
ModelResourceLocation overlayModel = getTurtleOverlayModel(
family,
overlay,
HolidayUtil.getCurrentHoliday() == Holiday.Christmas
);
@@ -232,72 +234,4 @@ public class TileEntityTurtleRenderer extends TileEntitySpecialRenderer<TileTurt
}
tessellator.draw();
}
private void renderLabel( BlockPos position, String label )
{
Minecraft mc = Minecraft.getMinecraft();
RayTraceResult mop = mc.objectMouseOver;
if( mop != null && mop.typeOfHit == RayTraceResult.Type.BLOCK && mop.getBlockPos().equals( position ) )
{
RenderManager renderManager = mc.getRenderManager();
FontRenderer fontrenderer = renderManager.getFontRenderer();
float scale = 0.016666668F * 1.6f;
GlStateManager.pushMatrix();
GlStateManager.disableLighting();
GlStateManager.enableBlend();
GlStateManager.blendFunc( GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA );
try
{
GlStateManager.translate( 0.5f, 1.25f, 0.5f );
GlStateManager.rotate( -renderManager.playerViewY, 0.0F, 1.0F, 0.0F );
GlStateManager.rotate( renderManager.playerViewX, 1.0F, 0.0F, 0.0F );
GlStateManager.scale( -scale, -scale, scale );
int yOffset = 0;
int xOffset = fontrenderer.getStringWidth( label ) / 2;
// Draw background
GlStateManager.depthMask( false );
GlStateManager.disableDepth();
try
{
// Quad
GlStateManager.disableTexture2D();
try
{
Tessellator tessellator = Tessellator.getInstance();
BufferBuilder renderer = tessellator.getBuffer();
renderer.begin( GL11.GL_QUADS, DefaultVertexFormats.POSITION_COLOR );
renderer.pos( -xOffset - 1, -1 + yOffset, 0.0D ).color( 0.0F, 0.0F, 0.0F, 0.25F ).endVertex();
renderer.pos( -xOffset - 1, 8 + yOffset, 0.0D ).color( 0.0F, 0.0F, 0.0F, 0.25F ).endVertex();
renderer.pos( xOffset + 1, 8 + yOffset, 0.0D ).color( 0.0F, 0.0F, 0.0F, 0.25F ).endVertex();
renderer.pos( xOffset + 1, -1 + yOffset, 0.0D ).color( 0.0F, 0.0F, 0.0F, 0.25F ).endVertex();
tessellator.draw();
}
finally
{
GlStateManager.enableTexture2D();
}
// Text
fontrenderer.drawString( label, -fontrenderer.getStringWidth( label ) / 2, yOffset, 0x20ffffff );
}
finally
{
GlStateManager.enableDepth();
GlStateManager.depthMask( true );
}
// Draw foreground text
fontrenderer.drawString( label, -fontrenderer.getStringWidth( label ) / 2, yOffset, -1 );
}
finally
{
GlStateManager.disableBlend();
GlStateManager.enableLighting();
GlStateManager.popMatrix();
}
}
}
}

View File

@@ -0,0 +1,121 @@
/*
* 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.client.render;
import com.google.common.collect.ImmutableMap;
import dan200.computercraft.ComputerCraft;
import net.minecraft.client.renderer.block.model.IBakedModel;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.renderer.vertex.VertexFormat;
import net.minecraft.client.resources.IResourceManager;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.client.model.ICustomModelLoader;
import net.minecraftforge.client.model.IModel;
import net.minecraftforge.client.model.ModelLoaderRegistry;
import net.minecraftforge.common.model.IModelState;
import javax.annotation.Nonnull;
import java.util.function.Function;
public class TurtleModelLoader implements ICustomModelLoader
{
private static final ResourceLocation NORMAL_TURTLE_MODEL = new ResourceLocation( ComputerCraft.MOD_ID, "block/turtle" );
private static final ResourceLocation ADVANCED_TURTLE_MODEL = new ResourceLocation( ComputerCraft.MOD_ID, "block/advanced_turtle" );
private static final ResourceLocation COLOUR_TURTLE_MODEL = new ResourceLocation( ComputerCraft.MOD_ID, "block/turtle_white" );
public static final TurtleModelLoader INSTANCE = new TurtleModelLoader();
private TurtleModelLoader()
{
}
@Override
public void onResourceManagerReload( @Nonnull IResourceManager manager )
{
}
@Override
public boolean accepts( @Nonnull ResourceLocation name )
{
return name.getNamespace().equals( ComputerCraft.MOD_ID )
&& (name.getPath().equals( "turtle" ) || name.getPath().equals( "turtle_advanced" ));
}
@Nonnull
@Override
public IModel loadModel( @Nonnull ResourceLocation name ) throws Exception
{
if( name.getNamespace().equals( ComputerCraft.MOD_ID ) )
{
IModel colourModel = ModelLoaderRegistry.getModel( COLOUR_TURTLE_MODEL );
switch( name.getPath() )
{
case "turtle":
return new TurtleModel( ModelLoaderRegistry.getModel( NORMAL_TURTLE_MODEL ), colourModel );
case "turtle_advanced":
return new TurtleModel( ModelLoaderRegistry.getModel( ADVANCED_TURTLE_MODEL ), colourModel );
}
}
throw new IllegalStateException( "Loader does not accept " + name );
}
private static class TurtleModel implements IModel
{
private final IModel family;
private final IModel colour;
private TurtleModel( IModel family, IModel colour )
{
this.family = family;
this.colour = colour;
}
@Nonnull
@Override
public IBakedModel bake( @Nonnull IModelState state, @Nonnull VertexFormat format, @Nonnull Function<ResourceLocation, TextureAtlasSprite> function )
{
return new TurtleSmartItemModel(
family.bake( state, format, function ),
colour.bake( state, format, function )
);
}
private TurtleModel copy( IModel family, IModel colour )
{
return this.family == family && this.colour == colour ? this : new TurtleModel( family, colour );
}
@Nonnull
@Override
public IModel smoothLighting( boolean value )
{
return copy( family.smoothLighting( value ), colour.smoothLighting( value ) );
}
@Nonnull
@Override
public IModel gui3d( boolean value )
{
return copy( family.gui3d( value ), colour.gui3d( value ) );
}
@Nonnull
@Override
public IModel uvlock( boolean value )
{
return copy( family.uvlock( value ), colour.uvlock( value ) );
}
@Nonnull
@Override
public IModel retexture( ImmutableMap<String, String> textures )
{
return copy( family.retexture( textures ), colour.retexture( textures ) );
}
}
}

View File

@@ -9,7 +9,6 @@ package dan200.computercraft.client.render;
import com.google.common.base.Objects;
import dan200.computercraft.api.turtle.ITurtleUpgrade;
import dan200.computercraft.api.turtle.TurtleSide;
import dan200.computercraft.shared.computer.core.ComputerFamily;
import dan200.computercraft.shared.turtle.items.ItemTurtleBase;
import dan200.computercraft.shared.util.Holiday;
import dan200.computercraft.shared.util.HolidayUtil;
@@ -17,15 +16,11 @@ import net.minecraft.block.state.IBlockState;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.block.model.*;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.resources.IResourceManager;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.ResourceLocation;
import net.minecraft.world.World;
import net.minecraftforge.client.resource.IResourceType;
import net.minecraftforge.client.resource.ISelectiveResourceReloadListener;
import net.minecraftforge.client.resource.VanillaResourceType;
import org.apache.commons.lang3.tuple.Pair;
import javax.annotation.Nonnull;
@@ -34,9 +29,8 @@ import javax.vecmath.Matrix4f;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.function.Predicate;
public class TurtleSmartItemModel implements IBakedModel, ISelectiveResourceReloadListener
public class TurtleSmartItemModel implements IBakedModel
{
private static final Matrix4f s_identity, s_flip;
@@ -53,17 +47,15 @@ public class TurtleSmartItemModel implements IBakedModel, ISelectiveResourceRelo
private static class TurtleModelCombination
{
public final ComputerFamily m_family;
public final boolean m_colour;
public final ITurtleUpgrade m_leftUpgrade;
public final ITurtleUpgrade m_rightUpgrade;
public final ResourceLocation m_overlay;
public final boolean m_christmas;
public final boolean m_flip;
final boolean m_colour;
final ITurtleUpgrade m_leftUpgrade;
final ITurtleUpgrade m_rightUpgrade;
final ResourceLocation m_overlay;
final boolean m_christmas;
final boolean m_flip;
public TurtleModelCombination( ComputerFamily family, boolean colour, ITurtleUpgrade leftUpgrade, ITurtleUpgrade rightUpgrade, ResourceLocation overlay, boolean christmas, boolean flip )
TurtleModelCombination( boolean colour, ITurtleUpgrade leftUpgrade, ITurtleUpgrade rightUpgrade, ResourceLocation overlay, boolean christmas, boolean flip )
{
m_family = family;
m_colour = colour;
m_leftUpgrade = leftUpgrade;
m_rightUpgrade = rightUpgrade;
@@ -79,8 +71,7 @@ public class TurtleSmartItemModel implements IBakedModel, ISelectiveResourceRelo
if( !(other instanceof TurtleModelCombination) ) return false;
TurtleModelCombination otherCombo = (TurtleModelCombination) other;
return otherCombo.m_family == m_family &&
otherCombo.m_colour == m_colour &&
return otherCombo.m_colour == m_colour &&
otherCombo.m_leftUpgrade == m_leftUpgrade &&
otherCombo.m_rightUpgrade == m_rightUpgrade &&
Objects.equal( otherCombo.m_overlay, m_overlay ) &&
@@ -92,8 +83,7 @@ public class TurtleSmartItemModel implements IBakedModel, ISelectiveResourceRelo
public int hashCode()
{
final int prime = 31;
int result = 1;
result = prime * result + m_family.hashCode();
int result = 0;
result = prime * result + (m_colour ? 1 : 0);
result = prime * result + (m_leftUpgrade != null ? m_leftUpgrade.hashCode() : 0);
result = prime * result + (m_rightUpgrade != null ? m_rightUpgrade.hashCode() : 0);
@@ -104,14 +94,18 @@ public class TurtleSmartItemModel implements IBakedModel, ISelectiveResourceRelo
}
}
private final IBakedModel familyModel;
private final IBakedModel colourModel;
private HashMap<TurtleModelCombination, IBakedModel> m_cachedModels;
private ItemOverrideList m_overrides;
private final TurtleModelCombination m_defaultCombination;
public TurtleSmartItemModel()
public TurtleSmartItemModel( IBakedModel familyModel, IBakedModel colourModel )
{
this.familyModel = familyModel;
this.colourModel = colourModel;
m_cachedModels = new HashMap<>();
m_defaultCombination = new TurtleModelCombination( ComputerFamily.Normal, false, null, null, null, false, false );
m_overrides = new ItemOverrideList( new ArrayList<>() )
{
@Nonnull
@@ -119,7 +113,6 @@ public class TurtleSmartItemModel implements IBakedModel, ISelectiveResourceRelo
public IBakedModel handleItemState( @Nonnull IBakedModel originalModel, @Nonnull ItemStack stack, @Nullable World world, @Nullable EntityLivingBase entity )
{
ItemTurtleBase turtle = (ItemTurtleBase) stack.getItem();
ComputerFamily family = turtle.getFamily( stack );
int colour = turtle.getColour( stack );
ITurtleUpgrade leftUpgrade = turtle.getUpgrade( stack, TurtleSide.Left );
ITurtleUpgrade rightUpgrade = turtle.getUpgrade( stack, TurtleSide.Right );
@@ -127,17 +120,11 @@ public class TurtleSmartItemModel implements IBakedModel, ISelectiveResourceRelo
boolean christmas = HolidayUtil.getCurrentHoliday() == Holiday.Christmas;
String label = turtle.getLabel( stack );
boolean flip = label != null && (label.equals( "Dinnerbone" ) || label.equals( "Grumm" ));
TurtleModelCombination combo = new TurtleModelCombination( family, colour != -1, leftUpgrade, rightUpgrade, overlay, christmas, flip );
if( m_cachedModels.containsKey( combo ) )
{
return m_cachedModels.get( combo );
}
else
{
IBakedModel model = buildModel( combo );
m_cachedModels.put( combo, model );
return model;
}
TurtleModelCombination combo = new TurtleModelCombination( colour != -1, leftUpgrade, rightUpgrade, overlay, christmas, flip );
IBakedModel model = m_cachedModels.get( combo );
if( model == null ) m_cachedModels.put( combo, model = buildModel( combo ) );
return model;
}
};
}
@@ -149,19 +136,13 @@ public class TurtleSmartItemModel implements IBakedModel, ISelectiveResourceRelo
return m_overrides;
}
@Override
public void onResourceManagerReload( @Nonnull IResourceManager resourceManager, @Nonnull Predicate<IResourceType> resourcePredicate )
{
if( resourcePredicate.test( VanillaResourceType.MODELS ) ) m_cachedModels.clear();
}
private IBakedModel buildModel( TurtleModelCombination combo )
{
Minecraft mc = Minecraft.getMinecraft();
ModelManager modelManager = mc.getRenderItem().getItemModelMesher().getModelManager();
ModelResourceLocation baseModelLocation = TileEntityTurtleRenderer.getTurtleModel( combo.m_family, combo.m_colour );
ModelResourceLocation overlayModelLocation = TileEntityTurtleRenderer.getTurtleOverlayModel( combo.m_family, combo.m_overlay, combo.m_christmas );
IBakedModel baseModel = modelManager.getModel( baseModelLocation );
ModelResourceLocation overlayModelLocation = TileEntityTurtleRenderer.getTurtleOverlayModel( combo.m_overlay, combo.m_christmas );
IBakedModel baseModel = combo.m_colour ? colourModel : familyModel;
IBakedModel overlayModel = (overlayModelLocation != null) ? modelManager.getModel( overlayModelLocation ) : null;
Matrix4f transform = combo.m_flip ? s_flip : s_identity;
Pair<IBakedModel, Matrix4f> leftModel = (combo.m_leftUpgrade != null) ? combo.m_leftUpgrade.getModel( null, TurtleSide.Left ) : null;
@@ -184,38 +165,36 @@ public class TurtleSmartItemModel implements IBakedModel, ISelectiveResourceRelo
}
}
// These should not be called:
@Nonnull
@Override
public List<BakedQuad> getQuads( IBlockState state, EnumFacing facing, long rand )
{
return getDefaultModel().getQuads( state, facing, rand );
return familyModel.getQuads( state, facing, rand );
}
@Override
public boolean isAmbientOcclusion()
{
return getDefaultModel().isAmbientOcclusion();
return familyModel.isAmbientOcclusion();
}
@Override
public boolean isGui3d()
{
return getDefaultModel().isGui3d();
return familyModel.isGui3d();
}
@Override
public boolean isBuiltInRenderer()
{
return getDefaultModel().isBuiltInRenderer();
return familyModel.isBuiltInRenderer();
}
@Nonnull
@Override
public TextureAtlasSprite getParticleTexture()
{
return getDefaultModel().getParticleTexture();
return familyModel.getParticleTexture();
}
@Nonnull
@@ -223,18 +202,7 @@ public class TurtleSmartItemModel implements IBakedModel, ISelectiveResourceRelo
@Deprecated
public ItemCameraTransforms getItemCameraTransforms()
{
return getDefaultModel().getItemCameraTransforms();
return familyModel.getItemCameraTransforms();
}
private IBakedModel getDefaultModel()
{
IBakedModel model = m_cachedModels.get( m_defaultCombination );
if( model == null )
{
model = buildModel( m_defaultCombination );
m_cachedModels.put( m_defaultCombination, model );
}
return model;
}
}

View File

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

View File

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

View File

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

View File

@@ -11,6 +11,7 @@ import dan200.computercraft.api.lua.ILuaContext;
import dan200.computercraft.api.lua.LuaException;
import dan200.computercraft.core.computer.IComputerEnvironment;
import dan200.computercraft.core.terminal.Terminal;
import dan200.computercraft.shared.util.Colour;
import dan200.computercraft.shared.util.Palette;
import org.apache.commons.lang3.ArrayUtils;
@@ -65,6 +66,8 @@ public class TermAPI implements ILuaAPI
"setPaletteColor",
"getPaletteColour",
"getPaletteColor",
"nativePaletteColour",
"nativePaletteColor",
"getCursorBlink",
};
}
@@ -289,6 +292,19 @@ public class TermAPI implements ILuaAPI
return null;
}
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
return new Object[] { m_terminal.getCursorBlink() };
default:

View File

@@ -169,27 +169,42 @@ public class BinaryReadableHandle extends HandleGeneric
{
ByteArrayOutputStream stream = new ByteArrayOutputStream();
boolean readAnything = false;
boolean readAnything = false, readRc = false;
while( true )
{
single.clear();
int r = m_reader.read( single );
if( r == -1 ) break;
int read = m_reader.read( single );
if( read <= 0 )
{
// 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;
byte b = single.get( 0 );
if( b == '\n' )
byte chr = single.get( 0 );
if( chr == '\n' )
{
if( withTrailing ) stream.write( b );
break;
if( withTrailing )
{
if( readRc ) stream.write( '\r' );
stream.write( chr );
}
return new Object[] { stream.toByteArray() };
}
else
{
stream.write( b );
// We want to skip \r\n, but obviously need to include cases where \r is not followed by \n.
// 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 )
{

View File

@@ -161,7 +161,10 @@ public class Websocket extends Resource<Websocket>
}
} )
.remoteAddress( socketAddress )
.connect();
.connect()
.addListener( c -> {
if( !c.isSuccess() ) failure( c.cause().getMessage() );
} );
// Do an additional check for cancellation
checkClosed();

View File

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

View File

@@ -0,0 +1,68 @@
/*
* 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,11 +8,10 @@ package dan200.computercraft.core.computer;
import com.google.common.base.Objects;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.api.filesystem.IFileSystem;
import dan200.computercraft.api.filesystem.IMount;
import dan200.computercraft.api.filesystem.IWritableMount;
import dan200.computercraft.api.lua.ILuaAPI;
import dan200.computercraft.api.lua.*;
import dan200.computercraft.api.lua.ILuaAPIFactory;
import dan200.computercraft.api.peripheral.IPeripheral;
import dan200.computercraft.core.apis.*;
import dan200.computercraft.core.filesystem.FileSystem;
@@ -20,11 +19,7 @@ import dan200.computercraft.core.filesystem.FileSystemException;
import dan200.computercraft.core.lua.CobaltLuaMachine;
import dan200.computercraft.core.lua.ILuaMachine;
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.InputStream;
import java.util.ArrayList;
@@ -32,10 +27,6 @@ import java.util.List;
public class Computer
{
public static final String[] s_sideNames = new String[] {
"bottom", "top", "back", "front", "right", "left",
};
private enum State
{
Off,
@@ -44,319 +35,81 @@ public class Computer
Stopping,
}
private static class APIEnvironment implements IAPIEnvironment
{
private Computer m_computer;
private IAPIEnvironment.IPeripheralChangeListener m_peripheralListener;
public APIEnvironment( Computer computer )
{
m_computer = computer;
m_peripheralListener = null;
}
@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 );
}
}
}
}
private static class ComputerSystem extends ComputerAccess implements IComputerSystem
{
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();
}
}
private static class APIWrapper implements ILuaAPI
{
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 );
}
}
private static IMount s_romMount = null;
private int m_id;
private String m_label;
private String m_label = null;
private final IComputerEnvironment m_environment;
private int m_ticksSinceStart;
private boolean m_startRequested;
private State m_state;
private boolean m_blinking;
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;
private final List<ILuaAPI> m_apis;
private final APIEnvironment m_apiEnvironment;
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;
private IWritableMount m_rootMount;
private FileSystem m_fileSystem = null;
private IWritableMount m_rootMount = null;
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 )
{
m_id = id;
m_environment = environment;
m_terminal = terminal;
// Ensure the computer thread is running as required.
ComputerThread.start();
m_id = id;
m_label = null;
m_environment = environment;
// 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 ) );
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++ )
// Load in the API registered APIs.
for( ILuaAPIFactory factory : ApiFactories.getAll() )
{
m_peripherals[i] = null;
ComputerSystem system = new ComputerSystem( m_internalEnvironment );
ILuaAPI api = factory.create( system );
if( api != null ) m_apis.add( new ApiWrapper( api, system ) );
}
}
m_rootMount = null;
createAPIs();
IComputerEnvironment getComputerEnvironment()
{
return m_environment;
}
FileSystem getFileSystem()
{
return m_fileSystem;
}
Terminal getTerminal()
{
return m_terminal;
}
public Environment getEnvironment()
{
return m_internalEnvironment;
}
public IAPIEnvironment getAPIEnvironment()
{
return m_apiEnvironment;
return m_internalEnvironment;
}
public void turnOn()
{
if( m_state == State.Off )
{
m_startRequested = true;
}
if( m_state == State.Off ) m_startRequested = true;
}
public void shutdown()
@@ -397,10 +150,7 @@ public class Computer
public void unload()
{
synchronized( this )
{
stopComputer( false );
}
stopComputer( false );
}
public int getID()
@@ -436,7 +186,7 @@ public class Computer
}
}
public void advance( double _dt )
public void advance()
{
synchronized( this )
{
@@ -453,67 +203,27 @@ public class Computer
if( m_state == State.Running )
{
// Fire the redstone event if our redstone input has changed
synchronized( m_input )
{
if( m_inputChanged )
{
queueEvent( "redstone", null );
m_inputChanged = false;
}
}
// Update the environment's internal state.
m_internalEnvironment.update();
// Advance our APIs
synchronized( m_apis )
{
for( ILuaAPI api : m_apis )
{
api.update();
}
}
for( ILuaAPI api : m_apis ) api.update();
}
}
// Set outputchanged if the internal redstone has changed
synchronized( m_internalOutput )
{
if( m_internalOutputChanged )
{
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;
}
}
}
// Prepare to propagate the environment's output to the world.
if( m_internalEnvironment.updateOutput() ) 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();
// 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;
m_externalOutputChanged = true;
}
if( blinking != m_blinking )
{
m_blinking = blinking;
m_externalOutputChanged = true;
}
}
@@ -529,10 +239,7 @@ public class Computer
public boolean isBlinking()
{
synchronized( m_terminal )
{
return isOn() && m_blinking;
}
return isOn() && m_blinking;
}
public IWritableMount getRootMount()
@@ -553,10 +260,7 @@ public class Computer
try
{
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 )
{
m_fileSystem.mount( "rom", "rom", s_romMount );
@@ -571,104 +275,6 @@ 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
public void addAPI( ILuaAPI api )
@@ -676,57 +282,8 @@ public class Computer
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
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()
{
// Create the lua machine
@@ -824,10 +381,7 @@ public class Computer
}
// Init terminal
synchronized( m_terminal )
{
m_terminal.reset();
}
m_terminal.reset();
// Init filesystem
if( !initFileSystem() )
@@ -920,10 +474,7 @@ public class Computer
if( m_machine != null )
{
synchronized( m_terminal )
{
m_terminal.reset();
}
m_terminal.reset();
synchronized( m_machine )
{
@@ -933,15 +484,7 @@ public class Computer
}
// Reset redstone output
synchronized( m_internalOutput )
{
for( int i = 0; i < 6; i++ )
{
m_internalOutput[i] = 0;
m_internalBundledOutput[i] = 0;
}
m_internalOutputChanged = true;
}
m_internalEnvironment.resetOutput();
m_state = State.Off;
m_externalOutputChanged = true;
@@ -1002,4 +545,23 @@ public class Computer
ComputerThread.queueTask( task, computer );
}
@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();
}
}

View File

@@ -0,0 +1,58 @@
/*
* 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

@@ -16,6 +16,7 @@ import java.util.WeakHashMap;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.locks.LockSupport;
public class ComputerThread
{
@@ -216,22 +217,37 @@ public class ComputerThread
// Interrupt the thread
if( !done )
{
StringBuilder builder = new StringBuilder( "Terminating " );
if( computer != null )
if( ComputerCraft.logPeripheralErrors )
{
builder.append( "computer " ).append( computer.getID() );
}
else
{
builder.append( "unknown computer" );
}
long time = System.nanoTime() - start;
StringBuilder builder = new StringBuilder( "Terminating " );
if( computer != null )
{
builder.append( "computer #" ).append( computer.getID() );
}
else
{
builder.append( "unknown computer" );
}
builder.append( ". Thread is currently running" );
for( StackTraceElement element : thread.getStackTrace() )
{
builder.append( "\n at " ).append( element );
{
builder.append( " due to timeout (running for " )
.append( time / 1e9 )
.append( " seconds). This is NOT a bug, but may mean a computer is misbehaving. " )
.append( thread.getName() )
.append( " is currently " )
.append( thread.getState() );
Object blocking = LockSupport.getBlocker( thread );
if( blocking != null ) builder.append( "\n on " ).append( blocking );
for( StackTraceElement element : thread.getStackTrace() )
{
builder.append( "\n at " ).append( element );
}
}
ComputerCraft.log.warn( builder.toString() );
}
ComputerCraft.log.error( builder.toString() );
thread.interrupt();
thread = null;

View File

@@ -0,0 +1,306 @@
/*
* 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

@@ -46,7 +46,7 @@ public class CobaltLuaMachine implements ILuaMachine
{
private static final ThreadPoolExecutor coroutines = new ThreadPoolExecutor(
0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
5L, TimeUnit.MINUTES,
new SynchronousQueue<>(),
ThreadUtils.factory( "Coroutine" )
);
@@ -74,12 +74,12 @@ public class CobaltLuaMachine implements ILuaMachine
private boolean hasSoftAbort;
@Override
public void onInstruction( DebugState ds, DebugFrame di, int pc, Varargs extras, int top ) throws LuaError
public void onInstruction( DebugState ds, DebugFrame di, int pc ) throws LuaError, UnwindThrowable
{
int count = ++this.count;
if( count > 100000 )
{
if( m_hardAbortMessage != null ) LuaThread.yield( m_state, NONE );
if( m_hardAbortMessage != null ) throw HardAbortError.INSTANCE;
this.count = 0;
}
else
@@ -87,13 +87,13 @@ public class CobaltLuaMachine implements ILuaMachine
handleSoftAbort();
}
super.onInstruction( ds, di, pc, extras, top );
super.onInstruction( ds, di, pc );
}
@Override
public void poll() throws LuaError
{
if( m_hardAbortMessage != null ) LuaThread.yield( m_state, NONE );
if( m_hardAbortMessage != null ) throw HardAbortError.INSTANCE;
handleSoftAbort();
}
@@ -117,7 +117,7 @@ public class CobaltLuaMachine implements ILuaMachine
throw new LuaError( message );
}
} )
.coroutineFactory( command -> {
.yieldThreader( command -> {
Tracking.addValue( m_computer, TrackingField.COROUTINES_CREATED, 1 );
coroutines.execute( () -> {
try
@@ -145,10 +145,10 @@ public class CobaltLuaMachine implements ILuaMachine
if( ComputerCraft.debug_enable ) m_globals.load( state, new DebugLib() );
// Register custom load/loadstring provider which automatically adds prefixes.
LibFunction.bind( state, m_globals, PrefixLoader.class, new String[] { "load", "loadstring" } );
LibFunction.bind( m_globals, PrefixLoader.class, new String[] { "load", "loadstring" } );
// Remove globals we don't want to expose
// m_globals.rawset( "collectgarbage", Constants.NIL );
m_globals.rawset( "collectgarbage", Constants.NIL );
m_globals.rawset( "dofile", Constants.NIL );
m_globals.rawset( "loadfile", Constants.NIL );
m_globals.rawset( "print", Constants.NIL );
@@ -222,26 +222,18 @@ public class CobaltLuaMachine implements ILuaMachine
resumeArgs = varargsOf( valueOf( eventName ), toValues( arguments ) );
}
Varargs results = m_mainRoutine.resume( resumeArgs );
if( m_hardAbortMessage != null )
{
throw new LuaError( m_hardAbortMessage );
}
else if( !results.first().checkBoolean() )
{
throw new LuaError( results.arg( 2 ).checkString() );
}
else
{
LuaValue filter = results.arg( 2 );
m_eventFilter = filter.isString() ? filter.toString() : null;
}
Varargs results = LuaThread.run( m_mainRoutine, resumeArgs );
if( m_hardAbortMessage != null ) throw new LuaError( m_hardAbortMessage );
LuaValue filter = results.first();
m_eventFilter = filter.isString() ? filter.toString() : null;
if( m_mainRoutine.getStatus().equals( "dead" ) ) unload();
}
catch( LuaError e )
catch( LuaError | HardAbortError e )
{
unload();
ComputerCraft.log.warn( "Top level coroutine errored", e );
}
finally
{
@@ -339,16 +331,12 @@ public class CobaltLuaMachine implements ILuaMachine
{
try
{
Varargs results = LuaThread.yield( state, toValues( yieldArgs ) );
Varargs results = LuaThread.yieldBlocking( state, toValues( yieldArgs ) );
return toObjects( results, 1 );
}
catch( OrphanedThread e )
catch( LuaError e )
{
throw new InterruptedException();
}
catch( Throwable e )
{
throw new RuntimeException( e );
throw new IllegalStateException( e );
}
}
@@ -699,7 +687,7 @@ public class CobaltLuaMachine implements ILuaMachine
LuaValue s;
try
{
s = OperationHelper.call( state, func );
s = OperationHelper.noYield( state, () -> OperationHelper.call( state, func ) );
}
catch( LuaError e )
{
@@ -731,4 +719,16 @@ public class CobaltLuaMachine implements ILuaMachine
return bytes[offset++];
}
}
private static class HardAbortError extends Error
{
private static final long serialVersionUID = 7954092008586367501L;
public static final HardAbortError INSTANCE = new HardAbortError();
private HardAbortError()
{
super( "Hard Abort", null, true, false );
}
}
}

View File

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

View File

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

View File

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

View File

@@ -11,11 +11,9 @@ import net.minecraft.block.ITileEntityProvider;
import net.minecraft.block.material.Material;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.EnumHand;
import net.minecraft.util.NonNullList;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;
@@ -35,108 +33,36 @@ public abstract class BlockGeneric extends Block implements ITileEntityProvider
protected abstract TileGeneric createTile( int damage );
@Override
public final void dropBlockAsItemWithChance( World world, @Nonnull BlockPos pos, @Nonnull IBlockState state, float chance, int fortune )
{
}
@Override
public final void getDrops( @Nonnull NonNullList<ItemStack> drops, IBlockAccess world, BlockPos pos, @Nonnull IBlockState state, int fortune )
{
TileEntity tile = world.getTileEntity( pos );
if( tile instanceof TileGeneric )
{
TileGeneric generic = (TileGeneric) tile;
generic.getDroppedItems( drops, false );
}
}
@Override
public boolean removedByPlayer( @Nonnull IBlockState state, World world, @Nonnull BlockPos pos, @Nonnull EntityPlayer player, boolean willHarvest )
{
if( !world.isRemote )
{
// Drop items
boolean creative = player.capabilities.isCreativeMode;
dropAllItems( world, pos, creative );
}
// Remove block
return super.removedByPlayer( state, world, pos, player, willHarvest );
}
public final void dropAllItems( World world, BlockPos pos, boolean creative )
{
// Get items to drop
NonNullList<ItemStack> drops = NonNullList.create();
TileEntity tile = world.getTileEntity( pos );
if( tile instanceof TileGeneric )
{
TileGeneric generic = (TileGeneric) tile;
generic.getDroppedItems( drops, creative );
}
// Drop items
if( drops.size() > 0 )
{
for( ItemStack item : drops )
{
dropItem( world, pos, item );
}
}
}
public final void dropItem( World world, BlockPos pos, @Nonnull ItemStack stack )
{
Block.spawnAsEntity( world, pos, stack );
}
@Override
public final void breakBlock( @Nonnull World world, @Nonnull BlockPos pos, @Nonnull IBlockState newState )
{
TileEntity tile = world.getTileEntity( pos );
super.breakBlock( world, pos, newState );
world.removeTileEntity( pos );
if( tile instanceof TileGeneric )
{
TileGeneric generic = (TileGeneric) tile;
generic.destroy();
}
if( tile instanceof TileGeneric ) ((TileGeneric) tile).destroy();
}
@Override
public final boolean onBlockActivated( World world, BlockPos pos, IBlockState state, EntityPlayer player, EnumHand hand, EnumFacing side, float hitX, float hitY, float hitZ )
{
TileEntity tile = world.getTileEntity( pos );
if( tile instanceof TileGeneric )
{
TileGeneric generic = (TileGeneric) tile;
return generic.onActivate( player, hand, side, hitX, hitY, hitZ );
}
return false;
return tile instanceof TileGeneric && ((TileGeneric) tile).onActivate( player, hand, side, hitX, hitY, hitZ );
}
@Override
@Deprecated
public final void neighborChanged( IBlockState state, World world, BlockPos pos, Block block, BlockPos neighorPos )
@SuppressWarnings( "deprecation" )
public final void neighborChanged( IBlockState state, World world, BlockPos pos, Block block, BlockPos neighbour )
{
TileEntity tile = world.getTileEntity( pos );
if( tile instanceof TileGeneric )
{
TileGeneric generic = (TileGeneric) tile;
generic.onNeighbourChange();
}
if( tile instanceof TileGeneric ) ((TileGeneric) tile).onNeighbourChange( neighbour );
}
@Override
public final void onNeighborChange( IBlockAccess world, BlockPos pos, BlockPos neighbour )
{
TileEntity tile = world.getTileEntity( pos );
if( tile instanceof TileGeneric )
{
TileGeneric generic = (TileGeneric) tile;
generic.onNeighbourTileEntityChange( neighbour );
}
if( tile instanceof TileGeneric ) ((TileGeneric) tile).onNeighbourTileEntityChange( neighbour );
}
@Override
@@ -157,12 +83,7 @@ public abstract class BlockGeneric extends Block implements ITileEntityProvider
public final boolean canConnectRedstone( IBlockState state, IBlockAccess world, BlockPos pos, EnumFacing side )
{
TileEntity tile = world.getTileEntity( pos );
if( tile instanceof TileGeneric )
{
TileGeneric generic = (TileGeneric) tile;
return generic.getRedstoneConnectivity( side );
}
return false;
return tile instanceof TileGeneric && ((TileGeneric) tile).getRedstoneConnectivity( side );
}
@Override
@@ -172,8 +93,7 @@ public abstract class BlockGeneric extends Block implements ITileEntityProvider
TileEntity tile = world.getTileEntity( pos );
if( tile instanceof TileGeneric && tile.hasWorld() )
{
TileGeneric generic = (TileGeneric) tile;
return generic.getRedstoneOutput( oppositeSide.getOpposite() );
return ((TileGeneric) tile).getRedstoneOutput( oppositeSide.getOpposite() );
}
return 0;
}
@@ -190,8 +110,7 @@ public abstract class BlockGeneric extends Block implements ITileEntityProvider
TileEntity tile = world.getTileEntity( pos );
if( tile instanceof TileGeneric )
{
TileGeneric generic = (TileGeneric) tile;
return generic.getBundledRedstoneConnectivity( side );
return ((TileGeneric) tile).getBundledRedstoneConnectivity( side );
}
return false;
}
@@ -201,8 +120,7 @@ public abstract class BlockGeneric extends Block implements ITileEntityProvider
TileEntity tile = world.getTileEntity( pos );
if( tile instanceof TileGeneric && tile.hasWorld() )
{
TileGeneric generic = (TileGeneric) tile;
return generic.getBundledRedstoneOutput( side );
return ((TileGeneric) tile).getBundledRedstoneOutput( side );
}
return 0;
}

View File

@@ -9,14 +9,12 @@ package dan200.computercraft.shared.common;
import net.minecraft.block.Block;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.network.NetworkManager;
import net.minecraft.network.play.server.SPacketUpdateTileEntity;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.EnumHand;
import net.minecraft.util.NonNullList;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
@@ -55,19 +53,22 @@ public abstract class TileGeneric extends TileEntity
getWorld().setBlockState( getPos(), newState, 3 );
}
public void getDroppedItems( @Nonnull NonNullList<ItemStack> drops, boolean creative )
{
}
public boolean onActivate( EntityPlayer player, EnumHand hand, EnumFacing side, float hitX, float hitY, float hitZ )
{
return false;
}
@Deprecated
public void onNeighbourChange()
{
}
@SuppressWarnings( "deprecation" )
public void onNeighbourChange( @Nonnull BlockPos neighbour )
{
onNeighbourChange();
}
public void onNeighbourTileEntityChange( @Nonnull BlockPos neighbour )
{
}

View File

@@ -8,11 +8,13 @@ package dan200.computercraft.shared.computer.blocks;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.shared.computer.core.ComputerFamily;
import dan200.computercraft.shared.computer.items.ComputerItemFactory;
import net.minecraft.block.material.Material;
import net.minecraft.block.properties.PropertyDirection;
import net.minecraft.block.properties.PropertyEnum;
import net.minecraft.block.state.BlockStateContainer;
import net.minecraft.block.state.IBlockState;
import net.minecraft.item.ItemStack;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos;
@@ -103,4 +105,11 @@ public class BlockCommandComputer extends BlockComputerBase
{
return new TileCommandComputer();
}
@Nonnull
@Override
protected ItemStack getItem( TileComputerBase tile )
{
return tile instanceof TileCommandComputer ? ComputerItemFactory.create( (TileComputer) tile ) : ItemStack.EMPTY;
}
}

View File

@@ -15,14 +15,11 @@ import net.minecraft.block.properties.PropertyDirection;
import net.minecraft.block.properties.PropertyEnum;
import net.minecraft.block.state.BlockStateContainer;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;
import javax.annotation.Nonnull;
@@ -136,9 +133,8 @@ public class BlockComputer extends BlockComputerBase
@Nonnull
@Override
public ItemStack getPickBlock( @Nonnull IBlockState state, RayTraceResult target, @Nonnull World world, @Nonnull BlockPos pos, EntityPlayer player )
protected ItemStack getItem( TileComputerBase tile )
{
TileEntity tile = world.getTileEntity( pos );
return tile instanceof TileComputer ? ComputerItemFactory.create( (TileComputer) tile ) : super.getPickBlock( state, target, world, pos, player );
return tile instanceof TileComputer ? ComputerItemFactory.create( (TileComputer) tile ) : ItemStack.EMPTY;
}
}

View File

@@ -12,9 +12,13 @@ import dan200.computercraft.shared.util.DirectionUtil;
import net.minecraft.block.material.Material;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.NonNullList;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;
@@ -49,6 +53,9 @@ public abstract class BlockComputerBase extends BlockDirectional
protected abstract TileComputerBase createTile( ComputerFamily family );
@Nonnull
protected abstract ItemStack getItem( TileComputerBase tile );
@Nonnull
@Override
@Deprecated
@@ -83,4 +90,55 @@ public abstract class BlockComputerBase extends BlockDirectional
computer.updateInput();
}
}
@Override
@Nonnull
public ItemStack getPickBlock( @Nonnull IBlockState state, RayTraceResult target, @Nonnull World world, @Nonnull BlockPos pos, EntityPlayer player )
{
TileEntity tile = world.getTileEntity( pos );
if( tile instanceof TileComputerBase )
{
ItemStack result = getItem( (TileComputerBase) tile );
if( !result.isEmpty() ) return result;
}
return super.getPickBlock( state, target, world, pos, player );
}
@Override
public final void dropBlockAsItemWithChance( World world, @Nonnull BlockPos pos, @Nonnull IBlockState state, float chance, int fortune )
{
}
@Override
public final void getDrops( @Nonnull NonNullList<ItemStack> drops, IBlockAccess world, BlockPos pos, @Nonnull IBlockState state, int fortune )
{
TileEntity tile = world.getTileEntity( pos );
if( tile instanceof TileComputerBase )
{
ItemStack stack = getItem( (TileComputerBase) tile );
if( !stack.isEmpty() ) drops.add( stack );
}
}
@Override
public boolean removedByPlayer( @Nonnull IBlockState state, World world, @Nonnull BlockPos pos, @Nonnull EntityPlayer player, boolean willHarvest )
{
if( !world.isRemote )
{
// We drop the item here instead of doing it in the harvest method, as we
// need to drop it for creative players too.
TileEntity tile = world.getTileEntity( pos );
if( tile instanceof TileComputerBase )
{
TileComputerBase computer = (TileComputerBase) tile;
if( !player.capabilities.isCreativeMode || computer.getLabel() != null )
{
spawnAsEntity( world, pos, getItem( computer ) );
}
}
}
return super.removedByPlayer( state, world, pos, player, willHarvest );
}
}

View File

@@ -9,13 +9,10 @@ package dan200.computercraft.shared.computer.blocks;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.shared.computer.core.ComputerFamily;
import dan200.computercraft.shared.computer.core.ServerComputer;
import dan200.computercraft.shared.computer.items.ComputerItemFactory;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.NonNullList;
import javax.annotation.Nonnull;
@@ -60,12 +57,6 @@ public class TileComputer extends TileComputerBase
return m_proxy;
}
@Override
public void getDroppedItems( @Nonnull NonNullList<ItemStack> drops, boolean creative )
{
if( !creative || getLabel() != null ) drops.add( ComputerItemFactory.create( this ) );
}
@Override
public void openGUI( EntityPlayer player )
{

View File

@@ -173,9 +173,9 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT
}
@Override
public void onNeighbourChange()
public void onNeighbourChange( @Nonnull BlockPos neighbour )
{
updateInput();
updateInput( neighbour );
}
@Override
@@ -296,7 +296,7 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT
int localDir = remapLocalSide( DirectionUtil.toLocal( this, dir ) );
if( !isRedstoneBlockedOnSide( localDir ) )
{
computer.setRedstoneInput( localDir, getWorld().getRedstonePower( offset, offsetSide ) );
computer.setRedstoneInput( localDir, getWorld().getRedstonePower( offset, dir ) );
computer.setBundledRedstoneInput( localDir, BundledRedstone.getOutput( getWorld(), offset, offsetSide ) );
}
if( !isPeripheralBlockedOnSide( localDir ) )

View File

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

View File

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

View File

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

View File

@@ -29,6 +29,7 @@ import net.minecraft.item.ItemStack;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.BlockRenderLayer;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.NonNullList;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.RayTraceResult;
@@ -375,17 +376,9 @@ public class BlockPeripheral extends BlockGeneric
{
case DiskDrive:
default:
{
IBlockState state = getDefaultState().withProperty( Properties.VARIANT, BlockPeripheralVariant.DiskDriveEmpty );
if( placedSide.getAxis() != EnumFacing.Axis.Y )
{
return state.withProperty( Properties.FACING, placedSide );
}
else
{
return state.withProperty( Properties.FACING, EnumFacing.NORTH );
}
}
return getDefaultState()
.withProperty( Properties.VARIANT, BlockPeripheralVariant.DiskDriveEmpty )
.withProperty( Properties.FACING, placedSide.getAxis() == EnumFacing.Axis.Y ? EnumFacing.NORTH : placedSide );
case WirelessModem:
{
EnumFacing dir = placedSide.getOpposite();
@@ -409,21 +402,13 @@ public class BlockPeripheral extends BlockGeneric
}
}
case Monitor:
{
return getDefaultState().withProperty( Properties.VARIANT, BlockPeripheralVariant.Monitor );
}
case Printer:
{
return getDefaultState().withProperty( Properties.VARIANT, BlockPeripheralVariant.PrinterEmpty );
}
case AdvancedMonitor:
{
return getDefaultState().withProperty( Properties.VARIANT, BlockPeripheralVariant.AdvancedMonitor );
}
case Speaker:
{
return getDefaultState().withProperty( Properties.VARIANT, BlockPeripheralVariant.Speaker );
}
}
}
@@ -465,19 +450,15 @@ public class BlockPeripheral extends BlockGeneric
case Speaker:
case DiskDrive:
case Printer:
{
EnumFacing dir = DirectionUtil.fromEntityRot( player );
if( stack.hasDisplayName() && tile instanceof TilePeripheralBase )
if( tile instanceof TilePeripheralBase )
{
TilePeripheralBase peripheral = (TilePeripheralBase) tile;
peripheral.setLabel( stack.getDisplayName() );
peripheral.setDirection( dir );
peripheral.setDirection( DirectionUtil.fromEntityRot( player ) );
if( stack.hasDisplayName() ) peripheral.setLabel( stack.getDisplayName() );
}
break;
}
case Monitor:
case AdvancedMonitor:
{
if( tile instanceof TileMonitor )
{
int direction = DirectionUtil.fromEntityRot( player ).getIndex();
@@ -504,7 +485,6 @@ public class BlockPeripheral extends BlockGeneric
}
}
break;
}
}
}
@@ -600,4 +580,10 @@ public class BlockPeripheral extends BlockGeneric
? PeripheralItemFactory.create( (ITilePeripheral) tile )
: super.getPickBlock( state, target, world, pos, player );
}
@Override
public void getDrops( @Nonnull NonNullList<ItemStack> drops, IBlockAccess world, BlockPos pos, @Nonnull IBlockState state, int fortune )
{
drops.add( PeripheralItemFactory.create( getPeripheralType( state ), null, 1 ) );
}
}

View File

@@ -10,11 +10,9 @@ import dan200.computercraft.api.peripheral.IPeripheral;
import dan200.computercraft.shared.common.IDirectionalTile;
import dan200.computercraft.shared.common.TileGeneric;
import dan200.computercraft.shared.peripheral.PeripheralType;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.ITickable;
import net.minecraft.util.NonNullList;
import javax.annotation.Nonnull;
@@ -42,15 +40,6 @@ public abstract class TilePeripheralBase extends TileGeneric implements IPeriphe
return (BlockPeripheral) super.getBlock();
}
@Override
public void getDroppedItems( @Nonnull NonNullList<ItemStack> drops, boolean creative )
{
if( !creative )
{
drops.add( PeripheralItemFactory.create( this ) );
}
}
@Override
public final PeripheralType getPeripheralType()
{

View File

@@ -14,6 +14,7 @@ import dan200.computercraft.shared.common.TileGeneric;
import dan200.computercraft.shared.peripheral.PeripheralType;
import dan200.computercraft.shared.peripheral.common.PeripheralItemFactory;
import dan200.computercraft.shared.util.WorldUtil;
import net.minecraft.block.Block;
import net.minecraft.block.material.Material;
import net.minecraft.block.properties.PropertyBool;
import net.minecraft.block.properties.PropertyEnum;
@@ -26,6 +27,7 @@ import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.NonNullList;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.RayTraceResult;
@@ -322,7 +324,10 @@ public class BlockCable extends BlockGeneric
cable.modemChanged();
cable.connectionsChanged();
if( !world.isRemote && !player.capabilities.isCreativeMode ) dropItem( world, pos, item );
if( !world.isRemote && !player.capabilities.isCreativeMode )
{
Block.spawnAsEntity( world, pos, item );
}
return false;
}
@@ -332,6 +337,23 @@ public class BlockCable extends BlockGeneric
return super.removedByPlayer( state, world, pos, player, willHarvest );
}
@Override
public void getDrops( @Nonnull NonNullList<ItemStack> drops, IBlockAccess world, BlockPos pos, @Nonnull IBlockState state, int fortune )
{
PeripheralType type = getPeripheralType( state );
switch( type )
{
case Cable:
case WiredModem:
drops.add( PeripheralItemFactory.create( type, null, 1 ) );
break;
case WiredModemWithCable:
drops.add( PeripheralItemFactory.create( PeripheralType.WiredModem, null, 1 ) );
drops.add( PeripheralItemFactory.create( PeripheralType.Cable, null, 1 ) );
break;
}
}
@Nonnull
@Override
public ItemStack getPickBlock( @Nonnull IBlockState state, RayTraceResult hit, @Nonnull World world, @Nonnull BlockPos pos, EntityPlayer player )

View File

@@ -20,13 +20,12 @@ import dan200.computercraft.shared.peripheral.common.PeripheralItemFactory;
import dan200.computercraft.shared.peripheral.modem.ModemState;
import dan200.computercraft.shared.util.TickScheduler;
import dan200.computercraft.shared.wired.CapabilityWiredElement;
import net.minecraft.block.Block;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.EnumHand;
import net.minecraft.util.NonNullList;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
import net.minecraft.util.text.TextComponentTranslation;
@@ -177,44 +176,17 @@ public class TileCable extends TileGeneric implements IPeripheralTile
}
@Override
public void getDroppedItems( @Nonnull NonNullList<ItemStack> drops, boolean creative )
{
if( !creative )
{
PeripheralType type = getPeripheralType();
switch( type )
{
case Cable:
case WiredModem:
{
drops.add( PeripheralItemFactory.create( type, null, 1 ) );
break;
}
case WiredModemWithCable:
{
drops.add( PeripheralItemFactory.create( PeripheralType.WiredModem, null, 1 ) );
drops.add( PeripheralItemFactory.create( PeripheralType.Cable, null, 1 ) );
break;
}
}
}
}
@Override
public void onNeighbourChange()
public void onNeighbourChange( @Nonnull BlockPos neighbour )
{
EnumFacing dir = getDirection();
if( !getWorld().isSideSolid(
getPos().offset( dir ),
dir.getOpposite()
) )
if( neighbour.equals( getPos().offset( dir ) ) && !getWorld().isSideSolid( neighbour, dir.getOpposite() ) )
{
switch( getPeripheralType() )
{
case WiredModem:
{
// Drop everything and remove block
getBlock().dropAllItems( getWorld(), getPos(), false );
getBlock().dropBlockAsItem( getWorld(), getPos(), getBlockState(), 0 );
getWorld().setBlockToAir( getPos() );
// This'll call #destroy(), so we don't need to reset the network here.
@@ -223,7 +195,7 @@ public class TileCable extends TileGeneric implements IPeripheralTile
case WiredModemWithCable:
{
// Drop the modem and convert to cable
getBlock().dropItem( getWorld(), getPos(), PeripheralItemFactory.create( PeripheralType.WiredModem, null, 1 ) );
Block.spawnAsEntity( getWorld(), getPos(), PeripheralItemFactory.create( PeripheralType.WiredModem, null, 1 ) );
setBlockState( getBlockState().withProperty( BlockCable.Properties.MODEM, BlockCableModemVariant.None ) );
modemChanged();
connectionsChanged();

View File

@@ -7,7 +7,6 @@
package dan200.computercraft.shared.peripheral.modem.wired;
import com.google.common.base.Objects;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.api.ComputerCraftAPI;
import dan200.computercraft.api.network.wired.IWiredElement;
import dan200.computercraft.api.network.wired.IWiredNode;
@@ -19,11 +18,9 @@ import dan200.computercraft.shared.peripheral.modem.ModemState;
import dan200.computercraft.shared.util.TickScheduler;
import dan200.computercraft.shared.wired.CapabilityWiredElement;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.EnumHand;
import net.minecraft.util.NonNullList;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
import net.minecraft.util.text.TextComponentString;
@@ -136,24 +133,9 @@ public class TileWiredModemFull extends TileGeneric implements IPeripheralTile
}
@Override
public void getDroppedItems( @Nonnull NonNullList<ItemStack> drops, boolean creative )
public void onNeighbourChange( @Nonnull BlockPos neighbour )
{
drops.add( new ItemStack( ComputerCraft.Items.wiredModemFull ) );
}
@Override
public void onNeighbourChange()
{
if( !world.isRemote && m_peripheralAccessAllowed )
{
boolean hasChanged = false;
for( EnumFacing facing : EnumFacing.VALUES )
{
hasChanged |= m_peripherals[facing.ordinal()].attach( world, getPos(), facing );
}
if( hasChanged ) updateConnectedPeripherals();
}
onNeighbourTileEntityChange( neighbour );
}
@Override

View File

@@ -6,24 +6,18 @@
package dan200.computercraft.shared.peripheral.modem.wireless;
import dan200.computercraft.ComputerCraft;
import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.NonNullList;
import javax.annotation.Nonnull;
public class TileAdvancedModem extends TileWirelessModemBase
{
public TileAdvancedModem()
{
super( true );
}
@Override
protected EnumFacing getDirection()
{
return getBlockState().getValue( BlockAdvancedModem.Properties.FACING );
}
@Override
public void getDroppedItems( @Nonnull NonNullList<ItemStack> drops, boolean creative )
{
if( !creative ) drops.add( new ItemStack( ComputerCraft.Items.advancedModem ) );
}
}

View File

@@ -12,11 +12,8 @@ import dan200.computercraft.shared.peripheral.PeripheralType;
import dan200.computercraft.shared.peripheral.common.BlockPeripheral;
import dan200.computercraft.shared.peripheral.common.BlockPeripheralVariant;
import dan200.computercraft.shared.peripheral.common.ITilePeripheral;
import dan200.computercraft.shared.peripheral.common.PeripheralItemFactory;
import net.minecraft.block.state.IBlockState;
import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.NonNullList;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
@@ -24,6 +21,11 @@ import javax.annotation.Nonnull;
public class TileWirelessModem extends TileWirelessModemBase implements IDirectionalTile, ITilePeripheral
{
public TileWirelessModem()
{
super( false );
}
@Override
public EnumFacing getDirection()
{
@@ -75,12 +77,6 @@ public class TileWirelessModem extends TileWirelessModemBase implements IDirecti
return super.shouldRefresh( world, pos, oldState, newState ) || ComputerCraft.Blocks.peripheral.getPeripheralType( newState ) != PeripheralType.WirelessModem;
}
@Override
public void getDroppedItems( @Nonnull NonNullList<ItemStack> drops, boolean creative )
{
if( !creative ) drops.add( PeripheralItemFactory.create( PeripheralType.WirelessModem, null, 1 ) );
}
@Override
public PeripheralType getPeripheralType()
{

View File

@@ -22,13 +22,19 @@ import javax.annotation.Nonnull;
public abstract class TileWirelessModemBase extends TileGeneric implements IPeripheralTile
{
protected TileWirelessModemBase( boolean advanced )
{
this.advanced = advanced;
this.modem = new Peripheral( this ); // Needs to be initialised after advanced
}
private static class Peripheral extends WirelessModemPeripheral
{
private final TileWirelessModemBase entity;
Peripheral( TileWirelessModemBase entity )
{
super( new ModemState( () -> TickScheduler.schedule( entity ) ), true );
super( new ModemState( () -> TickScheduler.schedule( entity ) ), entity.advanced );
this.entity = entity;
}
@@ -54,9 +60,10 @@ public abstract class TileWirelessModemBase extends TileGeneric implements IPeri
}
}
private final boolean advanced;
private boolean hasModemDirection = false;
private EnumFacing modemDirection = EnumFacing.DOWN;
private final ModemPeripheral modem = new Peripheral( this );
private final ModemPeripheral modem;
private boolean destroyed = false;
private boolean on = false;
@@ -115,13 +122,13 @@ public abstract class TileWirelessModemBase extends TileGeneric implements IPeri
protected abstract EnumFacing getDirection();
@Override
public void onNeighbourChange()
public void onNeighbourChange( @Nonnull BlockPos neighbour )
{
EnumFacing dir = getDirection();
if( !getWorld().isSideSolid( getPos().offset( dir ), dir.getOpposite() ) )
if( neighbour.equals( getPos().offset( dir ) ) && !getWorld().isSideSolid( neighbour, dir.getOpposite() ) )
{
// Drop everything and remove block
getBlock().dropAllItems( getWorld(), getPos(), false );
getBlock().dropBlockAsItem( getWorld(), getPos(), getBlockState(), 0 );
getWorld().setBlockToAir( getPos() );
}
}

View File

@@ -28,8 +28,6 @@ public class MonitorPeripheral implements IPeripheral
m_monitor = monitor;
}
// IPeripheral implementation
@Nonnull
@Override
public String getType()

View File

@@ -16,27 +16,23 @@ import dan200.computercraft.shared.peripheral.PeripheralType;
import dan200.computercraft.shared.peripheral.common.BlockPeripheral;
import dan200.computercraft.shared.peripheral.common.IPeripheralTile;
import dan200.computercraft.shared.peripheral.common.ITilePeripheral;
import dan200.computercraft.shared.peripheral.common.PeripheralItemFactory;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.EnumHand;
import net.minecraft.util.NonNullList;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import javax.annotation.Nonnull;
import java.util.HashSet;
import java.util.Collections;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
public class TileMonitor extends TileGeneric implements ITilePeripheral, IPeripheralTile
{
// Statics
public static final double RENDER_BORDER = (2.0 / 16.0);
public static final double RENDER_MARGIN = (0.5 / 16.0);
public static final double RENDER_PIXEL_SCALE = (1.0 / 64.0);
@@ -44,39 +40,23 @@ public class TileMonitor extends TileGeneric implements ITilePeripheral, IPeriph
private static final int MAX_WIDTH = 8;
private static final int MAX_HEIGHT = 6;
// Members
private ServerMonitor m_serverMonitor;
private ClientMonitor m_clientMonitor;
private MonitorPeripheral m_peripheral;
private final Set<IComputerAccess> m_computers;
private final Set<IComputerAccess> m_computers = Collections.newSetFromMap( new ConcurrentHashMap<>() );
private boolean m_destroyed;
private boolean m_ignoreMe;
private boolean m_destroyed = false;
private boolean m_ignoreMe = false;
private int m_width;
private int m_height;
private int m_xIndex;
private int m_yIndex;
private int m_width = 1;
private int m_height = 1;
private int m_xIndex = 0;
private int m_yIndex = 0;
private int m_dir;
private int m_dir = 2;
private boolean m_advanced;
public TileMonitor()
{
m_computers = new HashSet<>();
m_destroyed = false;
m_ignoreMe = false;
m_width = 1;
m_height = 1;
m_xIndex = 0;
m_yIndex = 0;
m_dir = 2;
}
@Override
public void onLoad()
{
@@ -697,20 +677,14 @@ public class TileMonitor extends TileGeneric implements ITilePeripheral, IPeriph
}
}
public void addComputer( IComputerAccess computer )
void addComputer( IComputerAccess computer )
{
synchronized( this )
{
m_computers.add( computer );
}
m_computers.add( computer );
}
public void removeComputer( IComputerAccess computer )
void removeComputer( IComputerAccess computer )
{
synchronized( this )
{
m_computers.remove( computer );
}
m_computers.remove( computer );
}
@Nonnull
@@ -757,10 +731,4 @@ public class TileMonitor extends TileGeneric implements ITilePeripheral, IPeriph
}
}
}
@Override
public void getDroppedItems( @Nonnull NonNullList<ItemStack> drops, boolean creative )
{
if( !creative ) drops.add( PeripheralItemFactory.create( this ) );
}
}

View File

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

View File

@@ -27,7 +27,6 @@ import net.minecraft.util.EnumBlockRenderType;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;
@@ -200,11 +199,10 @@ public class BlockTurtle extends BlockComputerBase
return super.getExplosionResistance( exploder );
}
@Override
@Nonnull
public ItemStack getPickBlock( @Nonnull IBlockState state, RayTraceResult target, @Nonnull World world, @Nonnull BlockPos pos, EntityPlayer player )
@Override
protected ItemStack getItem( TileComputerBase tile )
{
TileEntity tile = world.getTileEntity( pos );
return tile instanceof TileTurtle ? TurtleItemFactory.create( (TileTurtle) tile ) : super.getPickBlock( state, target, world, pos, player );
return tile instanceof TileTurtle ? TurtleItemFactory.create( (TileTurtle) tile ) : ItemStack.EMPTY;
}
}

View File

@@ -17,7 +17,6 @@ import dan200.computercraft.shared.computer.core.ComputerFamily;
import dan200.computercraft.shared.computer.core.ServerComputer;
import dan200.computercraft.shared.turtle.apis.TurtleAPI;
import dan200.computercraft.shared.turtle.core.TurtleBrain;
import dan200.computercraft.shared.turtle.items.TurtleItemFactory;
import dan200.computercraft.shared.util.DefaultInventory;
import dan200.computercraft.shared.util.InventoryUtil;
import dan200.computercraft.shared.util.RedstoneUtil;
@@ -81,7 +80,7 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default
m_inventory = NonNullList.withSize( INVENTORY_SIZE, ItemStack.EMPTY );
m_previousInventory = NonNullList.withSize( INVENTORY_SIZE, ItemStack.EMPTY );
m_inventoryChanged = false;
m_brain = createBrain();
m_brain = new TurtleBrain( this );
m_moveState = MoveState.NOT_MOVED;
m_family = family;
}
@@ -91,21 +90,12 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default
return m_moveState == MoveState.MOVED;
}
protected TurtleBrain createBrain()
{
return new TurtleBrain( this );
}
protected final ServerComputer createComputer( int instanceID, int id, int termWidth, int termHeight )
@Override
protected ServerComputer createComputer( int instanceID, int id )
{
ServerComputer computer = new ServerComputer(
getWorld(),
id,
m_label,
instanceID,
getFamily(),
termWidth,
termHeight
getWorld(), id, m_label, instanceID, getFamily(),
ComputerCraft.terminalWidth_turtle, ComputerCraft.terminalHeight_turtle
);
computer.setPosition( getPos() );
computer.addAPI( new TurtleAPI( computer.getAPIEnvironment(), getAccess() ) );
@@ -113,12 +103,6 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default
return computer;
}
@Override
protected ServerComputer createComputer( int instanceID, int id )
{
return createComputer( instanceID, id, ComputerCraft.terminalWidth_turtle, ComputerCraft.terminalHeight_turtle );
}
@Override
public ComputerProxy createProxy()
{
@@ -166,12 +150,6 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default
}
}
@Override
public void getDroppedItems( @Nonnull NonNullList<ItemStack> drops, boolean creative )
{
if( !creative || getLabel() != null ) drops.add( TurtleItemFactory.create( this ) );
}
@Override
public boolean onActivate( EntityPlayer player, EnumHand hand, EnumFacing side, float hitX, float hitY, float hitZ )
{
@@ -262,38 +240,26 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default
}
@Override
public void onNeighbourChange()
public void onNeighbourChange( @Nonnull BlockPos neighbour )
{
if( m_moveState == MoveState.NOT_MOVED )
{
super.onNeighbourChange();
}
if( m_moveState == MoveState.NOT_MOVED ) super.onNeighbourChange( neighbour );
}
@Override
public void onNeighbourTileEntityChange( @Nonnull BlockPos neighbour )
{
if( m_moveState == MoveState.NOT_MOVED )
{
super.onNeighbourTileEntityChange( neighbour );
}
if( m_moveState == MoveState.NOT_MOVED ) super.onNeighbourTileEntityChange( neighbour );
}
public void notifyMoveStart()
{
if( m_moveState == MoveState.NOT_MOVED )
{
m_moveState = MoveState.IN_PROGRESS;
}
if( m_moveState == MoveState.NOT_MOVED ) m_moveState = MoveState.IN_PROGRESS;
}
public void notifyMoveEnd()
{
// MoveState.MOVED is final
if( m_moveState == MoveState.IN_PROGRESS )
{
m_moveState = MoveState.NOT_MOVED;
}
if( m_moveState == MoveState.IN_PROGRESS ) m_moveState = MoveState.NOT_MOVED;
}
@Override

View File

@@ -13,6 +13,7 @@ import dan200.computercraft.api.lua.ILuaContext;
import dan200.computercraft.api.lua.LuaException;
import dan200.computercraft.api.peripheral.IPeripheral;
import dan200.computercraft.api.turtle.*;
import dan200.computercraft.core.tracking.Tracking;
import dan200.computercraft.shared.computer.blocks.ComputerProxy;
import dan200.computercraft.shared.computer.blocks.TileComputerBase;
import dan200.computercraft.shared.computer.core.ComputerFamily;
@@ -53,7 +54,7 @@ public class TurtleBrain implements ITurtleAccess
private int m_commandsIssued = 0;
private Map<TurtleSide, ITurtleUpgrade> m_upgrades = new EnumMap<>( TurtleSide.class );
private Map<TurtleSide, IPeripheral> m_peripherals = new EnumMap<>( TurtleSide.class );
private Map<TurtleSide, IPeripheral> peripherals = new EnumMap<>( TurtleSide.class );
private Map<TurtleSide, NBTTagCompound> m_upgradeNBTData = new EnumMap<>( TurtleSide.class );
private int m_selectedSlot = 0;
@@ -823,9 +824,9 @@ public class TurtleBrain implements ITurtleAccess
@Override
public IPeripheral getPeripheral( @Nonnull TurtleSide side )
{
if( m_peripherals.containsKey( side ) )
if( peripherals.containsKey( side ) )
{
return m_peripherals.get( side );
return peripherals.get( side );
}
return null;
}
@@ -923,13 +924,9 @@ public class TurtleBrain implements ITurtleAccess
}
}
public void updatePeripherals( ServerComputer serverComputer )
private void updatePeripherals( ServerComputer serverComputer )
{
if( serverComputer == null )
{
// Nothing to do
return;
}
if( serverComputer == null ) return;
// Update peripherals
for( TurtleSide side : TurtleSide.values() )
@@ -941,26 +938,20 @@ public class TurtleBrain implements ITurtleAccess
peripheral = upgrade.createPeripheral( this, side );
}
int dir = toDirection( side );
if( peripheral != null )
IPeripheral existing = peripherals.get( side );
if( existing == peripheral || (existing != null && peripheral != null && existing.equals( peripheral )) )
{
if( !m_peripherals.containsKey( side ) )
{
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 );
}
// If the peripheral is the same, just use that.
peripheral = existing;
}
else if( m_peripherals.containsKey( side ) )
else
{
serverComputer.setPeripheral( dir, null );
m_peripherals.remove( side );
// Otherwise update our map
peripherals.put( side, peripheral );
}
// Always update the computer: it may not be the same computer as before!
serverComputer.setPeripheral( toDirection( side ), peripheral );
}
}
@@ -972,17 +963,21 @@ public class TurtleBrain implements ITurtleAccess
TurtleCommandQueueEntry nextCommand = m_commandQueue.poll();
if( nextCommand != null )
{
ServerComputer computer = m_owner.getServerComputer();
// Execute the command
long start = System.nanoTime();
TurtleCommandResult result = nextCommand.command.execute( this );
long end = System.nanoTime();
// Dispatch the callback
int callbackID = nextCommand.callbackID;
if( callbackID >= 0 )
if( computer != null )
{
if( result != null && result.isSuccess() )
Tracking.addServerTiming( computer.getComputer(), end - start );
int callbackID = nextCommand.callbackID;
if( callbackID >= 0 )
{
ServerComputer computer = m_owner.getServerComputer();
if( computer != null )
if( result != null && result.isSuccess() )
{
Object[] results = result.getResults();
if( results != null )
@@ -1000,11 +995,7 @@ public class TurtleBrain implements ITurtleAccess
} );
}
}
}
else
{
ServerComputer computer = m_owner.getServerComputer();
if( computer != null )
else
{
computer.queueEvent( "turtle_response", new Object[] {
callbackID, false, result != null ? result.getErrorMessage() : null

View File

@@ -18,7 +18,7 @@ public class RedstoneUtil
@Deprecated
public static int getRedstoneOutput( World world, BlockPos pos, EnumFacing side )
{
return world.getRedstonePower( pos, side );
return world.getRedstonePower( pos, side.getOpposite() );
}
@Deprecated

View File

@@ -0,0 +1,25 @@
/*
* 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,22 +48,36 @@ function test( colors, color )
if type( color ) ~= "number" then
error( "bad argument #2 (expected number, got " .. type( color ) .. ")", 2 )
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, 0xFF ) * 2^16 +
bit32.band( g, 0xFF ) * 2^8 +
bit32.band( b, 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 ), bit32.band( bit32.rshift( rgb, 8 ), 0xFF ), bit32.band( rgb, 0xFF )
end
function rgb8( r, g, b )
if type( r ) ~= "number" then
error( "bad argument #1 (expected number, got " .. type( r ) .. ")", 2 )
elseif type(r) == "number" and g == nil and b == nil then
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 )
if g == nil and b == nil then
return unpackRGB( r )
else
return packRGB( r, g, b )
end
end

View File

@@ -42,11 +42,16 @@ term.native = function()
return native
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
if type( k ) == "string" and type( v ) == "function" then
if term[k] == nil then
term[k] = wrap( k )
end
if type( k ) == "string" and type( v ) == "function" and term[k] == nil then
term[k] = wrap( k )
end
end

View File

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

View File

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

View File

@@ -63,7 +63,7 @@ local function createShellEnv( sDir )
end
else
if #sError > 0 then
sError = sError .. "\n"
sError = sError .. "\n "
end
sError = sError .. "no file '" .. sPath .. "'"
end
@@ -78,27 +78,24 @@ local function createShellEnv( sDir )
error( "bad argument #1 (expected string, got " .. type( name ) .. ")", 2 )
end
if package.loaded[name] == sentinel then
error("Loop detected requiring '" .. name .. "'", 0)
error("loop or previous error loading module '" .. name .. "'", 0)
end
if package.loaded[name] then
return package.loaded[name]
end
local sError = "Error loading module '" .. name .. "':"
for n,searcher in ipairs(package.loaders) do
local loader, err = searcher(name)
if loader then
local sError = "module '" .. name .. "' not found:"
for _, searcher in ipairs(package.loaders) do
local loader = table.pack(searcher(name))
if loader[1] then
package.loaded[name] = sentinel
local result = loader( err )
if result ~= nil then
package.loaded[name] = result
return result
else
package.loaded[name] = true
return true
end
local result = loader[1](name, table.unpack(loader, 2, loader.n))
if result == nil then result = true end
package.loaded[name] = result
return result
else
sError = sError .. "\n" .. err
sError = sError .. "\n " .. loader[2]
end
end
error(sError, 2)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 230 B

After

Width:  |  Height:  |  Size: 190 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 222 B

After

Width:  |  Height:  |  Size: 181 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 643 B

After

Width:  |  Height:  |  Size: 641 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 312 B

After

Width:  |  Height:  |  Size: 205 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 332 B

After

Width:  |  Height:  |  Size: 296 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 333 B

After

Width:  |  Height:  |  Size: 294 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 273 B

After

Width:  |  Height:  |  Size: 179 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 381 B

After

Width:  |  Height:  |  Size: 237 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 273 B

After

Width:  |  Height:  |  Size: 267 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 259 B

After

Width:  |  Height:  |  Size: 224 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 250 B

After

Width:  |  Height:  |  Size: 248 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 258 B

After

Width:  |  Height:  |  Size: 234 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 263 B

After

Width:  |  Height:  |  Size: 235 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 222 B

After

Width:  |  Height:  |  Size: 179 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 266 B

After

Width:  |  Height:  |  Size: 221 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 261 B

After

Width:  |  Height:  |  Size: 224 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 337 B

After

Width:  |  Height:  |  Size: 302 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 619 B

After

Width:  |  Height:  |  Size: 294 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 254 B

After

Width:  |  Height:  |  Size: 241 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 316 B

After

Width:  |  Height:  |  Size: 282 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 253 B

After

Width:  |  Height:  |  Size: 239 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 259 B

After

Width:  |  Height:  |  Size: 235 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 974 B

After

Width:  |  Height:  |  Size: 426 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 989 B

After

Width:  |  Height:  |  Size: 436 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 992 B

After

Width:  |  Height:  |  Size: 430 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 490 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 241 B

After

Width:  |  Height:  |  Size: 223 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 211 B

After

Width:  |  Height:  |  Size: 200 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 299 B

After

Width:  |  Height:  |  Size: 260 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 212 B

After

Width:  |  Height:  |  Size: 200 B

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