1
0
mirror of https://github.com/SquidDev-CC/CC-Tweaked synced 2025-10-15 22:17:39 +00:00

Compare commits

..

39 Commits

Author SHA1 Message Date
SquidDev
8819f2559d Add some tests for the new executor system
And fix a couple of bugs picked up by said tests
2018-09-18 18:21:00 +01:00
SquidDev
4b741739e8 Update the executor to work with the new calling system 2018-09-13 10:32:45 +01:00
SquidDev
f23acef2dd Merge remote-tracking branch 'SquidDev-CC-ComputerCraft/feature/method-future' into feature/onethread-cobalt 2018-09-09 22:13:45 +01:00
SquidDev
ac8444b364 Migrate ComputerCraft's peripherals/APIs to use the non-blocking API
This is definitely a little ugly in places, mostly due to how we've
handled backwards compatibility.
2018-09-09 17:06:34 +01:00
SquidDev
3b4c1eac1c Proposal for replacing ILuaContext with a non-blocking alternative
This is an initial prototype for ways we could better integrate Lua's
asynchronous functionality (coroutines) with peripherals and other
Lua APIs.

The existing system assumes that coroutines each have a backing thread,
and so yields will suspect the current thread. This takes inspiration
from various "promise" libraries - asynchronous operations (such as
executing on the main thread or waiting for an event) return a promise -
the result of which can be consumed with `.then`.

While I am not aware of plans to change the Lua implementation, this
does give us greater flexibility in the future, leading the way for
Rembulan, single-threaded Cobalt, and even possibly OC support.
2018-09-09 17:04:07 +01:00
SquidDev
7cc77cb1ed Add a basic implementation of the single-thread Lua 2018-09-01 18:40:10 +01:00
SquidDev
0f70d68d0d A minor refactor to computer method calls
We move several rather complex classes into a separate file.
2018-09-01 17:34:26 +01:00
SquidDev
c6bd88f3ad Attempt to cut out a lot of synchronized calls
A lot of these don't actually have any effect as they'll only be called
on the main thread or they are getters where the state is guaranteed to
be consistent whenever it is accessed.

Hopefully this'll reduce the chance of world updates being blocked by
waiting for peripheral locks to be released.
2018-08-25 21:17:48 +01:00
SquidDev
efa57521c7 Bump version to 1.8pr1.8
While there haven't been a lot of changes, there's been a couple of bug
fixes and nice improvements.
2018-08-25 10:58:54 +01:00
SquidDev
4700f8831b Add a pull request template
Again, not entirely a fan of these, but there's been several PRs
which would have been better off targeting the original repo.
2018-08-24 17:37:20 +01:00
SquidDev
9428bee316 Merge pull request #65 from apemanzilla/fix/drop-consumer-overflow
Prevent stack overflows when using turtle.place() with a full inventory
2018-08-23 08:04:07 +01:00
apemanzilla
89c7183a1d Prevent stack overflows when using turtle.place() with a full inventory 2018-08-23 07:56:50 +01:00
SquidDev
d2a9e7e458 Reset a few more flags when rendering printouts
Closes #63
2018-08-13 22:25:58 +01:00
SquidDev
1774f1a079 Merge pull request #566 from SquidDev-CC/ComputerCraft/feature/tiny-lua-wins
A couple of small improvements to CraftOS
2018-08-12 15:49:19 +01:00
SquidDev
de1307913b A couple of small improvements to CraftOS
- Make window.reposition's argument validation a little more strict.
   Previously it would accept `window.reposition(x, y, width)` (no
   height argument), just not act upon it.
 - Use select instead of table.unpack within `pastebin run`.
 - Use `parallel.waitForAny` instead of `waitForAll` within the dance
   program.
 - Pipe the entire help file into `textutils.pagedPrint`, rather than
   doing it line by line.
 - Remove bytecode loading disabling from bios.lua. This never worked
   correctly, and serves little purpose as LuaJ is not vulnerable to
   such exploits.
2018-08-12 08:23:17 +01:00
SquidDev
093132533d Add charset bundled cable integration
- Bump MinecraftForge version so we don't crash on load. Oh boy, all
   the deprecation warnings.
 - Inject IBundledEmitter and IBundledReceiver capabilities onto all
   TileGenerics.
 - Register a IBundledRedstoneProvider instance for IBundledEmitter.
2018-08-11 10:49:21 +01:00
SquidDev
0685be6bfa Add issue templates
I'm not entirely a fan of massive templates, but there's 
been a couple of lacklustre issues recently, so it's probably
good to formalise my guidelines.
2018-08-04 10:52:26 +01:00
SquidDev
f40733e9a6 Error when missing computers after executing the command
This allows you to automate running various commands and still have them
"work" if some computers are not loaded.

Closes #47
2018-08-04 10:39:44 +01:00
SquidDev
a3d1cff298 Bump Cobalt version
This should allow us to do SquidDev-CC/mbs#18 due to the debug
improvements.
2018-08-03 20:58:20 +01:00
SquidDev
b8957cab5c Update to the latest mappings
This is a preliminary for updating to 1.13, as many of the name changes
apply to both. This will make it harder to remain consistent with
actual CC, though that will be less of a consideration when 1.13 hits.
2018-07-24 09:27:05 +01:00
SquidDev
3ac8dde779 Bump version 2018-07-09 21:02:20 +01:00
SquidDev
17dace979a Merge pull request #562 from SquidDev-CC/ComputerCraft/hotfix/turtle-sign-place
Be a little smarter about our detection of the placed sign
2018-07-09 20:57:42 +01:00
SquidDev
d405316a4b Be a little smarter about our detection of the placed sign
When placing a sign against a tile entity (such as a turtle or chest),
we would consider that block the "placed" one instead, meaning the text
was never set. This solution isn't entirely ideal either, but short of
capturing block snapshots I'm not sure of a better solution.

Fixes #552
2018-07-09 20:53:49 +01:00
SquidDev
7e18f2cead Clear the turtle's inventory on load 2018-07-09 18:22:42 +01:00
SquidDev
000786a1a7 Merge pull request #560 from SquidDev-CC/ComputerCraft/hotfix/turtle-destroy
Rewrite turtle block destroying
2018-07-08 23:01:13 +01:00
SquidDev
0bf13562b9 Provide a more direct way to get the related computer
Effectively shift extracting the computer away from Plethora into CC:T.
Ideally we wouldn't need this at all, but Plethora does some funky
things with tick timings.

See SquidDev-CC/plethora#125
2018-07-08 22:48:50 +01:00
SquidDev
45a189e834 Cache a turtle's fake player
Player construction can get a little expensive, and this is exacerbated
by Sponge. We now cache a turtle's fake player (updating the position
every time it is requested) in order to reduce this overhead.
2018-07-08 15:21:42 +01:00
SquidDev
0ce6f34a09 Rewrite printout rendering
- The current page is always centred when rendering in a GUI, with
   the turned pages moving from the sides.
 - Pages are no longer evenly distributed from the centre - they follow
   an exponential decay curve, so ones further out are closer together
   (a bit like an open book).
 - Render pages and books in item frames/in-hand (rather than just
   single pages).

This currently does some very dirty things with z values in order to
prevent z-fighting. It would be nice to avoid that, though turning off
writing to the z buffer causes issues with the bounding box.
2018-07-07 19:59:20 +01:00
SquidDev
4d984dc5ee Rewrite turtle block destroying
- Try to make drop capturing a little more generic. This now allows for
   capturing a block's drop at a given position, as well as any drop
   within a bounding box (for things which don't play nicely).

 - Use as much of Minecraft's block breaking logic as possible,
   hopefully simplifying things and making it more consistent with other
   mods.
2018-07-06 18:49:15 +01:00
SquidDev
984d358930 Provide .getNameLocal on modems
This provides the local modem's name on the remote network. Let's be
honest, I'll probably end up renaming this soon.
2018-06-29 20:29:04 +01:00
SquidDev
a95893b823 Send the terminal state to the pocket computer's player
As we only send the terminal to players using the GUI, the map interface
was never updated. We now will also send the terminal state to whoever
has the computer in their inventory.

This also marks the terminal as dirty when a new player picks the pocket
computer up, hopefully preventing any desync issues which might occur
then.

Fixes #42.
2018-06-24 19:18:30 +01:00
SquidDev
81aaead032 Improve using /computercraft as a non-player
- Fix text table only showing the first row (fixes #40)
 - Do not emit alignment characters in monospace environments
 - Reduce padding in monospace environments

Also make the output of dump consistent with that of the profiler: we
provide tp and view shortcuts for each computer.
2018-06-22 08:28:36 +01:00
SquidDev
a2083bcff1 Merge pull request #554 from SquidDev-CC/ComputerCraft/hotfix/gui-blemishes
Fix a couple of minor blemishes in the GUI textures
2018-06-19 22:24:32 +01:00
SquidDev
052f2a16dc Fix a couple of minor blemishes in the GUI textures
- Slight airbrush effect for normal turtles. While this is only really
   visible when upping the contrast, it's probably nice to fix.
 - A few off-colour pixels for advanced turtles
2018-06-19 22:18:48 +01:00
SquidDev
fd10ed6f62 Merge pull request #553 from SquidDev-CC/ComputerCraft/feature/fancy-printout
Fancy rendering of printouts
2018-06-19 19:44:51 +01:00
SquidDev
c0bdd4ff1d Add basic support for fancy rendering of printouts
- When held in first-person, single pages are displayed like a map.
 - When placed in an item frame, the page is drawn instead of the actual
   item.
2018-06-18 22:09:24 +01:00
SquidDev
5f0addbc3e Fix variable being declared too late 2018-06-18 19:01:36 +01:00
SquidDev
c9589ad0e7 Allow using any kind of skull for crafting heads
It's possible to acquire any mob head in vanilla, so it's probably best
if we allow any head to be used.
2018-06-02 11:12:29 +01:00
SquidDev
b21c495815 Update the README to be a bit more detailed
- Include a list of features, pretty similar to that on the forum
   thread or CurseForge page.
 - Replace CC: Tweaked with CC:T. After all, who wants to type all of
   that?
2018-05-15 12:27:04 +01:00
130 changed files with 3774 additions and 1276 deletions

16
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View File

@@ -0,0 +1,16 @@
---
name: Bug report
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.
-->
## 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.

View File

@@ -0,0 +1,15 @@
---
name: Feature request
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.
-->
## 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

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

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

View File

@@ -6,26 +6,42 @@ features of the mod. For a more stable experience, I recommend checking out the
[original mod](https://github.com/dan200/ComputerCraft).
## What?
CC: Tweaked 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: Tweaked aims to be a nurturing ground for various features, with
a pull request against the original mod being the end goal.
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.
CC: Tweaked also includes many pull requests from the community which have not yet been merged, offering a large number
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.
## Features
CC: Tweaked contains the all 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:
- 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
computers remotely.
- Add full-block wired modems, allowing one to wrap non-solid peripherals (such as turtles, or chests if Plethora is
installed).
## Relation to CCTweaks?
This mod has nothing to do with CCTweaks, though there is no denying the name is a throwback to it. However, I do plan
to migrate some features of CCTweaks into CC: Tweaked.
This mod has nothing to do with CCTweaks, though there is no denying the name is a throwback to it. That being said,
several features have been included, such as full block modems, the Cobalt runtime and map-like rendering for pocket
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 instead.
That being said, in order to start helping develop CC: Tweaked, you'll need to follow these steps:
That being said, in order to start helping develop CC:T, you'll need to follow these steps:
- **Clone the repository:** `git clone https://github.com/SquidDev-CC/CC-Tweaked.git && cd CC-Tweaked`
- **Setup Forge:** `./gradlew setupDecompWorkspace`
- **Test your changes:** `./gradlew runClient` (or run the `GradleStart` class from your IDE).
If you want to run CC: Tweaked in a normal Minecraft instance, run `./gradlew build` and copy the `.jar` from
`build/libs`.
If you want to run CC:T in a normal Minecraft instance, run `./gradlew build` and copy the `.jar` from `build/libs`.

View File

@@ -23,12 +23,12 @@ apply plugin: 'org.ajoberstar.grgit'
apply plugin: 'maven-publish'
apply plugin: 'maven'
version = "1.80pr1.6"
version = "1.80pr1.8"
group = "org.squiddev"
archivesBaseName = "cc-tweaked"
minecraft {
version = "1.12.2-14.23.2.2634"
version = "1.12.2-14.23.4.2749"
runDir = "run"
replace '${version}', project.version
@@ -37,11 +37,12 @@ minecraft {
// stable_# stables are built at the discretion of the MCP team.
// Use non-default mappings at your own risk. they may not allways work.
// simply re-run your setup task after changing the mappings to update your workspace.
mappings = "snapshot_20180324"
mappings = "snapshot_20180724"
// makeObfSourceJar = false // an Srg named sources jar is made by default. uncomment this to disable.
}
repositories {
mavenLocal()
maven {
name = "JEI"
url = "http://dvs1.progwml6.com/files/maven"
@@ -50,6 +51,8 @@ repositories {
name = "squiddev"
url = "https://dl.bintray.com/squiddev/maven"
}
ivy { artifactPattern "https://asie.pl/files/mods/Charset/LibOnly/[module]-[revision](-[classifier]).[ext]" }
}
configurations {
@@ -60,8 +63,11 @@ configurations {
dependencies {
deobfProvided "mezz.jei:jei_1.12.2:4.8.5.159:api"
deobfProvided "pl.asie:Charset-Lib:0.5.4.6"
runtime "mezz.jei:jei_1.12.2:4.8.5.159"
shade 'org.squiddev:Cobalt:0.3.1'
shade 'org.squiddev:Cobalt:0.3.2-nothread'
testCompile 'junit:junit:4.11'
@@ -191,3 +197,9 @@ gradle.projectsEvaluated {
runClient.outputs.upToDateWhen { false }
runServer.outputs.upToDateWhen { false }
test {
testLogging {
events "failed", "standardOut", "standardError"
}
}

View File

@@ -98,6 +98,7 @@ import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.*;
import java.util.function.Function;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
@@ -1124,13 +1125,18 @@ public class ComputerCraft
turtleProxy.addAllUpgradedTurtles( list );
}
public static void setEntityDropConsumer( Entity entity, IEntityDropConsumer consumer )
public static void setDropConsumer( Entity entity, Function<ItemStack, ItemStack> consumer )
{
turtleProxy.setEntityDropConsumer( entity, consumer );
turtleProxy.setDropConsumer( entity, consumer );
}
public static void clearEntityDropConsumer( Entity entity )
public static void setDropConsumer( World world, BlockPos pos, Function<ItemStack, ItemStack> consumer )
{
turtleProxy.clearEntityDropConsumer( entity );
turtleProxy.setDropConsumer( world, pos, consumer );
}
public static List<ItemStack> clearDropConsumer( )
{
return turtleProxy.clearDropConsumer();
}
}

View File

@@ -0,0 +1,31 @@
/*
* This file is part of the public ComputerCraft API - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2018. This API may be redistributed unmodified and in full only.
* For help using the API, and posting your mods, visit the forums at computercraft.info.
*/
package dan200.computercraft.api.lua;
import javax.annotation.Nonnull;
/**
* An interface passed to peripherals and {@link ILuaObject}s by computers or turtles, providing methods that allow the
* method to interact with the invoking computer.
*/
public interface ICallContext
{
/**
* Queue a task to be executed on the main server thread at the beginning of next tick, but do not wait for it to
* complete. This should be used when you need to interact with the world in a thread-safe manner but do not care
* about the result or you wish to run asynchronously.
*
* When the task has finished, it will enqueue a {@code task_completed} event, which takes the task id, a success
* value and the return values, or an error message if it failed. If you need to wait on this event, it may be
* better to use {@link MethodResult#onMainThread(ILuaCallable)}.
*
* @param task The task to execute on the main thread.
* @return The "id" of the task. This will be the first argument to the {@code task_completed} event.
* @throws LuaException If the task could not be queued.
*/
long issueMainThreadTask( @Nonnull ILuaTask task ) throws LuaException;
}

View File

@@ -0,0 +1,31 @@
/*
* This file is part of the public ComputerCraft API - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2018. This API may be redistributed unmodified and in full only.
* For help using the API, and posting your mods, visit the forums at computercraft.info.
*/
package dan200.computercraft.api.lua;
import javax.annotation.Nonnull;
/**
* A function which calls performs an action in a specific context (such as on the server thread) and returns a result.
*
* @see MethodResult#onMainThread(ILuaCallable)
* @see ILuaContext#executeMainThreadTask(ILuaTask)
*/
@FunctionalInterface
public interface ILuaCallable
{
/**
* Run the code within the specified context and return the result to continue with.
*
* @return The result of executing this function. Note that this may not be evaluated within the same context as
* this call is.
* @throws LuaException If you throw any exception from this function, a lua error will be raised with the
* same message as your exception. Use this to throw appropriate errors if the wrong
* arguments are supplied to your method.
*/
@Nonnull
MethodResult execute() throws LuaException;
}

View File

@@ -1,6 +1,6 @@
/*
* This file is part of the public ComputerCraft API - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2017. This API may be redistributed unmodified and in full only.
* Copyright Daniel Ratcliffe, 2011-2018. This API may be redistributed unmodified and in full only.
* For help using the API, and posting your mods, visit the forums at computercraft.info.
*/
@@ -13,8 +13,11 @@ import javax.annotation.Nullable;
* An interface passed to peripherals and {@link ILuaObject}s by computers or turtles, providing methods
* that allow the peripheral call to wait for events before returning, just like in lua. This is very useful if you need
* to signal work to be performed on the main thread, and don't want to return until the work has been completed.
*
* This interface mostly exists for integrating with older code. One should use {@link MethodResult} instead, as this
* encourages an asynchronous way of interacting with Lua coroutines.
*/
public interface ILuaContext
public interface ILuaContext extends ICallContext
{
/**
* Wait for an event to occur on the computer, suspending the thread until it arises. This method is exactly
@@ -30,8 +33,10 @@ public interface ILuaContext
* @throws InterruptedException If the user shuts down or reboots the computer while pullEvent() is waiting for an
* event, InterruptedException will be thrown. This exception must not be caught or
* intercepted, or the computer will leak memory and end up in a broken state.
* @deprecated Use {@link MethodResult#pullEvent(String, ILuaFunction)}
*/
@Nonnull
@Deprecated
Object[] pullEvent( @Nullable String filter ) throws LuaException, InterruptedException;
/**
@@ -45,8 +50,10 @@ public interface ILuaContext
* an event, InterruptedException will be thrown. This exception must not be caught or
* intercepted, or the computer will leak memory and end up in a broken state.
* @see #pullEvent(String)
* @deprecated Use {@link MethodResult#pullEventRaw(String, ILuaFunction)}
*/
@Nonnull
@Deprecated
Object[] pullEventRaw( @Nullable String filter ) throws InterruptedException;
/**
@@ -59,8 +66,10 @@ public interface ILuaContext
* InterruptedException will be thrown. This exception must not be caught or
* intercepted, or the computer will leak memory and end up in a broken state.
* @see #pullEvent(String)
* @deprecated Use {@link MethodResult#pullEventRaw(ILuaFunction)}
*/
@Nonnull
@Deprecated
Object[] yield( @Nullable Object[] arguments ) throws InterruptedException;
/**
@@ -76,22 +85,9 @@ public interface ILuaContext
* @throws InterruptedException If the user shuts down or reboots the computer the coroutine is suspended,
* InterruptedException will be thrown. This exception must not be caught or
* intercepted, or the computer will leak memory and end up in a broken state.
* @deprecated Use {@link MethodResult#onMainThread(ILuaCallable)}
*/
@Nullable
@Deprecated
Object[] executeMainThreadTask( @Nonnull ILuaTask task ) throws LuaException, InterruptedException;
/**
* Queue a task to be executed on the main server thread at the beginning of next tick, but do not wait for it to
* complete. This should be used when you need to interact with the world in a thread-safe manner but do not care
* about the result or you wish to run asynchronously.
*
* When the task has finished, it will enqueue a {@code task_completed} event, which takes the task id, a success
* value and the return values, or an error message if it failed. If you need to wait on this event, it may be
* better to use {@link #executeMainThreadTask(ILuaTask)}.
*
* @param task The task to execute on the main thread.
* @return The "id" of the task. This will be the first argument to the {@code task_completed} event.
* @throws LuaException If the task could not be queued.
*/
long issueMainThreadTask( @Nonnull ILuaTask task ) throws LuaException;
}

View File

@@ -0,0 +1,24 @@
/*
* This file is part of the public ComputerCraft API - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2018. This API may be redistributed unmodified and in full only.
* For help using the API, and posting your mods, visit the forums at computercraft.info.
*/
package dan200.computercraft.api.lua;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/**
* A function which executes using a {@link ILuaContext}.
*
* Like {@link ILuaContext}, this is not intended for use in the future - it purely exists as an argument for
* {@link MethodResult#withLuaContext(ILuaContextTask)}.
*/
@FunctionalInterface
public interface ILuaContextTask
{
@Nullable
@Deprecated
Object[] execute( @Nonnull ILuaContext context ) throws LuaException, InterruptedException;
}

View File

@@ -0,0 +1,33 @@
/*
* This file is part of the public ComputerCraft API - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2018. This API may be redistributed unmodified and in full only.
* For help using the API, and posting your mods, visit the forums at computercraft.info.
*/
package dan200.computercraft.api.lua;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/**
* A Lua function which consumes some values and returns a result.
*
* @see MethodResult#then(ILuaFunction)
* @see MethodResult#pullEvent(ILuaFunction)
* @see MethodResult#pullEventRaw(String)
*/
@FunctionalInterface
public interface ILuaFunction
{
/**
* Accept the values and return another method result.
*
* @param values The inputs for this function.
* @return The result of executing this function.
* @throws LuaException If you throw any exception from this function, a lua error will be raised with the
* same message as your exception. Use this to throw appropriate errors if the wrong
* arguments are supplied to your method.
*/
@Nonnull
MethodResult call( @Nullable Object[] values ) throws LuaException;
}

View File

@@ -1,6 +1,6 @@
/*
* This file is part of the public ComputerCraft API - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2017. This API may be redistributed unmodified and in full only.
* Copyright Daniel Ratcliffe, 2011-2018. This API may be redistributed unmodified and in full only.
* For help using the API, and posting your mods, visit the forums at computercraft.info.
*/
@@ -41,16 +41,45 @@ public interface ILuaObject
* wishes to call. The integer indicates the index into the getMethodNames() table
* that corresponds to the string passed into peripheral.call()
* @param arguments The arguments for this method. See {@link IPeripheral#callMethod(IComputerAccess, ILuaContext, int, Object[])}
* the possible values and conversion rules.
* @return An array of objects, representing the values you wish to return to the Lua program.
* See {@link IPeripheral#callMethod(IComputerAccess, ILuaContext, int, Object[])} for the valid values and
* conversion rules.
* @throws LuaException If the task could not be queued, or if the task threw an exception.
* for the possible values and conversion rules.
* @return An array of objects, representing the values you wish to return to the Lua program. See
* {@link MethodResult#of(Object...)} for the valid values and conversion rules.
* @throws LuaException If you throw any exception from this function, a lua error will be raised with the
* same message as your exception. Use this to throw appropriate errors if the wrong
* arguments are supplied to your method.
* @throws InterruptedException If the user shuts down or reboots the computer the coroutine is suspended,
* InterruptedException will be thrown. This exception must not be caught or
* intercepted, or the computer will leak memory and end up in a broken state.w
* intercepted, or the computer will leak memory and end up in a broken state.
* @see IPeripheral#callMethod(IComputerAccess, ILuaContext, int, Object[])
* @deprecated Use {@link #callMethod(ICallContext, int, Object[])} instead.
*/
@Nullable
@Deprecated
Object[] callMethod( @Nonnull ILuaContext context, int method, @Nonnull Object[] arguments ) throws LuaException, InterruptedException;
/**
* Called when a user calls one of the methods that this object implements. This works the same as
* {@link IPeripheral#callMethod(IComputerAccess, ICallContext, int, Object[])}}. See that method for detailed
* documentation.
*
* @param context The context of the current call.
* @param method An integer identifying which of the methods from getMethodNames() the computercraft
* wishes to call. The integer indicates the index into the getMethodNames() table
* that corresponds to the string passed into peripheral.call()
* @param arguments The arguments for this method. See {@link IPeripheral#callMethod(IComputerAccess, ICallContext, int, Object[])}
* for the possible values and conversion rules.
* @return The result of calling this method. Use {@link MethodResult#empty()} to return nothing or
* {@link MethodResult#of(Object...)} to return several values.
* @throws LuaException If you throw any exception from this function, a lua error will be raised with the
* same message as your exception. Use this to throw appropriate errors if the wrong
* arguments are supplied to your method.
* @see IPeripheral#callMethod(IComputerAccess, ICallContext, int, Object[])
* @see MethodResult
*/
@Nonnull
@SuppressWarnings( { "deprecation" } )
default MethodResult callMethod( @Nonnull ICallContext context, int method, @Nonnull Object[] arguments ) throws LuaException
{
return MethodResult.withLuaContext( lua -> callMethod( lua, method, arguments ) );
}
}

View File

@@ -0,0 +1,105 @@
/*
* This file is part of the public ComputerCraft API - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2018. This API may be redistributed unmodified and in full only.
* For help using the API, and posting your mods, visit the forums at computercraft.info.
*/
package dan200.computercraft.api.lua;
import javax.annotation.Nonnull;
import java.util.ArrayDeque;
import java.util.Deque;
/**
* Evaluates {@link MethodResult}s within a {@link ILuaContext}.
*
* @see MethodResult#evaluate(ILuaContext)
* @see MethodResult#withLuaContext(ILuaContextTask)
* @deprecated This should not be used except to interface between the two call call systems.
*/
@Deprecated
class LuaContextResultEvaluator
{
@Deprecated
public static Object[] evaluate( @Nonnull ILuaContext context, @Nonnull MethodResult future ) throws LuaException, InterruptedException
{
Deque<ILuaFunction> callbacks = null;
while( true )
{
if( future instanceof MethodResult.AndThen )
{
MethodResult.AndThen then = ((MethodResult.AndThen) future);
// Thens are "unwrapped", being pushed onto a stack
if( callbacks == null ) callbacks = new ArrayDeque<>();
callbacks.addLast( then.getCallback() );
future = then.getPrevious();
if( future == null ) throw new NullPointerException( "Null result from " + then.getCallback() );
}
else if( future instanceof MethodResult.Immediate )
{
Object[] values = ((MethodResult.Immediate) future).getResult();
// Immediate values values will attempt to call the previous "then", or return if nothing
// else needs to be done.
ILuaFunction callback = callbacks == null ? null : callbacks.pollLast();
if( callback == null ) return values;
future = callback.call( values );
if( future == null ) throw new NullPointerException( "Null result from " + callback );
}
else if( future instanceof MethodResult.OnEvent )
{
MethodResult.OnEvent onEvent = (MethodResult.OnEvent) future;
// Poll for an event, and then call the previous "then" or return if nothing else needs
// to be done.
Object[] values = onEvent.isRaw() ? context.pullEventRaw( onEvent.getFilter() ) : context.pullEvent( onEvent.getFilter() );
ILuaFunction callback = callbacks == null ? null : callbacks.pollLast();
if( callback == null ) return values;
future = callback.call( values );
if( future == null ) throw new NullPointerException( "Null result from " + callback );
}
else if( future instanceof MethodResult.OnMainThread )
{
MethodResult.OnMainThread onMainThread = (MethodResult.OnMainThread) future;
// Evaluate our task on the main thread and mark it as the next future to evaluate.
Reference temporary = new Reference();
context.executeMainThreadTask( () -> {
temporary.value = onMainThread.getTask().execute();
return null;
} );
future = temporary.value;
if( future == null ) throw new NullPointerException( "Null result from " + onMainThread.getTask() );
}
else if( future instanceof MethodResult.WithLuaContext )
{
MethodResult.WithLuaContext withContext = (MethodResult.WithLuaContext) future;
// Run the task, and then call the previous "then" or return if nothing else
// needs to be done.
Object[] values = withContext.getConsumer().execute( context );
ILuaFunction callback = callbacks == null ? null : callbacks.pollLast();
if( callback == null ) return values;
future = callback.call( values );
if( future == null ) throw new NullPointerException( "Null result from " + callback );
}
else
{
throw new IllegalStateException( "Unknown MethodResult " + future );
}
}
}
private static class Reference
{
MethodResult value;
}
}

View File

@@ -0,0 +1,354 @@
/*
* This file is part of the public ComputerCraft API - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2018. This API may be redistributed unmodified and in full only.
* For help using the API, and posting your mods, visit the forums at computercraft.info.
*/
package dan200.computercraft.api.lua;
import com.google.common.base.Preconditions;
import com.google.common.util.concurrent.ListenableFuture;
import dan200.computercraft.api.peripheral.IComputerAccess;
import dan200.computercraft.api.peripheral.IPeripheral;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.Map;
/**
* The result of calling a method, such as {@link ILuaObject#callMethod(ICallContext, int, Object[])} or
* {@link IPeripheral#callMethod(IComputerAccess, ICallContext, int, Object[])}.
*
* This is non-dissimilar to a promise or {@link ListenableFuture}. One can either return an immediate value through
* {@link #of(Object...)}, wait for an external action with {@link #onMainThread(ILuaCallable)} or {@link #pullEvent()}
* and then act on the result of either of those by using {@link #then(ILuaFunction)}.
*/
public abstract class MethodResult
{
private static MethodResult empty;
MethodResult()
{
}
/**
* A result which returns immediately with no value.
*
* Use {@link #of(Object...)} if you need to return one or more values.
*
* @return The empty method result.
* @see #of(Object...)
*/
@Nonnull
public static MethodResult empty()
{
if( empty == null ) empty = new Immediate( null );
return empty;
}
/**
* A result which returns several values.
*
* @param result The values to return, this may be {@code null}. {@link Number}s, {@link String}s, {@link Boolean}s,
* {@link Map}s, {@link ILuaObject}s, and {@code null} be converted to their corresponding lua type.
* All other types will be converted to nil.
* @return A result which will return these values when evaluated.
* @see #empty()
*/
@Nonnull
public static MethodResult of( Object... result )
{
return result == null ? empty() : new Immediate( result );
}
/**
* Wait for an event to occur on the computer, suspending the coroutine until it arises. This method is equivalent
* to {@code os.pullEvent()} in Lua.
*
* Normally you'll wish to consume the event using {@link #then(ILuaFunction)}. This can be done slightly more
* easily with {@link #pullEvent(ILuaFunction)}.
*
* If you want to listen to a specific event, it's easier to use {@link #pullEvent(String)} rather than
* running until the desired event is found.
*
* @return The constructed method result. This evaluates to the name of the event that occurred, and any event
* parameters.
* @see #pullEvent(ILuaFunction)
* @see #pullEvent(String)
*/
@Nonnull
public static MethodResult pullEvent()
{
return new OnEvent( false, null );
}
/**
* Wait for the specified event to occur on the computer, suspending the coroutine until it arises. This method is
* equivalent to {@code os.pullEvent(event)} in Lua.
*
* Normally you'll wish to consume the event using {@link #then(ILuaFunction)}. This can be done slightly more
* easily with {@link #pullEvent(String, ILuaFunction)}.
*
* @param filter The event name to filter on.
* @return The constructed method result. This evaluates to the name of the event that occurred, and any event
* parameters.
* @see #pullEvent(String, ILuaFunction)
* @see #pullEvent()
*/
@Nonnull
public static MethodResult pullEvent( @Nonnull String filter )
{
Preconditions.checkNotNull( filter, "event cannot be null" );
return new OnEvent( false, filter );
}
/**
* Wait for an event to occur on the computer, suspending the coroutine until it arises. This method to
* {@link #pullEvent()} and {@link #then(ILuaFunction)}.
*
* If you want to listen to a specific event, it's easier to use {@link #pullEvent(String, ILuaFunction)} rather
* than running until the desired event is found.
*
* @param callback The function to call when the event is received.
* @return The constructed method result. This evaluates to the result of the {@code callback}.
* @see #pullEvent()
* @see #pullEvent(String, ILuaFunction)
*/
@Nonnull
public static MethodResult pullEvent( @Nonnull ILuaFunction callback )
{
Preconditions.checkNotNull( callback, "callback cannot be null" );
return new OnEvent( false, null ).then( callback );
}
/**
* Wait for the specified event to occur on the computer, suspending the coroutine until it arises. This method to
* {@link #pullEvent(String)} and {@link #then(ILuaFunction)}.
*
* @param filter The event name to filter on.
* @param callback The function to call when the event is received.
* @return The constructed method result. This evaluates to the result of the {@code callback}.
* @see #pullEvent(String)
* @see #pullEvent(ILuaFunction)
*/
@Nonnull
public static MethodResult pullEvent( @Nullable String filter, @Nonnull ILuaFunction callback )
{
Preconditions.checkNotNull( callback, "callback cannot be null" );
return new OnEvent( false, filter ).then( callback );
}
/**
* The same as {@link #pullEvent()}, except {@code terminated} events are also passed to the callback, instead of
* throwing an error. Only use this if you want to prevent program termination, which is not recommended.
*
* @return The constructed method result. This evaluates to the name of the event that occurred, and any event
* parameters.
*/
@Nonnull
public static MethodResult pullEventRaw()
{
return new OnEvent( true, null );
}
/**
* The same as {@link #pullEvent(String)}, except {@code terminated} events are also passed to the callback, instead
* of throwing an error. Only use this if you want to prevent program termination, which is not recommended.
*
* @param filter The event name to filter on.
* @return The constructed method result. This evaluates to the name of the event that occurred, and any event
* parameters.
*/
@Nonnull
public static MethodResult pullEventRaw( @Nonnull String filter )
{
return new OnEvent( true, filter );
}
/**
* The same as {@link #pullEvent(ILuaFunction)}, except {@code terminated} events are also passed to the callback,
* instead of throwing an error. Only use this if you want to prevent program termination, which is not recommended.
*
* @param callback The function to call when the event is received.
* @return The constructed method result. This evaluates to the result of the {@code callback}.
*/
@Nonnull
public static MethodResult pullEventRaw( @Nonnull ILuaFunction callback )
{
Preconditions.checkNotNull( callback, "callback cannot be null" );
return new OnEvent( true, null ).then( callback );
}
/**
* The same as {@link #pullEvent(String, ILuaFunction)}, except {@code terminated} events are also passed to the
* callback, instead of throwing an error. Only use this if you want to prevent program termination, which is not
* recommended.
*
* @param filter The event name to filter on.
* @param callback The function to call when the event is received.
* @return The constructed method result. This evaluates to the result of the {@code callback}.
*/
@Nonnull
public static MethodResult pullEventRaw( @Nullable String filter, @Nonnull ILuaFunction callback )
{
Preconditions.checkNotNull( callback, "callback cannot be null" );
return new OnEvent( true, filter ).then( callback );
}
/**
* Queue a task to be executed on the main server thread at the beginning of next tick, waiting for it to complete.
* This should be used when you need to interact with the world in a thread-safe manner.
*
* @param callback The task to execute on the server thread.
* @return The constructed method result, which evaluates to the result of the {@code callback}.
*/
@Nonnull
public static MethodResult onMainThread( @Nonnull ILuaCallable callback )
{
Preconditions.checkNotNull( callback, "callback cannot be null" );
return new OnMainThread( callback );
}
/**
* Consume the result of this {@link MethodResult} and return another result.
*
* Note this does NOT modify the current method result, rather returning a new (wrapped) one. You must return the
* result of this call if you wish to use it.
*
* @param callback The function which consumes the provided values.
* @return The constructed method result.
*/
@Nonnull
public final MethodResult then( @Nonnull ILuaFunction callback )
{
Preconditions.checkNotNull( callback, "callback cannot be null" );
return new AndThen( this, callback );
}
/**
* Execute a blocking task within a {@link ILuaContext} and return its result.
*
* @param consumer The task to execute with the provided Lua context.
* @return The constructed method result.
* @see #evaluate(ILuaContext)
* @deprecated This should not be used except to interface between the two call systems.
*/
@Deprecated
public static MethodResult withLuaContext( @Nonnull ILuaContextTask consumer )
{
Preconditions.checkNotNull( consumer, "consumer cannot be null" );
return new WithLuaContext( consumer );
}
/**
* Evaluate this result task using {@link ILuaContext} and return its result.
*
* @param context The context to execute with.
* @return The resulting values.
* @throws LuaException If an error was thrown while executing one of the methods within this future.
* @throws InterruptedException If the user shuts down or reboots the computer while the coroutine is suspended.
* @see #withLuaContext(ILuaContextTask)
* @deprecated This should not be used except to interface between the two call systems.
*/
@Deprecated
public final Object[] evaluate( @Nonnull ILuaContext context ) throws LuaException, InterruptedException
{
return LuaContextResultEvaluator.evaluate( context, this );
}
public static class Immediate extends MethodResult
{
@Nullable
private final Object[] values;
@Nullable
private Immediate( Object[] values )
{
this.values = values;
}
public Object[] getResult()
{
return values;
}
}
public static class OnEvent extends MethodResult
{
private final boolean raw;
private final String filter;
private OnEvent( boolean raw, String filter )
{
this.raw = raw;
this.filter = filter;
}
public boolean isRaw()
{
return raw;
}
@Nullable
public String getFilter()
{
return filter;
}
}
public static class OnMainThread extends MethodResult
{
private final ILuaCallable task;
public OnMainThread( ILuaCallable task )
{
this.task = task;
}
@Nonnull
public ILuaCallable getTask()
{
return task;
}
}
public static class AndThen extends MethodResult
{
private final MethodResult previous;
private final ILuaFunction callback;
private AndThen( MethodResult previous, ILuaFunction callback )
{
this.previous = previous;
this.callback = callback;
}
@Nonnull
public MethodResult getPrevious()
{
return previous;
}
@Nonnull
public ILuaFunction getCallback()
{
return callback;
}
}
public static class WithLuaContext extends MethodResult
{
private final ILuaContextTask consumer;
private WithLuaContext( ILuaContextTask consumer )
{
this.consumer = consumer;
}
@Nonnull
public ILuaContextTask getConsumer()
{
return consumer;
}
}
}

View File

@@ -1,13 +1,15 @@
/*
* This file is part of the public ComputerCraft API - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2017. This API may be redistributed unmodified and in full only.
* Copyright Daniel Ratcliffe, 2011-2018. This API may be redistributed unmodified and in full only.
* For help using the API, and posting your mods, visit the forums at computercraft.info.
*/
package dan200.computercraft.api.peripheral;
import dan200.computercraft.api.lua.ICallContext;
import dan200.computercraft.api.lua.ILuaContext;
import dan200.computercraft.api.lua.LuaException;
import dan200.computercraft.api.lua.MethodResult;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
@@ -70,10 +72,46 @@ public interface IPeripheral
* InterruptedException will be thrown. This exception must not be caught or
* intercepted, or the computer will leak memory and end up in a broken state.
* @see #getMethodNames
* @deprecated Use {@link #callMethod(IComputerAccess, ICallContext, int, Object[])} instead.
*/
@Nullable
@Deprecated
Object[] callMethod( @Nonnull IComputerAccess computer, @Nonnull ILuaContext context, int method, @Nonnull Object[] arguments ) throws LuaException, InterruptedException;
/**
* This is called when a lua program on an attached computer calls {@code peripheral.call()} with
* one of the methods exposed by {@link #getMethodNames()}.
*
* Be aware that this will be called from the ComputerCraft Lua thread, and must be thread-safe
* when interacting with Minecraft objects.
*
* @param computer The interface to the computer that is making the call. Remember that multiple
* computers can be attached to a peripheral at once.
* @param context The context of the current call.
* @param method An integer identifying which of the methods from getMethodNames() the computercraft
* wishes to call. The integer indicates the index into the getMethodNames() table
* that corresponds to the string passed into peripheral.call()
* @param arguments An array of objects, representing the arguments passed into {@code peripheral.call()}.<br>
* Lua values of type "string" will be represented by Object type String.<br>
* Lua values of type "number" will be represented by Object type Double.<br>
* Lua values of type "boolean" will be represented by Object type Boolean.<br>
* Lua values of type "table" will be represented by Object type Map.<br>
* Lua values of any other type will be represented by a null object.<br>
* This array will be empty if no arguments are passed.
* @return The result of calling this method. Use {@link MethodResult#empty()} to return nothing or
* {@link MethodResult#of(Object...)} to return several values.
* @throws LuaException If you throw any exception from this function, a lua error will be raised with the
* same message as your exception. Use this to throw appropriate errors if the wrong
* arguments are supplied to your method.
* @see #getMethodNames
*/
@Nonnull
@SuppressWarnings({ "deprecation" })
default MethodResult callMethod( @Nonnull IComputerAccess computer, @Nonnull ICallContext context, int method, @Nonnull Object[] arguments ) throws LuaException
{
return MethodResult.withLuaContext( lua -> callMethod( computer, lua, method, arguments ) );
}
/**
* Is called when canAttachToSide has returned true, and a computer is attaching to the peripheral.
*

View File

@@ -9,6 +9,7 @@ package dan200.computercraft.api.turtle;
import com.mojang.authlib.GameProfile;
import dan200.computercraft.api.lua.ILuaContext;
import dan200.computercraft.api.lua.LuaException;
import dan200.computercraft.api.lua.MethodResult;
import dan200.computercraft.api.peripheral.IPeripheral;
import net.minecraft.inventory.IInventory;
import net.minecraft.nbt.NBTTagCompound;
@@ -238,10 +239,30 @@ public interface ITurtleAccess
* intercepted, or the computer will leak memory and end up in a broken state.
* @see ITurtleCommand
* @see ILuaContext#pullEvent(String)
* @deprecated Use {@link #executeCommand(ITurtleCommand)} instead.
*/
@Nonnull
@Deprecated
Object[] executeCommand( @Nonnull ILuaContext context, @Nonnull ITurtleCommand command ) throws LuaException, InterruptedException;
/**
* Adds a custom command to the turtles command queue. Unlike peripheral methods, these custom commands will be
* executed on the main thread, so are guaranteed to be able to access Minecraft objects safely, and will be queued
* up with the turtles standard movement and tool commands.
*
* An issued command will return an unique integer, which will be supplied as a parameter to a "turtle_response"
* event issued to the turtle after the command has completed. Look at the Lua source code for "rom/apis/turtle" for
* how to build a Lua wrapper around this functionality.
*
* @param command An object which will execute the custom command when its point in the queue is reached
* @return The constructed method result. This evaluates to the result of the provided {@code command}.
* @throws UnsupportedOperationException When attempting to execute a command on the client side.
* @see ITurtleCommand
* @see MethodResult#pullEvent(String)
*/
@Nonnull
MethodResult executeCommand( @Nonnull ITurtleCommand command );
/**
* Start playing a specific animation. This will prevent other turtle commands from executing until
* it is finished.

View File

@@ -133,7 +133,7 @@ public interface ITurtleUpgrade
* @return The model that you wish to be used to render your upgrade, and a transformation to apply to it. Returning
* a transformation of {@code null} has the same effect as the identify matrix.
*/
@SideOnly(Side.CLIENT)
@SideOnly( Side.CLIENT )
@Nonnull
Pair<IBakedModel, Matrix4f> getModel( @Nullable ITurtleAccess turtle, @Nonnull TurtleSide side );

View File

@@ -6,25 +6,19 @@
package dan200.computercraft.client.gui;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.core.terminal.TextBuffer;
import dan200.computercraft.shared.media.inventory.ContainerHeldItem;
import dan200.computercraft.shared.media.items.ItemPrintout;
import dan200.computercraft.shared.util.Palette;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.util.ResourceLocation;
import org.lwjgl.input.Mouse;
import java.io.IOException;
import static dan200.computercraft.client.render.PrintoutRenderer.*;
public class GuiPrintout extends GuiContainer
{
private static final ResourceLocation background = new ResourceLocation( "computercraft", "textures/gui/printout.png" );
private static final int xSize = 172;
private static final int ySize = 209;
private final boolean m_book;
private final int m_pages;
private final TextBuffer[] m_text;
@@ -34,23 +28,18 @@ public class GuiPrintout extends GuiContainer
public GuiPrintout( ContainerHeldItem container )
{
super( container );
m_book = (ItemPrintout.getType( container.getStack() ) == ItemPrintout.Type.Book);
String[] text = ItemPrintout.getText( container.getStack() );
m_text = new TextBuffer[ text.length ];
for( int i=0; i<m_text.length; ++i )
{
m_text[i] = new TextBuffer( text[i] );
}
for( int i = 0; i < m_text.length; ++i ) m_text[ i ] = new TextBuffer( text[ i ] );
String[] colours = ItemPrintout.getColours( container.getStack() );
m_colours = new TextBuffer[ colours.length ];
for( int i=0; i<m_colours.length; ++i )
{
m_colours[i] = new TextBuffer( colours[i] );
}
for( int i = 0; i < m_colours.length; ++i ) m_colours[ i ] = new TextBuffer( colours[ i ] );
m_pages = Math.max( m_text.length / ItemPrintout.LINES_PER_PAGE, 1 );
m_page = 0;
m_pages = Math.max( m_text.length / ItemPrintout.LINES_PER_PAGE, 1 );
m_book = ItemPrintout.getType( container.getStack() ) == ItemPrintout.Type.Book;
}
@Override
@@ -78,25 +67,19 @@ public class GuiPrintout extends GuiContainer
}
@Override
protected void keyTyped(char c, int k) throws IOException
protected void keyTyped( char c, int k ) throws IOException
{
super.keyTyped( c, k );
if( k == 205 )
{
// Right
if( m_page < m_pages - 1 )
{
m_page = m_page + 1;
}
if( m_page < m_pages - 1 ) m_page++;
}
else if( k == 203 )
{
// Left
if( m_page > 0 )
{
m_page = m_page - 1;
}
// Left
if( m_page > 0 ) m_page--;
}
}
@@ -106,21 +89,15 @@ public class GuiPrintout extends GuiContainer
super.handleMouseInput();
int mouseWheelChange = Mouse.getEventDWheel();
if (mouseWheelChange < 0)
if( mouseWheelChange < 0 )
{
// Up
if( m_page < m_pages - 1 )
{
m_page = m_page + 1;
}
if( m_page < m_pages - 1 ) m_page++;
}
else if (mouseWheelChange > 0)
else if( mouseWheelChange > 0 )
{
// Down
if( m_page > 0 )
{
m_page = m_page - 1;
}
if( m_page > 0 ) m_page--;
}
}
@@ -135,78 +112,20 @@ public class GuiPrintout extends GuiContainer
}
@Override
public void drawScreen(int mouseX, int mouseY, float f)
public void drawScreen( int mouseX, int mouseY, float f )
{
// Draw background
zLevel = zLevel - 1;
drawDefaultBackground();
zLevel = zLevel + 1;
// Draw the printout
GlStateManager.color( 1.0f, 1.0f, 1.0f, 1.0f );
this.mc.getTextureManager().bindTexture( background );
int startY = (height - ySize) / 2;
//int startX = (width - xSize) / 2 - (m_page * 8);
int startX = (width - (xSize + (m_pages - 1)*8)) / 2;
if( m_book )
{
// Border
drawTexturedModalRect( startX - 8, startY - 8, xSize + 48, 0, 12, ySize + 24);
drawTexturedModalRect( startX + xSize + (m_pages - 1)*8 - 4, startY - 8, xSize + 48 + 12, 0, 12, ySize + 24);
drawTexturedModalRect( startX, startY - 8, 0, ySize, xSize, 12);
drawTexturedModalRect( startX, startY + ySize - 4, 0, ySize + 12, xSize, 12);
for( int n=1; n<m_pages; ++n )
{
drawTexturedModalRect( startX + xSize + (n-1)*8, startY - 8, 0, ySize, 8, 12);
drawTexturedModalRect( startX + xSize + (n-1)*8, startY + ySize - 4, 0, ySize + 12, 8, 12);
}
}
// Left half
if( m_page == 0 )
{
drawTexturedModalRect( startX, startY, 24, 0, xSize / 2, ySize);
drawTexturedModalRect( startX, startY, 0, 0, 12, ySize);
}
else
{
drawTexturedModalRect( startX, startY, 0, 0, 12, ySize);
for( int n=1; n<m_page; ++n )
{
drawTexturedModalRect( startX + n*8, startY, 12, 0, 12, ySize);
}
drawTexturedModalRect( startX + m_page*8, startY, 24, 0, xSize / 2, ySize);
}
// Right half
if( m_page == (m_pages - 1) )
{
drawTexturedModalRect( startX + m_page*8 + xSize/2, startY, 24 + xSize / 2, 0, xSize / 2, ySize);
drawTexturedModalRect( startX + m_page*8 + (xSize - 12), startY, 24 + xSize + 12, 0, 12, ySize);
}
else
{
drawTexturedModalRect( startX + (m_pages - 1)*8 + (xSize - 12), startY, 24 + xSize + 12, 0, 12, ySize);
for( int n=m_pages-2; n>=m_page; --n )
{
drawTexturedModalRect( startX + n*8 + (xSize - 12), startY, 24 + xSize, 0, 12, ySize);
}
drawTexturedModalRect( startX + m_page*8 + xSize/2, startY, 24 + xSize / 2, 0, xSize / 2, ySize);
}
// Draw the text
FixedWidthFontRenderer fontRenderer = (FixedWidthFontRenderer)ComputerCraft.getFixedWidthFontRenderer();
int x = startX + m_page * 8 + 13;
int y = startY + 11;
for( int line=0; line<ItemPrintout.LINES_PER_PAGE; ++line )
{
int lineIdx = ItemPrintout.LINES_PER_PAGE * m_page + line;
if( lineIdx >= 0 && lineIdx < m_text.length )
{
fontRenderer.drawString( m_text[lineIdx], x, y, m_colours[lineIdx], null, 0, 0, false, Palette.DEFAULT );
}
y = y + FixedWidthFontRenderer.FONT_HEIGHT;
}
int startY = (height - Y_SIZE) / 2;
int startX = (width - X_SIZE) / 2;
drawBorder( startX, startY, zLevel, m_page, m_pages, m_book );
drawText( startX + X_TEXT_MARGIN, startY + Y_TEXT_MARGIN, ItemPrintout.LINES_PER_PAGE * m_page, m_text, m_colours );
}
}

View File

@@ -9,6 +9,7 @@ package dan200.computercraft.client.proxy;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.client.gui.*;
import dan200.computercraft.client.render.ItemPocketRenderer;
import dan200.computercraft.client.render.ItemPrintoutRenderer;
import dan200.computercraft.client.render.RenderOverlayCable;
import dan200.computercraft.client.render.TileEntityCableRenderer;
import dan200.computercraft.client.render.TileEntityMonitorRenderer;
@@ -497,6 +498,7 @@ public class ComputerCraftProxyClient extends ComputerCraftProxyCommon
MinecraftForge.EVENT_BUS.register( handlers );
MinecraftForge.EVENT_BUS.register( new RenderOverlayCable() );
MinecraftForge.EVENT_BUS.register( new ItemPocketRenderer() );
MinecraftForge.EVENT_BUS.register( new ItemPrintoutRenderer() );
}
public class ForgeHandlers

View File

@@ -0,0 +1,197 @@
package dan200.computercraft.client.render;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.shared.media.items.ItemPrintout;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.ItemRenderer;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumHand;
import net.minecraft.util.EnumHandSide;
import net.minecraft.util.math.MathHelper;
import net.minecraftforge.client.event.RenderItemInFrameEvent;
import net.minecraftforge.client.event.RenderSpecificHandEvent;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import static dan200.computercraft.client.gui.FixedWidthFontRenderer.FONT_HEIGHT;
import static dan200.computercraft.client.gui.FixedWidthFontRenderer.FONT_WIDTH;
import static dan200.computercraft.client.render.PrintoutRenderer.*;
import static dan200.computercraft.shared.media.items.ItemPrintout.LINES_PER_PAGE;
import static dan200.computercraft.shared.media.items.ItemPrintout.LINE_MAX_LENGTH;
public class ItemPrintoutRenderer
{
@SubscribeEvent
public void onRenderInHand( RenderSpecificHandEvent event )
{
ItemStack stack = event.getItemStack();
if( stack.getItem() != ComputerCraft.Items.printout ) return;
event.setCanceled( true );
EntityPlayer player = Minecraft.getMinecraft().player;
GlStateManager.pushMatrix();
if( event.getHand() == EnumHand.MAIN_HAND && player.getHeldItemOffhand().isEmpty() )
{
renderPrintoutFirstPersonCentre(
event.getInterpolatedPitch(),
event.getEquipProgress(),
event.getSwingProgress(),
stack
);
}
else
{
renderPrintoutFirstPersonSide(
event.getHand() == EnumHand.MAIN_HAND ? player.getPrimaryHand() : player.getPrimaryHand().opposite(),
event.getEquipProgress(),
event.getSwingProgress(),
stack
);
}
GlStateManager.popMatrix();
}
/**
* Renders a pocket computer to one side of the player.
*
* @param side The side to render on
* @param equipProgress The equip progress of this item
* @param swingProgress The swing progress of this item
* @param stack The stack to render
* @see ItemRenderer#renderMapFirstPersonSide(float, EnumHandSide, float, ItemStack)
*/
private void renderPrintoutFirstPersonSide( EnumHandSide side, float equipProgress, float swingProgress, ItemStack stack )
{
Minecraft minecraft = Minecraft.getMinecraft();
float offset = side == EnumHandSide.RIGHT ? 1f : -1f;
GlStateManager.translate( offset * 0.125f, -0.125f, 0f );
// If the player is not invisible then render a single arm
if( !minecraft.player.isInvisible() )
{
GlStateManager.pushMatrix();
GlStateManager.rotate( offset * 10f, 0f, 0f, 1f );
minecraft.getItemRenderer().renderArmFirstPerson( equipProgress, swingProgress, side );
GlStateManager.popMatrix();
}
// Setup the appropriate transformations. This is just copied from the
// corresponding method in ItemRenderer.
GlStateManager.pushMatrix();
GlStateManager.translate( offset * 0.51f, -0.08f + equipProgress * -1.2f, -0.75f );
float f1 = MathHelper.sqrt( swingProgress );
float f2 = MathHelper.sin( f1 * (float) Math.PI );
float f3 = -0.5f * f2;
float f4 = 0.4f * MathHelper.sin( f1 * ((float) Math.PI * 2f) );
float f5 = -0.3f * MathHelper.sin( swingProgress * (float) Math.PI );
GlStateManager.translate( offset * f3, f4 - 0.3f * f2, f5 );
GlStateManager.rotate( f2 * -45f, 1f, 0f, 0f );
GlStateManager.rotate( offset * f2 * -30f, 0f, 1f, 0f );
renderPrintoutFirstPerson( stack );
GlStateManager.popMatrix();
}
/**
* Render an item in the middle of the screen
*
* @param pitch The pitch of the player
* @param equipProgress The equip progress of this item
* @param swingProgress The swing progress of this item
* @param stack The stack to render
* @see ItemRenderer#renderMapFirstPerson(float, float, float)
*/
private void renderPrintoutFirstPersonCentre( float pitch, float equipProgress, float swingProgress, ItemStack stack )
{
ItemRenderer itemRenderer = Minecraft.getMinecraft().getItemRenderer();
// Setup the appropriate transformations. This is just copied from the
// corresponding method in ItemRenderer.
float swingRt = MathHelper.sqrt( swingProgress );
float tX = -0.2f * MathHelper.sin( swingProgress * (float) Math.PI );
float tZ = -0.4f * MathHelper.sin( swingRt * (float) Math.PI );
GlStateManager.translate( 0f, -tX / 2f, tZ );
float pitchAngle = itemRenderer.getMapAngleFromPitch( pitch );
GlStateManager.translate( 0f, 0.04f + equipProgress * -1.2f + pitchAngle * -0.5f, -0.72f );
GlStateManager.rotate( pitchAngle * -85f, 1f, 0f, 0f );
itemRenderer.renderArms();
float rX = MathHelper.sin( swingRt * (float) Math.PI );
GlStateManager.rotate( rX * 20f, 1f, 0f, 0f );
GlStateManager.scale( 2f, 2f, 2f );
renderPrintoutFirstPerson( stack );
}
private static void renderPrintoutFirstPerson( ItemStack stack )
{
// Setup various transformations. Note that these are partially adapated from the corresponding method
// in ItemRenderer.renderMapFirstPerson
GlStateManager.disableLighting();
GlStateManager.rotate( 180f, 0f, 1f, 0f );
GlStateManager.rotate( 180f, 0f, 0f, 1f );
GlStateManager.scale( 0.42f, 0.42f, -0.42f );
GlStateManager.translate( -0.5f, -0.48f, 0.0f );
drawPrintout( stack );
GlStateManager.enableLighting();
}
@SubscribeEvent
public void onRenderInFrame( RenderItemInFrameEvent event )
{
ItemStack stack = event.getItem();
if( stack.getItem() != ComputerCraft.Items.printout ) return;
event.setCanceled( true );
GlStateManager.disableLighting();
// Move a little bit forward to ensure we're not clipping with the frame
GlStateManager.translate( 0.0f, 0.0f, -0.001f );
GlStateManager.rotate( 180f, 0f, 0f, 1f );
GlStateManager.scale( 0.95f, 0.95f, -0.95f );
GlStateManager.translate( -0.5f, -0.5f, 0.0f );
drawPrintout( stack );
GlStateManager.enableLighting();
}
private static void drawPrintout( ItemStack stack )
{
int pages = ItemPrintout.getPageCount( stack );
boolean book = ItemPrintout.getType( stack ) == ItemPrintout.Type.Book;
double width = LINE_MAX_LENGTH * FONT_WIDTH + X_TEXT_MARGIN * 2;
double height = LINES_PER_PAGE * FONT_HEIGHT + Y_TEXT_MARGIN * 2;
// Non-books will be left aligned
if( !book ) width += offsetAt( pages );
double visualWidth = width, visualHeight = height;
// Meanwhile books will be centred
if( book )
{
visualWidth += 2 * COVER_SIZE + 2 * offsetAt( pages );
visualHeight += 2 * COVER_SIZE;
}
double max = Math.max( visualHeight, visualWidth );
// Scale the printout to fit correctly.
double scale = 1.0 / max;
GlStateManager.scale( scale, scale, scale );
GlStateManager.translate( (max - width) / 2.0f, (max - height) / 2.0f, 0.0f );
drawBorder( 0, 0, -0.01, 0, pages, book );
drawText( X_TEXT_MARGIN, Y_TEXT_MARGIN, 0, ItemPrintout.getText( stack ), ItemPrintout.getColours( stack ) );
}
}

View File

@@ -0,0 +1,169 @@
package dan200.computercraft.client.render;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.client.gui.FixedWidthFontRenderer;
import dan200.computercraft.core.terminal.TextBuffer;
import dan200.computercraft.shared.util.Palette;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.BufferBuilder;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.util.ResourceLocation;
import org.lwjgl.opengl.GL11;
import static dan200.computercraft.client.gui.FixedWidthFontRenderer.FONT_HEIGHT;
import static dan200.computercraft.shared.media.items.ItemPrintout.LINES_PER_PAGE;
public class PrintoutRenderer
{
private static final ResourceLocation BG = new ResourceLocation( "computercraft", "textures/gui/printout.png" );
private static final double BG_SIZE = 256.0;
/**
* Width of a page
*/
public static final int X_SIZE = 172;
/**
* Height of a page
*/
public static final int Y_SIZE = 209;
/**
* Padding between the left and right of a page and the text
*/
public static final int X_TEXT_MARGIN = 13;
/**
* Padding between the top and bottom of a page and the text
*/
public static final int Y_TEXT_MARGIN = 11;
/**
* Width of the extra page texture
*/
private static final int X_FOLD_SIZE = 12;
/**
* Size of the leather cover
*/
public static final int COVER_SIZE = 12;
private static final int COVER_Y = Y_SIZE;
private static final int COVER_X = X_SIZE + 4 * X_FOLD_SIZE;
public static void drawText( int x, int y, int start, TextBuffer[] text, TextBuffer[] colours )
{
FixedWidthFontRenderer fontRenderer = (FixedWidthFontRenderer) ComputerCraft.getFixedWidthFontRenderer();
for( int line = 0; line < LINES_PER_PAGE && line < text.length; ++line )
{
fontRenderer.drawString( text[ start + line ], x, y + line * FONT_HEIGHT, colours[ start + line ], null, 0, 0, false, Palette.DEFAULT );
}
}
public static void drawText( int x, int y, int start, String[] text, String[] colours )
{
GlStateManager.color( 1.0f, 1.0f, 1.0f, 1.0f );
GlStateManager.enableBlend();
GlStateManager.enableTexture2D();
FixedWidthFontRenderer fontRenderer = (FixedWidthFontRenderer) ComputerCraft.getFixedWidthFontRenderer();
for( int line = 0; line < LINES_PER_PAGE && line < text.length; ++line )
{
fontRenderer.drawString( new TextBuffer( text[ start + line ] ), x, y + line * FONT_HEIGHT, new TextBuffer( colours[ start + line ] ), null, 0, 0, false, Palette.DEFAULT );
}
}
public static void drawBorder( double x, double y, double z, int page, int pages, boolean isBook )
{
GlStateManager.color( 1.0f, 1.0f, 1.0f, 1.0f );
GlStateManager.enableBlend();
GlStateManager.enableTexture2D();
Minecraft.getMinecraft().getTextureManager().bindTexture( BG );
Tessellator tessellator = Tessellator.getInstance();
BufferBuilder buffer = tessellator.getBuffer();
buffer.begin( GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX );
int leftPages = page;
int rightPages = pages - page - 1;
if( isBook )
{
// Border
double offset = offsetAt( pages );
final double left = x - 4 - offset;
final double right = x + X_SIZE + offset - 4;
// Left and right border
drawTexture( buffer, left - 4, y - 8, z - 0.02, COVER_X, 0, COVER_SIZE, Y_SIZE + COVER_SIZE * 2 );
drawTexture( buffer, right, y - 8, z - 0.02, COVER_X + COVER_SIZE, 0, COVER_SIZE, Y_SIZE + COVER_SIZE * 2 );
// Draw centre panel (just stretched texture, sorry).
drawTexture( buffer,
x - offset, y, z - 0.02, X_SIZE + offset * 2, Y_SIZE,
COVER_X + COVER_SIZE / 2, COVER_SIZE, COVER_SIZE, Y_SIZE
);
double borderX = left;
while( borderX < right )
{
double thisWidth = Math.min( right - borderX, X_SIZE );
drawTexture( buffer, borderX, y - 8, z - 0.02, 0, COVER_Y, thisWidth, COVER_SIZE );
drawTexture( buffer, borderX, y + Y_SIZE - 4, z - 0.02, 0, COVER_Y + COVER_SIZE, thisWidth, COVER_SIZE );
borderX += thisWidth;
}
}
// Left half
drawTexture( buffer, x, y, z, X_FOLD_SIZE * 2, 0, X_SIZE / 2, Y_SIZE );
for( int n = 0; n <= leftPages; n++ )
{
drawTexture( buffer,
x - offsetAt( n ), y, z - 1e-3 * n,
// Use the left "bold" fold for the outermost page
n == leftPages ? 0 : X_FOLD_SIZE, 0,
X_FOLD_SIZE, Y_SIZE
);
}
// Right half
drawTexture( buffer, x + X_SIZE / 2, y, z, X_FOLD_SIZE * 2 + X_SIZE / 2, 0, X_SIZE / 2, Y_SIZE );
for( int n = 0; n <= rightPages; n++ )
{
drawTexture( buffer,
x + (X_SIZE - X_FOLD_SIZE) + offsetAt( n ), y, z - 1e-3 * n,
// Two folds, then the main page. Use the right "bold" fold for the outermost page.
X_FOLD_SIZE * 2 + X_SIZE + (n == rightPages ? X_FOLD_SIZE : 0), 0,
X_FOLD_SIZE, Y_SIZE
);
}
tessellator.draw();
}
private static void drawTexture( BufferBuilder buffer, double x, double y, double z, double u, double v, double width, double height )
{
buffer.pos( x, y + height, z ).tex( u / BG_SIZE, (v + height) / BG_SIZE ).endVertex();
buffer.pos( x + width, y + height, z ).tex( (u + width) / BG_SIZE, (v + height) / BG_SIZE ).endVertex();
buffer.pos( x + width, y, z ).tex( (u + width) / BG_SIZE, v / BG_SIZE ).endVertex();
buffer.pos( x, y, z ).tex( u / BG_SIZE, v / BG_SIZE ).endVertex();
}
private static void drawTexture( BufferBuilder buffer, double x, double y, double z, double width, double height, double u, double v, double tWidth, double tHeight )
{
buffer.pos( x, y + height, z ).tex( u / BG_SIZE, (v + tHeight) / BG_SIZE ).endVertex();
buffer.pos( x + width, y + height, z ).tex( (u + tWidth) / BG_SIZE, (v + tHeight) / BG_SIZE ).endVertex();
buffer.pos( x + width, y, z ).tex( (u + tWidth) / BG_SIZE, v / BG_SIZE ).endVertex();
buffer.pos( x, y, z ).tex( u / BG_SIZE, v / BG_SIZE ).endVertex();
}
public static double offsetAt( int page )
{
return 32 * (1 - Math.pow( 1.2, -page ));
}
}

View File

@@ -71,7 +71,7 @@ public class TileEntityCableRenderer extends TileEntitySpecialRenderer<TileCable
buffer.setTranslation( x - pos.getX(), y - pos.getY(), z - pos.getZ() );
buffer.noColor();
ForgeHooksClient.setRenderLayer( block.getBlockLayer() );
ForgeHooksClient.setRenderLayer( block.getRenderLayer() );
// See BlockRendererDispatcher#renderBlockDamage
TextureAtlasSprite breakingTexture = mc.getTextureMapBlocks().getAtlasSprite( "minecraft:blocks/destroy_stage_" + destroyStage );

View File

@@ -6,13 +6,12 @@
package dan200.computercraft.core.apis;
import dan200.computercraft.api.lua.*;
import dan200.computercraft.api.lua.ILuaAPI;
import dan200.computercraft.api.lua.ILuaContext;
import dan200.computercraft.api.lua.ILuaObject;
import dan200.computercraft.api.lua.LuaException;
import dan200.computercraft.core.terminal.TextBuffer;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import static dan200.computercraft.core.apis.ArgumentHelper.getString;
import static dan200.computercraft.core.apis.ArgumentHelper.optInt;
@@ -41,27 +40,28 @@ public class BufferAPI implements ILuaAPI
};
}
@Nonnull
@Override
public Object[] callMethod( @Nonnull ILuaContext context, int method, @Nonnull Object[] arguments ) throws LuaException, InterruptedException
public MethodResult callMethod( @Nonnull ICallContext context, int method, @Nonnull Object[] arguments ) throws LuaException
{
switch( method )
{
case 0:
{
// len
return new Object[] { m_buffer.length() };
return MethodResult.of( m_buffer.length() );
}
case 1:
{
// tostring
return new Object[] { m_buffer.toString() };
return MethodResult.of( m_buffer.toString() );
}
case 2:
{
// read
int start = optInt( arguments, 0, 0 );
int end = optInt( arguments, 1, m_buffer.length() );
return new Object[] { m_buffer.read( start, end ) };
return MethodResult.of( m_buffer.read( start, end ) );
}
case 3:
{
@@ -70,7 +70,7 @@ public class BufferAPI implements ILuaAPI
int start = optInt( arguments, 1, 0 );
int end = optInt( arguments, 2, start + text.length() );
m_buffer.write( text, start, end );
return null;
return MethodResult.empty();
}
case 4:
{
@@ -79,14 +79,22 @@ public class BufferAPI implements ILuaAPI
int start = optInt( arguments, 1, 0 );
int end = optInt( arguments, 2, m_buffer.length() );
m_buffer.fill( text, start, end );
return null;
return MethodResult.empty();
}
default:
{
return null;
return MethodResult.empty();
}
}
}
@Nullable
@Override
@Deprecated
public Object[] callMethod( @Nonnull ILuaContext context, int method, @Nonnull Object[] arguments ) throws LuaException, InterruptedException
{
return callMethod( (ICallContext) context, method, arguments ).evaluate( context );
}
}
public BufferAPI( IAPIEnvironment _env )
@@ -110,8 +118,9 @@ public class BufferAPI implements ILuaAPI
};
}
@Nonnull
@Override
public Object[] callMethod( @Nonnull ILuaContext context, int method, @Nonnull Object[] arguments ) throws LuaException, InterruptedException
public MethodResult callMethod( @Nonnull ICallContext context, int method, @Nonnull Object[] arguments ) throws LuaException
{
switch( method )
{
@@ -124,12 +133,20 @@ public class BufferAPI implements ILuaAPI
throw ArgumentHelper.badArgument( 1, "positive number", Integer.toString( repetitions ) );
}
TextBuffer buffer = new TextBuffer( text, repetitions );
return new Object[] { new BufferLuaObject( buffer ) };
return MethodResult.of( new BufferLuaObject( buffer ) );
}
default:
{
return null;
return MethodResult.empty();
}
}
}
@Nullable
@Override
@Deprecated
public Object[] callMethod( @Nonnull ILuaContext context, int method, @Nonnull Object[] arguments ) throws LuaException, InterruptedException
{
return callMethod( (ICallContext) context, method, arguments ).evaluate( context );
}
}

View File

@@ -3,14 +3,17 @@ package dan200.computercraft.core.apis;
import dan200.computercraft.api.filesystem.IMount;
import dan200.computercraft.api.filesystem.IWritableMount;
import dan200.computercraft.api.peripheral.IComputerAccess;
import dan200.computercraft.core.computer.Computer;
import dan200.computercraft.core.computer.IComputerOwned;
import dan200.computercraft.core.filesystem.FileSystem;
import dan200.computercraft.core.filesystem.FileSystemException;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.HashSet;
import java.util.Set;
public abstract class ComputerAccess implements IComputerAccess
public abstract class ComputerAccess implements IComputerAccess, IComputerOwned
{
private final IAPIEnvironment m_environment;
private final Set<String> m_mounts = new HashSet<>();
@@ -133,6 +136,13 @@ public abstract class ComputerAccess implements IComputerAccess
m_environment.queueEvent( event, arguments );
}
@Nullable
@Override
public Computer getComputer()
{
return m_environment.getComputer();
}
private String findFreeLocation( String desiredLoc )
{
try

View File

@@ -6,9 +6,8 @@
package dan200.computercraft.core.apis;
import dan200.computercraft.api.lua.*;
import dan200.computercraft.api.lua.ILuaAPI;
import dan200.computercraft.api.lua.ILuaContext;
import dan200.computercraft.api.lua.LuaException;
import dan200.computercraft.core.apis.handles.BinaryInputHandle;
import dan200.computercraft.core.apis.handles.BinaryOutputHandle;
import dan200.computercraft.core.apis.handles.EncodedInputHandle;
@@ -18,6 +17,7 @@ import dan200.computercraft.core.filesystem.FileSystemException;
import dan200.computercraft.core.tracking.TrackingField;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.HashMap;
@@ -80,8 +80,9 @@ public class FSAPI implements ILuaAPI
};
}
@Nonnull
@Override
public Object[] callMethod( @Nonnull ILuaContext context, int method, @Nonnull Object[] args ) throws LuaException
public MethodResult callMethod( @Nonnull ICallContext context, int method, @Nonnull Object[] args ) throws LuaException
{
switch( method )
{
@@ -96,7 +97,7 @@ public class FSAPI implements ILuaAPI
for(int i=0; i<results.length; ++i ) {
table.put( i+1, results[i] );
}
return new Object[] { table };
return MethodResult.of( table );
}
catch( FileSystemException e )
{
@@ -108,13 +109,13 @@ public class FSAPI implements ILuaAPI
// combine
String pathA = getString( args, 0 );
String pathB = getString( args, 1 );
return new Object[] { m_fileSystem.combine( pathA, pathB ) };
return MethodResult.of( m_fileSystem.combine( pathA, pathB ) );
}
case 2:
{
// getName
String path = getString( args, 0 );
return new Object[]{ FileSystem.getName( path ) };
return MethodResult.of( FileSystem.getName( path ) );
}
case 3:
{
@@ -122,7 +123,7 @@ public class FSAPI implements ILuaAPI
String path = getString( args, 0 );
try
{
return new Object[]{ m_fileSystem.getSize( path ) };
return MethodResult.of( m_fileSystem.getSize( path ) );
}
catch( FileSystemException e )
{
@@ -134,9 +135,9 @@ public class FSAPI implements ILuaAPI
// exists
String path = getString( args, 0 );
try {
return new Object[]{ m_fileSystem.exists( path ) };
return MethodResult.of( m_fileSystem.exists( path ) );
} catch( FileSystemException e ) {
return new Object[]{ false };
return MethodResult.of( false );
}
}
case 5:
@@ -144,9 +145,9 @@ public class FSAPI implements ILuaAPI
// isDir
String path = getString( args, 0 );
try {
return new Object[]{ m_fileSystem.isDir( path ) };
return MethodResult.of( m_fileSystem.isDir( path ) );
} catch( FileSystemException e ) {
return new Object[]{ false };
return MethodResult.of( false );
}
}
case 6:
@@ -154,9 +155,9 @@ public class FSAPI implements ILuaAPI
// isReadOnly
String path = getString( args, 0 );
try {
return new Object[]{ m_fileSystem.isReadOnly( path ) };
return MethodResult.of( m_fileSystem.isReadOnly( path ) );
} catch( FileSystemException e ) {
return new Object[]{ false };
return MethodResult.of( false );
}
}
case 7:
@@ -166,7 +167,7 @@ public class FSAPI implements ILuaAPI
try {
m_env.addTrackingChange( TrackingField.FS_OPS );
m_fileSystem.makeDir( path );
return null;
return MethodResult.empty();
} catch( FileSystemException e ) {
throw new LuaException( e.getMessage() );
}
@@ -179,7 +180,7 @@ public class FSAPI implements ILuaAPI
try {
m_env.addTrackingChange( TrackingField.FS_OPS );
m_fileSystem.move( path, dest );
return null;
return MethodResult.empty();
} catch( FileSystemException e ) {
throw new LuaException( e.getMessage() );
}
@@ -192,7 +193,7 @@ public class FSAPI implements ILuaAPI
try {
m_env.addTrackingChange( TrackingField.FS_OPS );
m_fileSystem.copy( path, dest );
return null;
return MethodResult.empty();
} catch( FileSystemException e ) {
throw new LuaException( e.getMessage() );
}
@@ -204,7 +205,7 @@ public class FSAPI implements ILuaAPI
try {
m_env.addTrackingChange( TrackingField.FS_OPS );
m_fileSystem.delete( path );
return null;
return MethodResult.empty();
} catch( FileSystemException e ) {
throw new LuaException( e.getMessage() );
}
@@ -222,43 +223,43 @@ public class FSAPI implements ILuaAPI
{
// Open the file for reading, then create a wrapper around the reader
InputStream reader = m_fileSystem.openForRead( path );
return new Object[] { new EncodedInputHandle( reader ) };
return MethodResult.of( new EncodedInputHandle( reader ) );
}
case "w":
{
// Open the file for writing, then create a wrapper around the writer
OutputStream writer = m_fileSystem.openForWrite( path, false );
return new Object[] { new EncodedOutputHandle( writer ) };
return MethodResult.of( new EncodedOutputHandle( writer ) );
}
case "a":
{
// Open the file for appending, then create a wrapper around the writer
OutputStream writer = m_fileSystem.openForWrite( path, true );
return new Object[] { new EncodedOutputHandle( writer ) };
return MethodResult.of( new EncodedOutputHandle( writer ) );
}
case "rb":
{
// Open the file for binary reading, then create a wrapper around the reader
InputStream reader = m_fileSystem.openForRead( path );
return new Object[] { new BinaryInputHandle( reader ) };
return MethodResult.of( new BinaryInputHandle( reader ) );
}
case "wb":
{
// Open the file for binary writing, then create a wrapper around the writer
OutputStream writer = m_fileSystem.openForWrite( path, false );
return new Object[] { new BinaryOutputHandle( writer ) };
return MethodResult.of( new BinaryOutputHandle( writer ) );
}
case "ab":
{
// Open the file for binary appending, then create a wrapper around the reader
OutputStream writer = m_fileSystem.openForWrite( path, true );
return new Object[] { new BinaryOutputHandle( writer ) };
return MethodResult.of( new BinaryOutputHandle( writer ) );
}
default:
throw new LuaException( "Unsupported mode" );
}
} catch( FileSystemException e ) {
return new Object[] { null, e.getMessage() };
return MethodResult.of( null, e.getMessage() );
}
}
case 12:
@@ -268,9 +269,9 @@ public class FSAPI implements ILuaAPI
try {
if( !m_fileSystem.exists( path ) )
{
return null;
return MethodResult.empty();
}
return new Object[]{ m_fileSystem.getMountLabel( path ) };
return MethodResult.of( m_fileSystem.getMountLabel( path ) );
} catch( FileSystemException e ) {
throw new LuaException( e.getMessage() );
}
@@ -283,9 +284,9 @@ public class FSAPI implements ILuaAPI
long freeSpace = m_fileSystem.getFreeSpace( path );
if( freeSpace >= 0 )
{
return new Object[]{ freeSpace };
return MethodResult.of( freeSpace );
}
return new Object[]{ "unlimited" };
return MethodResult.of( "unlimited" );
} catch( FileSystemException e ) {
throw new LuaException( e.getMessage() );
}
@@ -301,7 +302,7 @@ public class FSAPI implements ILuaAPI
for(int i=0; i<results.length; ++i ) {
table.put( i+1, results[i] );
}
return new Object[] { table };
return MethodResult.of( table );
} catch( FileSystemException e ) {
throw new LuaException( e.getMessage() );
}
@@ -310,13 +311,21 @@ public class FSAPI implements ILuaAPI
{
// getDir
String path = getString( args, 0 );
return new Object[]{ FileSystem.getDirectory( path ) };
return MethodResult.of( FileSystem.getDirectory( path ) );
}
default:
{
assert( false );
return null;
return MethodResult.empty();
}
}
}
@Nullable
@Override
@Deprecated
public Object[] callMethod( @Nonnull ILuaContext context, int method, @Nonnull Object[] arguments ) throws LuaException, InterruptedException
{
return callMethod( (ICallContext) context, method, arguments ).evaluate( context );
}
}

View File

@@ -8,12 +8,12 @@ package dan200.computercraft.core.apis;
import com.google.common.collect.ImmutableSet;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.api.lua.*;
import dan200.computercraft.api.lua.ILuaAPI;
import dan200.computercraft.api.lua.ILuaContext;
import dan200.computercraft.api.lua.LuaException;
import dan200.computercraft.core.apis.http.*;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.io.Closeable;
import java.io.IOException;
import java.net.URI;
@@ -102,8 +102,9 @@ public class HTTPAPI implements ILuaAPI
};
}
@Nonnull
@Override
public Object[] callMethod( @Nonnull ILuaContext context, int method, @Nonnull Object[] args ) throws LuaException
public MethodResult callMethod( @Nonnull ICallContext context, int method, @Nonnull Object[] args ) throws LuaException
{
switch( method )
{
@@ -164,11 +165,11 @@ public class HTTPAPI implements ILuaAPI
{
m_httpTasks.add( HTTPExecutor.EXECUTOR.submit( request ) );
}
return new Object[]{ true };
return MethodResult.of(true);
}
catch( HTTPRequestException e )
{
return new Object[]{ false, e.getMessage() };
return MethodResult.of( false, e.getMessage() );
}
}
case 1:
@@ -186,11 +187,11 @@ public class HTTPAPI implements ILuaAPI
{
m_httpTasks.add( HTTPExecutor.EXECUTOR.submit( check ) );
}
return new Object[]{ true };
return MethodResult.of( true );
}
catch( HTTPRequestException e )
{
return new Object[]{ false, e.getMessage() };
return MethodResult.of( false, e.getMessage() );
}
}
case 2: // websocket
@@ -223,20 +224,28 @@ public class HTTPAPI implements ILuaAPI
{
m_httpTasks.add( connector );
}
return new Object[]{ true };
return MethodResult.of(true);
}
catch( HTTPRequestException e )
{
return new Object[]{ false, e.getMessage() };
return MethodResult.of( false, e.getMessage() );
}
}
default:
{
return null;
return MethodResult.empty();
}
}
}
@Nullable
@Override
@Deprecated
public Object[] callMethod( @Nonnull ILuaContext context, int method, @Nonnull Object[] arguments ) throws LuaException, InterruptedException
{
return callMethod( (ICallContext) context, method, arguments ).evaluate( context );
}
public void addCloseable( Closeable closeable )
{
synchronized( m_closeables )

View File

@@ -9,17 +9,19 @@ package dan200.computercraft.core.apis;
import dan200.computercraft.api.peripheral.IPeripheral;
import dan200.computercraft.core.computer.Computer;
import dan200.computercraft.core.computer.IComputerEnvironment;
import dan200.computercraft.core.computer.IComputerOwned;
import dan200.computercraft.core.filesystem.FileSystem;
import dan200.computercraft.core.terminal.Terminal;
import dan200.computercraft.core.tracking.TrackingField;
public interface IAPIEnvironment
public interface IAPIEnvironment extends IComputerOwned
{
interface IPeripheralChangeListener
{
void onPeripheralChanged( int side, IPeripheral newPeripheral );
}
@Override
Computer getComputer();
int getComputerID();
IComputerEnvironment getComputerEnvironment();

View File

@@ -6,12 +6,12 @@
package dan200.computercraft.core.apis;
import dan200.computercraft.api.lua.*;
import dan200.computercraft.api.lua.ILuaAPI;
import dan200.computercraft.api.lua.ILuaContext;
import dan200.computercraft.api.lua.LuaException;
import dan200.computercraft.shared.util.StringUtil;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.*;
import static dan200.computercraft.core.apis.ArgumentHelper.*;
@@ -221,7 +221,8 @@ public class OSAPI implements ILuaAPI
}
@Override
public Object[] callMethod( @Nonnull ILuaContext context, int method, @Nonnull Object[] args ) throws LuaException
@Nonnull
public MethodResult callMethod( @Nonnull ICallContext context, int method, @Nonnull Object[] args ) throws LuaException
{
switch( method )
{
@@ -229,7 +230,7 @@ public class OSAPI implements ILuaAPI
{
// queueEvent
queueLuaEvent( getString( args, 0 ), trimArray( args, 1 ) );
return null;
return MethodResult.empty();
}
case 1:
{
@@ -238,7 +239,7 @@ public class OSAPI implements ILuaAPI
synchronized( m_timers )
{
m_timers.put( m_nextTimerToken, new Timer( (int)Math.round( timer / 0.05 ) ) );
return new Object[] { m_nextTimerToken++ };
return MethodResult.of( m_nextTimerToken++ );
}
}
case 2:
@@ -253,33 +254,33 @@ public class OSAPI implements ILuaAPI
{
int day = (time > m_time) ? m_day : (m_day + 1);
m_alarms.put( m_nextAlarmToken, new Alarm( time, day ) );
return new Object[] { m_nextAlarmToken++ };
return MethodResult.of( m_nextAlarmToken++ );
}
}
case 3:
{
// shutdown
m_apiEnvironment.shutdown();
return null;
return MethodResult.empty();
}
case 4:
{
// reboot
m_apiEnvironment.reboot();
return null;
return MethodResult.empty();
}
case 5:
case 6:
{
// computerID/getComputerID
return new Object[] { getComputerID() };
return MethodResult.of( getComputerID() );
}
case 7:
{
// setComputerLabel
String label = optString( args, 0, null );
m_apiEnvironment.setLabel( StringUtil.normaliseLabel( label ) );
return null;
return MethodResult.empty();
}
case 8:
case 9:
@@ -288,16 +289,16 @@ public class OSAPI implements ILuaAPI
String label = m_apiEnvironment.getLabel();
if( label != null )
{
return new Object[] { label };
return MethodResult.of( label );
}
return null;
return MethodResult.empty();
}
case 10:
{
// clock
synchronized( m_timers )
{
return new Object[] { m_clock * 0.05 };
return MethodResult.of( m_clock * 0.05 );
}
}
case 11:
@@ -310,19 +311,19 @@ public class OSAPI implements ILuaAPI
{
// Get Hour of day (UTC)
Calendar c = Calendar.getInstance( TimeZone.getTimeZone( "UTC" ) );
return new Object[] { getTimeForCalendar( c ) };
return MethodResult.of( getTimeForCalendar( c ) );
}
case "local":
{
// Get Hour of day (local time)
Calendar c = Calendar.getInstance();
return new Object[] { getTimeForCalendar( c ) };
return MethodResult.of( getTimeForCalendar( c ) );
}
case "ingame":
// Get ingame hour
synchronized( m_alarms )
{
return new Object[] { m_time };
return MethodResult.of( m_time );
}
default:
throw new LuaException( "Unsupported operation" );
@@ -338,19 +339,19 @@ public class OSAPI implements ILuaAPI
{
// Get numbers of days since 1970-01-01 (utc)
Calendar c = Calendar.getInstance( TimeZone.getTimeZone( "UTC" ) );
return new Object[] { getDayForCalendar( c ) };
return MethodResult.of( getDayForCalendar( c ) );
}
case "local":
{
// Get numbers of days since 1970-01-01 (local time)
Calendar c = Calendar.getInstance();
return new Object[] { getDayForCalendar( c ) };
return MethodResult.of( getDayForCalendar( c ) );
}
case "ingame":
// Get game day
synchronized( m_alarms )
{
return new Object[] { m_day };
return MethodResult.of( m_day );
}
default:
throw new LuaException( "Unsupported operation" );
@@ -367,7 +368,7 @@ public class OSAPI implements ILuaAPI
m_timers.remove( token );
}
}
return null;
return MethodResult.empty();
}
case 14:
{
@@ -380,7 +381,7 @@ public class OSAPI implements ILuaAPI
m_alarms.remove( token );
}
}
return null;
return MethodResult.empty();
}
case 15:
{
@@ -392,21 +393,21 @@ public class OSAPI implements ILuaAPI
{
// Get utc epoch
Calendar c = Calendar.getInstance( TimeZone.getTimeZone( "UTC" ) );
return new Object[] { getEpochForCalendar( c ) };
return MethodResult.of( getEpochForCalendar( c ) );
}
case "local":
{
// Get local epoch
Calendar c = Calendar.getInstance();
return new Object[] { getEpochForCalendar( c ) };
return MethodResult.of( getEpochForCalendar( c ) );
}
case "ingame":
// Get in-game epoch
synchronized( m_alarms )
{
return new Object[] {
return MethodResult.of(
m_day * 86400000 + (int) (m_time * 3600000.0f)
};
);
}
default:
throw new LuaException( "Unsupported operation" );
@@ -414,11 +415,18 @@ public class OSAPI implements ILuaAPI
}
default:
{
return null;
return MethodResult.empty();
}
}
}
@Nullable
@Override
@Deprecated
public Object[] callMethod( @Nonnull ILuaContext context, int method, @Nonnull Object[] arguments ) throws LuaException, InterruptedException
{
return callMethod( (ICallContext) context, method, arguments ).evaluate( context );
}
// Private methods
private void queueLuaEvent( String event, Object[] args )

View File

@@ -8,9 +8,8 @@ package dan200.computercraft.core.apis;
import dan200.computercraft.api.filesystem.IMount;
import dan200.computercraft.api.filesystem.IWritableMount;
import dan200.computercraft.api.lua.*;
import dan200.computercraft.api.lua.ILuaAPI;
import dan200.computercraft.api.lua.ILuaContext;
import dan200.computercraft.api.lua.LuaException;
import dan200.computercraft.api.peripheral.IPeripheral;
import dan200.computercraft.core.computer.Computer;
import dan200.computercraft.core.computer.ComputerThread;
@@ -98,7 +97,7 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange
m_attached = false;
}
public Object[] call( ILuaContext context, String methodName, Object[] arguments ) throws LuaException, InterruptedException
public MethodResult call( ICallContext context, String methodName, Object[] arguments ) throws LuaException
{
int method = -1;
synchronized( this )
@@ -368,8 +367,9 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange
};
}
@Nonnull
@Override
public Object[] callMethod( @Nonnull ILuaContext context, int method, @Nonnull Object[] args ) throws LuaException, InterruptedException
public MethodResult callMethod( @Nonnull ICallContext context, int method, @Nonnull Object[] args ) throws LuaException
{
switch( method )
{
@@ -389,7 +389,7 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange
}
}
}
return new Object[] { present };
return MethodResult.of( present );
}
case 1:
{
@@ -408,10 +408,10 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange
}
if( type != null )
{
return new Object[] { type };
return MethodResult.of( type );
}
}
return null;
return MethodResult.empty();
}
case 2:
{
@@ -435,9 +435,9 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange
for(int i=0; i<methods.length; ++i ) {
table.put( i+1, methods[i] );
}
return new Object[] { table };
return MethodResult.of( table );
}
return null;
return MethodResult.empty();
}
case 3:
{
@@ -462,11 +462,19 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange
}
default:
{
return null;
return MethodResult.empty();
}
}
}
@Nullable
@Override
@Deprecated
public Object[] callMethod( @Nonnull ILuaContext context, int method, @Nonnull Object[] arguments ) throws LuaException, InterruptedException
{
return callMethod( (ICallContext) context, method, arguments ).evaluate( context );
}
// Privates
private int parseSide( Object[] args ) throws LuaException

View File

@@ -6,12 +6,12 @@
package dan200.computercraft.core.apis;
import dan200.computercraft.api.lua.*;
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 javax.annotation.Nullable;
import java.util.HashMap;
import java.util.Map;
@@ -56,8 +56,9 @@ public class RedstoneAPI implements ILuaAPI
};
}
@Nonnull
@Override
public Object[] callMethod( @Nonnull ILuaContext context, int method, @Nonnull Object[] args ) throws LuaException
public MethodResult callMethod( @Nonnull ICallContext context, int method, @Nonnull Object[] args ) throws LuaException
{
switch( method )
{
@@ -69,7 +70,7 @@ public class RedstoneAPI implements ILuaAPI
{
table.put( i+1, Computer.s_sideNames[i] );
}
return new Object[] { table };
return MethodResult.of( table );
}
case 1:
{
@@ -77,19 +78,19 @@ public class RedstoneAPI implements ILuaAPI
int side = parseSide( args );
boolean output = getBoolean( args, 1 );
m_environment.setOutput( side, output ? 15 : 0 );
return null;
return MethodResult.empty();
}
case 2:
{
// getOutput
int side = parseSide( args );
return new Object[] { m_environment.getOutput( side ) > 0 };
return MethodResult.of( m_environment.getOutput( side ) > 0 );
}
case 3:
{
// getInput
int side = parseSide( args );
return new Object[] { m_environment.getInput( side ) > 0 };
return MethodResult.of( m_environment.getInput( side ) > 0 );
}
case 4:
{
@@ -97,19 +98,19 @@ public class RedstoneAPI implements ILuaAPI
int side = parseSide( args );
int output = getInt( args, 1 );
m_environment.setBundledOutput( side, output );
return null;
return MethodResult.empty();
}
case 5:
{
// getBundledOutput
int side = parseSide( args );
return new Object[] { m_environment.getBundledOutput( side ) };
return MethodResult.of( m_environment.getBundledOutput( side ) );
}
case 6:
{
// getBundledInput
int side = parseSide( args );
return new Object[] { m_environment.getBundledInput( side ) };
return MethodResult.of( m_environment.getBundledInput( side ) );
}
case 7:
{
@@ -117,7 +118,7 @@ public class RedstoneAPI implements ILuaAPI
int side = parseSide( args );
int mask = getInt( args, 1 );
int input = m_environment.getBundledInput( side );
return new Object[] { ((input & mask) == mask) };
return MethodResult.of( ((input & mask) == mask) );
}
case 8:
case 9:
@@ -130,28 +131,36 @@ public class RedstoneAPI implements ILuaAPI
throw new LuaException( "Expected number in range 0-15" );
}
m_environment.setOutput( side, output );
return null;
return MethodResult.empty();
}
case 10:
case 11:
{
// getAnalogOutput/getAnalogueOutput
int side = parseSide( args );
return new Object[] { m_environment.getOutput( side ) };
return MethodResult.of( m_environment.getOutput( side ) );
}
case 12:
case 13:
{
// getAnalogInput/getAnalogueInput
int side = parseSide( args );
return new Object[] { m_environment.getInput( side ) };
return MethodResult.of( m_environment.getInput( side ) );
}
default:
{
return null;
return MethodResult.empty();
}
}
}
@Nullable
@Override
@Deprecated
public Object[] callMethod( @Nonnull ILuaContext context, int method, @Nonnull Object[] arguments ) throws LuaException, InterruptedException
{
return callMethod( (ICallContext) context, method, arguments ).evaluate( context );
}
private int parseSide( Object[] args ) throws LuaException
{

View File

@@ -6,15 +6,15 @@
package dan200.computercraft.core.apis;
import dan200.computercraft.api.lua.*;
import dan200.computercraft.api.lua.ILuaAPI;
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.Palette;
import org.apache.commons.lang3.ArrayUtils;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import static dan200.computercraft.core.apis.ArgumentHelper.*;
@@ -83,11 +83,9 @@ public class TermAPI implements ILuaAPI
return colour;
}
public static Object[] encodeColour( int colour ) throws LuaException
public static MethodResult encodeColour( int colour )
{
return new Object[] {
1 << colour
};
return MethodResult.of( 1 << colour );
}
public static void setColour( Terminal terminal, int colour, double r, double g, double b )
@@ -99,8 +97,9 @@ public class TermAPI implements ILuaAPI
}
}
@Nonnull
@Override
public Object[] callMethod( @Nonnull ILuaContext context, int method, @Nonnull Object[] args ) throws LuaException
public MethodResult callMethod( @Nonnull ICallContext context, int method, @Nonnull Object[] args ) throws LuaException
{
switch( method )
{
@@ -119,7 +118,7 @@ public class TermAPI implements ILuaAPI
m_terminal.write( text );
m_terminal.setCursorPos( m_terminal.getCursorX() + text.length(), m_terminal.getCursorY() );
}
return null;
return MethodResult.empty();
}
case 1:
{
@@ -129,7 +128,7 @@ public class TermAPI implements ILuaAPI
{
m_terminal.scroll(y);
}
return null;
return MethodResult.empty();
}
case 2:
{
@@ -140,7 +139,7 @@ public class TermAPI implements ILuaAPI
{
m_terminal.setCursorPos( x, y );
}
return null;
return MethodResult.empty();
}
case 3:
{
@@ -150,7 +149,7 @@ public class TermAPI implements ILuaAPI
{
m_terminal.setCursorBlink( b );
}
return null;
return MethodResult.empty();
}
case 4:
{
@@ -161,7 +160,7 @@ public class TermAPI implements ILuaAPI
x = m_terminal.getCursorX();
y = m_terminal.getCursorY();
}
return new Object[] { x + 1, y + 1 };
return MethodResult.of( x + 1, y + 1 );
}
case 5:
{
@@ -172,7 +171,7 @@ public class TermAPI implements ILuaAPI
width = m_terminal.getWidth();
height = m_terminal.getHeight();
}
return new Object[] { width, height };
return MethodResult.of( width, height );
}
case 6:
{
@@ -181,7 +180,7 @@ public class TermAPI implements ILuaAPI
{
m_terminal.clear();
}
return null;
return MethodResult.empty();
}
case 7:
{
@@ -190,7 +189,7 @@ public class TermAPI implements ILuaAPI
{
m_terminal.clearLine();
}
return null;
return MethodResult.empty();
}
case 8:
case 9:
@@ -201,7 +200,7 @@ public class TermAPI implements ILuaAPI
{
m_terminal.setTextColour( colour );
}
return null;
return MethodResult.empty();
}
case 10:
case 11:
@@ -212,13 +211,13 @@ public class TermAPI implements ILuaAPI
{
m_terminal.setBackgroundColour( colour );
}
return null;
return MethodResult.empty();
}
case 12:
case 13:
{
// isColour/isColor
return new Object[] { m_environment.isColour() };
return MethodResult.of( m_environment.isColour() );
}
case 14:
case 15:
@@ -248,7 +247,7 @@ public class TermAPI implements ILuaAPI
m_terminal.blit( text, textColour, backgroundColour );
m_terminal.setCursorPos( m_terminal.getCursorX() + text.length(), m_terminal.getCursorY() );
}
return null;
return MethodResult.empty();
}
case 19:
case 20:
@@ -268,7 +267,7 @@ public class TermAPI implements ILuaAPI
double b = getReal( args, 3 );
setColour( m_terminal, colour, r, g, b );
}
return null;
return MethodResult.empty();
}
case 21:
case 22:
@@ -279,18 +278,26 @@ public class TermAPI implements ILuaAPI
{
if ( m_terminal.getPalette() != null )
{
return ArrayUtils.toObject( m_terminal.getPalette().getColour( colour ) );
return MethodResult.of( (Object[]) ArrayUtils.toObject( m_terminal.getPalette().getColour( colour ) ) );
}
}
return null;
return MethodResult.empty();
}
default:
{
return null;
return MethodResult.empty();
}
}
}
@Nullable
@Override
@Deprecated
public Object[] callMethod( @Nonnull ILuaContext context, int method, @Nonnull Object[] arguments ) throws LuaException, InterruptedException
{
return callMethod( (ICallContext) context, method, arguments ).evaluate( context );
}
private static int getHighestBit( int group )
{
int bit = 0;

View File

@@ -1,8 +1,9 @@
package dan200.computercraft.core.apis.handles;
import com.google.common.io.ByteStreams;
import dan200.computercraft.api.lua.ILuaContext;
import dan200.computercraft.api.lua.ICallContext;
import dan200.computercraft.api.lua.LuaException;
import dan200.computercraft.api.lua.MethodResult;
import javax.annotation.Nonnull;
import java.io.ByteArrayOutputStream;
@@ -35,8 +36,9 @@ public class BinaryInputHandle extends HandleGeneric
};
}
@Nonnull
@Override
public Object[] callMethod( @Nonnull ILuaContext context, int method, @Nonnull Object[] args ) throws LuaException
public MethodResult callMethod( @Nonnull ICallContext context, int method, @Nonnull Object[] args ) throws LuaException
{
switch( method )
{
@@ -60,9 +62,9 @@ public class BinaryInputHandle extends HandleGeneric
byte[] bytes = new byte[ count ];
int read = m_stream.read( bytes );
if( read < 0 ) return null;
if( read < 0 ) return MethodResult.empty();
if( read < count ) bytes = Arrays.copyOf( bytes, read );
return new Object[] { bytes };
return MethodResult.of( bytes );
}
else
{
@@ -86,18 +88,18 @@ public class BinaryInputHandle extends HandleGeneric
out.write( buffer, 0, read );
}
return new Object[] { out.toByteArray() };
return MethodResult.of( new Object[]{ out.toByteArray() } );
}
}
else
{
int b = m_stream.read();
return b == -1 ? null : new Object[] { b };
return b == -1 ? MethodResult.empty() : MethodResult.of( b );
}
}
catch( IOException e )
{
return null;
return MethodResult.empty();
}
case 1:
// readAll
@@ -105,18 +107,18 @@ public class BinaryInputHandle extends HandleGeneric
try
{
byte[] out = ByteStreams.toByteArray( m_stream );
return out == null ? null : new Object[] { out };
return out == null ? MethodResult.empty() : MethodResult.of( out );
}
catch( IOException e )
{
return null;
return MethodResult.empty();
}
case 2:
//close
close();
return null;
return MethodResult.empty();
default:
return null;
return MethodResult.empty();
}
}
}

View File

@@ -1,7 +1,8 @@
package dan200.computercraft.core.apis.handles;
import dan200.computercraft.api.lua.ILuaContext;
import dan200.computercraft.api.lua.ICallContext;
import dan200.computercraft.api.lua.LuaException;
import dan200.computercraft.api.lua.MethodResult;
import dan200.computercraft.core.apis.ArgumentHelper;
import dan200.computercraft.shared.util.StringUtil;
@@ -30,8 +31,9 @@ public class BinaryOutputHandle extends HandleGeneric
};
}
@Nonnull
@Override
public Object[] callMethod( @Nonnull ILuaContext context, int method, @Nonnull Object[] args ) throws LuaException
public MethodResult callMethod( @Nonnull ICallContext context, int method, @Nonnull Object[] args ) throws LuaException
{
switch( method )
{
@@ -54,7 +56,7 @@ public class BinaryOutputHandle extends HandleGeneric
{
throw ArgumentHelper.badArgument( 0, "string or number", args.length > 0 ? args[ 0 ] : null );
}
return null;
return MethodResult.empty();
}
catch( IOException e )
{
@@ -66,18 +68,18 @@ public class BinaryOutputHandle extends HandleGeneric
try
{
m_writer.flush();
return null;
return MethodResult.empty();
}
catch( IOException e )
{
return null;
return MethodResult.empty();
}
case 2:
//close
close();
return null;
return MethodResult.empty();
default:
return null;
return MethodResult.empty();
}
}
}

View File

@@ -1,7 +1,8 @@
package dan200.computercraft.core.apis.handles;
import dan200.computercraft.api.lua.ILuaContext;
import dan200.computercraft.api.lua.ICallContext;
import dan200.computercraft.api.lua.LuaException;
import dan200.computercraft.api.lua.MethodResult;
import javax.annotation.Nonnull;
import java.io.*;
@@ -57,8 +58,9 @@ public class EncodedInputHandle extends HandleGeneric
};
}
@Nonnull
@Override
public Object[] callMethod( @Nonnull ILuaContext context, int method, @Nonnull Object[] args ) throws LuaException
public MethodResult callMethod( @Nonnull ICallContext context, int method, @Nonnull Object[] args ) throws LuaException
{
switch( method )
{
@@ -70,16 +72,16 @@ public class EncodedInputHandle extends HandleGeneric
String line = m_reader.readLine();
if( line != null )
{
return new Object[] { line };
return MethodResult.of( line );
}
else
{
return null;
return MethodResult.empty();
}
}
catch( IOException e )
{
return null;
return MethodResult.empty();
}
case 1:
// readAll
@@ -97,16 +99,16 @@ public class EncodedInputHandle extends HandleGeneric
result.append( "\n" );
}
}
return new Object[] { result.toString() };
return MethodResult.of( result.toString() );
}
catch( IOException e )
{
return null;
return MethodResult.empty();
}
case 2:
// close
close();
return null;
return MethodResult.empty();
case 3:
// read
checkOpen();
@@ -125,7 +127,7 @@ public class EncodedInputHandle extends HandleGeneric
char[] chars = new char[ count ];
int read = m_reader.read( chars );
return read < 0 ? null : new Object[] { new String( chars, 0, read ) };
return read < 0 ? MethodResult.empty() : MethodResult.of( new String( chars, 0, read ) );
}
else
{
@@ -150,15 +152,15 @@ public class EncodedInputHandle extends HandleGeneric
out.append( buffer, 0, read );
}
return new Object[] { out.toString() };
return MethodResult.of( out.toString() );
}
}
catch( IOException e )
{
return null;
return MethodResult.empty();
}
default:
return null;
return MethodResult.empty();
}
}
}

View File

@@ -1,7 +1,8 @@
package dan200.computercraft.core.apis.handles;
import dan200.computercraft.api.lua.ILuaContext;
import dan200.computercraft.api.lua.ICallContext;
import dan200.computercraft.api.lua.LuaException;
import dan200.computercraft.api.lua.MethodResult;
import javax.annotation.Nonnull;
import java.io.*;
@@ -53,8 +54,9 @@ public class EncodedOutputHandle extends HandleGeneric
};
}
@Nonnull
@Override
public Object[] callMethod( @Nonnull ILuaContext context, int method, @Nonnull Object[] args ) throws LuaException
public MethodResult callMethod( @Nonnull ICallContext context, int method, @Nonnull Object[] args ) throws LuaException
{
switch( method )
{
@@ -74,7 +76,7 @@ public class EncodedOutputHandle extends HandleGeneric
try
{
m_writer.write( text, 0, text.length() );
return null;
return MethodResult.empty();
}
catch( IOException e )
{
@@ -98,7 +100,7 @@ public class EncodedOutputHandle extends HandleGeneric
{
m_writer.write( text, 0, text.length() );
m_writer.newLine();
return null;
return MethodResult.empty();
}
catch( IOException e )
{
@@ -111,18 +113,18 @@ public class EncodedOutputHandle extends HandleGeneric
try
{
m_writer.flush();
return null;
return MethodResult.empty();
}
catch( IOException e )
{
return null;
return MethodResult.empty();
}
case 3:
// close
close();
return null;
return MethodResult.empty();
default:
return null;
return MethodResult.empty();
}
}
}

View File

@@ -1,8 +1,12 @@
package dan200.computercraft.core.apis.handles;
import dan200.computercraft.api.lua.ICallContext;
import dan200.computercraft.api.lua.ILuaContext;
import dan200.computercraft.api.lua.ILuaObject;
import dan200.computercraft.api.lua.LuaException;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.io.Closeable;
import java.io.IOException;
@@ -32,4 +36,12 @@ public abstract class HandleGeneric implements ILuaObject
{
}
}
@Nullable
@Override
@Deprecated
public Object[] callMethod( @Nonnull ILuaContext context, int method, @Nonnull Object[] arguments ) throws LuaException, InterruptedException
{
return callMethod( (ICallContext) context, method, arguments ).evaluate( context );
}
}

View File

@@ -9,15 +9,14 @@ package dan200.computercraft.core.apis.http;
import com.google.common.base.Joiner;
import com.google.common.io.ByteStreams;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.api.lua.ILuaContext;
import dan200.computercraft.api.lua.ILuaObject;
import dan200.computercraft.api.lua.LuaException;
import dan200.computercraft.api.lua.*;
import dan200.computercraft.core.apis.IAPIEnvironment;
import dan200.computercraft.core.apis.handles.BinaryInputHandle;
import dan200.computercraft.core.apis.handles.EncodedInputHandle;
import dan200.computercraft.core.tracking.TrackingField;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.io.*;
import java.net.*;
import java.util.Arrays;
@@ -236,8 +235,9 @@ public class HTTPRequest implements Runnable
return newMethods;
}
@Nonnull
@Override
public Object[] callMethod( @Nonnull ILuaContext context, int method, @Nonnull Object[] args ) throws LuaException, InterruptedException
public MethodResult callMethod( @Nonnull ICallContext context, int method, @Nonnull Object[] args ) throws LuaException
{
if( method < methodOffset )
{
@@ -248,19 +248,27 @@ public class HTTPRequest implements Runnable
case 0:
{
// getResponseCode
return new Object[]{ responseCode };
return MethodResult.of( responseCode );
}
case 1:
{
// getResponseHeaders
return new Object[]{ responseHeaders };
return MethodResult.of( responseHeaders );
}
default:
{
return null;
return MethodResult.empty();
}
}
}
@Nullable
@Override
@Deprecated
public Object[] callMethod( @Nonnull ILuaContext context, int method, @Nonnull Object[] arguments ) throws LuaException, InterruptedException
{
return callMethod( (ICallContext) context, method, arguments ).evaluate( context );
}
};
}

View File

@@ -7,9 +7,7 @@
package dan200.computercraft.core.apis.http;
import com.google.common.base.Objects;
import dan200.computercraft.api.lua.ILuaContext;
import dan200.computercraft.api.lua.ILuaObject;
import dan200.computercraft.api.lua.LuaException;
import dan200.computercraft.api.lua.*;
import dan200.computercraft.core.apis.HTTPAPI;
import dan200.computercraft.core.apis.IAPIEnvironment;
import dan200.computercraft.core.tracking.TrackingField;
@@ -156,33 +154,48 @@ public class WebsocketConnection extends SimpleChannelInboundHandler<Object> imp
@Nullable
@Override
@Deprecated
public Object[] callMethod( @Nonnull ILuaContext context, int method, @Nonnull Object[] arguments ) throws LuaException, InterruptedException
{
return callMethod( (ICallContext) context, method, arguments ).evaluate( context );
}
@Nonnull
@Override
public MethodResult callMethod( @Nonnull ICallContext context, int method, @Nonnull Object[] arguments ) throws LuaException
{
switch( method )
{
case 0:
while( true )
checkOpen();
return MethodResult.pullEvent( MESSAGE_EVENT, new ILuaFunction()
{
checkOpen();
Object[] event = context.pullEvent( MESSAGE_EVENT );
if( event.length >= 3 && Objects.equal( event[1], url ) )
@Nonnull
@Override
public MethodResult call( @Nullable Object[] event ) throws LuaException
{
return new Object[]{ event[2] };
if( event != null && event.length >= 3 && Objects.equal( event[1], url ) )
{
return MethodResult.of( event[2] );
}
checkOpen();
return MethodResult.pullEvent( MESSAGE_EVENT, this );
}
}
} );
case 1:
{
checkOpen();
String text = arguments.length > 0 && arguments[0] != null ? arguments[0].toString() : "";
computer.addTrackingChange( TrackingField.WEBSOCKET_OUTGOING, text.length() );
channel.writeAndFlush( new TextWebSocketFrame( text ) );
return null;
return MethodResult.empty();
}
case 2:
close( true );
return null;
return MethodResult.empty();
default:
return null;
return MethodResult.empty();
}
}

View File

@@ -265,10 +265,18 @@ public class Computer
@Nullable
@Override
@Deprecated
public Object[] callMethod( @Nonnull ILuaContext context, int method, @Nonnull Object[] arguments ) throws LuaException, InterruptedException
{
return delegate.callMethod( context, method, arguments );
}
@Nonnull
@Override
public MethodResult callMethod( @Nonnull ICallContext context, int method, @Nonnull Object[] arguments ) throws LuaException
{
return delegate.callMethod( context, method, arguments );
}
}
private static IMount s_romMount = null;
@@ -960,7 +968,7 @@ public class Computer
return;
}
}
final Computer computer = this;
ITask task = new ITask() {
@Override

View File

@@ -0,0 +1,9 @@
package dan200.computercraft.core.computer;
import javax.annotation.Nullable;
public interface IComputerOwned
{
@Nullable
Computer getComputer();
}

View File

@@ -0,0 +1,87 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2018. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.core.lua;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.api.lua.ICallContext;
import dan200.computercraft.api.lua.ILuaTask;
import dan200.computercraft.api.lua.LuaException;
import dan200.computercraft.core.computer.Computer;
import dan200.computercraft.core.computer.ITask;
import dan200.computercraft.core.computer.MainThread;
import javax.annotation.Nonnull;
class CobaltCallContext implements ICallContext
{
private final Computer computer;
CobaltCallContext( Computer computer )
{
this.computer = computer;
}
@Override
public long issueMainThreadTask( @Nonnull final ILuaTask task ) throws LuaException
{
// Issue command
final long taskID = MainThread.getUniqueTaskID();
final ITask iTask = new ITask()
{
@Override
public Computer getOwner()
{
return computer;
}
@Override
public void execute()
{
try
{
Object[] results = task.execute();
if( results != null )
{
Object[] eventArguments = new Object[results.length + 2];
eventArguments[0] = taskID;
eventArguments[1] = true;
System.arraycopy( results, 0, eventArguments, 2, results.length );
computer.queueEvent( "task_complete", eventArguments );
}
else
{
computer.queueEvent( "task_complete", new Object[]{ taskID, true } );
}
}
catch( LuaException e )
{
computer.queueEvent( "task_complete", new Object[]{
taskID, false, e.getMessage()
} );
}
catch( Throwable t )
{
if( ComputerCraft.logPeripheralErrors )
{
ComputerCraft.log.error( "Error running task", t );
}
computer.queueEvent( "task_complete", new Object[]{
taskID, false, "Java Exception Thrown: " + t.toString()
} );
}
}
};
if( MainThread.queueTask( iTask ) )
{
return taskID;
}
else
{
throw new LuaException( "Task limit exceeded" );
}
}
}

View File

@@ -0,0 +1,191 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2018. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.core.lua;
import dan200.computercraft.api.lua.ILuaContext;
import dan200.computercraft.api.lua.ILuaContextTask;
import dan200.computercraft.api.lua.ILuaTask;
import dan200.computercraft.api.lua.LuaException;
import dan200.computercraft.core.computer.Computer;
import org.squiddev.cobalt.LuaError;
import org.squiddev.cobalt.LuaState;
import org.squiddev.cobalt.LuaThread;
import org.squiddev.cobalt.UnwindThrowable;
import javax.annotation.Nonnull;
import java.lang.ref.WeakReference;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
/**
* An ugly wrapper for {@link ILuaContext} style calls, which executes them on a separate thread.
*/
class CobaltLuaContext extends CobaltCallContext implements ILuaContext
{
private static final ThreadGroup group = new ThreadGroup( "ComputerCraft-Lua" );
private static final AtomicInteger threadCounter = new AtomicInteger();
private static final ExecutorService threads = new ThreadPoolExecutor(
4, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<>(),
task -> {
Thread thread = new Thread( group, task, group.getName() + "-" + threadCounter.incrementAndGet() );
if( !thread.isDaemon() ) thread.setDaemon( true );
if( thread.getPriority() != Thread.NORM_PRIORITY ) thread.setPriority( Thread.NORM_PRIORITY );
return thread;
}
);
private boolean done = false;
private Object[] values;
private LuaError exception;
private final Semaphore yield = new Semaphore();
private final Semaphore resume = new Semaphore();
private WeakReference<LuaThread> thread;
CobaltLuaContext( Computer computer, LuaState state )
{
super( computer );
this.thread = state.getCurrentThread().getReference();
}
@Nonnull
@Override
@Deprecated
public Object[] pullEvent( String filter ) throws LuaException, InterruptedException
{
Object[] results = pullEventRaw( filter );
if( results.length >= 1 && results[0].equals( "terminate" ) )
{
throw new LuaException( "Terminated", 0 );
}
return results;
}
@Nonnull
@Override
@Deprecated
public Object[] pullEventRaw( String filter ) throws InterruptedException
{
return yield( new Object[]{ filter } );
}
@Nonnull
@Override
@Deprecated
public Object[] yield( Object[] yieldArgs ) throws InterruptedException
{
if( done ) throw new IllegalStateException( "Cannot yield when complete" );
values = yieldArgs;
yield.signal();
// Every 30 seconds check to see if the coroutine has been GCed
// if so then abort this task.
while( !resume.await( 30000 ) )
{
if( thread.get() == null ) throw new InterruptedException( "Orphaned async task" );
}
return values;
}
@Override
@Deprecated
public Object[] executeMainThreadTask( @Nonnull final ILuaTask task ) throws LuaException, InterruptedException
{
// Issue task
final long taskID = issueMainThreadTask( task );
// Wait for response
while( true )
{
Object[] response = pullEvent( "task_complete" );
if( response.length >= 3 && response[1] instanceof Number && response[2] instanceof Boolean )
{
if( ((Number) response[1]).intValue() == taskID )
{
Object[] returnValues = new Object[response.length - 3];
if( (Boolean) response[2] )
{
// Extract the return values from the event and return them
System.arraycopy( response, 3, returnValues, 0, returnValues.length );
return returnValues;
}
else
{
// Extract the error message from the event and raise it
if( response.length >= 4 && response[3] instanceof String )
{
throw new LuaException( (String) response[3] );
}
else
{
throw new LuaException();
}
}
}
}
}
}
void execute( ILuaContextTask task )
{
threads.submit( () -> {
try
{
values = task.execute( this );
}
catch( LuaException e )
{
exception = new LuaError( e.getMessage(), e.getLevel() );
}
catch( InterruptedException e )
{
exception = new LuaError( "Java Exception Thrown: " + e.toString(), 0 );
}
finally
{
done = true;
yield.signal();
}
} );
}
void resume( Object[] args )
{
values = args;
resume.signal();
}
Object[] await( LuaState state, CobaltLuaMachine machine ) throws LuaError, UnwindThrowable
{
if( !done )
{
try
{
yield.await();
}
catch( InterruptedException e )
{
throw new LuaError( "Java Exception Thrown: " + e.toString(), 0 );
}
}
if( done )
{
if( exception != null ) throw exception;
return values;
}
else
{
LuaThread.yield( state, machine.toValues( values ) );
throw new IllegalStateException( "Unreachable" );
}
}
}

View File

@@ -7,14 +7,9 @@
package dan200.computercraft.core.lua;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.api.lua.ILuaContext;
import dan200.computercraft.api.lua.ILuaObject;
import dan200.computercraft.api.lua.ILuaTask;
import dan200.computercraft.api.lua.LuaException;
import dan200.computercraft.api.lua.ILuaAPI;
import dan200.computercraft.api.lua.ILuaObject;
import dan200.computercraft.core.computer.Computer;
import dan200.computercraft.core.computer.ITask;
import dan200.computercraft.core.computer.MainThread;
import org.squiddev.cobalt.*;
import org.squiddev.cobalt.compiler.CompileException;
import org.squiddev.cobalt.compiler.LoadState;
@@ -27,7 +22,6 @@ import org.squiddev.cobalt.function.VarArgFunction;
import org.squiddev.cobalt.lib.*;
import org.squiddev.cobalt.lib.platform.AbstractResourceManipulator;
import javax.annotation.Nonnull;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
@@ -76,7 +70,7 @@ public class CobaltLuaMachine implements ILuaMachine
int count = ++this.count;
if( count > 100000 )
{
if( m_hardAbortMessage != null ) LuaThread.yield( state, NONE );
if( m_hardAbortMessage != null ) throw new LuaError( m_hardAbortMessage );
this.count = 0;
}
else
@@ -90,7 +84,7 @@ public class CobaltLuaMachine implements ILuaMachine
@Override
public void poll() throws LuaError
{
if( m_hardAbortMessage != null ) LuaThread.yield( state, NONE );
if( m_hardAbortMessage != null ) throw new LuaError( m_hardAbortMessage );
handleSoftAbort();
}
@@ -125,7 +119,7 @@ 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 );
@@ -216,18 +210,13 @@ public class CobaltLuaMachine implements ILuaMachine
resumeArgs = varargsOf( valueOf( eventName ), toValues( arguments ) );
}
Varargs results = m_mainRoutine.resume( resumeArgs );
LuaValue filter = LuaThread.run( m_mainRoutine, resumeArgs ).first();
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 );
if( filter.isString() )
{
m_eventFilter = filter.toString();
@@ -246,6 +235,7 @@ public class CobaltLuaMachine implements ILuaMachine
}
catch( LuaError e )
{
if( ComputerCraft.logPeripheralErrors ) ComputerCraft.log.error( "Main thread crashed", e );
m_mainRoutine.abandon();
m_mainRoutine = null;
}
@@ -302,181 +292,12 @@ public class CobaltLuaMachine implements ILuaMachine
{
LuaTable table = new LuaTable();
String[] methods = object.getMethodNames();
for( int i = 0; i < methods.length; ++i )
for( int method = 0; method < methods.length; method++ )
{
if( methods[ i ] != null )
if( methods[method] != null )
{
final int method = i;
final ILuaObject apiObject = object;
final String methodName = methods[ i ];
table.rawset( methodName, new VarArgFunction()
{
@Override
public Varargs invoke( final LuaState state, Varargs _args ) throws LuaError
{
Object[] arguments = toObjects( _args, 1 );
Object[] results;
try
{
results = apiObject.callMethod( new ILuaContext()
{
@Nonnull
@Override
public Object[] pullEvent( String filter ) throws LuaException, InterruptedException
{
Object[] results = pullEventRaw( filter );
if( results.length >= 1 && results[ 0 ].equals( "terminate" ) )
{
throw new LuaException( "Terminated", 0 );
}
return results;
}
@Nonnull
@Override
public Object[] pullEventRaw( String filter ) throws InterruptedException
{
return yield( new Object[] { filter } );
}
@Nonnull
@Override
public Object[] yield( Object[] yieldArgs ) throws InterruptedException
{
try
{
Varargs results = LuaThread.yield( state, toValues( yieldArgs ) );
return toObjects( results, 1 );
}
catch( OrphanedThread e )
{
throw new InterruptedException();
}
catch( Throwable e )
{
throw new RuntimeException( e );
}
}
@Override
public long issueMainThreadTask( @Nonnull final ILuaTask task ) throws LuaException
{
// Issue command
final long taskID = MainThread.getUniqueTaskID();
final ITask iTask = new ITask()
{
@Override
public Computer getOwner()
{
return m_computer;
}
@Override
public void execute()
{
try
{
Object[] results = task.execute();
if( results != null )
{
Object[] eventArguments = new Object[ results.length + 2 ];
eventArguments[ 0 ] = taskID;
eventArguments[ 1 ] = true;
System.arraycopy( results, 0, eventArguments, 2, results.length );
m_computer.queueEvent( "task_complete", eventArguments );
}
else
{
m_computer.queueEvent( "task_complete", new Object[] { taskID, true } );
}
}
catch( LuaException e )
{
m_computer.queueEvent( "task_complete", new Object[] {
taskID, false, e.getMessage()
} );
}
catch( Throwable t )
{
if( ComputerCraft.logPeripheralErrors )
{
ComputerCraft.log.error( "Error running task", t );
}
m_computer.queueEvent( "task_complete", new Object[] {
taskID, false, "Java Exception Thrown: " + t.toString()
} );
}
}
};
if( MainThread.queueTask( iTask ) )
{
return taskID;
}
else
{
throw new LuaException( "Task limit exceeded" );
}
}
@Override
public Object[] executeMainThreadTask( @Nonnull final ILuaTask task ) throws LuaException, InterruptedException
{
// Issue task
final long taskID = issueMainThreadTask( task );
// Wait for response
while( true )
{
Object[] response = pullEvent( "task_complete" );
if( response.length >= 3 && response[ 1 ] instanceof Number && response[ 2 ] instanceof Boolean )
{
if( ((Number) response[ 1 ]).intValue() == taskID )
{
Object[] returnValues = new Object[ response.length - 3 ];
if( (Boolean) response[ 2 ] )
{
// Extract the return values from the event and return them
System.arraycopy( response, 3, returnValues, 0, returnValues.length );
return returnValues;
}
else
{
// Extract the error message from the event and raise it
if( response.length >= 4 && response[ 3 ] instanceof String )
{
throw new LuaException( (String) response[ 3 ] );
}
else
{
throw new LuaException();
}
}
}
}
}
}
}, method, arguments );
}
catch( InterruptedException e )
{
throw new OrphanedThread();
}
catch( LuaException e )
{
throw new LuaError( e.getMessage(), e.getLevel() );
}
catch( Throwable t )
{
if( ComputerCraft.logPeripheralErrors )
{
ComputerCraft.log.error( "Error calling " + methodName + " on " + apiObject, t );
}
throw new LuaError( "Java Exception Thrown: " + t.toString(), 0 );
}
return toValues( results );
}
} );
final String methodName = methods[method];
table.rawset( methodName, new CobaltWrapperFunction( this, m_computer, object, method, methodName ) );
}
}
return table;
@@ -544,7 +365,7 @@ public class CobaltLuaMachine implements ILuaMachine
}
}
private Varargs toValues( Object[] objects )
Varargs toValues( Object[] objects )
{
if( objects == null || objects.length == 0 )
{
@@ -635,7 +456,7 @@ public class CobaltLuaMachine implements ILuaMachine
}
}
private static Object[] toObjects( Varargs values, int startIdx )
static Object[] toObjects( Varargs values, int startIdx )
{
int count = values.count();
Object[] objects = new Object[ count - startIdx + 1 ];
@@ -703,13 +524,23 @@ public class CobaltLuaMachine implements ILuaMachine
if( remaining <= 0 )
{
LuaValue s;
state.getCurrentThread().disableYield();
try
{
s = OperationHelper.call( state, func );
} catch (LuaError e)
}
catch( UnwindThrowable e )
{
throw new IOException( "Impossible yield within load" );
}
catch( LuaError e )
{
throw new IOException( e );
}
finally
{
state.getCurrentThread().enableYield();
}
if( s.isNil() )
{
@@ -735,4 +566,5 @@ public class CobaltLuaMachine implements ILuaMachine
return bytes[offset++];
}
}
}

View File

@@ -0,0 +1,292 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2018. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.core.lua;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.api.lua.ILuaFunction;
import dan200.computercraft.api.lua.ILuaObject;
import dan200.computercraft.api.lua.LuaException;
import dan200.computercraft.api.lua.MethodResult;
import dan200.computercraft.core.computer.Computer;
import org.squiddev.cobalt.*;
import org.squiddev.cobalt.debug.DebugState;
import org.squiddev.cobalt.function.VarArgFunction;
import java.util.ArrayDeque;
import java.util.Deque;
class CobaltWrapperFunction extends VarArgFunction implements Resumable<CobaltWrapperFunction.State>
{
private final CobaltLuaMachine machine;
private final Computer computer;
private final CobaltCallContext callContext;
private final ILuaObject delegate;
private final int method;
private final String methodName;
CobaltWrapperFunction( CobaltLuaMachine machine, Computer computer, ILuaObject delegate, int method, String methodName )
{
this.machine = machine;
this.computer = computer;
this.callContext = new CobaltCallContext( computer );
this.delegate = delegate;
this.method = method;
this.methodName = methodName;
}
@Override
public Varargs invoke( final LuaState state, Varargs args ) throws LuaError, UnwindThrowable
{
MethodResult future;
try
{
future = delegate.callMethod( callContext, method, CobaltLuaMachine.toObjects( args, 1 ) );
}
catch( LuaException e )
{
throw new LuaError( e.getMessage(), e.getLevel() );
}
catch( Exception e )
{
if( ComputerCraft.logPeripheralErrors )
{
ComputerCraft.log.error( "Error calling " + methodName + " on " + delegate, e );
}
throw new LuaError( "Java Exception Thrown: " + e.toString(), 0 );
}
// Verify we've a "well formed" future
if( future == null )
{
ComputerCraft.log.error( "Null result from " + delegate );
throw new LuaError( "Java Exception Thrown: Null result" );
}
// Fast path for immediate results
if( future instanceof MethodResult.Immediate )
{
return machine.toValues( ((MethodResult.Immediate) future).getResult() );
}
State context = new State();
try
{
return runFuture( state, context, future );
}
catch( UnwindThrowable e )
{
// Push our state onto the stack if need-be. Normally this wouldn't be safe and we
// should do this at the very beginning, but we know that we won't be calling anything
// else which will push to the resume stack.
DebugState ds = state.debug.getDebugState();
state.debug.onCall( ds, this, context );
throw e;
}
}
@Override
public Varargs resume( LuaState state, State context, Varargs args ) throws LuaError, UnwindThrowable
{
Varargs result;
try
{
result = doResume( state, context, args );
}
catch( LuaError e )
{
state.debug.onReturn();
throw e;
}
catch( Exception e )
{
state.debug.onReturn();
throw new LuaError( e );
}
state.debug.onReturn();
return result;
}
private Varargs doResume( LuaState state, State context, Varargs args ) throws LuaError, UnwindThrowable
{
MethodResult future = context.pending;
if( future instanceof MethodResult.OnEvent )
{
MethodResult.OnEvent onEvent = (MethodResult.OnEvent) future;
if( !onEvent.isRaw() && args.first().toString().equals( "terminate" ) )
{
throw new LuaError( "Terminated", 0 );
}
return runCallback( state, context, CobaltLuaMachine.toObjects( args, 1 ) );
}
else if( future instanceof MethodResult.OnMainThread )
{
if( args.arg( 2 ).isNumber() && args.arg( 3 ).isBoolean() && args.arg( 2 ).toLong() == context.taskId )
{
if( args.arg( 3 ).toBoolean() )
{
// Extract the return values from the event and return them
return runFuture( state, context, context.taskResult );
}
else
{
// Extract the error message from the event and raise it
throw new LuaError( args.arg( 4 ) );
}
}
else
{
LuaThread.yield( state, ValueFactory.valueOf( "task_complete" ) );
throw new IllegalStateException( "Unreachable" );
}
}
else if( future instanceof MethodResult.WithLuaContext )
{
context.luaContext.resume( CobaltLuaMachine.toObjects( args, 1 ) );
return runCallback( state, context, context.luaContext.await( state, machine ) );
}
else
{
ComputerCraft.log.error( "Unknown method result " + future );
throw new LuaError( "Java Exception Thrown: Unknown method result" );
}
}
@Override
public Varargs resumeError( LuaState state, State context, LuaError error ) throws LuaError
{
state.debug.onReturn();
throw error;
}
private Varargs runFuture( LuaState state, State context, MethodResult future ) throws LuaError, UnwindThrowable
{
Deque<ILuaFunction> callbacks = context.callbacks;
while( true )
{
if( future instanceof MethodResult.AndThen )
{
MethodResult.AndThen then = ((MethodResult.AndThen) future);
// Thens are "unwrapped", being pushed onto a stack
if( callbacks == null ) callbacks = context.callbacks = new ArrayDeque<>();
callbacks.addLast( then.getCallback() );
future = then.getPrevious();
}
else if( future instanceof MethodResult.Immediate )
{
Object[] values = ((MethodResult.Immediate) future).getResult();
// Immediate values values will attempt to call the previous "then", or return if nothing
// else needs to be done.
ILuaFunction callback = callbacks == null ? null : callbacks.pollLast();
if( callback == null ) return machine.toValues( values );
future = runFunction( callback, values );
}
else if( future instanceof MethodResult.OnEvent )
{
MethodResult.OnEvent onEvent = (MethodResult.OnEvent) future;
// Mark this future as pending and yield
context.pending = future;
String filter = onEvent.getFilter();
LuaThread.yield( state, filter == null ? Constants.NIL : ValueFactory.valueOf( filter ) );
throw new IllegalStateException( "Unreachable" );
}
else if( future instanceof MethodResult.OnMainThread )
{
MethodResult.OnMainThread onMainThread = (MethodResult.OnMainThread) future;
// Mark this future as pending and yield
context.pending = future;
try
{
context.taskId = callContext.issueMainThreadTask( () -> {
context.taskResult = onMainThread.getTask().execute();
return null;
} );
}
catch( LuaException e )
{
throw new LuaError( e.getMessage(), e.getLevel() );
}
LuaThread.yield( state, ValueFactory.valueOf( "task_complete" ) );
throw new IllegalStateException( "Unreachable" );
}
else if( future instanceof MethodResult.WithLuaContext )
{
MethodResult.WithLuaContext withContext = (MethodResult.WithLuaContext) future;
// Mark this future as pending and execute on a separate thread.
context.pending = future;
CobaltLuaContext luaContext = context.luaContext = new CobaltLuaContext( computer, state );
luaContext.execute( withContext.getConsumer() );
return runCallback( state, context, luaContext.await( state, machine ) );
}
else
{
ComputerCraft.log.error( "Unknown method result " + future );
throw new LuaError( "Java Exception Thrown: Unknown method result" );
}
}
}
private Varargs runCallback( LuaState state, State context, Object[] args ) throws LuaError, UnwindThrowable
{
Deque<ILuaFunction> callbacks = context.callbacks;
ILuaFunction callback = callbacks == null ? null : callbacks.pollLast();
if( callback == null ) return machine.toValues( args );
return runFuture( state, context, runFunction( callback, args ) );
}
private MethodResult runFunction( ILuaFunction func, Object[] args ) throws LuaError
{
MethodResult result;
try
{
result = func.call( args );
}
catch( LuaException e )
{
throw new LuaError( e.getMessage(), e.getLevel() );
}
catch( Exception e )
{
if( ComputerCraft.logPeripheralErrors )
{
ComputerCraft.log.error( "Error calling " + methodName + " on " + delegate, e );
}
throw new LuaError( "Java Exception Thrown: " + e.toString(), 0 );
}
if( result == null )
{
ComputerCraft.log.error( "Null result from " + func );
throw new LuaError( "Java Exception Thrown: Null result" );
}
return result;
}
static class State
{
Deque<ILuaFunction> callbacks;
MethodResult pending;
CobaltLuaContext luaContext;
long taskId;
MethodResult taskResult;
}
}

View File

@@ -0,0 +1,38 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2018. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.core.lua;
/**
* A trivial way of signalling
*/
public final class Semaphore
{
private volatile boolean state = false;
public synchronized void signal()
{
state = true;
notify();
}
public synchronized void await() throws InterruptedException
{
while( !state ) wait();
state = false;
}
public synchronized boolean await( long timeout ) throws InterruptedException
{
if( !state )
{
wait( timeout );
if( !state ) return false;
}
state = false;
return true;
}
}

View File

@@ -20,10 +20,10 @@ import net.minecraft.util.math.BlockPos;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.text.TextComponentString;
import net.minecraft.world.World;
import net.minecraftforge.common.util.FakePlayer;
import javax.annotation.Nonnull;
import java.util.*;
import java.util.function.Consumer;
import static dan200.computercraft.shared.command.framework.ChatHelpers.*;
@@ -59,7 +59,7 @@ public final class CommandComputerCraft extends CommandDelegate
{
if( arguments.size() == 0 )
{
TextTable table = new TextTable( DUMP_LIST_ID, "Instance", "Id", "On", "Position" );
TextTable table = new TextTable( DUMP_LIST_ID, "Computer", "On", "Position" );
List<ServerComputer> computers = new ArrayList<>( ComputerCraft.serverComputerRegistry.getComputers() );
@@ -92,8 +92,7 @@ public final class CommandComputerCraft extends CommandDelegate
for( ServerComputer computer : computers )
{
table.addRow(
linkComputer( computer ),
text( Integer.toString( computer.getID() ) ),
linkComputer( context, computer, computer.getID() ),
bool( computer.isOn() ),
linkPosition( context, computer )
);
@@ -149,26 +148,15 @@ public final class CommandComputerCraft extends CommandDelegate
@Override
public void execute( @Nonnull CommandContext context, @Nonnull List<String> arguments ) throws CommandException
{
Set<ServerComputer> computers = Sets.newHashSet();
if( arguments.size() > 0 )
{
for( String arg : arguments )
withComputers( arguments, computers -> {
int shutdown = 0;
for( ServerComputer computer : computers )
{
computers.addAll( ComputerSelector.getComputers( arg ) );
if( computer.isOn() ) shutdown++;
computer.unload();
}
}
else
{
computers.addAll( ComputerCraft.serverComputerRegistry.getComputers() );
}
int shutdown = 0;
for( ServerComputer computer : computers )
{
if( computer.isOn() ) shutdown++;
computer.unload();
}
context.getSender().sendMessage( text( "Shutdown " + shutdown + " / " + computers.size() + " computers" ) );
context.getSender().sendMessage( text( "Shutdown " + shutdown + " / " + computers.size() + " computers" ) );
} );
}
@Nonnull
@@ -190,26 +178,15 @@ public final class CommandComputerCraft extends CommandDelegate
@Override
public void execute( @Nonnull CommandContext context, @Nonnull List<String> arguments ) throws CommandException
{
Set<ServerComputer> computers = Sets.newHashSet();
if( arguments.size() > 0 )
{
for( String arg : arguments )
withComputers( arguments, computers -> {
int on = 0;
for( ServerComputer computer : computers )
{
computers.addAll( ComputerSelector.getComputers( arg ) );
if( !computer.isOn() ) on++;
computer.turnOn();
}
}
else
{
computers.addAll( ComputerCraft.serverComputerRegistry.getComputers() );
}
int on = 0;
for( ServerComputer computer : computers )
{
if( !computer.isOn() ) on++;
computer.turnOn();
}
context.getSender().sendMessage( text( "Turned on " + on + " / " + computers.size() + " computers" ) );
context.getSender().sendMessage( text( "Turned on " + on + " / " + computers.size() + " computers" ) );
} );
}
@Nonnull
@@ -406,13 +383,46 @@ public final class CommandComputerCraft extends CommandDelegate
return root;
}
private static ITextComponent linkComputer( ServerComputer computer )
private static ITextComponent linkComputer( CommandContext context, ServerComputer serverComputer, int computerId )
{
return link(
text( Integer.toString( computer.getInstanceID() ) ),
"/computercraft dump " + computer.getInstanceID(),
"View more info about this computer"
);
ITextComponent out = new TextComponentString( "" );
// Append the computer instance
if( serverComputer == null )
{
out.appendSibling( text( "?" ) );
}
else
{
out.appendSibling( link(
text( Integer.toString( serverComputer.getInstanceID() ) ),
"/computercraft dump " + serverComputer.getInstanceID(),
"View more info about this computer"
) );
}
// And ID
out.appendText( " (id " + computerId + ")" );
// And, if we're a player, some useful links
if( serverComputer != null && UserLevel.OP.canExecute( context ) && context.fromPlayer() )
{
out
.appendText( " " )
.appendSibling( link(
text( "\u261b" ),
"/computercraft tp " + serverComputer.getInstanceID(),
"Teleport to this computer"
) )
.appendText( " " )
.appendSibling( link(
text( "\u20e2" ),
"/computercraft view " + serverComputer.getInstanceID(),
"View this computer"
) );
}
return out;
}
private static ITextComponent linkPosition( CommandContext context, ServerComputer computer )
@@ -458,9 +468,6 @@ public final class CommandComputerCraft extends CommandDelegate
if( server.getID() > maxId ) maxId = server.getID();
}
ICommandSender sender = context.getSender();
boolean isPlayer = sender instanceof EntityPlayerMP && !(sender instanceof FakePlayer);
timings.sort( Comparator.<ComputerTracker, Long>comparing( x -> x.get( field ) ).reversed() );
boolean defaultLayout = field == TrackingField.TASKS || field == TrackingField.TOTAL_TIME
@@ -476,26 +483,7 @@ public final class CommandComputerCraft extends CommandDelegate
Computer computer = entry.getComputer();
ServerComputer serverComputer = computer == null ? null : lookup.get( computer );
ITextComponent computerComponent = new TextComponentString( "" )
.appendSibling( serverComputer == null ? text( "?" ) : linkComputer( serverComputer ) )
.appendText( " (id " + entry.getComputerId() + ")" );
if( serverComputer != null && UserLevel.OP.canExecute( context ) && isPlayer )
{
computerComponent
.appendText( " " )
.appendSibling( link(
text( "\u261b" ),
"/computercraft tp " + serverComputer.getInstanceID(),
"Teleport to this computer"
) )
.appendText( " " )
.appendSibling( link(
text( "\u20e2" ),
"/computercraft view " + serverComputer.getInstanceID(),
"View this computer"
) );
}
ITextComponent computerComponent = linkComputer( context, serverComputer, entry.getComputerId() );
if( defaultLayout )
{
@@ -515,4 +503,30 @@ public final class CommandComputerCraft extends CommandDelegate
table.displayTo( context.getSender() );
}
private static void withComputers( List<String> selectors, Consumer<Collection<ServerComputer>> action ) throws CommandException
{
Set<ServerComputer> computers = Sets.newHashSet();
List<String> failed = new ArrayList<>();
if( selectors.isEmpty() )
{
computers.addAll( ComputerCraft.serverComputerRegistry.getComputers() );
}
else
{
for( String selector : selectors )
{
List<ServerComputer> selected = ComputerSelector.getComputers( selector );
computers.addAll( selected );
if( selected.isEmpty() ) failed.add( selector );
}
}
action.accept( computers );
if( !failed.isEmpty() )
{
throw new CommandException( "Could not find computers matching " + String.join( ", ", failed ) );
}
}
}

View File

@@ -12,30 +12,22 @@ import java.util.function.Predicate;
public final class ComputerSelector
{
private static List<ServerComputer> getComputers( Predicate<ServerComputer> predicate, String selector ) throws CommandException
private static List<ServerComputer> getComputers( Predicate<ServerComputer> predicate ) throws CommandException
{
// We copy it to prevent concurrent modifications.
List<ServerComputer> computers = Lists.newArrayList( ComputerCraft.serverComputerRegistry.getComputers() );
List<ServerComputer> candidates = Lists.newArrayList();
for( ServerComputer searchComputer : computers )
{
if( predicate.test( searchComputer ) ) candidates.add( searchComputer );
}
if( candidates.isEmpty() )
{
throw new CommandException( "No computer matching " + selector );
}
else
{
return candidates;
}
ArrayList<ServerComputer> computers = new ArrayList<>( ComputerCraft.serverComputerRegistry.getComputers() );
computers.removeIf( predicate.negate() );
return computers;
}
public static ServerComputer getComputer( String selector ) throws CommandException
{
List<ServerComputer> computers = getComputers( selector );
if( computers.size() == 1 )
if( computers.size() == 0 )
{
throw new CommandException( "No computer matching " + selector );
}
else if( computers.size() == 1 )
{
return computers.get( 0 );
}
@@ -46,7 +38,7 @@ public final class ComputerSelector
for( int i = 0; i < computers.size(); i++ )
{
if( i > 1 ) builder.append( ", " );
if( i > 0 ) builder.append( ", " );
builder.append( computers.get( i ).getInstanceID() );
}
builder.append( ")" );
@@ -71,17 +63,17 @@ public final class ComputerSelector
throw new CommandException( "'" + selector + "' is not a valid number" );
}
return getComputers( x -> x.getID() == id, selector );
return getComputers( x -> x.getID() == id );
}
else if( selector.length() > 0 && selector.charAt( 0 ) == '@' )
{
String label = selector.substring( 1 );
return getComputers( x -> Objects.equals( label, x.getLabel() ), selector );
return getComputers( x -> Objects.equals( label, x.getLabel() ) );
}
else if( selector.length() > 0 && selector.charAt( 0 ) == '~' )
{
String familyName = selector.substring( 1 );
return getComputers( x -> x.getFamily().name().equalsIgnoreCase( familyName ), selector );
return getComputers( x -> x.getFamily().name().equalsIgnoreCase( familyName ) );
}
else
{
@@ -96,14 +88,7 @@ public final class ComputerSelector
}
ServerComputer computer = ComputerCraft.serverComputerRegistry.get( instance );
if( computer == null )
{
throw new CommandException( "No such computer for instance id " + instance );
}
else
{
return Collections.singletonList( computer );
}
return computer == null ? Collections.emptyList() : Collections.singletonList( computer );
}
}

View File

@@ -2,7 +2,9 @@ package dan200.computercraft.shared.command.framework;
import com.google.common.collect.Lists;
import net.minecraft.command.ICommandSender;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.server.MinecraftServer;
import net.minecraftforge.common.util.FakePlayer;
import java.util.Collections;
import java.util.List;
@@ -90,4 +92,9 @@ public final class CommandContext
{
return sender;
}
public boolean fromPlayer()
{
return sender instanceof EntityPlayerMP && !(sender instanceof FakePlayer);
}
}

View File

@@ -17,7 +17,6 @@ import static dan200.computercraft.shared.command.framework.ChatHelpers.coloured
*/
public class TextFormatter
{
private static final int SPACE_WIDTH = 4;
private static final char PADDING_CHAR = '\u02cc';
/**
@@ -54,7 +53,7 @@ public class TextFormatter
8, 4,
};
private static int getWidth( int codePoint )
public static int getWidth( int codePoint )
{
// Escape codes
if( codePoint == 167 ) return -1;
@@ -73,7 +72,7 @@ public class TextFormatter
return 0;
}
private static int getWidth( ITextComponent component )
public static int getWidth( ITextComponent component )
{
int total = 0;
if( component instanceof TextComponentString )
@@ -132,19 +131,17 @@ public class TextFormatter
int width = getWidthFor( entry, sender );
int delta = maxWidth - width;
if( delta > 0 )
int spaceWidth = getWidthFor( ' ', sender );
int spaces = delta / spaceWidth;
int extra = delta % spaces;
// Append a fixed number of spaces
if( spaces > 0 ) out.appendSibling( new TextComponentString( StringUtils.repeat( ' ', spaces ) ) );
// Append several minor characters to pad to a full string
if( extra > 0 )
{
int spaces = delta / SPACE_WIDTH;
int extra = delta % SPACE_WIDTH;
// Append a fixed number of spaces
if( spaces > 0 ) out.appendSibling( new TextComponentString( StringUtils.repeat( ' ', spaces ) ) );
// Append several minor characters to pad to a full string
if( extra > 0 )
{
out.appendSibling( coloured( StringUtils.repeat( PADDING_CHAR, extra ), TextFormatting.GRAY ) );
}
out.appendSibling( coloured( StringUtils.repeat( PADDING_CHAR, extra ), TextFormatting.GRAY ) );
}
}
}

View File

@@ -35,7 +35,7 @@ public class TextTable
this.columns = header.length;
}
public TextTable(int id)
public TextTable( int id )
{
this.id = id;
this.header = null;
@@ -90,14 +90,15 @@ public class TextTable
ITextComponent[] row = rows.get( y );
for( int i = 0; i < row.length; i++ )
{
int width = getWidthFor( row[i], sender ) + 3;
int width = getWidthFor( row[i], sender );
if( width > maxWidths[i] ) maxWidths[i] = width;
}
}
// Add a small amount of extra padding. We include this here instead of the separator to allow
// for "extra" characters
for( int i = 0; i < maxWidths.length; i++ ) maxWidths[i] += 4;
// Add a small amount of extra padding. This defaults to 3 spaces for players
// and 1 for everyone else.
int padding = isPlayer( sender ) ? getWidth( ' ' ) * 3 : 1;
for( int i = 0; i < maxWidths.length; i++ ) maxWidths[i] += padding;
int totalWidth = (columns - 1) * getWidthFor( SEPARATOR, sender );
for( int x : maxWidths ) totalWidth += x;
@@ -161,7 +162,7 @@ public class TextTable
for( int i = 0; i < out.size(); i++ )
{
if( i > 0 ) result.appendSibling( LINE );
result.appendSibling( out.get( 0 ) );
result.appendSibling( out.get( i ) );
}
sender.sendMessage( result );
}

View File

@@ -54,6 +54,11 @@ public class ServerTerminal implements ITerminal
}
}
protected void markTerminalChanged()
{
m_terminalChanged = true;
}
public void update()
{
m_terminalChangedLastFrame = m_terminalChanged || (m_terminal != null && m_terminal.getChanged());

View File

@@ -8,9 +8,7 @@ package dan200.computercraft.shared.computer.apis;
import com.google.common.collect.ImmutableMap;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.api.lua.ILuaAPI;
import dan200.computercraft.api.lua.ILuaContext;
import dan200.computercraft.api.lua.LuaException;
import dan200.computercraft.api.lua.*;
import dan200.computercraft.shared.computer.blocks.TileCommandComputer;
import dan200.computercraft.shared.util.WorldUtil;
import net.minecraft.block.Block;
@@ -24,6 +22,7 @@ import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.HashMap;
import java.util.Map;
@@ -82,7 +81,7 @@ public class CommandAPI implements ILuaAPI
sender.clearOutput();
int result = commandManager.executeCommand( sender, command );
return new Object[]{ (result > 0), sender.copyOutput() };
return new Object[] { (result > 0), sender.copyOutput() };
}
catch( Throwable t )
{
@@ -90,7 +89,7 @@ public class CommandAPI implements ILuaAPI
{
ComputerCraft.log.error( "Error running command.", t );
}
return new Object[]{ false, createOutput( "Java Exception Thrown: " + t.toString() ) };
return new Object[] { false, createOutput( "Java Exception Thrown: " + t.toString() ) };
}
}
else
@@ -131,7 +130,8 @@ public class CommandAPI implements ILuaAPI
}
@Override
public Object[] callMethod( @Nonnull ILuaContext context, int method, @Nonnull Object[] arguments ) throws LuaException, InterruptedException
@Nonnull
public MethodResult callMethod( @Nonnull ICallContext context, int method, @Nonnull Object[] arguments ) throws LuaException
{
switch( method )
{
@@ -139,19 +139,19 @@ public class CommandAPI implements ILuaAPI
{
// exec
final String command = getString( arguments, 0 );
return context.executeMainThreadTask( () -> doCommand( command ) );
return MethodResult.onMainThread( () -> MethodResult.of( doCommand( command ) ) );
}
case 1:
{
// execAsync
final String command = getString( arguments, 0 );
long taskID = context.issueMainThreadTask( () -> doCommand( command ) );
return new Object[] { taskID };
return MethodResult.of( taskID );
}
case 2:
{
// list
return context.executeMainThreadTask( () ->
return MethodResult.onMainThread( () ->
{
int i = 1;
Map<Object, Object> result = new HashMap<>();
@@ -182,7 +182,7 @@ public class CommandAPI implements ILuaAPI
}
}
}
return new Object[]{ result };
return MethodResult.of( result );
} );
}
case 3:
@@ -190,7 +190,7 @@ public class CommandAPI implements ILuaAPI
// getBlockPosition
// This is probably safe to do on the Lua thread. Probably.
BlockPos pos = m_computer.getPos();
return new Object[] { pos.getX(), pos.getY(), pos.getZ() };
return MethodResult.of( pos.getX(), pos.getY(), pos.getZ() );
}
case 4:
{
@@ -201,7 +201,7 @@ public class CommandAPI implements ILuaAPI
final int maxx = getInt( arguments, 3 );
final int maxy = getInt( arguments, 4 );
final int maxz = getInt( arguments, 5 );
return context.executeMainThreadTask( () ->
return MethodResult.onMainThread( () ->
{
// Get the details of the block
World world = m_computer.getWorld();
@@ -236,7 +236,7 @@ public class CommandAPI implements ILuaAPI
}
}
}
return new Object[]{ results };
return MethodResult.of( results );
} );
}
case 5:
@@ -245,14 +245,14 @@ public class CommandAPI implements ILuaAPI
final int x = getInt( arguments, 0 );
final int y = getInt( arguments, 1 );
final int z = getInt( arguments, 2 );
return context.executeMainThreadTask( () ->
return MethodResult.onMainThread( () ->
{
// Get the details of the block
World world = m_computer.getWorld();
BlockPos position = new BlockPos( x, y, z );
if( WorldUtil.isBlockInWorld( world, position ) )
{
return new Object[]{ getBlockInfo( world, position ) };
return MethodResult.of( getBlockInfo( world, position ) );
}
else
{
@@ -262,8 +262,16 @@ public class CommandAPI implements ILuaAPI
}
default:
{
return null;
return MethodResult.empty();
}
}
}
@Nullable
@Override
@Deprecated
public Object[] callMethod( @Nonnull ILuaContext context, int method, @Nonnull Object[] arguments ) throws LuaException, InterruptedException
{
return callMethod( (ICallContext) context, method, arguments ).evaluate( context );
}
}

View File

@@ -42,7 +42,7 @@ public class BlockCommandComputer extends BlockComputerBase
super( Material.IRON );
setBlockUnbreakable();
setResistance( 6000000.0F );
setUnlocalizedName( "computercraft:command_computer" );
setTranslationKey( "computercraft:command_computer" );
setCreativeTab( ComputerCraft.mainCreativeTab );
setDefaultState( this.blockState.getBaseState()
.withProperty( Properties.FACING, EnumFacing.NORTH )
@@ -62,7 +62,7 @@ public class BlockCommandComputer extends BlockComputerBase
@Deprecated
public IBlockState getStateFromMeta( int meta )
{
EnumFacing dir = EnumFacing.getFront( meta & 0x7 );
EnumFacing dir = EnumFacing.byIndex( meta & 0x7 );
if( dir.getAxis() == EnumFacing.Axis.Y )
{
dir = EnumFacing.NORTH;

View File

@@ -44,7 +44,7 @@ public class BlockComputer extends BlockComputerBase
{
super( Material.ROCK );
setHardness( 2.0f );
setUnlocalizedName( "computercraft:computer" );
setTranslationKey( "computercraft:computer" );
setCreativeTab( ComputerCraft.mainCreativeTab );
setDefaultState( this.blockState.getBaseState()
.withProperty( Properties.FACING, EnumFacing.NORTH )
@@ -65,7 +65,7 @@ public class BlockComputer extends BlockComputerBase
@Deprecated
public IBlockState getStateFromMeta( int meta )
{
EnumFacing dir = EnumFacing.getFront( meta & 0x7 );
EnumFacing dir = EnumFacing.byIndex( meta & 0x7 );
if( dir.getAxis() == EnumFacing.Axis.Y )
{
dir = EnumFacing.NORTH;

View File

@@ -6,11 +6,15 @@
package dan200.computercraft.shared.computer.blocks;
import dan200.computercraft.api.lua.ICallContext;
import dan200.computercraft.api.lua.ILuaContext;
import dan200.computercraft.api.lua.LuaException;
import dan200.computercraft.api.lua.MethodResult;
import dan200.computercraft.api.peripheral.IComputerAccess;
import dan200.computercraft.api.peripheral.IPeripheral;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public class ComputerPeripheral
implements IPeripheral
@@ -23,7 +27,7 @@ public class ComputerPeripheral
m_type = type;
m_computer = computer;
}
// IPeripheral implementation
@Nonnull
@@ -47,8 +51,9 @@ public class ComputerPeripheral
};
}
@Nonnull
@Override
public Object[] callMethod( @Nonnull IComputerAccess computer, @Nonnull ILuaContext context, int method, @Nonnull Object[] arguments )
public MethodResult callMethod( @Nonnull IComputerAccess computer, @Nonnull ICallContext context, int method, @Nonnull Object[] arguments )
{
switch( method )
{
@@ -56,42 +61,48 @@ public class ComputerPeripheral
{
// turnOn
m_computer.turnOn();
return null;
return MethodResult.empty();
}
case 1:
{
// shutdown
m_computer.shutdown();
return null;
return MethodResult.empty();
}
case 2:
{
// reboot
m_computer.reboot();
return null;
return MethodResult.empty();
}
case 3:
{
// getID
return new Object[] {
m_computer.assignID()
};
return MethodResult.of( m_computer.assignID() );
}
case 4:
{
// isOn
return new Object[] { m_computer.isOn() };
return MethodResult.of( m_computer.isOn() );
}
case 5:
// getLabel
return new Object[] { m_computer.getLabel() };
return MethodResult.of( m_computer.getLabel() );
default:
{
return null;
return MethodResult.empty();
}
}
}
@Nullable
@Override
@Deprecated
public Object[] callMethod( @Nonnull IComputerAccess access, @Nonnull ILuaContext context, int method, @Nonnull Object[] arguments ) throws LuaException, InterruptedException
{
return callMethod( access, (ICallContext) context, method, arguments ).evaluate( context );
}
@Override
public boolean equals( IPeripheral other )
{

View File

@@ -154,7 +154,7 @@ public class ServerComputer extends ServerTerminal
return packet;
}
private ComputerCraftPacket createTerminalPacket() {
protected ComputerCraftPacket createTerminalPacket() {
ComputerCraftPacket packet = new ComputerCraftPacket();
packet.m_packetType = ComputerCraftPacket.ComputerTerminalChanged;
packet.m_dataInt = new int[] { getInstanceID() };
@@ -465,7 +465,7 @@ public class ServerComputer extends ServerTerminal
}
}
private boolean isInteracting( EntityPlayer player )
protected boolean isInteracting( EntityPlayer player )
{
if( player == null ) return false;

View File

@@ -24,7 +24,7 @@ public class ItemCommandComputer extends ItemComputer
super( block );
setMaxStackSize( 64 );
setHasSubtypes( true );
setUnlocalizedName( "computercraft:command_computer" );
setTranslationKey( "computercraft:command_computer" );
setCreativeTab( ComputerCraft.mainCreativeTab );
}

View File

@@ -33,7 +33,7 @@ public class ItemComputer extends ItemComputerBase
super( block );
setMaxStackSize( 64 );
setHasSubtypes( true );
setUnlocalizedName( "computercraft:computer" );
setTranslationKey( "computercraft:computer" );
setCreativeTab( ComputerCraft.mainCreativeTab );
}
@@ -114,7 +114,7 @@ public class ItemComputer extends ItemComputerBase
@Nonnull
@Override
public String getUnlocalizedName( @Nonnull ItemStack stack )
public String getTranslationKey( @Nonnull ItemStack stack )
{
switch( getFamily( stack ) )
{

View File

@@ -0,0 +1,88 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2018. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.shared.integration.charset;
import dan200.computercraft.shared.common.TileGeneric;
import net.minecraft.util.EnumFacing;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.capabilities.ICapabilityProvider;
import pl.asie.charset.api.wires.IBundledEmitter;
import pl.asie.charset.api.wires.IBundledReceiver;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import static dan200.computercraft.shared.integration.charset.IntegrationCharset.CAPABILITY_EMITTER;
import static dan200.computercraft.shared.integration.charset.IntegrationCharset.CAPABILITY_RECEIVER;
final class BundledCapabilityProvider implements ICapabilityProvider
{
private final TileGeneric tile;
private IBundledReceiver receiver;
private IBundledEmitter[] emitters;
BundledCapabilityProvider( TileGeneric tile )
{
this.tile = tile;
}
@Override
public boolean hasCapability( @Nonnull Capability<?> capability, @Nullable EnumFacing side )
{
return capability == CAPABILITY_EMITTER || capability == CAPABILITY_RECEIVER;
}
@Nullable
@Override
public <T> T getCapability( @Nonnull Capability<T> capability, @Nullable EnumFacing side )
{
if( capability == CAPABILITY_RECEIVER )
{
IBundledReceiver receiver = this.receiver;
if( receiver == null ) receiver = this.receiver = tile::onNeighbourChange;
return CAPABILITY_RECEIVER.cast( receiver );
}
else if( capability == CAPABILITY_EMITTER )
{
IBundledEmitter[] emitters = this.emitters;
if( emitters == null ) emitters = this.emitters = new IBundledEmitter[7];
int index = side == null ? 6 : side.getIndex();
IBundledEmitter emitter = emitters[index];
if( emitter == null )
{
if( side == null )
{
emitter = emitters[index] = () -> {
int flags = 0;
for( EnumFacing facing : EnumFacing.VALUES ) flags |= tile.getBundledRedstoneOutput( facing );
return toBytes( flags );
};
}
else
{
emitter = emitters[index] = () -> toBytes( tile.getBundledRedstoneOutput( side ) );
}
}
;
return CAPABILITY_EMITTER.cast( emitter );
}
else
{
return null;
}
}
private static byte[] toBytes( int flag )
{
byte[] channels = new byte[16];
for( int i = 0; i < 16; i++ ) channels[i] = (flag & (1 << i)) == 0 ? (byte) 0 : 15;
return channels;
}
}

View File

@@ -0,0 +1,34 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2018. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.shared.integration.charset;
import dan200.computercraft.api.redstone.IBundledRedstoneProvider;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import javax.annotation.Nonnull;
import static dan200.computercraft.shared.integration.charset.IntegrationCharset.CAPABILITY_EMITTER;
public class BundledRedstoneProvider implements IBundledRedstoneProvider
{
@Override
public int getBundledRedstoneOutput( @Nonnull World world, @Nonnull BlockPos pos, @Nonnull EnumFacing side )
{
TileEntity tile = world.getTileEntity( pos );
if( tile == null || !tile.hasCapability( CAPABILITY_EMITTER, side ) ) return -1;
byte[] signal = tile.getCapability( CAPABILITY_EMITTER, side ).getBundledSignal();
if( signal == null ) return -1;
int flag = 0;
for( int i = 0; i < signal.length; i++ ) flag |= signal[i] > 0 ? (1 << i) : 0;
return flag;
}
}

View File

@@ -0,0 +1,53 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2018. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.shared.integration.charset;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.api.ComputerCraftAPI;
import dan200.computercraft.shared.common.TileGeneric;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.capabilities.CapabilityInject;
import net.minecraftforge.event.AttachCapabilitiesEvent;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import pl.asie.charset.api.wires.IBundledEmitter;
import pl.asie.charset.api.wires.IBundledReceiver;
public final class IntegrationCharset
{
private static final ResourceLocation CAPABILITY_KEY = new ResourceLocation( ComputerCraft.MOD_ID, "charset" );
@CapabilityInject( IBundledEmitter.class )
public static final Capability<IBundledEmitter> CAPABILITY_EMITTER = null;
@CapabilityInject( IBundledReceiver.class )
public static final Capability<IBundledReceiver> CAPABILITY_RECEIVER = null;
private IntegrationCharset()
{
}
public static void register()
{
if( CAPABILITY_EMITTER == null || CAPABILITY_RECEIVER == null ) return;
MinecraftForge.EVENT_BUS.register( new IntegrationCharset() );
ComputerCraftAPI.registerBundledRedstoneProvider( new BundledRedstoneProvider() );
}
@SubscribeEvent
public void attachGenericCapabilities( AttachCapabilitiesEvent<TileEntity> event)
{
TileEntity tile = event.getObject();
if(tile instanceof TileGeneric)
{
event.addCapability( CAPABILITY_KEY, new BundledCapabilityProvider( (TileGeneric) tile ) );
}
}
}

View File

@@ -33,7 +33,7 @@ public class ItemDiskLegacy extends Item
{
setMaxStackSize( 1 );
setHasSubtypes( true );
setUnlocalizedName( "computercraft:disk" );
setTranslationKey( "computercraft:disk" );
setCreativeTab( ComputerCraft.mainCreativeTab );
}

View File

@@ -39,7 +39,7 @@ public class ItemPrintout extends Item
{
setMaxStackSize( 1 );
setHasSubtypes( true );
setUnlocalizedName( "computercraft:page" );
setTranslationKey( "computercraft:page" );
setCreativeTab( ComputerCraft.mainCreativeTab );
}
@@ -64,7 +64,7 @@ public class ItemPrintout extends Item
@Nonnull
@Override
public String getUnlocalizedName( @Nonnull ItemStack stack )
public String getTranslationKey( @Nonnull ItemStack stack )
{
Type type = getType( stack );
switch( type )

View File

@@ -34,7 +34,7 @@ public class ItemTreasureDisk extends Item
{
setMaxStackSize( 1 );
setHasSubtypes( true );
setUnlocalizedName( "computercraft:treasure_disk" );
setTranslationKey( "computercraft:treasure_disk" );
}
@Override

View File

@@ -6,14 +6,17 @@
package dan200.computercraft.shared.peripheral.commandblock;
import dan200.computercraft.api.lua.ICallContext;
import dan200.computercraft.api.lua.ILuaContext;
import dan200.computercraft.api.lua.LuaException;
import dan200.computercraft.api.lua.MethodResult;
import dan200.computercraft.api.peripheral.IComputerAccess;
import dan200.computercraft.api.peripheral.IPeripheral;
import net.minecraft.tileentity.TileEntityCommandBlock;
import net.minecraft.util.math.BlockPos;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import static dan200.computercraft.core.apis.ArgumentHelper.getString;
@@ -46,17 +49,18 @@ public class CommandBlockPeripheral implements IPeripheral
};
}
@Nonnull
@Override
public Object[] callMethod( @Nonnull IComputerAccess computer, @Nonnull ILuaContext context, int method, @Nonnull final Object[] arguments ) throws LuaException, InterruptedException
public MethodResult callMethod( @Nonnull IComputerAccess computer, @Nonnull ICallContext context, int method, @Nonnull final Object[] arguments ) throws LuaException
{
switch (method)
switch( method )
{
case 0:
{
// getCommand
return context.executeMainThreadTask( () -> new Object[] {
m_commandBlock.getCommandBlockLogic().getCommand()
} );
return MethodResult.onMainThread( () ->
MethodResult.of( m_commandBlock.getCommandBlockLogic().getCommand() )
);
}
case 1:
{
@@ -69,27 +73,35 @@ public class CommandBlockPeripheral implements IPeripheral
m_commandBlock.getWorld().markBlockRangeForRenderUpdate( pos, pos );
return null;
} );
return null;
return MethodResult.empty();
}
case 2:
{
// runCommand
return context.executeMainThreadTask( () ->
return MethodResult.onMainThread( () ->
{
m_commandBlock.getCommandBlockLogic().trigger( m_commandBlock.getWorld() );
int result = m_commandBlock.getCommandBlockLogic().getSuccessCount();
if( result > 0 )
{
return new Object[] { true };
return MethodResult.of( true );
}
else
{
return new Object[] { false, "Command failed" };
return MethodResult.of( false, "Command failed" );
}
} );
}
}
return null;
return MethodResult.empty();
}
@Nullable
@Override
@Deprecated
public Object[] callMethod( @Nonnull IComputerAccess access, @Nonnull ILuaContext context, int method, @Nonnull Object[] arguments ) throws LuaException, InterruptedException
{
return callMethod( access, (ICallContext) context, method, arguments ).evaluate( context );
}
@Override

View File

@@ -55,7 +55,7 @@ public class BlockCable extends BlockPeripheralBase
public BlockCable()
{
setHardness( 1.5f );
setUnlocalizedName( "computercraft:cable" );
setTranslationKey( "computercraft:cable" );
setCreativeTab( ComputerCraft.mainCreativeTab );
setDefaultState( this.blockState.getBaseState()
.withProperty( Properties.MODEM, BlockCableModemVariant.None )
@@ -94,12 +94,12 @@ public class BlockCable extends BlockPeripheralBase
if( meta < 6 )
{
state = state.withProperty( Properties.CABLE, BlockCableCableVariant.NONE );
state = state.withProperty( Properties.MODEM, BlockCableModemVariant.fromFacing( EnumFacing.getFront( meta ) ) );
state = state.withProperty( Properties.MODEM, BlockCableModemVariant.fromFacing( EnumFacing.byIndex( meta ) ) );
}
else if( meta < 12 )
{
state = state.withProperty( Properties.CABLE, BlockCableCableVariant.ANY );
state = state.withProperty( Properties.MODEM, BlockCableModemVariant.fromFacing( EnumFacing.getFront( meta - 6 ) ) );
state = state.withProperty( Properties.MODEM, BlockCableModemVariant.fromFacing( EnumFacing.byIndex( meta - 6 ) ) );
}
else if( meta == 13 )
{
@@ -296,7 +296,7 @@ public class BlockCable extends BlockPeripheralBase
}
}
return result == null ? null : new RayTraceResult( result.hitVec.addVector( pos.getX(), pos.getY(), pos.getZ() ), result.sideHit, pos );
return result == null ? null : new RayTraceResult( result.hitVec.add( pos.getX(), pos.getY(), pos.getZ() ), result.sideHit, pos );
}
else
{

View File

@@ -44,7 +44,7 @@ public class BlockPeripheral extends BlockPeripheralBase
public BlockPeripheral()
{
setHardness( 2.0f );
setUnlocalizedName( "computercraft:peripheral" );
setTranslationKey( "computercraft:peripheral" );
setCreativeTab( ComputerCraft.mainCreativeTab );
setDefaultState( this.blockState.getBaseState()
.withProperty( Properties.FACING, EnumFacing.NORTH )
@@ -55,7 +55,7 @@ public class BlockPeripheral extends BlockPeripheralBase
@Override
@Nonnull
@SideOnly( Side.CLIENT)
public BlockRenderLayer getBlockLayer()
public BlockRenderLayer getRenderLayer()
{
return BlockRenderLayer.CUTOUT;
}
@@ -76,7 +76,7 @@ public class BlockPeripheral extends BlockPeripheralBase
if( meta >= 2 && meta <= 5 )
{
state = state.withProperty( Properties.VARIANT, BlockPeripheralVariant.DiskDriveEmpty );
state = state.withProperty( Properties.FACING, EnumFacing.getFront( meta ) );
state = state.withProperty( Properties.FACING, EnumFacing.byIndex( meta ) );
}
else if( meta <= 9 )
{
@@ -93,7 +93,7 @@ public class BlockPeripheral extends BlockPeripheralBase
else
{
state = state.withProperty( Properties.VARIANT, BlockPeripheralVariant.WirelessModemOff );
state = state.withProperty( Properties.FACING, EnumFacing.getFront( meta - 4 ) );
state = state.withProperty( Properties.FACING, EnumFacing.byIndex( meta - 4 ) );
}
}
else if( meta == 10 )
@@ -651,7 +651,7 @@ public class BlockPeripheral extends BlockPeripheralBase
public boolean causesSuffocation(IBlockState state)
{
// This normally uses the default state
return blockMaterial.blocksMovement() && state.isOpaqueCube();
return material.blocksMovement() && state.isOpaqueCube();
}
@Override

View File

@@ -34,7 +34,7 @@ public class BlockWiredModemFull extends BlockPeripheralBase
public BlockWiredModemFull()
{
setHardness( 1.5f );
setUnlocalizedName( "computercraft:wired_modem_full" );
setTranslationKey( "computercraft:wired_modem_full" );
setCreativeTab( ComputerCraft.mainCreativeTab );
setDefaultState( blockState.getBaseState()
.withProperty( Properties.MODEM_ON, false )

View File

@@ -21,7 +21,7 @@ public class ItemAdvancedModem extends ItemPeripheralBase
public ItemAdvancedModem( Block block )
{
super( block );
setUnlocalizedName( "computercraft:advanced_modem" );
setTranslationKey( "computercraft:advanced_modem" );
setCreativeTab( ComputerCraft.mainCreativeTab );
}

View File

@@ -28,7 +28,7 @@ public class ItemCable extends ItemPeripheralBase
public ItemCable( Block block )
{
super( block );
setUnlocalizedName( "computercraft:cable" );
setTranslationKey( "computercraft:cable" );
setCreativeTab( ComputerCraft.mainCreativeTab );
}

View File

@@ -20,7 +20,7 @@ public class ItemPeripheral extends ItemPeripheralBase
public ItemPeripheral( Block block )
{
super( block );
setUnlocalizedName( "computercraft:peripheral" );
setTranslationKey( "computercraft:peripheral" );
setCreativeTab( ComputerCraft.mainCreativeTab );
}

View File

@@ -59,7 +59,7 @@ public abstract class ItemPeripheralBase extends ItemBlock implements IPeriphera
@Nonnull
@Override
public String getUnlocalizedName( @Nonnull ItemStack stack )
public String getTranslationKey( @Nonnull ItemStack stack )
{
PeripheralType type = getPeripheralType( stack );
switch( type )

View File

@@ -112,12 +112,12 @@ public abstract class TilePeripheralBase extends TileGeneric
}
}
public synchronized int getAnim()
public int getAnim()
{
return m_anim;
}
public synchronized void setAnim( int anim )
public void setAnim( int anim )
{
if( anim != m_anim )
{
@@ -127,12 +127,12 @@ public abstract class TilePeripheralBase extends TileGeneric
}
@Override
public synchronized void update()
public void update()
{
if( m_changed )
{
updateBlock();
m_changed = false;
updateBlock();
}
}
@@ -143,7 +143,7 @@ public abstract class TilePeripheralBase extends TileGeneric
super.readFromNBT(nbttagcompound);
if( nbttagcompound.hasKey( "dir" ) )
{
m_dir = EnumFacing.getFront( nbttagcompound.getInteger( "dir" ) );
m_dir = EnumFacing.byIndex( nbttagcompound.getInteger( "dir" ) );
}
if( nbttagcompound.hasKey( "anim" ) )
{
@@ -174,7 +174,7 @@ public abstract class TilePeripheralBase extends TileGeneric
public void readDescription( @Nonnull NBTTagCompound nbttagcompound )
{
super.readDescription( nbttagcompound );
m_dir = EnumFacing.getFront( nbttagcompound.getInteger( "dir" ) );
m_dir = EnumFacing.byIndex( nbttagcompound.getInteger( "dir" ) );
m_anim = nbttagcompound.getInteger( "anim" );
if( nbttagcompound.hasKey( "label" ) )
{

View File

@@ -6,8 +6,10 @@
package dan200.computercraft.shared.peripheral.diskdrive;
import dan200.computercraft.api.lua.ICallContext;
import dan200.computercraft.api.lua.ILuaContext;
import dan200.computercraft.api.lua.LuaException;
import dan200.computercraft.api.lua.MethodResult;
import dan200.computercraft.api.media.IMedia;
import dan200.computercraft.api.peripheral.IComputerAccess;
import dan200.computercraft.api.peripheral.IPeripheral;
@@ -17,6 +19,7 @@ import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import static dan200.computercraft.core.apis.ArgumentHelper.optString;
@@ -55,17 +58,18 @@ public class DiskDrivePeripheral implements IPeripheral
};
}
@Nonnull
@Override
public Object[] callMethod( @Nonnull IComputerAccess computer, @Nonnull ILuaContext context, int method, @Nonnull Object[] arguments ) throws LuaException
public MethodResult callMethod( @Nonnull IComputerAccess computer, @Nonnull ICallContext context, int method, @Nonnull Object[] arguments ) throws LuaException
{
switch( method )
{
case 0:
{
// isDiskPresent
return new Object[] {
return MethodResult.of(
!m_diskDrive.getDiskStack().isEmpty()
};
);
}
case 1:
{
@@ -73,9 +77,9 @@ public class DiskDrivePeripheral implements IPeripheral
IMedia media = m_diskDrive.getDiskMedia();
if( media != null )
{
return new Object[] { media.getLabel( m_diskDrive.getDiskStack() ) };
return MethodResult.of( media.getLabel( m_diskDrive.getDiskStack() ) );
}
return null;
return MethodResult.empty();
}
case 2:
{
@@ -96,21 +100,21 @@ public class DiskDrivePeripheral implements IPeripheral
throw new LuaException( "Disk label cannot be changed" );
}
}
return null;
return MethodResult.empty();
}
case 3:
{
// hasData
return new Object[] {
return MethodResult.of(
m_diskDrive.getDiskMountPath( computer ) != null
};
);
}
case 4:
{
// getMountPath
return new Object[] {
return MethodResult.of(
m_diskDrive.getDiskMountPath( computer )
};
);
}
case 5:
{
@@ -118,9 +122,9 @@ public class DiskDrivePeripheral implements IPeripheral
IMedia media = m_diskDrive.getDiskMedia();
if( media != null )
{
return new Object[] { media.getAudio( m_diskDrive.getDiskStack() ) != null };
return MethodResult.of( media.getAudio( m_diskDrive.getDiskStack() ) != null );
}
return new Object[] { false };
return MethodResult.of( false );
}
case 6:
{
@@ -128,27 +132,27 @@ public class DiskDrivePeripheral implements IPeripheral
IMedia media = m_diskDrive.getDiskMedia();
if( media != null )
{
return new Object[] { media.getAudioTitle( m_diskDrive.getDiskStack() ) };
return MethodResult.of( media.getAudioTitle( m_diskDrive.getDiskStack() ) );
}
return new Object[] { false };
return MethodResult.of( false );
}
case 7:
{
// playAudio
m_diskDrive.playDiskAudio();
return null;
return MethodResult.empty();
}
case 8:
{
// stopAudio
m_diskDrive.stopDiskAudio();
return null;
return MethodResult.empty();
}
case 9:
{
// eject
m_diskDrive.ejectDisk();
return null;
return MethodResult.empty();
}
case 10:
{
@@ -159,18 +163,27 @@ public class DiskDrivePeripheral implements IPeripheral
Item item = disk.getItem();
if( item instanceof ItemDiskLegacy )
{
return new Object[] { ((ItemDiskLegacy)item).getDiskID( disk ) };
return MethodResult.of( ((ItemDiskLegacy)item).getDiskID( disk ) );
}
}
return null;
return MethodResult.empty();
}
default:
{
return null;
return MethodResult.empty();
}
}
}
@Nullable
@Override
@Deprecated
public Object[] callMethod( @Nonnull IComputerAccess access, @Nonnull ILuaContext context, int method, @Nonnull Object[] arguments ) throws LuaException, InterruptedException
{
return callMethod( access, (ICallContext) context, method, arguments ).evaluate( context );
}
@Override
public void attach( @Nonnull IComputerAccess computer )
{

View File

@@ -80,12 +80,9 @@ public class TileDiskDrive extends TilePeripheralBase
public void destroy()
{
ejectContents( true );
synchronized( this )
if( m_recordPlaying )
{
if( m_recordPlaying )
{
stopRecord();
}
stopRecord();
}
}
@@ -170,13 +167,10 @@ public class TileDiskDrive extends TilePeripheralBase
super.update();
// Ejection
synchronized( this )
if( m_ejectQueued )
{
if( m_ejectQueued )
{
ejectContents( false );
m_ejectQueued = false;
}
ejectContents( false );
m_ejectQueued = false;
}
// Music
@@ -391,10 +385,7 @@ public class TileDiskDrive extends TilePeripheralBase
@Override
public void clear()
{
synchronized( this )
{
setInventorySlotContents( 0, ItemStack.EMPTY );
}
setInventorySlotContents( 0, ItemStack.EMPTY );
}
@Override
@@ -425,18 +416,12 @@ public class TileDiskDrive extends TilePeripheralBase
@Nonnull
public ItemStack getDiskStack()
{
synchronized( this )
{
return getStackInSlot( 0 );
}
return getStackInSlot( 0 );
}
public void setDiskStack( @Nonnull ItemStack stack )
{
synchronized( this )
{
setInventorySlotContents( 0, stack );
}
setInventorySlotContents( 0, stack );
}
public IMedia getDiskMedia()
@@ -569,7 +554,7 @@ public class TileDiskDrive extends TilePeripheralBase
}
}
private synchronized void updateAnim()
private void updateAnim()
{
if( !m_diskStack.isEmpty() )
{
@@ -605,8 +590,8 @@ public class TileDiskDrive extends TilePeripheralBase
if( !destroyed )
{
EnumFacing dir = getDirection();
xOff = dir.getFrontOffsetX();
zOff = dir.getFrontOffsetZ();
xOff = dir.getXOffset();
zOff = dir.getZOffset();
}
BlockPos pos = getPos();

View File

@@ -33,7 +33,7 @@ public class BlockAdvancedModem extends BlockPeripheralBase
public BlockAdvancedModem()
{
setHardness( 2.0f );
setUnlocalizedName( "computercraft:advanced_modem" );
setTranslationKey( "computercraft:advanced_modem" );
setCreativeTab( ComputerCraft.mainCreativeTab );
setDefaultState( this.blockState.getBaseState()
.withProperty( Properties.FACING, EnumFacing.NORTH )
@@ -54,7 +54,7 @@ public class BlockAdvancedModem extends BlockPeripheralBase
public IBlockState getStateFromMeta( int meta )
{
IBlockState state = getDefaultState();
state = state.withProperty( Properties.FACING, EnumFacing.getFront( meta ) );
state = state.withProperty( Properties.FACING, EnumFacing.byIndex( meta ) );
state = state.withProperty( Properties.ON, false );
return state;
}

View File

@@ -6,8 +6,10 @@
package dan200.computercraft.shared.peripheral.modem;
import dan200.computercraft.api.lua.ICallContext;
import dan200.computercraft.api.lua.ILuaContext;
import dan200.computercraft.api.lua.LuaException;
import dan200.computercraft.api.lua.MethodResult;
import dan200.computercraft.api.network.IPacketNetwork;
import dan200.computercraft.api.network.IPacketReceiver;
import dan200.computercraft.api.network.IPacketSender;
@@ -20,6 +22,7 @@ import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import static dan200.computercraft.core.apis.ArgumentHelper.getInt;
@@ -75,7 +78,7 @@ public abstract class ModemPeripheral
m_open = false;
}
public synchronized boolean pollChanged()
public boolean pollChanged()
{
if( m_changed )
{
@@ -85,9 +88,9 @@ public abstract class ModemPeripheral
return false;
}
public synchronized boolean isActive()
public boolean isActive()
{
return (m_computer != null) && m_open;
return m_computer != null && m_open;
}
@Override
@@ -157,8 +160,9 @@ public abstract class ModemPeripheral
return channel;
}
@Nonnull
@Override
public Object[] callMethod( @Nonnull IComputerAccess computer, @Nonnull ILuaContext context, int method, @Nonnull Object[] arguments ) throws LuaException, InterruptedException
public MethodResult callMethod( @Nonnull IComputerAccess computer, @Nonnull ICallContext context, int method, @Nonnull Object[] arguments ) throws LuaException
{
switch( method )
{
@@ -183,7 +187,7 @@ public abstract class ModemPeripheral
}
}
}
return null;
return MethodResult.empty();
}
case 1:
{
@@ -192,7 +196,7 @@ public abstract class ModemPeripheral
synchronized( this )
{
boolean open = m_channels.contains( channel );
return new Object[] { open };
return MethodResult.of( open );
}
}
case 2:
@@ -210,7 +214,7 @@ public abstract class ModemPeripheral
}
}
}
return null;
return MethodResult.empty();
}
case 3:
{
@@ -228,7 +232,7 @@ public abstract class ModemPeripheral
}
}
}
return null;
return MethodResult.empty();
}
case 4:
{
@@ -253,7 +257,7 @@ public abstract class ModemPeripheral
}
}
}
return null;
return MethodResult.empty();
}
case 5:
{
@@ -262,18 +266,26 @@ public abstract class ModemPeripheral
{
if( m_network != null )
{
return new Object[] { m_network.isWireless() };
return MethodResult.of( m_network.isWireless() );
}
}
return new Object[] { false };
return MethodResult.of(false);
}
default:
{
return null;
return MethodResult.empty();
}
}
}
@Nullable
@Override
@Deprecated
public Object[] callMethod( @Nonnull IComputerAccess computer, @Nonnull ILuaContext context, int method, @Nonnull Object[] arguments ) throws LuaException, InterruptedException
{
return callMethod( computer, (ICallContext) context, method, arguments ).evaluate( context );
}
@Override
public synchronized void attach( @Nonnull IComputerAccess computer )
{

View File

@@ -108,10 +108,11 @@ public class TileCable extends TileModemBase
m_node = m_cable.getNode();
return new WiredModemPeripheral( m_cable )
{
@Nonnull
@Override
protected boolean canSeePeripheral( @Nonnull String peripheralName )
protected WiredModemLocalPeripheral getLocalPeripheral()
{
return !peripheralName.equals( m_peripheral.getConnectedName() );
return m_peripheral;
}
@Nonnull

View File

@@ -37,7 +37,7 @@ public abstract class TileModemBase extends TilePeripheralBase
protected abstract ModemPeripheral createPeripheral();
@Override
public synchronized void destroy()
public void destroy()
{
if( m_modem != null )
{

View File

@@ -401,12 +401,14 @@ public class TileWiredModemFull extends TilePeripheralBase
WiredModemPeripheral peripheral = m_modems[side.ordinal()];
if( peripheral == null )
{
WiredModemLocalPeripheral localPeripheral = m_peripherals[side.ordinal()];
peripheral = m_modems[side.ordinal()] = new WiredModemPeripheral( m_element )
{
@Nonnull
@Override
protected boolean canSeePeripheral( @Nonnull String peripheralName )
protected WiredModemLocalPeripheral getLocalPeripheral()
{
return !peripheralName.equals( m_peripherals[side.ordinal()].getConnectedName() );
return localPeripheral;
}
@Nonnull

View File

@@ -3,13 +3,16 @@ package dan200.computercraft.shared.peripheral.modem;
import com.google.common.collect.ImmutableMap;
import dan200.computercraft.api.filesystem.IMount;
import dan200.computercraft.api.filesystem.IWritableMount;
import dan200.computercraft.api.lua.ILuaContext;
import dan200.computercraft.api.lua.ICallContext;
import dan200.computercraft.api.lua.LuaException;
import dan200.computercraft.api.lua.MethodResult;
import dan200.computercraft.api.network.IPacketNetwork;
import dan200.computercraft.api.network.wired.IWiredNode;
import dan200.computercraft.api.network.wired.IWiredSender;
import dan200.computercraft.api.peripheral.IComputerAccess;
import dan200.computercraft.api.peripheral.IPeripheral;
import dan200.computercraft.core.computer.Computer;
import dan200.computercraft.core.computer.IComputerOwned;
import net.minecraft.world.World;
import javax.annotation.Nonnull;
@@ -56,7 +59,8 @@ public abstract class WiredModemPeripheral extends ModemPeripheral implements IW
return modem.getWorld();
}
protected abstract boolean canSeePeripheral( @Nonnull String peripheralName );
@Nonnull
protected abstract WiredModemLocalPeripheral getLocalPeripheral();
//endregion
//region IPeripheral
@@ -65,18 +69,20 @@ public abstract class WiredModemPeripheral extends ModemPeripheral implements IW
public String[] getMethodNames()
{
String[] methods = super.getMethodNames();
String[] newMethods = new String[methods.length + 5];
String[] newMethods = new String[methods.length + 6];
System.arraycopy( methods, 0, newMethods, 0, methods.length );
newMethods[methods.length] = "getNamesRemote";
newMethods[methods.length + 1] = "isPresentRemote";
newMethods[methods.length + 2] = "getTypeRemote";
newMethods[methods.length + 3] = "getMethodsRemote";
newMethods[methods.length + 4] = "callRemote";
newMethods[methods.length + 5] = "getNameLocal";
return newMethods;
}
@Nonnull
@Override
public Object[] callMethod( @Nonnull IComputerAccess computer, @Nonnull ILuaContext context, int method, @Nonnull Object[] arguments ) throws LuaException, InterruptedException
public MethodResult callMethod( @Nonnull IComputerAccess computer, @Nonnull ICallContext context, int method, @Nonnull Object[] arguments ) throws LuaException
{
String[] methods = super.getMethodNames();
switch( method - methods.length )
@@ -92,14 +98,14 @@ public abstract class WiredModemPeripheral extends ModemPeripheral implements IW
{
table.put( idx++, name );
}
return new Object[]{ table };
return MethodResult.of( table );
}
}
case 1:
{
// isPresentRemote
String type = getTypeRemote( getString( arguments, 0 ) );
return new Object[]{ type != null };
return MethodResult.of( type != null );
}
case 2:
{
@@ -107,9 +113,9 @@ public abstract class WiredModemPeripheral extends ModemPeripheral implements IW
String type = getTypeRemote( getString( arguments, 0 ) );
if( type != null )
{
return new Object[]{ type };
return MethodResult.of( type );
}
return null;
return MethodResult.empty();
}
case 3:
{
@@ -122,9 +128,9 @@ public abstract class WiredModemPeripheral extends ModemPeripheral implements IW
{
table.put( i + 1, methodNames[i] );
}
return new Object[]{ table };
return MethodResult.of( table );
}
return null;
return MethodResult.empty();
}
case 4:
{
@@ -135,6 +141,12 @@ public abstract class WiredModemPeripheral extends ModemPeripheral implements IW
System.arraycopy( arguments, 2, methodArgs, 0, arguments.length - 2 );
return callMethodRemote( remoteName, context, methodName, methodArgs );
}
case 5:
{
// getNameLocal
String local = getLocalPeripheral().getConnectedName();
return local == null ? MethodResult.empty() : MethodResult.of( local );
}
default:
{
// The regular modem methods
@@ -217,7 +229,7 @@ public abstract class WiredModemPeripheral extends ModemPeripheral implements IW
private void attachPeripheralImpl( String periphName, IPeripheral peripheral )
{
if( !peripheralWrappers.containsKey( periphName ) && canSeePeripheral( periphName ) )
if( !peripheralWrappers.containsKey( periphName ) && !periphName.equals( getLocalPeripheral().getConnectedName() ) )
{
RemotePeripheralWrapper wrapper = new RemotePeripheralWrapper( modem, peripheral, getComputer(), periphName );
peripheralWrappers.put( periphName, wrapper );
@@ -251,7 +263,7 @@ public abstract class WiredModemPeripheral extends ModemPeripheral implements IW
return null;
}
private Object[] callMethodRemote( String remoteName, ILuaContext context, String method, Object[] arguments ) throws LuaException, InterruptedException
private MethodResult callMethodRemote( String remoteName, ICallContext context, String method, Object[] arguments ) throws LuaException
{
RemotePeripheralWrapper wrapper;
synchronized( peripheralWrappers )
@@ -265,7 +277,7 @@ public abstract class WiredModemPeripheral extends ModemPeripheral implements IW
throw new LuaException( "No peripheral: " + remoteName );
}
private static class RemotePeripheralWrapper implements IComputerAccess
private static class RemotePeripheralWrapper implements IComputerAccess, IComputerOwned
{
private final WiredModemElement m_element;
private final IPeripheral m_peripheral;
@@ -320,7 +332,7 @@ public abstract class WiredModemPeripheral extends ModemPeripheral implements IW
return m_methods;
}
public Object[] callMethod( ILuaContext context, String methodName, Object[] arguments ) throws LuaException, InterruptedException
public MethodResult callMethod( ICallContext context, String methodName, Object[] arguments ) throws LuaException
{
if( m_methodMap.containsKey( methodName ) )
{
@@ -400,5 +412,12 @@ public abstract class WiredModemPeripheral extends ModemPeripheral implements IW
return m_element.getRemotePeripherals().get( name );
}
}
@Nullable
@Override
public Computer getComputer()
{
return m_computer instanceof IComputerOwned ? ((IComputerOwned) m_computer).getComputer() : null;
}
}
}

View File

@@ -6,8 +6,10 @@
package dan200.computercraft.shared.peripheral.monitor;
import dan200.computercraft.api.lua.ICallContext;
import dan200.computercraft.api.lua.ILuaContext;
import dan200.computercraft.api.lua.LuaException;
import dan200.computercraft.api.lua.MethodResult;
import dan200.computercraft.api.peripheral.IComputerAccess;
import dan200.computercraft.api.peripheral.IPeripheral;
import dan200.computercraft.core.apis.TermAPI;
@@ -16,6 +18,7 @@ import dan200.computercraft.shared.util.Palette;
import org.apache.commons.lang3.ArrayUtils;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import static dan200.computercraft.core.apis.ArgumentHelper.*;
@@ -70,8 +73,9 @@ public class MonitorPeripheral implements IPeripheral
};
}
@Nonnull
@Override
public Object[] callMethod( @Nonnull IComputerAccess computer, @Nonnull ILuaContext context, int method, @Nonnull Object args[] ) throws LuaException
public MethodResult callMethod( @Nonnull IComputerAccess computer, @Nonnull ICallContext context, int method, @Nonnull Object args[] ) throws LuaException
{
ServerMonitor monitor = m_monitor.getCachedServerMonitor();
if( monitor == null ) throw new LuaException( "Monitor has been detatched" );
@@ -85,21 +89,24 @@ public class MonitorPeripheral implements IPeripheral
{
// write
String text;
if( args.length > 0 && args[0] != null ) {
text = args[0].toString();
} else {
if( args.length > 0 && args[ 0 ] != null )
{
text = args[ 0 ].toString();
}
else
{
text = "";
}
terminal.write( text );
terminal.setCursorPos( terminal.getCursorX() + text.length(), terminal.getCursorY() );
return null;
return MethodResult.empty();
}
case 1:
{
// scroll
int value = getInt( args, 0 );
terminal.scroll( value );
return null;
return MethodResult.empty();
}
case 2:
{
@@ -107,42 +114,42 @@ public class MonitorPeripheral implements IPeripheral
int x = getInt( args, 0 ) - 1;
int y = getInt( args, 1 ) - 1;
terminal.setCursorPos( x, y );
return null;
return MethodResult.empty();
}
case 3:
{
// setCursorBlink
boolean blink = getBoolean( args, 0 );
terminal.setCursorBlink( blink );
return null;
return MethodResult.empty();
}
case 4:
{
// getCursorPos
return new Object[] {
return MethodResult.of(
terminal.getCursorX() + 1,
terminal.getCursorY() + 1
};
);
}
case 5:
{
// getSize
return new Object[] {
return MethodResult.of(
terminal.getWidth(),
terminal.getHeight()
};
);
}
case 6:
{
// clear
terminal.clear();
return null;
return MethodResult.empty();
}
case 7:
{
// clearLine
terminal.clearLine();
return null;
return MethodResult.empty();
}
case 8:
{
@@ -153,7 +160,7 @@ public class MonitorPeripheral implements IPeripheral
throw new LuaException( "Expected number in range 0.5-5" );
}
monitor.setTextScale( scale );
return null;
return MethodResult.empty();
}
case 9:
case 10:
@@ -161,7 +168,7 @@ public class MonitorPeripheral implements IPeripheral
// setTextColour/setTextColor
int colour = TermAPI.parseColour( args );
terminal.setTextColour( colour );
return null;
return MethodResult.empty();
}
case 11:
case 12:
@@ -169,15 +176,15 @@ public class MonitorPeripheral implements IPeripheral
// setBackgroundColour/setBackgroundColor
int colour = TermAPI.parseColour( args );
terminal.setBackgroundColour( colour );
return null;
return MethodResult.empty();
}
case 13:
case 14:
{
// isColour/isColor
return new Object[] {
return MethodResult.of(
monitor.isColour()
};
);
}
case 15:
case 16:
@@ -204,7 +211,7 @@ public class MonitorPeripheral implements IPeripheral
terminal.blit( text, textColour, backgroundColour );
terminal.setCursorPos( terminal.getCursorX() + text.length(), terminal.getCursorY() );
return null;
return MethodResult.empty();
}
case 20:
case 21:
@@ -224,7 +231,7 @@ public class MonitorPeripheral implements IPeripheral
double b = getReal( args, 3 );
TermAPI.setColour( terminal, colour, r, g, b );
}
return null;
return MethodResult.empty();
}
case 22:
case 23:
@@ -236,17 +243,25 @@ public class MonitorPeripheral implements IPeripheral
if( palette != null )
{
return ArrayUtils.toObject( palette.getColour( colour ) );
return MethodResult.of( (Object[]) ArrayUtils.toObject( palette.getColour( colour ) ) );
}
return null;
return MethodResult.empty();
}
case 24:
{
// getTextScale
return new Object[] { monitor.getTextScale() / 2.0 };
return MethodResult.of( monitor.getTextScale() / 2.0 );
}
}
return null;
return MethodResult.empty();
}
@Nullable
@Override
@Deprecated
public Object[] callMethod( @Nonnull IComputerAccess access, @Nonnull ILuaContext context, int method, @Nonnull Object[] arguments ) throws LuaException, InterruptedException
{
return callMethod( access, (ICallContext) context, method, arguments ).evaluate( context );
}
@Override
@@ -266,7 +281,7 @@ public class MonitorPeripheral implements IPeripheral
{
if( other != null && other instanceof MonitorPeripheral )
{
MonitorPeripheral otherMonitor = (MonitorPeripheral)other;
MonitorPeripheral otherMonitor = (MonitorPeripheral) other;
if( otherMonitor.m_monitor == this.m_monitor )
{
return true;

View File

@@ -344,7 +344,7 @@ public class TileMonitor extends TilePeripheralBase
public EnumFacing getFront()
{
return m_dir <= 5 ? EnumFacing.getFront( m_dir ) : (m_dir <= 11 ? EnumFacing.DOWN : EnumFacing.UP);
return m_dir <= 5 ? EnumFacing.byIndex( m_dir ) : (m_dir <= 11 ? EnumFacing.DOWN : EnumFacing.UP);
}
public EnumFacing getRight()

View File

@@ -6,13 +6,16 @@
package dan200.computercraft.shared.peripheral.printer;
import dan200.computercraft.api.lua.ICallContext;
import dan200.computercraft.api.lua.ILuaContext;
import dan200.computercraft.api.lua.LuaException;
import dan200.computercraft.api.lua.MethodResult;
import dan200.computercraft.api.peripheral.IComputerAccess;
import dan200.computercraft.api.peripheral.IPeripheral;
import dan200.computercraft.core.terminal.Terminal;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import static dan200.computercraft.core.apis.ArgumentHelper.getInt;
import static dan200.computercraft.core.apis.ArgumentHelper.optString;
@@ -50,8 +53,9 @@ public class PrinterPeripheral implements IPeripheral
};
}
@Nonnull
@Override
public Object[] callMethod( @Nonnull IComputerAccess computer, @Nonnull ILuaContext context, int method, @Nonnull Object[] args ) throws LuaException
public MethodResult callMethod( @Nonnull IComputerAccess computer, @Nonnull ICallContext context, int method, @Nonnull Object[] args ) throws LuaException
{
switch( method )
{
@@ -68,7 +72,7 @@ public class PrinterPeripheral implements IPeripheral
Terminal page = getCurrentPage();
page.write( text );
page.setCursorPos( page.getCursorX() + text.length(), page.getCursorY() );
return null;
return MethodResult.empty();
}
case 1:
{
@@ -77,7 +81,7 @@ public class PrinterPeripheral implements IPeripheral
int y = getInt( args, 1 ) - 1;
Terminal page = getCurrentPage();
page.setCursorPos( x, y );
return null;
return MethodResult.empty();
}
case 2:
{
@@ -85,7 +89,7 @@ public class PrinterPeripheral implements IPeripheral
Terminal page = getCurrentPage();
int x = page.getCursorX();
int y = page.getCursorY();
return new Object[] { x + 1, y + 1 };
return MethodResult.of( x + 1, y + 1 );
}
case 3:
{
@@ -93,23 +97,23 @@ public class PrinterPeripheral implements IPeripheral
Terminal page = getCurrentPage();
int width = page.getWidth();
int height = page.getHeight();
return new Object[] { width, height };
return MethodResult.of( width, height );
}
case 4:
{
// newPage
return new Object[] { m_printer.startNewPage() };
return MethodResult.of( m_printer.startNewPage() );
}
case 5:
{
// endPage
getCurrentPage();
return new Object[] { m_printer.endCurrentPage() };
return MethodResult.of( m_printer.endCurrentPage() );
}
case 6:
{
// getInkLevel
return new Object[] { m_printer.getInkLevel() };
return MethodResult.of( m_printer.getInkLevel() );
}
case 7:
{
@@ -117,20 +121,28 @@ public class PrinterPeripheral implements IPeripheral
String title = optString( args, 0, "" );
getCurrentPage();
m_printer.setPageTitle( title );
return null;
return MethodResult.empty();
}
case 8:
{
// getPaperLevel
return new Object[] { m_printer.getPaperLevel() };
return MethodResult.of( m_printer.getPaperLevel() );
}
default:
{
return null;
return MethodResult.empty();
}
}
}
@Nullable
@Override
@Deprecated
public Object[] callMethod( @Nonnull IComputerAccess access, @Nonnull ILuaContext context, int method, @Nonnull Object[] arguments ) throws LuaException, InterruptedException
{
return callMethod( access, (ICallContext) context, method, arguments ).evaluate( context );
}
@Override
public boolean equals( IPeripheral other )
{

View File

@@ -190,10 +190,7 @@ public class TilePrinter extends TilePeripheralBase
@Override
public ItemStack getStackInSlot(int i)
{
synchronized( m_inventory )
{
return m_inventory.get( i );
}
return m_inventory.get( i );
}
@Nonnull

View File

@@ -7,9 +7,7 @@
package dan200.computercraft.shared.peripheral.speaker;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.api.lua.ILuaContext;
import dan200.computercraft.api.lua.ILuaTask;
import dan200.computercraft.api.lua.LuaException;
import dan200.computercraft.api.lua.*;
import dan200.computercraft.api.peripheral.IComputerAccess;
import dan200.computercraft.api.peripheral.IPeripheral;
import net.minecraft.util.ResourceLocation;
@@ -20,6 +18,7 @@ import net.minecraft.world.World;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.concurrent.atomic.AtomicInteger;
import static dan200.computercraft.core.apis.ArgumentHelper.getString;
import static dan200.computercraft.core.apis.ArgumentHelper.optReal;
@@ -28,13 +27,13 @@ public class SpeakerPeripheral implements IPeripheral {
private TileSpeaker m_speaker;
private long m_clock;
private long m_lastPlayTime;
private int m_notesThisTick;
private final AtomicInteger m_notesThisTick;
public SpeakerPeripheral()
{
m_clock = 0;
m_lastPlayTime = 0;
m_notesThisTick = 0;
m_notesThisTick = new AtomicInteger( );
}
SpeakerPeripheral(TileSpeaker speaker)
@@ -43,10 +42,10 @@ public class SpeakerPeripheral implements IPeripheral {
m_speaker = speaker;
}
public synchronized void update()
public void update()
{
m_clock++;
m_notesThisTick = 0;
m_notesThisTick.set( 0 );
}
public World getWorld()
@@ -59,9 +58,9 @@ public class SpeakerPeripheral implements IPeripheral {
return m_speaker.getPos();
}
public synchronized boolean madeSound(long ticks)
public boolean madeSound(long ticks)
{
return (m_clock - m_lastPlayTime <= ticks) ;
return m_clock - m_lastPlayTime <= ticks;
}
/* IPeripheral implementation */
@@ -97,21 +96,22 @@ public class SpeakerPeripheral implements IPeripheral {
};
}
@Nonnull
@Override
public Object[] callMethod( @Nonnull IComputerAccess computerAccess, @Nonnull ILuaContext context, int methodIndex, @Nonnull Object[] args ) throws LuaException
public MethodResult callMethod( @Nonnull IComputerAccess computer, @Nonnull ICallContext context, int methodIndex, @Nonnull Object[] args ) throws LuaException
{
switch( methodIndex )
{
// playSound
case 0:
{
return playSound(args, context, false);
return MethodResult.of( playSound( args, context, false ) );
}
// playNote
case 1:
{
return playNote(args, context);
return MethodResult.of( playNote( args, context ) );
}
default:
@@ -122,8 +122,16 @@ public class SpeakerPeripheral implements IPeripheral {
}
}
@Nonnull
private synchronized Object[] playNote( Object[] arguments, ILuaContext context ) throws LuaException
@Nullable
@Override
@Deprecated
public Object[] callMethod( @Nonnull IComputerAccess access, @Nonnull ILuaContext context, int method, @Nonnull Object[] arguments ) throws LuaException, InterruptedException
{
return callMethod( access, (ICallContext) context, method, arguments ).evaluate( context );
}
private synchronized boolean playNote( Object[] arguments, ICallContext context ) throws LuaException
{
String name = getString(arguments, 0);
float volume = (float) optReal( arguments, 1, 1.0 );
@@ -136,7 +144,7 @@ public class SpeakerPeripheral implements IPeripheral {
}
// If the resource location for note block notes changes, this method call will need to be updated
Object[] returnValue = playSound(
boolean success = playSound(
new Object[] {
"block.note." + name,
(double)Math.min( volume, 3f ),
@@ -144,16 +152,15 @@ public class SpeakerPeripheral implements IPeripheral {
}, context, true
);
if( returnValue[0] instanceof Boolean && (Boolean) returnValue[0] )
if( success )
{
m_notesThisTick++;
m_notesThisTick.incrementAndGet();
}
return returnValue;
return success;
}
@Nonnull
private synchronized Object[] playSound( Object[] arguments, ILuaContext context, boolean isNote ) throws LuaException
private synchronized boolean playSound( Object[] arguments, ICallContext context, boolean isNote ) throws LuaException
{
String name = getString(arguments, 0);
float volume = (float) optReal( arguments, 1, 1.0 );
@@ -161,7 +168,7 @@ public class SpeakerPeripheral implements IPeripheral {
ResourceLocation resourceName = new ResourceLocation( name );
if( m_clock - m_lastPlayTime >= TileSpeaker.MIN_TICKS_BETWEEN_SOUNDS || ( ( m_clock - m_lastPlayTime == 0 ) && ( m_notesThisTick < ComputerCraft.maxNotesPerTick ) && isNote ) )
if( m_clock - m_lastPlayTime >= TileSpeaker.MIN_TICKS_BETWEEN_SOUNDS || (isNote && m_clock - m_lastPlayTime == 0 && m_notesThisTick.get() < ComputerCraft.maxNotesPerTick) )
{
if( SoundEvent.REGISTRY.containsKey(resourceName) )
{
@@ -183,16 +190,16 @@ public class SpeakerPeripheral implements IPeripheral {
});
m_lastPlayTime = m_clock;
return new Object[]{true}; // Success, return true
return true; // Success, return true
}
else
{
return new Object[]{false}; // Failed - sound not existent, return false
return false; // Failed - sound not existent, return false
}
}
else
{
return new Object[]{false}; // Failed - rate limited, return false
return false; // Failed - rate limited, return false
}
}
}

View File

@@ -25,7 +25,7 @@ public class TileSpeaker extends TilePeripheralBase
}
@Override
public synchronized void update()
public void update()
{
m_peripheral.update();
}

View File

@@ -7,9 +7,7 @@
package dan200.computercraft.shared.pocket.apis;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.api.lua.ILuaAPI;
import dan200.computercraft.api.lua.ILuaContext;
import dan200.computercraft.api.lua.LuaException;
import dan200.computercraft.api.lua.*;
import dan200.computercraft.api.pocket.IPocketUpgrade;
import dan200.computercraft.shared.pocket.core.PocketServerComputer;
import dan200.computercraft.shared.util.InventoryUtil;
@@ -21,6 +19,7 @@ import net.minecraft.util.NonNullList;
import net.minecraftforge.items.wrapper.PlayerMainInvWrapper;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public class PocketAPI implements ILuaAPI
{
@@ -49,14 +48,15 @@ public class PocketAPI implements ILuaAPI
};
}
@Nonnull
@Override
public Object[] callMethod( @Nonnull ILuaContext context, int method, @Nonnull Object[] arguments ) throws LuaException, InterruptedException
public MethodResult callMethod( @Nonnull ICallContext context, int method, @Nonnull Object[] arguments ) throws LuaException
{
switch( method )
{
case 0:
// equipBack
return context.executeMainThreadTask( () ->
return MethodResult.onMainThread( () ->
{
if( !(m_computer.getEntity() instanceof EntityPlayer) )
{
@@ -94,12 +94,12 @@ public class PocketAPI implements ILuaAPI
// Set the new upgrade
m_computer.setUpgrade( newUpgrade );
return null;
return MethodResult.empty();
} );
case 1:
// unequipBack
return context.executeMainThreadTask( () ->
return MethodResult.onMainThread( () ->
{
if( !(m_computer.getEntity() instanceof EntityPlayer) )
{
@@ -125,13 +125,21 @@ public class PocketAPI implements ILuaAPI
}
}
return null;
return MethodResult.empty();
} );
default:
return null;
return MethodResult.empty();
}
}
@Override
@Nullable
@Deprecated
public Object[] callMethod( @Nonnull ILuaContext context, int method, @Nonnull Object[] arguments ) throws LuaException, InterruptedException
{
return callMethod( (ICallContext) context, method, arguments ).evaluate( context );
}
private static IPocketUpgrade findUpgrade( NonNullList<ItemStack> inv, int start, IPocketUpgrade previous )
{
for( int i = 0; i < inv.size(); i++ )

View File

@@ -8,6 +8,7 @@ import dan200.computercraft.shared.computer.core.ComputerFamily;
import dan200.computercraft.shared.computer.core.ServerComputer;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.entity.player.InventoryPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
@@ -138,7 +139,7 @@ public class PocketServerComputer extends ServerComputer implements IPocketAcces
{
if( this.m_upgrade == upgrade ) return;
synchronized (this)
synchronized( this )
{
ComputerCraft.Items.pocketComputer.setUpgrade( m_stack, upgrade );
if( m_entity instanceof EntityPlayer ) ((EntityPlayer) m_entity).inventory.markDirty();
@@ -156,6 +157,9 @@ public class PocketServerComputer extends ServerComputer implements IPocketAcces
setPosition( entity.getPosition() );
}
// If a new entity has picked it up then rebroadcast the terminal to them
if( entity != m_entity && entity instanceof EntityPlayerMP ) markTerminalChanged();
m_entity = entity;
m_stack = stack;
@@ -165,4 +169,19 @@ public class PocketServerComputer extends ServerComputer implements IPocketAcces
invalidatePeripheral();
}
}
public void broadcastState( boolean force )
{
super.broadcastState( force );
if( (hasTerminalChanged() || force) && m_entity instanceof EntityPlayerMP )
{
// Broadcast the state to the current entity if they're not already interacting with it.
EntityPlayerMP player = (EntityPlayerMP) m_entity;
if( player.connection != null && !isInteracting( player ) )
{
ComputerCraft.sendToPlayer( player, createTerminalPacket() );
}
}
}
}

View File

@@ -43,7 +43,7 @@ public class ItemPocketComputer extends Item implements IComputerItem, IMedia, I
{
setMaxStackSize( 1 );
setHasSubtypes( true );
setUnlocalizedName( "computercraft:pocket_computer" );
setTranslationKey( "computercraft:pocket_computer" );
setCreativeTab( ComputerCraft.mainCreativeTab );
}
@@ -189,7 +189,7 @@ public class ItemPocketComputer extends Item implements IComputerItem, IMedia, I
@Nonnull
@Override
public String getUnlocalizedName( @Nonnull ItemStack stack )
public String getTranslationKey( @Nonnull ItemStack stack )
{
switch( getFamily( stack ) )
{
@@ -209,7 +209,7 @@ public class ItemPocketComputer extends Item implements IComputerItem, IMedia, I
@Override
public String getItemStackDisplayName( @Nonnull ItemStack stack )
{
String baseString = getUnlocalizedName( stack );
String baseString = getTranslationKey( stack );
IPocketUpgrade upgrade = getUpgrade( stack );
if( upgrade != null )
{

View File

@@ -21,7 +21,6 @@ import dan200.computercraft.shared.turtle.items.ItemTurtleNormal;
import dan200.computercraft.shared.turtle.items.TurtleItemFactory;
import dan200.computercraft.shared.turtle.recipes.TurtleUpgradeRecipe;
import dan200.computercraft.shared.turtle.upgrades.*;
import dan200.computercraft.shared.util.IEntityDropConsumer;
import dan200.computercraft.shared.util.ImpostorRecipe;
import dan200.computercraft.shared.util.InventoryUtil;
import net.minecraft.block.Block;
@@ -33,33 +32,49 @@ import net.minecraft.item.ItemStack;
import net.minecraft.item.crafting.IRecipe;
import net.minecraft.util.NonNullList;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.RegistryEvent;
import net.minecraftforge.event.entity.EntityJoinWorldEvent;
import net.minecraftforge.event.entity.living.LivingDropsEvent;
import net.minecraftforge.event.world.BlockEvent;
import net.minecraftforge.fml.common.eventhandler.EventPriority;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.registry.EntityRegistry;
import net.minecraftforge.fml.common.registry.GameRegistry;
import net.minecraftforge.registries.IForgeRegistry;
import javax.annotation.Nonnull;
import java.util.*;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
public abstract class CCTurtleProxyCommon implements ICCTurtleProxy
{
{
private Map<Integer, ITurtleUpgrade> m_legacyTurtleUpgrades;
private Map<String, ITurtleUpgrade> m_turtleUpgrades;
private Map<Entity, IEntityDropConsumer> m_dropConsumers;
private Function<ItemStack, ItemStack> dropConsumer;
private List<ItemStack> remainingDrops;
private WeakReference<World> dropWorld;
private BlockPos dropPos;
private AxisAlignedBB dropBounds;
private WeakReference<Entity> dropEntity;
public CCTurtleProxyCommon()
{
m_legacyTurtleUpgrades = new HashMap<>();
m_turtleUpgrades = new HashMap<>();
m_dropConsumers = new WeakHashMap<>();
}
// ICCTurtleProxy implementation
@Override
@Override
public void preInit()
{
MinecraftForge.EVENT_BUS.register( this );
@@ -75,8 +90,8 @@ public abstract class CCTurtleProxyCommon implements ICCTurtleProxy
// RecipeSorter.register( "computercraft:turtle", TurtleRecipe.class, RecipeSorter.Category.SHAPED, "after:minecraft:shapeless" );
// RecipeSorter.register( "computercraft:turtle_upgrade", TurtleUpgradeRecipe.class, RecipeSorter.Category.SHAPED, "after:minecraft:shapeless" );
}
@Override
@Override
public void init()
{
registerForgeHandlers();
@@ -94,7 +109,7 @@ public abstract class CCTurtleProxyCommon implements ICCTurtleProxy
ComputerCraft.log.error( message );
throw new RuntimeException( message );
}
// Register
registerTurtleUpgradeInternal( upgrade );
}
@@ -110,7 +125,7 @@ public abstract class CCTurtleProxyCommon implements ICCTurtleProxy
{
return m_legacyTurtleUpgrades.get( legacyId );
}
@Override
public ITurtleUpgrade getTurtleUpgrade( @Nonnull ItemStack stack )
{
@@ -126,7 +141,7 @@ public abstract class CCTurtleProxyCommon implements ICCTurtleProxy
}
catch( Exception e )
{
ComputerCraft.log.error("Error getting computer upgrade item", e);
ComputerCraft.log.error( "Error getting computer upgrade item", e );
}
}
return null;
@@ -148,7 +163,7 @@ public abstract class CCTurtleProxyCommon implements ICCTurtleProxy
return true;
}
}
private void addAllUpgradedTurtles( ComputerFamily family, NonNullList<ItemStack> list )
{
ItemStack basicStack = TurtleItemFactory.create( -1, null, -1, family, null, null, 0, null );
@@ -169,7 +184,7 @@ public abstract class CCTurtleProxyCommon implements ICCTurtleProxy
private void addUpgradedTurtle( ComputerFamily family, ITurtleUpgrade upgrade, List<ItemStack> list )
{
if ( isUpgradeSuitableForFamily( family, upgrade ) )
if( isUpgradeSuitableForFamily( family, upgrade ) )
{
ItemStack stack = TurtleItemFactory.create( -1, null, -1, family, upgrade, null, 0, null );
if( !stack.isEmpty() )
@@ -178,54 +193,65 @@ public abstract class CCTurtleProxyCommon implements ICCTurtleProxy
}
}
}
@Override
public void addAllUpgradedTurtles( NonNullList<ItemStack> list )
{
addAllUpgradedTurtles( ComputerFamily.Normal, list );
addAllUpgradedTurtles( ComputerFamily.Advanced, list );
}
@Override
public void setEntityDropConsumer( Entity entity, IEntityDropConsumer consumer )
public void setDropConsumer( Entity entity, Function<ItemStack, ItemStack> consumer )
{
if( !m_dropConsumers.containsKey( entity ) )
{
boolean captured = entity.captureDrops;
if( !captured )
{
entity.captureDrops = true;
ArrayList<EntityItem> items = entity.capturedDrops;
if( items == null || items.size() == 0 )
{
m_dropConsumers.put( entity, consumer );
}
}
}
}
dropConsumer = consumer;
remainingDrops = new ArrayList<>();
dropEntity = new WeakReference<>( entity );
dropWorld = new WeakReference<>( entity.world );
dropPos = null;
dropBounds = new AxisAlignedBB( entity.getPosition() ).grow( 2, 2, 2 );
entity.captureDrops = true;
}
@Override
public void clearEntityDropConsumer( Entity entity )
public void setDropConsumer( World world, BlockPos pos, Function<ItemStack, ItemStack> consumer )
{
if( m_dropConsumers.containsKey( entity ) )
dropConsumer = consumer;
remainingDrops = new ArrayList<>();
dropEntity = null;
dropWorld = new WeakReference<>( world );
dropPos = pos;
dropBounds = new AxisAlignedBB( pos ).grow( 2, 2, 2 );
}
@Override
public List<ItemStack> clearDropConsumer()
{
if( dropEntity != null )
{
boolean captured = entity.captureDrops;
if( captured )
Entity entity = dropEntity.get();
if( entity != null )
{
entity.captureDrops = false;
ArrayList<EntityItem> items = entity.capturedDrops;
if( items != null )
if( entity.capturedDrops != null )
{
dispatchEntityDrops( entity, items );
items.clear();
for( EntityItem entityItem : entity.capturedDrops ) handleDrops( entityItem.getItem() );
entity.capturedDrops.clear();
}
}
m_dropConsumers.remove( entity );
}
List<ItemStack> remainingStacks = remainingDrops;
dropConsumer = null;
remainingDrops = null;
dropEntity = null;
dropWorld = null;
dropPos = null;
dropBounds = null;
return remainingStacks;
}
private void registerTurtleUpgradeInternal( ITurtleUpgrade upgrade )
@@ -289,7 +315,7 @@ public abstract class CCTurtleProxyCommon implements ICCTurtleProxy
{
IForgeRegistry<Item> registry = event.getRegistry();
registry.register( new ItemTurtleLegacy( ComputerCraft.Blocks.turtle).setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "turtle" ) ) );
registry.register( new ItemTurtleLegacy( ComputerCraft.Blocks.turtle ).setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "turtle" ) ) );
registry.register( new ItemTurtleNormal( ComputerCraft.Blocks.turtleExpanded ).setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "turtle_expanded" ) ) );
registry.register( new ItemTurtleAdvanced( ComputerCraft.Blocks.turtleAdvanced ).setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "turtle_advanced" ) ) );
}
@@ -362,7 +388,7 @@ public abstract class CCTurtleProxyCommon implements ICCTurtleProxy
private void registerUpgrades()
{
// Upgrades
ComputerCraft.Upgrades.wirelessModem = new TurtleModem( false, new ResourceLocation( "computercraft", "wireless_modem" ), 1 );
ComputerCraft.Upgrades.wirelessModem = new TurtleModem( false, new ResourceLocation( "computercraft", "wireless_modem" ), 1 );
registerTurtleUpgradeInternal( ComputerCraft.Upgrades.wirelessModem );
ComputerCraft.Upgrades.craftingTable = new TurtleCraftingTable( 2 );
@@ -396,10 +422,10 @@ public abstract class CCTurtleProxyCommon implements ICCTurtleProxy
// We have to use mappings.getAllMappings() as the mod ID is upper case but the domain lower.
for( RegistryEvent.MissingMappings.Mapping<Item> mapping : mappings.getAllMappings() )
{
String domain = mapping.key.getResourceDomain();
String domain = mapping.key.getNamespace();
if( !domain.equalsIgnoreCase( ComputerCraft.MOD_ID ) ) continue;
String key = mapping.key.getResourcePath();
String key = mapping.key.getPath();
if( key.equalsIgnoreCase( "CC-Turtle" ) )
{
mapping.remap( Item.getItemFromBlock( ComputerCraft.Blocks.turtle ) );
@@ -421,10 +447,10 @@ public abstract class CCTurtleProxyCommon implements ICCTurtleProxy
// We have to use mappings.getAllMappings() as the mod ID is upper case but the domain lower.
for( RegistryEvent.MissingMappings.Mapping<Block> mapping : mappings.getAllMappings() )
{
String domain = mapping.key.getResourceDomain();
String domain = mapping.key.getNamespace();
if( !domain.equalsIgnoreCase( ComputerCraft.MOD_ID ) ) continue;
String key = mapping.key.getResourcePath();
String key = mapping.key.getPath();
if( key.equalsIgnoreCase( "CC-Turtle" ) )
{
mapping.remap( ComputerCraft.Blocks.turtle );
@@ -447,26 +473,60 @@ public abstract class CCTurtleProxyCommon implements ICCTurtleProxy
GameRegistry.registerTileEntity( TileTurtleExpanded.class, ComputerCraft.LOWER_ID + " : " + "turtleex" );
GameRegistry.registerTileEntity( TileTurtleAdvanced.class, ComputerCraft.LOWER_ID + " : " + "turtleadv" );
}
private void registerForgeHandlers()
{
ForgeHandlers handlers = new ForgeHandlers();
MinecraftForge.EVENT_BUS.register( handlers );
}
public class ForgeHandlers
{
private ForgeHandlers()
{
}
// Forge event responses
@SubscribeEvent
private void handleDrops(ItemStack stack)
{
ItemStack remaining = dropConsumer.apply(stack);
if (!remaining.isEmpty()) remainingDrops.add(remaining);
}
private class ForgeHandlers
{
@SubscribeEvent(priority = EventPriority.LOWEST)
public void onEntityLivingDrops( LivingDropsEvent event )
{
dispatchEntityDrops( event.getEntity(), event.getDrops() );
// Capture any mob drops for the current entity
if( dropEntity != null && event.getEntity() == dropEntity.get() )
{
List<EntityItem> drops = event.getDrops();
for( EntityItem entityItem : drops ) handleDrops( entityItem.getItem() );
drops.clear();
}
}
@SubscribeEvent(priority = EventPriority.LOWEST)
public void onHarvestDrops( BlockEvent.HarvestDropsEvent event )
{
// Capture block drops for the current entity
if( dropWorld != null && dropWorld.get() == event.getWorld()
&& dropPos != null && dropPos.equals( event.getPos() ) )
{
for( ItemStack item : event.getDrops() )
{
if( event.getWorld().rand.nextFloat() < event.getDropChance() ) handleDrops( item );
}
event.getDrops().clear();
}
}
@SubscribeEvent(priority = EventPriority.LOWEST)
public void onEntitySpawn( EntityJoinWorldEvent event )
{
// Capture any nearby item spawns
if( dropWorld != null && dropWorld.get() == event.getWorld() && event.getEntity() instanceof EntityItem
&& dropBounds.contains( event.getEntity().getPositionVector() ) )
{
handleDrops( ((EntityItem) event.getEntity()).getItem() );
event.setCanceled( true );
}
}
@SubscribeEvent
public void onTurtleAction( TurtleActionEvent event) {
if( ComputerCraft.turtleDisabledActions.contains( event.getAction() ) )
@@ -475,18 +535,5 @@ public abstract class CCTurtleProxyCommon implements ICCTurtleProxy
}
}
}
private void dispatchEntityDrops( Entity entity, java.util.List<EntityItem> drops )
{
IEntityDropConsumer consumer = m_dropConsumers.get( entity );
if( consumer != null )
{
// All checks have passed, lets dispatch the drops
for(EntityItem entityItem : drops)
{
consumer.consumeDrop( entity, entityItem.getItem() );
}
drops.clear();
}
}
}

View File

@@ -24,6 +24,7 @@ import dan200.computercraft.shared.computer.core.*;
import dan200.computercraft.shared.computer.inventory.ContainerComputer;
import dan200.computercraft.shared.computer.items.ItemCommandComputer;
import dan200.computercraft.shared.computer.items.ItemComputer;
import dan200.computercraft.shared.integration.charset.IntegrationCharset;
import dan200.computercraft.shared.media.common.DefaultMediaProvider;
import dan200.computercraft.shared.media.inventory.ContainerHeldItem;
import dan200.computercraft.shared.media.items.ItemDiskExpanded;
@@ -76,6 +77,7 @@ import net.minecraftforge.event.RegistryEvent;
import net.minecraftforge.event.entity.player.PlayerContainerEvent;
import net.minecraftforge.event.world.WorldEvent;
import net.minecraftforge.fml.client.event.ConfigChangedEvent;
import net.minecraftforge.fml.common.Loader;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.gameevent.TickEvent;
import net.minecraftforge.fml.common.network.FMLNetworkEvent;
@@ -83,6 +85,7 @@ import net.minecraftforge.fml.common.network.IGuiHandler;
import net.minecraftforge.fml.common.network.NetworkRegistry;
import net.minecraftforge.fml.common.registry.GameRegistry;
import net.minecraftforge.registries.IForgeRegistry;
import pl.asie.charset.ModCharset;
import javax.annotation.Nonnull;
import java.io.File;
@@ -117,6 +120,8 @@ public abstract class ComputerCraftProxyCommon implements IComputerCraftProxy
{
registerTileEntities();
registerForgeHandlers();
if( Loader.isModLoaded( ModCharset.MODID ) ) IntegrationCharset.register();
}
@Override
@@ -414,10 +419,10 @@ public abstract class ComputerCraftProxyCommon implements IComputerCraftProxy
// We have to use mappings.getAllMappings() as the mod ID is upper case but the domain lower.
for( RegistryEvent.MissingMappings.Mapping<Item> mapping : mappings.getAllMappings() )
{
String domain = mapping.key.getResourceDomain();
String domain = mapping.key.getNamespace();
if( !domain.equalsIgnoreCase( ComputerCraft.MOD_ID ) ) continue;
String key = mapping.key.getResourcePath();
String key = mapping.key.getPath();
if( key.equalsIgnoreCase( "CC-Computer" ) )
{
mapping.remap( Item.getItemFromBlock( ComputerCraft.Blocks.computer ) );
@@ -451,10 +456,10 @@ public abstract class ComputerCraftProxyCommon implements IComputerCraftProxy
// We have to use mappings.getAllMappings() as the mod ID is upper case but the domain lower.
for( RegistryEvent.MissingMappings.Mapping<Block> mapping : mappings.getAllMappings() )
{
String domain = mapping.key.getResourceDomain();
String domain = mapping.key.getNamespace();
if( !domain.equalsIgnoreCase( ComputerCraft.MOD_ID ) ) continue;
String key = mapping.key.getResourcePath();
String key = mapping.key.getPath();
if( key.equalsIgnoreCase( "CC-Computer" ) )
{
mapping.remap( ComputerCraft.Blocks.computer );

View File

@@ -7,12 +7,16 @@
package dan200.computercraft.shared.proxy;
import dan200.computercraft.api.turtle.ITurtleUpgrade;
import dan200.computercraft.shared.util.IEntityDropConsumer;
import net.minecraft.entity.Entity;
import net.minecraft.item.ItemStack;
import net.minecraft.util.NonNullList;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import javax.annotation.Nonnull;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Function;
public interface ICCTurtleProxy
{
@@ -25,6 +29,7 @@ public interface ICCTurtleProxy
ITurtleUpgrade getTurtleUpgrade( @Nonnull ItemStack item );
void addAllUpgradedTurtles( NonNullList<ItemStack> list );
void setEntityDropConsumer( Entity entity, IEntityDropConsumer consumer );
void clearEntityDropConsumer( Entity entity );
void setDropConsumer( Entity entity, Function<ItemStack, ItemStack> consumer );
void setDropConsumer( World world, BlockPos pos, Function<ItemStack, ItemStack> consumer );
List<ItemStack> clearDropConsumer();
}

View File

@@ -6,9 +6,7 @@
package dan200.computercraft.shared.turtle.apis;
import dan200.computercraft.api.lua.ILuaAPI;
import dan200.computercraft.api.lua.ILuaContext;
import dan200.computercraft.api.lua.LuaException;
import dan200.computercraft.api.lua.*;
import dan200.computercraft.api.turtle.ITurtleAccess;
import dan200.computercraft.api.turtle.ITurtleCommand;
import dan200.computercraft.api.turtle.TurtleSide;
@@ -22,6 +20,7 @@ import net.minecraft.item.ItemStack;
import net.minecraftforge.common.MinecraftForge;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
@@ -99,9 +98,9 @@ public class TurtleAPI implements ILuaAPI
};
}
private Object[] tryCommand( ILuaContext context, ITurtleCommand command ) throws LuaException, InterruptedException
private MethodResult tryCommand( ITurtleCommand command ) throws LuaException
{
return m_turtle.executeCommand( context, command );
return m_turtle.executeCommand( command );
}
private int parseSlotNumber( Object[] arguments, int index ) throws LuaException
@@ -155,7 +154,8 @@ public class TurtleAPI implements ILuaAPI
}
@Override
public Object[] callMethod( @Nonnull ILuaContext context, int method, @Nonnull Object[] args ) throws LuaException, InterruptedException
@Nonnull
public MethodResult callMethod( @Nonnull ICallContext context, int method, @Nonnull Object[] args ) throws LuaException
{
switch( method )
{
@@ -163,89 +163,89 @@ public class TurtleAPI implements ILuaAPI
{
// forward
m_environment.addTrackingChange( TrackingField.TURTLE_OPS );
return tryCommand( context, new TurtleMoveCommand( MoveDirection.Forward ) );
return tryCommand( new TurtleMoveCommand( MoveDirection.Forward ) );
}
case 1:
{
// back
m_environment.addTrackingChange( TrackingField.TURTLE_OPS );
return tryCommand( context, new TurtleMoveCommand( MoveDirection.Back ) );
return tryCommand( new TurtleMoveCommand( MoveDirection.Back ) );
}
case 2:
{
// up
m_environment.addTrackingChange( TrackingField.TURTLE_OPS );
return tryCommand( context, new TurtleMoveCommand( MoveDirection.Up ) );
return tryCommand( new TurtleMoveCommand( MoveDirection.Up ) );
}
case 3:
{
// down
m_environment.addTrackingChange( TrackingField.TURTLE_OPS );
return tryCommand( context, new TurtleMoveCommand( MoveDirection.Down ) );
return tryCommand( new TurtleMoveCommand( MoveDirection.Down ) );
}
case 4:
{
// turnLeft
m_environment.addTrackingChange( TrackingField.TURTLE_OPS );
return tryCommand( context, new TurtleTurnCommand( TurnDirection.Left ) );
return tryCommand( new TurtleTurnCommand( TurnDirection.Left ) );
}
case 5:
{
// turnRight
m_environment.addTrackingChange( TrackingField.TURTLE_OPS );
return tryCommand( context, new TurtleTurnCommand( TurnDirection.Right ) );
return tryCommand( new TurtleTurnCommand( TurnDirection.Right ) );
}
case 6:
{
// dig
Optional<TurtleSide> side = parseSide( args, 0 );
m_environment.addTrackingChange( TrackingField.TURTLE_OPS );
return tryCommand( context, new TurtleDigCommand( InteractDirection.Forward, side ) );
return tryCommand( new TurtleDigCommand( InteractDirection.Forward, side ) );
}
case 7:
{
// digUp
Optional<TurtleSide> side = parseSide( args, 0 );
m_environment.addTrackingChange( TrackingField.TURTLE_OPS );
return tryCommand( context, new TurtleDigCommand( InteractDirection.Up, side ) );
return tryCommand( new TurtleDigCommand( InteractDirection.Up, side ) );
}
case 8:
{
// digDown
Optional<TurtleSide> side = parseSide( args, 0 );
m_environment.addTrackingChange( TrackingField.TURTLE_OPS );
return tryCommand( context, new TurtleDigCommand( InteractDirection.Down, side ) );
return tryCommand( new TurtleDigCommand( InteractDirection.Down, side ) );
}
case 9:
{
// place
m_environment.addTrackingChange( TrackingField.TURTLE_OPS );
return tryCommand( context, new TurtlePlaceCommand( InteractDirection.Forward, args ) );
return tryCommand( new TurtlePlaceCommand( InteractDirection.Forward, args ) );
}
case 10:
{
// placeUp
m_environment.addTrackingChange( TrackingField.TURTLE_OPS );
return tryCommand( context, new TurtlePlaceCommand( InteractDirection.Up, args ) );
return tryCommand( new TurtlePlaceCommand( InteractDirection.Up, args ) );
}
case 11:
{
// placeDown
m_environment.addTrackingChange( TrackingField.TURTLE_OPS );
return tryCommand( context, new TurtlePlaceCommand( InteractDirection.Down, args ) );
return tryCommand( new TurtlePlaceCommand( InteractDirection.Down, args ) );
}
case 12:
{
// drop
int count = parseCount( args, 0 );
m_environment.addTrackingChange( TrackingField.TURTLE_OPS );
return tryCommand( context, new TurtleDropCommand( InteractDirection.Forward, count ) );
return tryCommand( new TurtleDropCommand( InteractDirection.Forward, count ) );
}
case 13:
{
// select
int slot = parseSlotNumber( args, 0 );
return tryCommand( context, new TurtleSelectCommand( slot ) );
return tryCommand( new TurtleSelectCommand( slot ) );
}
case 14:
{
@@ -254,11 +254,11 @@ public class TurtleAPI implements ILuaAPI
ItemStack stack = m_turtle.getInventory().getStackInSlot( slot );
if( !stack.isEmpty() )
{
return new Object[] { stack.getCount() };
return MethodResult.of( stack.getCount() );
}
else
{
return new Object[] { 0 };
return MethodResult.of( 0 );
}
}
case 15:
@@ -268,172 +268,172 @@ public class TurtleAPI implements ILuaAPI
ItemStack stack = m_turtle.getInventory().getStackInSlot( slot );
if( !stack.isEmpty() )
{
return new Object[] {
return MethodResult.of(
Math.min( stack.getMaxStackSize(), 64 ) - stack.getCount()
};
);
}
return new Object[] { 64 };
return MethodResult.of( 64 );
}
case 16:
{
// detect
return tryCommand( context, new TurtleDetectCommand( InteractDirection.Forward ) );
return tryCommand( new TurtleDetectCommand( InteractDirection.Forward ) );
}
case 17:
{
// detectUp
return tryCommand( context, new TurtleDetectCommand( InteractDirection.Up ) );
return tryCommand( new TurtleDetectCommand( InteractDirection.Up ) );
}
case 18:
{
// detectDown
return tryCommand( context, new TurtleDetectCommand( InteractDirection.Down ) );
return tryCommand( new TurtleDetectCommand( InteractDirection.Down ) );
}
case 19:
{
// compare
return tryCommand( context, new TurtleCompareCommand( InteractDirection.Forward ) );
return tryCommand( new TurtleCompareCommand( InteractDirection.Forward ) );
}
case 20:
{
// compareUp
return tryCommand( context, new TurtleCompareCommand( InteractDirection.Up ) );
return tryCommand( new TurtleCompareCommand( InteractDirection.Up ) );
}
case 21:
{
// compareDown
return tryCommand( context, new TurtleCompareCommand( InteractDirection.Down ) );
return tryCommand( new TurtleCompareCommand( InteractDirection.Down ) );
}
case 22:
{
// attack
Optional<TurtleSide> side = parseSide( args, 0 );
m_environment.addTrackingChange( TrackingField.TURTLE_OPS );
return tryCommand( context, new TurtleAttackCommand( InteractDirection.Forward, side ) );
return tryCommand( new TurtleAttackCommand( InteractDirection.Forward, side ) );
}
case 23:
{
// attackUp
Optional<TurtleSide> side = parseSide( args, 0 );
m_environment.addTrackingChange( TrackingField.TURTLE_OPS );
return tryCommand( context, new TurtleAttackCommand( InteractDirection.Up, side ) );
return tryCommand( new TurtleAttackCommand( InteractDirection.Up, side ) );
}
case 24:
{
// attackDown
Optional<TurtleSide> side = parseSide( args, 0 );
m_environment.addTrackingChange( TrackingField.TURTLE_OPS );
return tryCommand( context, new TurtleAttackCommand( InteractDirection.Down, side ) );
return tryCommand( new TurtleAttackCommand( InteractDirection.Down, side ) );
}
case 25:
{
// dropUp
int count = parseCount( args, 0 );
m_environment.addTrackingChange( TrackingField.TURTLE_OPS );
return tryCommand( context, new TurtleDropCommand( InteractDirection.Up, count ) );
return tryCommand( new TurtleDropCommand( InteractDirection.Up, count ) );
}
case 26:
{
// dropDown
int count = parseCount( args, 0 );
m_environment.addTrackingChange( TrackingField.TURTLE_OPS );
return tryCommand( context, new TurtleDropCommand( InteractDirection.Down, count ) );
return tryCommand( new TurtleDropCommand( InteractDirection.Down, count ) );
}
case 27:
{
// suck
int count = parseCount( args, 0 );
m_environment.addTrackingChange( TrackingField.TURTLE_OPS );
return tryCommand( context, new TurtleSuckCommand( InteractDirection.Forward, count ) );
return tryCommand( new TurtleSuckCommand( InteractDirection.Forward, count ) );
}
case 28:
{
// suckUp
int count = parseCount( args, 0 );
m_environment.addTrackingChange( TrackingField.TURTLE_OPS );
return tryCommand( context, new TurtleSuckCommand( InteractDirection.Up, count ) );
return tryCommand( new TurtleSuckCommand( InteractDirection.Up, count ) );
}
case 29:
{
// suckDown
int count = parseCount( args, 0 );
m_environment.addTrackingChange( TrackingField.TURTLE_OPS );
return tryCommand( context, new TurtleSuckCommand( InteractDirection.Down, count ) );
return tryCommand( new TurtleSuckCommand( InteractDirection.Down, count ) );
}
case 30:
{
// getFuelLevel
if( m_turtle.isFuelNeeded() )
{
return new Object[] { m_turtle.getFuelLevel() };
return MethodResult.of( m_turtle.getFuelLevel() );
}
else
{
return new Object[] { "unlimited" };
return MethodResult.of( "unlimited" );
}
}
case 31:
{
// refuel
int count = parseCount( args, 0 );
return tryCommand( context, new TurtleRefuelCommand( count ) );
return tryCommand( new TurtleRefuelCommand( count ) );
}
case 32:
{
// compareTo
int slot = parseSlotNumber( args, 0 );
return tryCommand( context, new TurtleCompareToCommand( slot ) );
return tryCommand( new TurtleCompareToCommand( slot ) );
}
case 33:
{
// transferTo
int slot = parseSlotNumber( args, 0 );
int count = parseCount( args, 1 );
return tryCommand( context, new TurtleTransferToCommand( slot, count ) );
return tryCommand( new TurtleTransferToCommand( slot, count ) );
}
case 34:
{
// getSelectedSlot
return new Object[] { m_turtle.getSelectedSlot() + 1 };
return MethodResult.of( m_turtle.getSelectedSlot() + 1 );
}
case 35:
{
// getFuelLimit
if( m_turtle.isFuelNeeded() )
{
return new Object[] { m_turtle.getFuelLimit() };
return MethodResult.of( m_turtle.getFuelLimit() );
}
else
{
return new Object[] { "unlimited" };
return MethodResult.of( "unlimited" );
}
}
case 36:
{
// equipLeft
m_environment.addTrackingChange( TrackingField.TURTLE_OPS );
return tryCommand( context, new TurtleEquipCommand( TurtleSide.Left ) );
return tryCommand( new TurtleEquipCommand( TurtleSide.Left ) );
}
case 37:
{
// equipRight
m_environment.addTrackingChange( TrackingField.TURTLE_OPS );
return tryCommand( context, new TurtleEquipCommand( TurtleSide.Right ) );
return tryCommand( new TurtleEquipCommand( TurtleSide.Right ) );
}
case 38:
{
// inspect
return tryCommand( context, new TurtleInspectCommand( InteractDirection.Forward ) );
return tryCommand( new TurtleInspectCommand( InteractDirection.Forward ) );
}
case 39:
{
// inspectUp
return tryCommand( context, new TurtleInspectCommand( InteractDirection.Up ) );
return tryCommand( new TurtleInspectCommand( InteractDirection.Up ) );
}
case 40:
{
// inspectDown
return tryCommand( context, new TurtleInspectCommand( InteractDirection.Down ) );
return tryCommand( new TurtleInspectCommand( InteractDirection.Down ) );
}
case 41:
{
@@ -455,20 +455,28 @@ public class TurtleAPI implements ILuaAPI
TurtleActionEvent event = new TurtleActionEvent( m_turtle, TurtleAction.INSPECT_ITEM );
if( MinecraftForge.EVENT_BUS.post( event ) )
{
return new Object[] { false, event.getFailureMessage() };
return MethodResult.of( false, event.getFailureMessage() );
}
return new Object[] { table };
return MethodResult.of( table );
}
else
{
return new Object[] { null };
return MethodResult.of( new Object[] { null } );
}
}
default:
{
return null;
return MethodResult.empty();
}
}
}
@Override
@Nullable
@Deprecated
public Object[] callMethod( @Nonnull ILuaContext context, int method, @Nonnull Object[] arguments ) throws LuaException, InterruptedException
{
return callMethod( (ICallContext) context, method, arguments ).evaluate( context );
}
}

View File

@@ -48,7 +48,7 @@ public class BlockTurtle extends BlockComputerBase
{
super( Material.IRON );
setHardness( 2.5f );
setUnlocalizedName( "computercraft:turtle" );
setTranslationKey( "computercraft:turtle" );
setCreativeTab( ComputerCraft.mainCreativeTab );
setDefaultState( this.blockState.getBaseState()
.withProperty( Properties.FACING, EnumFacing.NORTH )

View File

@@ -10,7 +10,9 @@ import com.google.common.base.Objects;
import com.mojang.authlib.GameProfile;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.api.lua.ILuaContext;
import dan200.computercraft.api.lua.ILuaFunction;
import dan200.computercraft.api.lua.LuaException;
import dan200.computercraft.api.lua.MethodResult;
import dan200.computercraft.api.peripheral.IPeripheral;
import dan200.computercraft.api.turtle.*;
import dan200.computercraft.shared.computer.blocks.ComputerProxy;
@@ -127,6 +129,8 @@ public class TurtleBrain implements ITurtleAccess
private TurtleAnimation m_animation;
private int m_animationProgress;
private int m_lastAnimationProgress;
TurtlePlayer m_cachedPlayer;
public TurtleBrain( TileTurtle turtle )
{
@@ -224,7 +228,7 @@ public class TurtleBrain implements ITurtleAccess
public void readFromNBT( NBTTagCompound nbttagcompound )
{
// Read state
m_direction = EnumFacing.getFront( nbttagcompound.getInteger( "dir" ) );
m_direction = EnumFacing.byIndex( nbttagcompound.getInteger( "dir" ) );
m_selectedSlot = nbttagcompound.getInteger( "selectedSlot" );
if( nbttagcompound.hasKey( "fuelLevel" ) )
{
@@ -368,8 +372,8 @@ public class TurtleBrain implements ITurtleAccess
// Write overlay
if( m_overlay != null )
{
nbttagcompound.setString( "overlay_mod", m_overlay.getResourceDomain() );
nbttagcompound.setString( "overlay_path", m_overlay.getResourcePath() );
nbttagcompound.setString( "overlay_mod", m_overlay.getNamespace() );
nbttagcompound.setString( "overlay_path", m_overlay.getPath() );
}
// Write NBT
@@ -427,8 +431,8 @@ public class TurtleBrain implements ITurtleAccess
// Overlay
if( m_overlay != null )
{
nbttagcompound.setString( "overlay_mod", m_overlay.getResourceDomain() );
nbttagcompound.setString( "overlay_path", m_overlay.getResourcePath() );
nbttagcompound.setString( "overlay_mod", m_overlay.getNamespace() );
nbttagcompound.setString( "overlay_path", m_overlay.getPath() );
}
// Animation
@@ -503,7 +507,7 @@ public class TurtleBrain implements ITurtleAccess
m_lastAnimationProgress = 0;
}
m_direction = EnumFacing.getFront( nbttagcompound.getInteger( "direction" ) );
m_direction = EnumFacing.byIndex( nbttagcompound.getInteger( "direction" ) );
m_fuelLevel = nbttagcompound.getInteger( "fuelLevel" );
}
@@ -759,6 +763,7 @@ public class TurtleBrain implements ITurtleAccess
@Nonnull
@Override
@Deprecated
public Object[] executeCommand( @Nonnull ILuaContext context, @Nonnull ITurtleCommand command ) throws LuaException, InterruptedException
{
if( getWorld().isRemote )
@@ -785,6 +790,38 @@ public class TurtleBrain implements ITurtleAccess
}
}
@Nonnull
@Override
public MethodResult executeCommand( @Nonnull ITurtleCommand command )
{
if( getWorld().isRemote )
{
throw new UnsupportedOperationException();
}
// Issue command
int commandID = issueCommand( command );
// Wait for response
return MethodResult.pullEvent( "turtle_response", new ILuaFunction()
{
@Nonnull
@Override
public MethodResult call( Object[] response )
{
if( response.length >= 3 && response[ 1 ] instanceof Number && ((Number) response[ 1 ]).intValue() == commandID
&& response[ 2 ] instanceof Boolean )
{
Object[] returnValues = new Object[ response.length - 2 ];
System.arraycopy( response, 2, returnValues, 0, returnValues.length );
return MethodResult.of( returnValues );
}
return MethodResult.pullEvent( "turtle_response", this );
}
} );
}
@Override
public void playAnimation( @Nonnull TurtleAnimation animation )
{
@@ -996,9 +1033,9 @@ public class TurtleBrain implements ITurtleAccess
double distance = -1.0 + getAnimationFraction( f );
return new Vec3d(
distance * dir.getFrontOffsetX(),
distance * dir.getFrontOffsetY(),
distance * dir.getFrontOffsetZ()
distance * dir.getXOffset(),
distance * dir.getYOffset(),
distance * dir.getZOffset()
);
}
default:
@@ -1182,31 +1219,31 @@ public class TurtleBrain implements ITurtleAccess
float pushFrac = 1.0f - ((float)(m_animationProgress + 1) / (float)ANIM_DURATION);
float push = Math.max( pushFrac + 0.0125f, 0.0f );
if (moveDir.getFrontOffsetX() < 0)
if (moveDir.getXOffset() < 0)
{
minX += moveDir.getFrontOffsetX() * push;
minX += moveDir.getXOffset() * push;
}
else
{
maxX -= moveDir.getFrontOffsetX() * push;
maxX -= moveDir.getXOffset() * push;
}
if (moveDir.getFrontOffsetY() < 0)
if (moveDir.getYOffset() < 0)
{
minY += moveDir.getFrontOffsetY() * push;
minY += moveDir.getYOffset() * push;
}
else
{
maxY -= moveDir.getFrontOffsetY() * push;
maxY -= moveDir.getYOffset() * push;
}
if (moveDir.getFrontOffsetZ() < 0)
if (moveDir.getZOffset() < 0)
{
minZ += moveDir.getFrontOffsetZ() * push;
minZ += moveDir.getZOffset() * push;
}
else
{
maxZ -= moveDir.getFrontOffsetZ() * push;
maxZ -= moveDir.getZOffset() * push;
}
AxisAlignedBB aabb = new AxisAlignedBB( minX, minY, minZ, maxX, maxY, maxZ );
@@ -1214,9 +1251,9 @@ public class TurtleBrain implements ITurtleAccess
if( !list.isEmpty() )
{
double pushStep = 1.0f / ANIM_DURATION;
double pushStepX = moveDir.getFrontOffsetX() * pushStep;
double pushStepY = moveDir.getFrontOffsetY() * pushStep;
double pushStepZ = moveDir.getFrontOffsetZ() * pushStep;
double pushStepX = moveDir.getXOffset() * pushStep;
double pushStepY = moveDir.getYOffset() * pushStep;
double pushStepZ = moveDir.getZOffset() * pushStep;
for (Entity entity : list)
{
entity.move( MoverType.PISTON, pushStepX, pushStepY, pushStepZ );

View File

@@ -126,7 +126,7 @@ public class TurtleCompareCommand implements ITurtleCommand
{
return TurtleCommandResult.success();
}
else if( selectedStack.getUnlocalizedName().equals( lookAtStack.getUnlocalizedName() ) )
else if( selectedStack.getTranslationKey().equals( lookAtStack.getTranslationKey() ) )
{
return TurtleCommandResult.success();
}

View File

@@ -87,9 +87,9 @@ public class TurtleMoveCommand implements ITurtleCommand
if( entityBB != null )
{
AxisAlignedBB pushedBB = entityBB.offset(
direction.getFrontOffsetX(),
direction.getFrontOffsetY(),
direction.getFrontOffsetZ()
direction.getXOffset(),
direction.getYOffset(),
direction.getZOffset()
);
if( !oldWorld.getCollisionBoxes( null, pushedBB ).isEmpty() )
{

View File

@@ -30,7 +30,6 @@ import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
import net.minecraft.util.text.TextComponentString;
import net.minecraft.world.World;
import net.minecraft.world.WorldServer;
import net.minecraftforge.common.ForgeHooks;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.entity.player.PlayerInteractEvent;
@@ -38,6 +37,7 @@ import net.minecraftforge.fml.common.eventhandler.Event;
import org.apache.commons.lang3.tuple.Pair;
import javax.annotation.Nonnull;
import java.util.List;
public class TurtlePlaceCommand implements ITurtleCommand
{
@@ -180,12 +180,12 @@ public class TurtlePlaceCommand implements ITurtleCommand
public static TurtlePlayer createPlayer( ITurtleAccess turtle, BlockPos position, EnumFacing direction )
{
TurtlePlayer turtlePlayer = new TurtlePlayer( turtle );
TurtlePlayer turtlePlayer = TurtlePlayer.get( turtle );
orientPlayer( turtle, turtlePlayer, position, direction );
return turtlePlayer;
}
public static void orientPlayer( ITurtleAccess turtle, TurtlePlayer turtlePlayer, BlockPos position, EnumFacing direction )
private static void orientPlayer( ITurtleAccess turtle, TurtlePlayer turtlePlayer, BlockPos position, EnumFacing direction )
{
turtlePlayer.posX = position.getX() + 0.5;
turtlePlayer.posY = position.getY() + 0.5;
@@ -194,9 +194,9 @@ public class TurtlePlaceCommand implements ITurtleCommand
// Stop intersection with the turtle itself
if( turtle.getPosition().equals( position ) )
{
turtlePlayer.posX += 0.48 * direction.getFrontOffsetX();
turtlePlayer.posY += 0.48 * direction.getFrontOffsetY();
turtlePlayer.posZ += 0.48 * direction.getFrontOffsetZ();
turtlePlayer.posX += 0.48 * direction.getXOffset();
turtlePlayer.posY += 0.48 * direction.getYOffset();
turtlePlayer.posZ += 0.48 * direction.getZOffset();
}
if( direction.getAxis() != EnumFacing.Axis.Y )
@@ -241,14 +241,10 @@ public class TurtlePlaceCommand implements ITurtleCommand
// Start claiming entity drops
Entity hitEntity = hit.getKey();
Vec3d hitPos = hit.getValue();
ComputerCraft.setEntityDropConsumer( hitEntity, ( entity, drop ) ->
{
ItemStack remainder = InventoryUtil.storeItems( drop, turtle.getItemHandler(), turtle.getSelectedSlot() );
if( !remainder.isEmpty() )
{
WorldUtil.dropItemStack( remainder, world, position, turtle.getDirection().getOpposite() );
}
} );
ComputerCraft.setDropConsumer(
hitEntity,
drop -> InventoryUtil.storeItems( drop, turtle.getItemHandler(), turtle.getSelectedSlot() )
);
// Place on the entity
boolean placed = false;
@@ -285,7 +281,11 @@ public class TurtlePlaceCommand implements ITurtleCommand
}
// Stop claiming drops
ComputerCraft.clearEntityDropConsumer( hitEntity );
List<ItemStack> remainingDrops = ComputerCraft.clearDropConsumer();
for( ItemStack remaining : remainingDrops )
{
WorldUtil.dropItemStack( remaining, world, position, turtle.getDirection().getOpposite() );
}
// Put everything we collected into the turtles inventory, then return
ItemStack remainder = turtlePlayer.unloadInventory( turtle );
@@ -367,9 +367,9 @@ public class TurtlePlaceCommand implements ITurtleCommand
orientPlayer( turtle, turtlePlayer, playerPosition, playerDir );
// Calculate where the turtle would hit the block
float hitX = 0.5f + side.getFrontOffsetX() * 0.5f;
float hitY = 0.5f + side.getFrontOffsetY() * 0.5f;
float hitZ = 0.5f + side.getFrontOffsetZ() * 0.5f;
float hitX = 0.5f + side.getXOffset() * 0.5f;
float hitY = 0.5f + side.getYOffset() * 0.5f;
float hitZ = 0.5f + side.getZOffset() * 0.5f;
if( Math.abs( hitY - 0.5f ) < 0.01f )
{
hitY = 0.45f;
@@ -382,7 +382,7 @@ public class TurtlePlaceCommand implements ITurtleCommand
// Do the deploying (put everything in the players inventory)
boolean placed = false;
TileEntity existingTile = turtle.getWorld().getTileEntity( position );
// See PlayerInteractionManager.processRightClickBlock
PlayerInteractEvent.RightClickBlock event = ForgeHooks.onRightClickBlock( turtlePlayer, EnumHand.MAIN_HAND, position, side, new Vec3d( hitX, hitY, hitZ ) );
@@ -426,12 +426,11 @@ public class TurtlePlaceCommand implements ITurtleCommand
{
World world = turtle.getWorld();
TileEntity tile = world.getTileEntity( position );
if( tile == null )
if( tile == null || tile == existingTile )
{
BlockPos newPosition = WorldUtil.moveCoords( position, side );
tile = world.getTileEntity( newPosition );
tile = world.getTileEntity( WorldUtil.moveCoords( position, side ) );
}
if( tile != null && tile instanceof TileEntitySign )
if( tile instanceof TileEntitySign )
{
TileEntitySign signTile = (TileEntitySign) tile;
String s = (String)extraArguments[0];

View File

@@ -36,16 +36,31 @@ public class TurtlePlayer extends FakePlayer
"[ComputerCraft]"
);
/**
* Construct a TurtlePlayer which exists in the world
*
* @param world The world the player exists in
* @deprecated This is required by {@link Entity}.
*/
@Deprecated
public TurtlePlayer( World world )
{
super( (WorldServer) world, DEFAULT_PROFILE );
}
public TurtlePlayer( ITurtleAccess turtle )
{
super( (WorldServer) turtle.getWorld(), getProfile( turtle.getOwningPlayer() ));
private TurtlePlayer( ITurtleAccess turtle )
{
super( (WorldServer) turtle.getWorld(), getProfile( turtle.getOwningPlayer() ) );
setState( turtle );
}
private static GameProfile getProfile( @Nullable GameProfile profile )
{
return profile != null && profile.isComplete() ? profile : DEFAULT_PROFILE;
}
private void setState( ITurtleAccess turtle )
{
BlockPos position = turtle.getPosition();
posX = position.getX() + 0.5;
posY = position.getY() + 0.5;
@@ -53,11 +68,27 @@ public class TurtlePlayer extends FakePlayer
rotationYaw = turtle.getDirection().getHorizontalAngle();
rotationPitch = 0.0f;
inventory.clear();
}
private static GameProfile getProfile( @Nullable GameProfile profile )
public static TurtlePlayer get( ITurtleAccess access )
{
return profile != null && profile.isComplete() ? profile : DEFAULT_PROFILE;
if( !(access instanceof TurtleBrain) ) return new TurtlePlayer( access );
TurtleBrain brain = (TurtleBrain) access;
TurtlePlayer player = brain.m_cachedPlayer;
if( player == null || player.getGameProfile() != getProfile( access.getOwningPlayer() )
|| player.getEntityWorld() != access.getWorld() )
{
player = brain.m_cachedPlayer = new TurtlePlayer( brain );
}
else
{
player.setState( access );
}
return player;
}
public void loadInventory( @Nonnull ItemStack currentStack )
@@ -76,7 +107,7 @@ public class TurtlePlayer extends FakePlayer
// Store (or drop) anything else we found
BlockPos dropPosition = turtle.getPosition();
EnumFacing dropDirection = turtle.getDirection().getOpposite();
for( int i=0; i<inventory.getSizeInventory(); ++i )
for( int i = 0; i < inventory.getSizeInventory(); ++i )
{
ItemStack stack = inventory.getStackInSlot( i );
if( !stack.isEmpty() )

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