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

Compare commits

...

85 Commits

Author SHA1 Message Date
SquidDev
0f3c44c926 Merge branch 'master' into mc-1.13.x 2019-06-08 08:21:08 +01:00
SquidDev
a0e7c4a74c Add a little bit of source code checking to Gradle
- Adds a CheckStyle configuration which is pretty similar to CC's
   existing one.
 - Add the Gradle license plugin.
 - Ensure the existing source code is compatible with these additional
   checks.

See #239
2019-06-08 00:28:03 +01:00
Lignum
7d428030df Fix some warnings (#235)
Remove some unused code and fix a bunch of warnings
2019-06-07 14:35:17 +01:00
JakobDev
00c395f689 Add Check to delete.lua (#236) 2019-06-06 16:43:48 +01:00
SquidDev
d8e1c73d26 Ensure files cannot be closed multiple times
Also fix an NPE if we try to close them twice.

Fixes #230
2019-06-04 21:34:19 +01:00
SquidDev
ffa4cc241b Add a test utility for capturing program output
- Make mcfly's stubbing system a little more fault-tolerant.
 - Add a small utility function which redirects print, printError and
   write to capture their output, rather than printing to the terminal.
   This can then be matched against in order to determine a program's
   output.
   It's a little flakey - you can't use it multiple times in an it
   block, etc... but it's a nice feature.
 - Add a small couple of tests to delete as a proof-of-concept.
2019-06-03 20:33:09 +01:00
SquidDev
6f1b740c8f Un-localise paths in mount error messages
This is probably a little more complex than it needs to be, as we try to
handle the mounts as well (which generally don't error).

Fixes #229
2019-06-03 19:58:16 +01:00
SquidDev
3406ba3ebf Fix a build from a clean state failing 2019-06-02 18:48:36 +01:00
SquidDev
b6715bd812 Fix a couple of build failures 2019-06-02 18:36:34 +01:00
SquidDev
18aee02221 Mark CurseForge builds as release
They're almost definitely not, but I've had no bug reports so they must
work!
2019-06-02 17:28:13 +01:00
SquidDev
401bbf2e6a Fix turtle block placing failing 2019-06-02 17:25:49 +01:00
SquidDev
7467b7f88a Fix several deprecated warnings 2019-06-02 17:23:33 +01:00
SquidDev
c82d8a7c2a Merge branch 'master' into mc-1.13.x 2019-06-02 16:46:45 +01:00
SquidDev
6b81bcf334 Bump version 2019-06-02 16:20:15 +01:00
SquidDev
3d67421d98 Bump Forge version 2019-06-02 16:18:44 +01:00
SquidDev
acac70675d Add link to CF on the README
Not sure how useful this is - people are far more likely to come across
the CurseForge page than the GH one, but there's no harm I guess.

Closes #227
2019-06-01 15:15:39 +01:00
JakobDev
56434259c1 Add Checks for Turtle and Pocket programs (#226)
Error if turtle and pocket computers programs are not run on
their respective devices.
2019-06-01 12:48:33 +01:00
JakobDev
da7e4b9016 Add more MOTD messages. (#225) 2019-06-01 12:41:01 +01:00
SquidDev
d4b8650d21 Use select('#', ...) instead of ipairs on varargs
This means we don't discard any value after nil, meaning that
calls such as colors.combine(nil, 1, 2, 3) will error, rather
than returning 0.
2019-06-01 10:12:10 +01:00
SquidDev
17645a79f0 Fix type check on rednet.lookup
Fixes #224
2019-06-01 09:23:18 +01:00
SquidDev
ce1f14a010 Fix a couple of problems in the release buildscript
Otherwise that went pretty smoothly!
2019-05-31 13:56:48 +01:00
SquidDev
43050426de Bump version
First time using the new changelog tooling, let's see how this goes.
2019-05-31 13:53:15 +01:00
SquidDev
b05f60c98b Add small task to verify changelog is correct
Also use the changelog contents as the GH release notes
2019-05-31 10:19:24 +01:00
SquidDev
c44c560f96 Update changelog and whatsnew
- Convert existing changelog over to use Markdown. This mostly involves
   wrapping code in backticks, and marking things as headers where
   appropriate.
 - Copy all of CC:T's release notes over to the changelog. This is
   somewhat more verbose than Dan's notes, but keeping them in sync
   seems reasonable (and allows for automation!).
2019-05-31 09:35:45 +01:00
SquidDev
e839ef54af Forbid mutating empty_json_array
It's definitely still possible (rawset), but should prevent people
accidentally trying to modify it when they shouldn't.
2019-05-30 20:01:09 +01:00
SquidDev
0cb659d78c Ensure require is usable within the REPL
As 'require' operates relative to the current program's directory,
rather than the current directory, it meant we were trying to load files
from /rom/programs.

This is never a good idea, so we add the current directory to the
package path, allowing you to use require as one'd expect.
2019-05-30 19:52:55 +01:00
hydraz
9048deeb95 Add a function for type-checking arguments (#207)
- Define an expect(index, actual_value, types...) helper function which
   takes an argument index, value and list of permissable types and
   ensures the value is of one of those types.
   If not, it will produce an error message with the expected and actual
   type, as well as the argument number and (if available) the function
   name.
 - Expose expect in the global scope as _G["~expect"], hopefully making
   it clear it is internal.
 - Replace most manual type checks with this helper method.
 - Write tests to ensure this argument validation works as expected

Also fix a couple of bugs exposed by this refactor and the subsequent
tests:
 - Make rednet checks a little more strict - rednet.close(false) is no
   longer valid.
 - Error when attempting to redirect the terminal to itself 
   (term.redirect(term)).
2019-05-30 19:36:28 +01:00
SquidDev
5592ebae7d A small bit of housekeeping
- Add a link to discord and the forums. Oh goodness, I hope this
   doesn't count as making things official.
   I've had a couple of people email me with support requests, which is
   /fine/, but there's better channels for it!
 - Add a couple of PR templates
   - Ask people to write tests for CraftOS changes. This is a standard
     I'm trying to impose on myself, so seems reasonable to impose on
     everyone. Sorry!
   - Require same levels of explanation for PRs as we do for issues.
 - Try to expand on the feature request "rationale" section a little.
   Just trying to explan my process a little bit more.
2019-05-30 08:44:15 +01:00
SquidDev
b076c32fd1 Merge remote-tracking branch 'origin' 2019-05-30 07:57:30 +01:00
SquidDev
a48f1e310f Add a custom renderer for monitor block highlights (#220)
This only renders the bounding box on non-screen edges of the monitor,
meaning you have an uninterrupted view of the screen when hovering
hover.

Closes #219
2019-05-30 07:51:35 +01:00
SquidDev
19aca001d7 A couple of stability improvements to ComputerThread
- Be more generous in what errors we catch, handling some of the more
   "recoverable" ones.
 - Should a runner crash, attempt to restart it.
2019-05-29 09:03:31 +01:00
SquidDev
114f913bf8 Rework rendering of in-hand pocket computers (#215)
Rendering an item worked in principle, but had several caveats:
 - The terminal did not fit well within the item's texture, so we had a
   rather large border.
 - The "correctness" of this was very tied to Minecraft's item rendering
   code. This changed a little in 1.13, causing problems like #208.

Instead we effectively reuse the computer GUI rendering code, though
also handling coloured pocket computers and rendering the modem light.

This fixes #208, and hopefully fixes #212.
2019-05-26 15:24:37 +01:00
Daniel Ratcliffe
1c9810890a Merge pull request #577 from SquidDev-CC/feature/get-blink
Add .getCursorBlink to monitors and terminals
2019-05-26 00:14:02 +01:00
SquidDev
b11beb508b Convert mkdir motd note to plural
*shrug*
2019-05-25 19:17:10 +01:00
SquidDev
af8d4da594 Ensure the test name is ASCII
Gradle really doesn't like unicode apparently
2019-05-25 18:11:14 +01:00
JakobDev
a81db2cda6 Allow multiple arguments for mkdir (#216) 2019-05-25 18:04:56 +01:00
SquidDev
99bdff0f92 Automatically label issues created with templates 2019-05-25 14:53:48 +01:00
SquidDev
bb138326df Use correct model for blinking pocket computers
Fixes #211211211211211211211211211211211211211211211211211211211211211
2019-05-25 09:28:15 +01:00
hydraz
5b0ce7410d Make delete delete many files (#210)
Actually, many *globs*. It additionally prints the glob if no files
matched it, since that's clearer.

Also move the ComputerTestDelegate's filesystem to be disk-based. This
is what actual computers use, and the MemoryMount is a little broken.
2019-05-25 09:02:42 +01:00
SquidDev
d5ea22d1a0 Jolly good job 2019-05-24 22:43:59 +01:00
SquidDev
210f3fa9e2 Add mostly standard compliant os.time/os.date
- os.time, when given a table, will act the same as PUC Lua - returning
   the seconds since the epoch. We preserve the previous string/nil
   behaviour though - os.epoch("local") is equivalent to PUC's
   os.time().

 - os.date will now act accept a string and (optional) time, returning
   an appropriate table.

Somewhat resolves the madness which was dan200/ComputerCraft#183, and
hopefully (though probably not) makes @Vexatos happy.
2019-05-24 22:33:56 +01:00
SquidDev
d661cfa88b Set the arg table within shell.run
This makes us a little more compatible with Lua
2019-05-24 18:42:19 +01:00
SquidDev
68bf3a71dc Lazilly instantiate the terminal packet
This means we don't create an NBT tag every tick if the screen is
updating, unless we actually need to.
2019-05-24 18:32:56 +01:00
SquidDev
3cdb12d293 Stop shipping jars with GH releases
The build appears to be a little bit broken, I haven't got willpower to
look into it, and it's not really used anyway.
2019-05-14 07:44:19 +01:00
Wilma456 (Jakob0815)
ad33acd7d1 Add MOTD (#175) 2019-05-13 16:54:19 +01:00
SquidDev
0ec3884e98 Handle websockets which close while receiving
This changes the previous behaviour a little, but hopefully is more
sane:

 - Only require the socket to be open when first calling receive. This
   means if it closes while receving, you won't get an error.

   This behaviour is still not perfect - the socket could have closed,
   but the event not reached the user yet, but it's better.

 - Listen to websocket_close events while receiving, and return null
   should it match ours.

See #201
2019-05-08 08:16:21 +01:00
SquidDev
7f2471d6b2 Fix list-like config options not reloading
Closes #199
2019-05-08 08:00:07 +01:00
xuyu0v0
e0660b1dab Create zh_cn.json 2019-05-06 21:47:43 +01:00
SquidDev
2182cfbeb7 Merge branch 'master' into mc-1.13.x 2019-05-06 21:32:56 +01:00
SquidDev
8fafec4915 Fix budget growing too much
We were using += instead of =, meaning the budget always grew,
rather than growing while there was still space. As a result, computers
were never correctly rate limited.

Further more, if a computer went into a deficit, we would continue to
increase the budget by a negative amount, exponentially decreasing until
overflowing!

Yes, this is a very embarrassing mistake. I'd been aware that rate
limiting wasn't working as expected for a while, I hadn't realised
the problem would be this stupid.
2019-05-01 17:24:30 +01:00
SquidDev
b9fd690ecb Mark CC:T as incompatible with ComputerCraft
Just so people using the Twitch client don't try to use both.
2019-05-01 17:24:30 +01:00
xuyu0v0
2f2ada4416 Create zh_cn.lang (#186) 2019-04-24 15:41:13 +01:00
SquidDev
9c951c58d9 Revert "Switch over to Curse maven for now"
This reverts commit 4b4b47e231.

Didn't need it for that long. Woops.
2019-04-24 15:17:13 +01:00
SquidDev
4b4b47e231 Switch over to Curse maven for now
It stinks, but it's a suitable workaround.

Closes #184
2019-04-24 14:48:11 +01:00
SquidDev
2c027adb68 Fix advancements
Looks like these were never properly updated. Woops.
2019-04-24 12:15:03 +01:00
SquidDev
4a25e7a178 Fix GH release uploading 2019-04-24 10:40:44 +01:00
SquidDev
55d54fec63 Bump versions 2019-04-24 10:33:50 +01:00
SquidDev
220e4bd660 Merge branch 'master' into mc-1.13.x 2019-04-24 10:15:33 +01:00
SquidDev
978c28a686 Bump version 2019-04-24 09:48:28 +01:00
SquidDev
b867ada5e5 Merge pull request #182 from SquidDev-CC/hotfix/redstone-checks
Redstone behaviour tweaks
2019-04-24 09:45:28 +01:00
SquidDev
7071cc972b Make redstone behaviour consistent with repeaters
This uses the same behaviour that repeaters and comparators do for
determining their input, meaning that redstone directly connected to the
computer is read (as you would expect).

It's worth noting that this is a shift from previous behaviour.
Therefore, it runs the (small) risk of breaking existing builds.
However, I believe it is more consistent with the expected behaviour.
2019-04-22 11:52:53 +01:00
SquidDev
6898f932a0 Remove redstone blocked checks
This has been returning false for almost 2 years (since
8abff95441). At this point, it's probably
worth just dropping it entirely.
2019-04-22 11:40:19 +01:00
SquidDev
2e0ef6385d Fix TurtleCompareCommand throwing exceptions
Originally introduced in 173ea72001, but
the underlying cause has been happening for much longer.

 - Fix order of method name parameters. Looks like this has been broken
   since 1.11. Woops.
 - Catch RuntimeExceptions too, as Forge converts checked into unchecked
   ones.

Fixes #179
2019-04-19 18:57:12 +01:00
SquidDev
f93da7ea51 Bump Cobalt version
I promise! The joys of using -SNAPSHOT I guess...

This will now correctly cause orphaned threads to be cleaned up,
reducing the risk of thread saturation.
2019-04-18 09:49:52 +01:00
SquidDev
1210bb8a4d Fix Gradle dependencies
I'm not entirely sure why it didn't like the previous version, but there
we go.
2019-04-16 10:43:11 +01:00
SquidDev
48a71e96eb Bump version 2019-04-16 10:35:15 +01:00
SquidDev
3bf47b5290 Make refuelling a little more flexible
This removes the link between item size and refuel limit, meaning
working with other items (such as FE items) is a little easier.
2019-04-16 10:28:10 +01:00
SquidDev
9e9f199e55 Remove a couple of over-eager error logs 2019-04-16 10:08:12 +01:00
SquidDev
5a8a111857 You didn't see nothing 2019-04-15 18:33:59 +01:00
SquidDev
48ba247ab4 Create an IMultipartTile for all BlockPeripheral tiles
Fixes #176
2019-04-15 09:21:10 +01:00
SquidDev
362dbd97ac Correctly handle capability creation & invalidation
Also make cable part detection more consistent.
2019-04-09 17:29:23 +01:00
SquidDev
aa0e1883d1 Add check for if item/block registration has failed
If mod loading fails, we'll continue to load colour handlers. As
blocks/items have not been registered, then we'll throw an NPE.

See MinecraftForge/MinecraftForge#5682. Somewhat fixes #168.
2019-04-09 16:32:20 +01:00
SquidDev
9cdbcb4332 Use int instead of long for configs
Forge's config system will read the default values as integers, meaning
it fails to validate against the config spec. Ideally this'd be fixed in
forge, but this is a suitable work around.
2019-04-09 16:31:00 +01:00
SquidDev
23ddd4feb5 Fix several deprecation warnings 2019-04-09 16:30:44 +01:00
SquidDev
fcaa777c95 Merge branch 'master' into mc-1.13.x 2019-04-09 11:11:12 +01:00
SquidDev
b195cab6a7 Add a couple of colours unit tests 2019-04-09 10:35:23 +01:00
SquidDev
63dc0daa09 Convert computer sides to an enum
Previously we just relied on magic int values, which was confusing and
potentially error-prone. We could use EnumFacing, but that's a)
dependent on MC and b) incorrect, as we're referring to local
coordinates.
2019-04-09 10:02:54 +01:00
SquidDev
34602ec4be Move null checks from Preconditions to Objects 2019-04-08 14:54:57 +01:00
SquidDev
f3ce44042f Update all inputs if the block is not a neighbour
Fixes #172, and acts as a workaround for MrTJP/ProjectRed#1472.
2019-04-08 14:52:24 +01:00
SquidDev
4205f18f0c Publish jar files to GH too
I'm not sure if I'll keep this, as it's a little redundant. We're on an
older version of the plugin, as 2.2.7 seems to fail for me.

Closes #165.
2019-04-07 15:30:27 +01:00
SquidDev
6be330ae8d Expose Computer.getRootMount again
It's a little evil, but we need it for CCEmuX. There's other ways of
achieving this, but not with supporting CC and CC:T.
2019-04-07 14:58:25 +01:00
SquidDev
4569af2130 Bump version 2019-04-06 22:42:44 +01:00
SquidDev
765c31315a Make redstone updates identical to how MC does it
Also fixes rather embarassing bug with redstone not updating.
2019-04-06 22:42:03 +01:00
Wilma456 (Jakob0815)
0e191e42a0 Update de_de.lang (#166) 2019-04-03 14:58:04 +01:00
SquidDev
ca34b2a1b8 Update the dependency info a little 2019-04-02 21:37:19 +01:00
206 changed files with 4436 additions and 1489 deletions

View File

@@ -1,7 +1,7 @@
---
name: Bug report
about: Report some misbehaviour in the mod
labels: bug
---
<!--

View File

@@ -1,7 +1,7 @@
---
name: Feature request
about: Suggest an idea or improvement
labels: enhancement
---
<!--
@@ -11,4 +11,4 @@ about: Suggest an idea or improvement
## Useful information to include:
- Explanation of how the feature/change should work.
- Some rationale/use case for a feature. I'd like to keep CC:T as minimal as possible, so I like have a solid justification for each feature.
- Some rationale/use case for a feature. My general approach to designing new features is to ask yourself "what issue are we trying to solve" and _then_ "is this the best way to solve this issue?".

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

@@ -0,0 +1,3 @@
## A quick checklist
- If there's a existing issue, please link to it. If not, provide fill out the same information you would in a normal issue - reproduction steps for bugs, rationale for use-case.
- If you're working on CraftOS, try to write a few test cases so we can ensure everything continues to work in the future. Tests live in `src/test/resources/test-rom/spec` and can be run with `./gradlew check`.

6
.gitignore vendored
View File

@@ -15,3 +15,9 @@
.idea
.gradle
*.DS_Store
.classpath
.project
.settings/
bin/
*.launch

View File

@@ -1,5 +1,5 @@
# ![CC: Tweaked](logo.png)
[![Build Status](https://travis-ci.org/SquidDev-CC/CC-Tweaked.svg?branch=master)](https://travis-ci.org/SquidDev-CC/CC-Tweaked)
[![Current build status](https://travis-ci.org/SquidDev-CC/CC-Tweaked.svg?branch=master)](https://travis-ci.org/SquidDev-CC/CC-Tweaked "Current build status") [![Download CC: Tweaked on CurseForge](https://cf.way2muchnoise.eu/title/cc-tweaked.svg)](https://minecraft.curseforge.com/projects/cc-tweaked "Download CC: Tweaked on CurseForge")
CC: Tweaked is a fork of [ComputerCraft](https://github.com/dan200/ComputerCraft), adding programmable computers,
turtles and more to Minecraft.
@@ -9,7 +9,7 @@ ComputerCraft has always held a fond place in my heart: it's the mod which reall
mod which has kept me playing it for many years. However, development of the original mod has slowed, as the original
developers have had less time to work on the mod, and moved onto other projects and commitments.
CC:Tweaked (or CC:T for short) is an attempt to continue ComputerCraft's legacy. It's not intended to be a competitor
CC: Tweaked (or CC:T for short) is an attempt to continue ComputerCraft's legacy. It's not intended to be a competitor
to CC, nor do I want to take it in a vastly different direction to the original mod. Instead, CC:T focuses on making the
ComputerCraft experience as _solid_ as possible, ironing out any wrinkles that may have developed over time.
@@ -46,8 +46,17 @@ develop CC:T, you'll need to follow these steps:
If you want to run CC:T in a normal Minecraft instance, run `./gradlew build` and copy the `.jar` from `build/libs`.
## Community
If you need help getting started with CC: Tweaked, want to show off your latest project, or just want to chat about
ComputerCraft we have a [forum](https://forums.computercraft.cc/) and [Discord guild](https://discord.gg/H2UyJXe)!
There's also a fairly populated, albeit quiet [IRC channel](http://webchat.esper.net/?channels=#computercraft), if
that's more your cup of tea.
I'd generally recommend you don't contact me directly (email, DM, etc...) unless absolutely necessary (i.e. in order to
report exploits). You'll get a far quicker response if you ask the whole community!
## Using
If you want to depend on CC:Tweaked, we have a maven repo. However, you should be wary that some functionality is only
If you want to depend on CC: Tweaked, we have a maven repo. However, you should be wary that some functionality is only
exposed by CC:T's API and not vanilla ComputerCraft. If you wish to support all variations of ComputerCraft, I recommend
using [cc.crzd.me's maven](https://cc.crzd.me/maven/) instead.
@@ -57,7 +66,7 @@ dependencies {
}
dependencies {
implementation "org.squiddev:cc-tweaked:${mc_version}-${cct_version}"
implementation "org.squiddev:cc-tweaked-${mc_version}:${cct_version}"
}
```

View File

@@ -9,14 +9,17 @@ buildscript {
}
dependencies {
classpath 'com.google.code.gson:gson:2.8.1'
classpath 'net.minecraftforge.gradle:ForgeGradle:3.0.115'
classpath 'net.minecraftforge.gradle:ForgeGradle:3.0.117'
classpath 'net.sf.proguard:proguard-gradle:6.1.0beta2'
classpath 'org.ajoberstar.grgit:grgit-gradle:3.0.0'
}
}
plugins {
id 'com.matthewprenger.cursegradle' version '1.2.0'
id "checkstyle"
id "com.github.hierynomus.license" version "0.15.0"
id "com.matthewprenger.cursegradle" version "1.3.0"
id "com.github.breadmoirai.github-release" version "2.2.4"
}
apply plugin: 'net.minecraftforge.gradle'
@@ -87,13 +90,15 @@ configurations {
}
dependencies {
checkstyle "com.puppycrawl.tools:checkstyle:8.21"
minecraft "net.minecraftforge:forge:${mc_version}-${forge_version}"
compileOnly "mezz.jei:jei-1.13.2:5.0.0.8:api"
compileOnly fg.deobf("mezz.jei:jei-1.13.2:5.0.0.20:api")
// deobfProvided "pl.asie:Charset-Lib:0.5.4.6"
// deobfProvided "MCMultiPart2:MCMultiPart:2.5.3"
deobf "mezz.jei:jei-1.13.2:5.0.0.8"
runtimeOnly fg.deobf("mezz.jei:jei-1.13.2:5.0.0.20")
shade 'org.squiddev:Cobalt:0.5.0-SNAPSHOT'
@@ -142,6 +147,8 @@ import java.util.zip.*
import com.google.gson.GsonBuilder
import com.google.gson.JsonElement
import com.hierynomus.gradle.license.tasks.LicenseCheck
import com.hierynomus.gradle.license.tasks.LicenseFormat
import org.ajoberstar.grgit.Grgit
import proguard.gradle.ProGuardTask
@@ -164,7 +171,7 @@ task proguard(type: ProGuardTask, dependsOn: jar) {
dontobfuscate; dontoptimize; keepattributes; keepparameternames
// Proguard will remove directories by default, but that breaks JarMount.
keepdirectories 'assets/computercraft/lua**'
keepdirectories 'data/computercraft/lua**'
// Preserve ComputerCraft classes - we only want to strip shadowed files.
keep 'class dan200.computercraft.** { *; }'
@@ -241,6 +248,7 @@ task compressJson(dependsOn: jar) {
// Copy over all files in the current jar to the new one, running json files from GSON. As pretty printing
// is turned off, they should be minified.
new ZipFile(jarPath).withCloseable { inJar ->
tempPath.getParentFile().mkdirs()
new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(tempPath))).withCloseable { outJar ->
inJar.entries().each { entry ->
if(entry.directory) {
@@ -268,12 +276,91 @@ task compressJson(dependsOn: jar) {
assemble.dependsOn compressJson
/* Check tasks */
license {
mapping("java", "SLASHSTAR_STYLE")
strictCheck true
ext.year = Calendar.getInstance().get(Calendar.YEAR)
}
[licenseMain, licenseFormatMain].forEach {
it.configure {
include("**/*.java")
exclude("dan200/computercraft/api/**")
header rootProject.file('config/license/main.txt')
}
}
[licenseTest, licenseFormatTest].forEach {
it.configure {
include("**/*.java")
header rootProject.file('config/license/main.txt')
}
}
task licenseAPI(type: LicenseCheck);
task licenseFormatAPI(type: LicenseFormat);
[licenseAPI, licenseFormatAPI].forEach {
it.configure {
source = sourceSets.main.java
include("dan200/computercraft/api/**")
header rootProject.file('config/license/api.txt')
}
}
/* Upload tasks */
task checkRelease {
group "upload"
description "Verifies that everything is ready for a release"
inputs.property "version", mod_version
inputs.file("src/main/resources/data/computercraft/lua/rom/help/changelog.txt")
inputs.file("src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt")
doLast {
def ok = true
// Check we're targetting the current version
def whatsnew = new File("src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt").readLines()
if (whatsnew[0] != "New features in CC: Tweaked $mod_version") {
ok = false
project.logger.error("Expected `whatsnew.txt' to target $mod_version.")
}
// Check "read more" exists and trim it
def idx = whatsnew.findIndexOf { it == 'Type "help changelog" to see the full version history.' }
if (idx == -1) {
ok = false
project.logger.error("Must mention the changelog in whatsnew.txt")
} else {
whatsnew = whatsnew.getAt(0 ..< idx)
}
// Check whatsnew and changelog match.
def versionChangelog = "# " + whatsnew.join("\n")
def changelog = new File("src/main/resources/data/computercraft/lua/rom/help/changelog.txt").getText()
if (!changelog.startsWith(versionChangelog)) {
ok = false
project.logger.error("whatsnew and changelog are not in sync")
}
if (!ok) throw new IllegalStateException("Could not check release")
}
}
curseforge {
apiKey = project.hasProperty('curseForgeApiKey') ? project.curseForgeApiKey : ''
project {
id = '282001'
releaseType = 'beta'
releaseType = 'release'
changelog = "Release notes can be found on the GitHub repository (https://github.com/SquidDev-CC/CC-Tweaked/releases/tag/v${mc_version}-${mod_version})."
relations {
incompatible "computercraft"
}
}
}
@@ -330,6 +417,31 @@ uploadArchives {
}
}
githubRelease {
token project.hasProperty('githubApiKey') ? project.githubApiKey : ''
owner 'SquidDev-CC'
repo 'CC-Tweaked'
targetCommitish { Grgit.open(dir: '.').branch.current().name }
tagName "v${mc_version}-${mod_version}"
releaseName "[${mc_version}] ${mod_version}"
body {
"## " + new File("src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt")
.readLines()
.takeWhile { it != 'Type "help changelog" to see the full version history.' }
.join("\n").trim()
}
prerelease false
}
def uploadTasks = ["uploadArchives", "curseforge", "githubRelease"]
uploadTasks.forEach { tasks.getByName(it).dependsOn checkRelease }
task uploadAll(dependsOn: uploadTasks) {
group "upload"
description "Uploads to all repositories (Maven, Curse, GitHub release)"
}
test {
useJUnitPlatform()
testLogging {
@@ -343,5 +455,9 @@ gradle.projectsEvaluated {
tasks.withType(JavaCompile) {
options.compilerArgs << "-Xlint" << "-Xlint:-processing" // Causes Forge build to fail << "-Werror"
}
tasks.withType(LicenseFormat) {
outputs.upToDateWhen { false }
}
}

View File

@@ -0,0 +1,159 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE module PUBLIC
"-//Checkstyle//DTD Checkstyle Configuration 1.3//EN"
"https://checkstyle.org/dtds/configuration_1_3.dtd">
<module name="Checker">
<property name="tabWidth" value="4"/>
<property name="charset" value="UTF-8" />
<module name="SuppressionFilter">
<property name="file" value="config/checkstyle/suppressions.xml" />
</module>
<module name="TreeWalker">
<!-- Annotations -->
<module name="AnnotationLocation" />
<module name="AnnotationUseStyle" />
<module name="MissingDeprecated">
<property name="skipNoJavadoc" value="true" />
</module>
<module name="MissingOverride" />
<!-- Blocks -->
<module name="EmptyBlock" />
<module name="EmptyCatchBlock">
<property name="exceptionVariableName" value="ignored" />
</module>
<module name="LeftCurly">
<property name="option" value="nl" />
<!-- The defaults, minus lambdas. -->
<property name="tokens" value="ANNOTATION_DEF,CLASS_DEF,CTOR_DEF,ENUM_CONSTANT_DEF,ENUM_DEF,INTERFACE_DEF,LITERAL_CASE,LITERAL_CATCH,LITERAL_DEFAULT,LITERAL_DO,LITERAL_ELSE,LITERAL_FINALLY,LITERAL_FOR,LITERAL_IF,LITERAL_SWITCH,LITERAL_SYNCHRONIZED,LITERAL_TRY,LITERAL_WHILE,METHOD_DEF,OBJBLOCK,STATIC_INIT" />
</module>
<module name="NeedBraces">
<property name="allowSingleLineStatement" value="true"/>
</module>
<module name="RightCurly">
<property name="option" value="alone" />
</module>
<!-- Class design. As if we've ever followed good practice here. -->
<module name="FinalClass" />
<module name="InterfaceIsType" />
<module name="MutableException" />
<module name="OneTopLevelClass" />
<!-- Coding -->
<module name="ArrayTrailingComma" />
<module name="EqualsHashCode" />
<!-- FallThrough does not handle unreachable code well -->
<module name="IllegalInstantiation" />
<module name="IllegalThrows" />
<module name="ModifiedControlVariable" />
<module name="NoClone" />
<module name="NoFinalizer" />
<module name="OneStatementPerLine" />
<module name="PackageDeclaration" />
<module name="SimplifyBooleanExpression" />
<module name="SimplifyBooleanReturn" />
<module name="StringLiteralEquality" />
<module name="UnnecessaryParentheses" />
<!-- Imports -->
<module name="CustomImportOrder" />
<module name="IllegalImport" />
<module name="RedundantImport" />
<module name="UnusedImports" />
<!-- Javadoc -->
<module name="AtclauseOrder" />
<!-- TODO: Cleanup our documentation before enabling JavadocMethod, JavadocStyle, JavadocType and SummaryJavadoc. -->
<module name="NonEmptyAtclauseDescription" />
<module name="SingleLineJavadoc" />
<!-- Misc -->
<module name="ArrayTypeStyle" />
<module name="CommentsIndentation" />
<module name="Indentation" />
<module name="OuterTypeFilename" />
<!-- Modifiers -->
<module name="ModifierOrder" />
<module name="RedundantModifier" />
<!-- Naming -->
<module name="ClassTypeParameterName" />
<module name="InterfaceTypeParameterName" />
<module name="LambdaParameterName" />
<module name="LocalFinalVariableName" />
<module name="LocalVariableName" />
<!-- Allow an optional m_ on private members -->
<module name="MemberName">
<property name="applyToPrivate" value="false" />
<property name="applyToPackage" value="false" />
</module>
<module name="MemberName">
<property name="format" value="^(m_)?[a-z][a-zA-Z0-9]*$" />
<property name="applyToPrivate" value="true" />
<property name="applyToPackage" value="true" />
</module>
<module name="MethodName" />
<module name="MethodTypeParameterName" />
<module name="PackageName">
<property name="format" value="^dan200\.computercraf(\.[a-z][a-z0-9]*)*" />
</module>
<module name="ParameterName" />
<module name="StaticVariableName">
<property name="format" value="^[a-z][a-zA-Z0-9]*|CAPABILITY(_[A-Z]+)?$" />
<property name="applyToPrivate" value="false" />
</module>
<module name="StaticVariableName">
<property name="format" value="^(s_)?[a-z][a-zA-Z0-9]*|CAPABILITY(_[A-Z]+)?$" />
<property name="applyToPrivate" value="true" />
</module>
<module name="TypeName" />
<!-- Whitespace -->
<module name="EmptyForInitializerPad"/>
<module name="EmptyForIteratorPad">
<property name="option" value="space"/>
</module>
<module name="GenericWhitespace" />
<module name="MethodParamPad" />
<module name="NoLineWrap" />
<module name="NoWhitespaceAfter">
<property name="tokens" value="AT,INC,DEC,UNARY_MINUS,UNARY_PLUS,BNOT,LNOT,DOT,ARRAY_DECLARATOR,INDEX_OP" />
</module>
<module name="NoWhitespaceBefore" />
<!-- TODO: Decide on an OperatorWrap style. -->
<module name="ParenPad">
<property name="option" value="space" />
<property name="tokens" value="ANNOTATION,ANNOTATION_FIELD_DEF,CTOR_CALL,CTOR_DEF,ENUM_CONSTANT_DEF,LITERAL_CATCH,LITERAL_DO,LITERAL_FOR,LITERAL_IF,LITERAL_NEW,LITERAL_SWITCH,LITERAL_SYNCHRONIZED,LITERAL_WHILE,METHOD_CALL,METHOD_DEF,RESOURCE_SPECIFICATION,SUPER_CTOR_CALL,LAMBDA" />
</module>
<module name="ParenPad">
<property name="option" value="nospace" />
<property name="tokens" value="DOT,EXPR,QUESTION" />
</module>
<module name="SeparatorWrap">
<property name="option" value="eol" />
<property name="tokens" value="COMMA,SEMI,ELLIPSIS,ARRAY_DECLARATOR,RBRACK,METHOD_REF" />
</module>
<module name="SeparatorWrap">
<property name="option" value="nl" />
<property name="tokens" value="DOT,AT" />
</module>
<module name="SingleSpaceSeparator" />
<module name="TypecastParenPad" />
<module name="WhitespaceAfter">
<property name="tokens" value="COMMA" />
</module>
<module name="WhitespaceAround">
<property name="allowEmptyConstructors" value="true" />
<property name="ignoreEnhancedForColon" value="false" />
<property name="tokens" value="ASSIGN,BAND,BAND_ASSIGN,BOR,BOR_ASSIGN,BSR,BSR_ASSIGN,BXOR,BXOR_ASSIGN,COLON,DIV,DIV_ASSIGN,DO_WHILE,EQUAL,GE,GT,LAMBDA,LAND,LCURLY,LE,LITERAL_RETURN,LOR,LT,MINUS,MINUS_ASSIGN,MOD,MOD_ASSIGN,NOT_EQUAL,PLUS,PLUS_ASSIGN,QUESTION,RCURLY,SL,SLIST,SL_ASSIGN,SR,SR_ASSIGN,STAR,STAR_ASSIGN,LITERAL_ASSERT,TYPE_EXTENSION_AND" />
</module>
</module>
<module name="FileTabCharacter" />
<module name="NewlineAtEndOfFile" />
</module>

View File

@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suppressions PUBLIC
"-//Checkstyle//DTD SuppressionFilter Configuration 1.2//EN"
"https://checkstyle.org/dtds/suppressions_1_2.dtd">
<suppressions>
<!-- Has a public m_label field. We need to check if this is used in other projects before renaming it. -->
<suppress checks="MemberName" files=".*[\\/]TileComputerBase.java"
message="Name 'm_label' must match pattern .*" />
<!-- All the config options and method fields. -->
<suppress checks="StaticVariableName" files=".*[\\/]ComputerCraft.java" />
<suppress checks="StaticVariableName" files=".*[\\/]ComputerCraftAPI.java" />
</suppressions>

3
config/license/api.txt Normal file
View File

@@ -0,0 +1,3 @@
This file is part of the public ComputerCraft API - http://www.computercraft.info
Copyright Daniel Ratcliffe, 2011-${year}. 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.

3
config/license/main.txt Normal file
View File

@@ -0,0 +1,3 @@
This file is part of ComputerCraft - http://www.computercraft.info
Copyright Daniel Ratcliffe, 2011-${year}. Do not distribute without permission.
Send enquiries to dratcliffe@gmail.com

View File

@@ -1,7 +1,7 @@
# Mod properties
mod_version=1.82.0
mod_version=1.83.1
# Minecraft properties
mc_version=1.13.2
forge_version=25.0.100
mappings_version=20190327-1.13.2
forge_version=25.0.219
mappings_version=20190530-1.13.2

View File

@@ -43,6 +43,7 @@ public final class ComputerCraftAPIImpl implements IComputerCraftAPI
{
}
@Nonnull
@Override
public String getInstalledVersion()
{
@@ -110,6 +111,7 @@ public final class ComputerCraftAPIImpl implements IComputerCraftAPI
PocketUpgrades.register( upgrade );
}
@Nonnull
@Override
public IPacketNetwork getWirelessNetwork()
{
@@ -122,19 +124,18 @@ public final class ComputerCraftAPIImpl implements IComputerCraftAPI
ApiFactories.register( factory );
}
@Nonnull
@Override
public IWiredNode createWiredNodeForElement( @Nonnull IWiredElement element )
{
return new WiredNode( element );
}
@Nonnull
@Override
public IWiredElement getWiredElementAt( @Nonnull IBlockReader world, @Nonnull BlockPos pos, @Nonnull EnumFacing side )
public LazyOptional<IWiredElement> getWiredElementAt( @Nonnull IBlockReader world, @Nonnull BlockPos pos, @Nonnull EnumFacing side )
{
TileEntity tile = world.getTileEntity( pos );
if( tile == null ) return null;
LazyOptional<IWiredElement> element = tile.getCapability( CapabilityWiredElement.CAPABILITY, side );
return CapabilityWiredElement.unwrap( element );
return tile == null ? LazyOptional.empty() : tile.getCapability( CapabilityWiredElement.CAPABILITY, side );
}
}

View File

@@ -1,9 +1,8 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
* This file is part of the public ComputerCraft API - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2019. 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;
import dan200.computercraft.api.turtle.ITurtleUpgrade;

View File

@@ -24,6 +24,7 @@ import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IBlockReader;
import net.minecraft.world.World;
import net.minecraftforge.common.util.LazyOptional;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
@@ -240,8 +241,8 @@ public final class ComputerCraftAPI
* @return The element's node
* @see IWiredElement#getNode()
*/
@Nullable
public static IWiredElement getWiredElementAt( @Nonnull IBlockReader world, @Nonnull BlockPos pos, @Nonnull EnumFacing side )
@Nonnull
public static LazyOptional<IWiredElement> getWiredElementAt( @Nonnull IBlockReader world, @Nonnull BlockPos pos, @Nonnull EnumFacing side )
{
return getInstance().getWiredElementAt( world, pos, side );
}
@@ -266,12 +267,15 @@ public final class ComputerCraftAPI
public interface IComputerCraftAPI
{
@Nonnull
String getInstalledVersion();
int createUniqueNumberedSaveDir( @Nonnull World world, @Nonnull String parentSubPath );
@Nullable
IWritableMount createSaveDirMount( @Nonnull World world, @Nonnull String subPath, long capacity );
@Nullable
IMount createResourceMount( @Nonnull String domain, @Nonnull String subPath );
void registerPeripheralProvider( @Nonnull IPeripheralProvider provider );
@@ -286,12 +290,15 @@ public final class ComputerCraftAPI
void registerPocketUpgrade( @Nonnull IPocketUpgrade upgrade );
@Nonnull
IPacketNetwork getWirelessNetwork();
void registerAPIFactory( @Nonnull ILuaAPIFactory factory );
@Nonnull
IWiredNode createWiredNodeForElement( @Nonnull IWiredElement element );
IWiredElement getWiredElementAt( @Nonnull IBlockReader world, @Nonnull BlockPos pos, @Nonnull EnumFacing side );
@Nonnull
LazyOptional<IWiredElement> getWiredElementAt( @Nonnull IBlockReader world, @Nonnull BlockPos pos, @Nonnull EnumFacing side );
}
}

View File

@@ -0,0 +1,41 @@
/*
* This file is part of the public ComputerCraft API - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2019. 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.filesystem;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.io.IOException;
import java.util.Objects;
/**
* An {@link IOException} which occurred on a specific file.
*
* This may be thrown from a {@link IMount} or {@link IWritableMount} to give more information about a failure.
*/
public class FileOperationException extends IOException
{
private static final long serialVersionUID = -8809108200853029849L;
private final String filename;
public FileOperationException( @Nullable String filename, @Nonnull String message )
{
super( Objects.requireNonNull( message, "message cannot be null" ) );
this.filename = filename;
}
public FileOperationException( String message )
{
super( Objects.requireNonNull( message, "message cannot be null" ) );
this.filename = null;
}
@Nullable
public String getFilename()
{
return filename;
}
}

View File

@@ -90,7 +90,6 @@ public interface IMount
* @throws IOException If the file does not exist, or could not be opened.
*/
@Nonnull
@SuppressWarnings( "deprecation" )
default ReadableByteChannel openChannelForRead( @Nonnull String path ) throws IOException
{
return Channels.newChannel( openForRead( path ) );

View File

@@ -67,7 +67,6 @@ public interface IWritableMount extends IMount
* @throws IOException If the file could not be opened for writing.
*/
@Nonnull
@SuppressWarnings( "deprecation" )
default WritableByteChannel openChannelForWrite( @Nonnull String path ) throws IOException
{
return Channels.newChannel( openForWrite( path ) );
@@ -94,7 +93,6 @@ public interface IWritableMount extends IMount
* @throws IOException If the file could not be opened for writing.
*/
@Nonnull
@SuppressWarnings( "deprecation" )
default WritableByteChannel openChannelForAppend( @Nonnull String path ) throws IOException
{
return Channels.newChannel( openForAppend( path ) );

View File

@@ -1,9 +1,8 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
* This file is part of the public ComputerCraft API - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2019. 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 javax.annotation.Nonnull;

View File

@@ -1,9 +1,8 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
* This file is part of the public ComputerCraft API - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2019. 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.pocket;
import net.minecraft.item.ItemStack;

View File

@@ -1,9 +1,8 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
* This file is part of the public ComputerCraft API - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2019. 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.turtle.event;
import dan200.computercraft.api.lua.ILuaContext;

View File

@@ -1,9 +1,8 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
* This file is part of the public ComputerCraft API - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2019. 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.turtle.event;
import dan200.computercraft.api.turtle.ITurtleAccess;

View File

@@ -121,6 +121,12 @@ public final class ClientRegistry
@SubscribeEvent
public static void onItemColours( ColorHandlerEvent.Item event )
{
if( ComputerCraft.Items.disk == null || ComputerCraft.Blocks.turtleNormal == null )
{
ComputerCraft.log.warn( "Block/item registration has failed. Skipping registration of item colours." );
return;
}
event.getItemColors().register(
( stack, layer ) -> layer == 1 ? ((ItemDisk) stack.getItem()).getColour( stack ) : 0xFFFFFF,
ComputerCraft.Items.disk

View File

@@ -20,9 +20,10 @@ import net.minecraft.util.ResourceLocation;
public class GuiComputer extends GuiContainer
{
private static final ResourceLocation BACKGROUND_NORMAL = new ResourceLocation( "computercraft", "textures/gui/corners_normal.png" );
private static final ResourceLocation BACKGROUND_ADVANCED = new ResourceLocation( "computercraft", "textures/gui/corners_advanced.png" );
private static final ResourceLocation BACKGROUND_COMMAND = new ResourceLocation( "computercraft", "textures/gui/corners_command.png" );
public static final ResourceLocation BACKGROUND_NORMAL = new ResourceLocation( ComputerCraft.MOD_ID, "textures/gui/corners_normal.png" );
public static final ResourceLocation BACKGROUND_ADVANCED = new ResourceLocation( ComputerCraft.MOD_ID, "textures/gui/corners_advanced.png" );
public static final ResourceLocation BACKGROUND_COMMAND = new ResourceLocation( ComputerCraft.MOD_ID, "textures/gui/corners_command.png" );
public static final ResourceLocation BACKGROUND_COLOUR = new ResourceLocation( ComputerCraft.MOD_ID, "textures/gui/corners_colour.png" );
private final ComputerFamily m_family;
private final ClientComputer m_computer;
@@ -118,12 +119,12 @@ public class GuiComputer extends GuiContainer
}
drawTexturedModalRect( startX - 12, startY - 12, 12, 28, 12, 12 );
drawTexturedModalRect( startX - 12, endY, 12, 40, 12, 16 );
drawTexturedModalRect( startX - 12, endY, 12, 40, 12, 12 );
drawTexturedModalRect( endX, startY - 12, 24, 28, 12, 12 );
drawTexturedModalRect( endX, endY, 24, 40, 12, 16 );
drawTexturedModalRect( endX, endY, 24, 40, 12, 12 );
drawTexturedModalRect( startX, startY - 12, 0, 0, endX - startX, 12 );
drawTexturedModalRect( startX, endY, 0, 12, endX - startX, 16 );
drawTexturedModalRect( startX, endY, 0, 12, endX - startX, 12 );
drawTexturedModalRect( startX - 12, startY, 0, 28, 12, endY - startY );
drawTexturedModalRect( endX, startY, 36, 28, 12, endY - startY );

View File

@@ -88,7 +88,7 @@ public class GuiTurtle extends GuiContainer
int slotX = slot % 4;
int slotY = slot / 4;
mc.getTextureManager().bindTexture( advanced ? BACKGROUND_ADVANCED : BACKGROUND_NORMAL );
drawTexturedModalRect( guiLeft + m_container.m_turtleInvStartX - 2 + slotX * 18, guiTop + m_container.m_playerInvStartY - 2 + slotY * 18, 0, 217, 24, 24 );
drawTexturedModalRect( guiLeft + m_container.turtleInvStartX - 2 + slotX * 18, guiTop + m_container.playerInvStartY - 2 + slotY * 18, 0, 217, 24, 24 );
}
}

View File

@@ -75,8 +75,9 @@ public final class ComputerCraftProxyClient
ModLoadingContext.get().registerExtensionPoint( ExtensionPoint.GUIFACTORY, () -> packet -> {
ContainerType<?> type = ContainerType.factories.get( packet.getId() ).get();
if( packet.getAdditionalData() != null ) type.fromBytes( packet.getAdditionalData() );
return ((BiFunction<ContainerType<?>, EntityPlayer, GuiContainer>) ContainerType.guiFactories.get( packet.getId() ))
.apply( type, Minecraft.getInstance().player );
@SuppressWarnings( "unchecked" )
BiFunction<ContainerType<?>, EntityPlayer, GuiContainer> factory = (BiFunction<ContainerType<?>, EntityPlayer, GuiContainer>) ContainerType.guiFactories.get( packet.getId() );
return factory.apply( type, Minecraft.getInstance().player );
} );
}

View File

@@ -26,9 +26,9 @@ import net.minecraftforge.fml.common.Mod;
import org.lwjgl.opengl.GL11;
@Mod.EventBusSubscriber( modid = ComputerCraft.MOD_ID, value = Dist.CLIENT )
public final class RenderOverlayCable
public final class CableHighlightRenderer
{
private RenderOverlayCable()
private CableHighlightRenderer()
{
}
@@ -74,7 +74,8 @@ public final class RenderOverlayCable
double z = player.lastTickPosZ + (player.posZ - player.lastTickPosZ) * partialTicks;
VoxelShape shape = WorldUtil.isVecInside( CableShapes.getModemShape( state ), event.getTarget().hitVec.subtract( pos.getX(), pos.getY(), pos.getZ() ) )
? CableShapes.getModemShape( state ) : CableShapes.getCableShape( state );
? CableShapes.getModemShape( state )
: CableShapes.getCableShape( state );
WorldRenderer.drawShape( shape, pos.getX() - x, pos.getY() - y, pos.getZ() - z, 0.0F, 0.0F, 0.0F, 0.4F );

View File

@@ -12,25 +12,24 @@ import dan200.computercraft.client.gui.FixedWidthFontRenderer;
import dan200.computercraft.core.terminal.Terminal;
import dan200.computercraft.core.terminal.TextBuffer;
import dan200.computercraft.shared.computer.core.ClientComputer;
import dan200.computercraft.shared.computer.core.ComputerFamily;
import dan200.computercraft.shared.pocket.items.ItemPocketComputer;
import dan200.computercraft.shared.util.Colour;
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.ItemRenderer;
import net.minecraft.client.renderer.model.IBakedModel;
import net.minecraft.client.renderer.model.ItemCameraTransforms.TransformType;
import net.minecraft.client.renderer.texture.TextureManager;
import net.minecraft.client.renderer.texture.TextureMap;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.item.ItemStack;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.client.ForgeHooksClient;
import net.minecraftforge.client.event.RenderSpecificHandEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
import org.lwjgl.opengl.GL11;
import static dan200.computercraft.client.gui.FixedWidthFontRenderer.FONT_HEIGHT;
import static dan200.computercraft.client.gui.FixedWidthFontRenderer.FONT_WIDTH;
import static dan200.computercraft.client.gui.FixedWidthFontRenderer.*;
import static dan200.computercraft.client.gui.GuiComputer.*;
/**
* Emulates map rendering for pocket computers
@@ -38,6 +37,10 @@ import static dan200.computercraft.client.gui.FixedWidthFontRenderer.FONT_WIDTH;
@Mod.EventBusSubscriber( modid = ComputerCraft.MOD_ID, value = Dist.CLIENT )
public final class ItemPocketRenderer extends ItemMapLikeRenderer
{
private static final int MARGIN = 2;
private static final int FRAME = 12;
private static final int LIGHT_HEIGHT = 8;
private static final ItemPocketRenderer INSTANCE = new ItemPocketRenderer();
private ItemPocketRenderer()
@@ -57,115 +60,195 @@ public final class ItemPocketRenderer extends ItemMapLikeRenderer
@Override
protected void renderItem( ItemStack stack )
{
ClientComputer computer = ItemPocketComputer.createClientComputer( stack );
Terminal terminal = computer == null ? null : computer.getTerminal();
int termWidth, termHeight;
if( terminal == null )
{
termWidth = ComputerCraft.terminalWidth_pocketComputer;
termHeight = ComputerCraft.terminalHeight_pocketComputer;
}
else
{
termWidth = terminal.getWidth();
termHeight = terminal.getHeight();
}
int width = termWidth * FONT_WIDTH + MARGIN * 2;
int height = termHeight * FONT_HEIGHT + MARGIN * 2;
// Setup various transformations. Note that these are partially adapted from the corresponding method
// in ItemRenderer
GlStateManager.pushMatrix();
GlStateManager.disableLighting();
GlStateManager.disableDepthTest();
GlStateManager.rotatef( 180f, 0f, 1f, 0f );
GlStateManager.rotatef( 180f, 0f, 0f, 1f );
GlStateManager.scalef( 0.5f, 0.5f, 0.5f );
ClientComputer computer = ItemPocketComputer.createClientComputer( stack );
double scale = 0.75 / Math.max( width + FRAME * 2, height + FRAME * 2 + LIGHT_HEIGHT );
GlStateManager.scaled( scale, scale, 0 );
GlStateManager.translated( -0.5 * width, -0.5 * height, 0 );
// Render the main frame
ItemPocketComputer item = (ItemPocketComputer) stack.getItem();
ComputerFamily family = item.getFamily();
int frameColour = item.getColour( stack );
renderFrame( family, frameColour, width, height );
// Render the light
int lightColour = ItemPocketComputer.getLightState( stack );
if( lightColour == -1 ) lightColour = Colour.Black.getHex();
renderLight( lightColour, width, height );
if( computer != null && terminal != null )
{
// First render the background item. We use the item's model rather than a direct texture as this ensures
// we display the pocket light and other such decorations.
GlStateManager.pushMatrix();
// If we've a computer and terminal then attempt to render it.
renderTerminal( terminal, !computer.isColour(), width, height );
}
else
{
// Otherwise render a plain background
Minecraft.getInstance().getTextureManager().bindTexture( BACKGROUND );
GlStateManager.scalef( 1.0f, -1.0f, 1.0f );
Tessellator tessellator = Tessellator.getInstance();
BufferBuilder buffer = tessellator.getBuffer();
Minecraft minecraft = Minecraft.getInstance();
TextureManager textureManager = minecraft.getTextureManager();
ItemRenderer renderItem = minecraft.getItemRenderer();
// Copy of RenderItem#renderItemModelIntoGUI but without the translation or scaling
textureManager.bindTexture( TextureMap.LOCATION_BLOCKS_TEXTURE );
textureManager.getTexture( TextureMap.LOCATION_BLOCKS_TEXTURE ).setBlurMipmap( false, false );
GlStateManager.enableRescaleNormal();
GlStateManager.enableAlphaTest();
GlStateManager.alphaFunc( GL11.GL_GREATER, 0.1F );
GlStateManager.enableBlend();
GlStateManager.blendFunc( GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA );
GlStateManager.color4f( 1.0F, 1.0F, 1.0F, 1.0F );
IBakedModel baked = renderItem.getItemModelWithOverrides( stack, null, null );
baked = ForgeHooksClient.handleCameraTransforms( baked, TransformType.GUI, false );
renderItem.renderItem( stack, baked );
GlStateManager.disableAlphaTest();
GlStateManager.disableRescaleNormal();
GlStateManager.popMatrix();
Colour black = Colour.Black;
buffer.begin( GL11.GL_QUADS, DefaultVertexFormats.POSITION );
renderTexture( buffer, 0, 0, 0, 0, width, height, black.getR(), black.getG(), black.getB() );
tessellator.draw();
}
// If we've a computer and terminal then attempt to render it.
if( computer != null )
GlStateManager.enableDepthTest();
GlStateManager.enableLighting();
GlStateManager.popMatrix();
}
private static void renderFrame( ComputerFamily family, int colour, int width, int height )
{
Minecraft.getInstance().getTextureManager().bindTexture( colour != -1
? BACKGROUND_COLOUR
: family == ComputerFamily.Normal ? BACKGROUND_NORMAL : BACKGROUND_ADVANCED
);
float r = ((colour >>> 16) & 0xFF) / 255.0f;
float g = ((colour >>> 8) & 0xFF) / 255.0f;
float b = (colour & 0xFF) / 255.0f;
Tessellator tessellator = Tessellator.getInstance();
BufferBuilder buffer = tessellator.getBuffer();
buffer.begin( GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX_COLOR );
// Top left, middle, right
renderTexture( buffer, -FRAME, -FRAME, 12, 28, FRAME, FRAME, r, g, b );
renderTexture( buffer, 0, -FRAME, 0, 0, width, FRAME, r, g, b );
renderTexture( buffer, width, -FRAME, 24, 28, FRAME, FRAME, r, g, b );
// Left and bright border
renderTexture( buffer, -FRAME, 0, 0, 28, FRAME, height, r, g, b );
renderTexture( buffer, width, 0, 36, 28, FRAME, height, r, g, b );
// Bottom left, middle, right. We do this in three portions: the top inner corners, an extended region for
// lights, and then the bottom outer corners.
renderTexture( buffer, -FRAME, height, 12, 40, FRAME, FRAME / 2, r, g, b );
renderTexture( buffer, 0, height, 0, 12, width, FRAME / 2, r, g, b );
renderTexture( buffer, width, height, 24, 40, FRAME, FRAME / 2, r, g, b );
renderTexture( buffer, -FRAME, height + FRAME / 2, 12, 44, FRAME, LIGHT_HEIGHT, FRAME, 4, r, g, b );
renderTexture( buffer, 0, height + FRAME / 2, 0, 16, width, LIGHT_HEIGHT, FRAME, 4, r, g, b );
renderTexture( buffer, width, height + FRAME / 2, 24, 44, FRAME, LIGHT_HEIGHT, FRAME, 4, r, g, b );
renderTexture( buffer, -FRAME, height + LIGHT_HEIGHT + FRAME / 2, 12, 40 + FRAME / 2, FRAME, FRAME / 2, r, g, b );
renderTexture( buffer, 0, height + LIGHT_HEIGHT + FRAME / 2, 0, 12 + FRAME / 2, width, FRAME / 2, r, g, b );
renderTexture( buffer, width, height + LIGHT_HEIGHT + FRAME / 2, 24, 40 + FRAME / 2, FRAME, FRAME / 2, r, g, b );
tessellator.draw();
}
private static void renderLight( int colour, int width, int height )
{
GlStateManager.enableBlend();
GlStateManager.disableTexture2D();
float r = ((colour >>> 16) & 0xFF) / 255.0f;
float g = ((colour >>> 8) & 0xFF) / 255.0f;
float b = (colour & 0xFF) / 255.0f;
Tessellator tessellator = Tessellator.getInstance();
BufferBuilder buffer = tessellator.getBuffer();
buffer.begin( GL11.GL_QUADS, DefaultVertexFormats.POSITION_COLOR );
buffer.pos( width - LIGHT_HEIGHT * 2, height + LIGHT_HEIGHT + FRAME / 2.0f, 0.0D ).color( r, g, b, 1.0f ).endVertex();
buffer.pos( width, height + LIGHT_HEIGHT + FRAME / 2.0f, 0.0D ).color( r, g, b, 1.0f ).endVertex();
buffer.pos( width, height + FRAME / 2.0f, 0.0D ).color( r, g, b, 1.0f ).endVertex();
buffer.pos( width - LIGHT_HEIGHT * 2, height + FRAME / 2.0f, 0.0D ).color( r, g, b, 1.0f ).endVertex();
tessellator.draw();
GlStateManager.enableTexture2D();
}
private static void renderTerminal( Terminal terminal, boolean greyscale, int width, int height )
{
synchronized( terminal )
{
Terminal terminal = computer.getTerminal();
if( terminal != null )
int termWidth = terminal.getWidth();
int termHeight = terminal.getHeight();
FixedWidthFontRenderer fontRenderer = FixedWidthFontRenderer.instance();
Palette palette = terminal.getPalette();
// Render top/bottom borders
TextBuffer emptyLine = new TextBuffer( ' ', termWidth );
fontRenderer.drawString(
emptyLine, MARGIN, 0,
terminal.getTextColourLine( 0 ), terminal.getBackgroundColourLine( 0 ), MARGIN, MARGIN, greyscale, palette
);
fontRenderer.drawString(
emptyLine, MARGIN, 2 * MARGIN + (termHeight - 1) * FixedWidthFontRenderer.FONT_HEIGHT,
terminal.getTextColourLine( termHeight - 1 ), terminal.getBackgroundColourLine( termHeight - 1 ), MARGIN, MARGIN, greyscale, palette
);
// Render the actual text
for( int line = 0; line < termWidth; line++ )
{
synchronized( terminal )
{
GlStateManager.pushMatrix();
GlStateManager.disableDepthTest();
TextBuffer text = terminal.getLine( line );
TextBuffer colour = terminal.getTextColourLine( line );
TextBuffer backgroundColour = terminal.getBackgroundColourLine( line );
fontRenderer.drawString(
text, MARGIN, MARGIN + line * FONT_HEIGHT,
colour, backgroundColour, MARGIN, MARGIN, greyscale, palette
);
}
// Reset the position to be at the top left corner of the pocket computer
// Note we translate towards the screen slightly too.
GlStateManager.translated( -8 / 16.0, -8 / 16.0, 0.5 / 16.0 );
// Translate to the top left of the screen.
GlStateManager.translated( 4 / 16.0, 3 / 16.0, 0 );
// Work out the scaling required to resize the terminal in order to fit on the computer
final int margin = 2;
int tw = terminal.getWidth();
int th = terminal.getHeight();
int width = tw * FONT_WIDTH + margin * 2;
int height = th * FONT_HEIGHT + margin * 2;
int max = Math.max( height, width );
// The grid is 8 * 8 wide, so we start with a base of 1/2 (8 / 16).
double scale = 1.0 / 2.0 / max;
GlStateManager.scaled( scale, scale, scale );
// The margin/start positions are determined in order for the terminal to be centred.
int startX = (max - width) / 2 + margin;
int startY = (max - height) / 2 + margin;
FixedWidthFontRenderer fontRenderer = FixedWidthFontRenderer.instance();
boolean greyscale = !computer.isColour();
Palette palette = terminal.getPalette();
// Render the actual text
for( int line = 0; line < th; line++ )
{
TextBuffer text = terminal.getLine( line );
TextBuffer colour = terminal.getTextColourLine( line );
TextBuffer backgroundColour = terminal.getBackgroundColourLine( line );
fontRenderer.drawString(
text, startX, startY + line * FONT_HEIGHT,
colour, backgroundColour, margin, margin, greyscale, palette
);
}
// And render the cursor;
int tx = terminal.getCursorX(), ty = terminal.getCursorY();
if( terminal.getCursorBlink() && FrameInfo.getGlobalCursorBlink() &&
tx >= 0 && ty >= 0 && tx < tw && ty < th )
{
TextBuffer cursorColour = new TextBuffer( "0123456789abcdef".charAt( terminal.getTextColour() ), 1 );
fontRenderer.drawString(
new TextBuffer( '_', 1 ), startX + FONT_WIDTH * tx, startY + FONT_HEIGHT * ty,
cursorColour, null, 0, 0, greyscale, palette
);
}
GlStateManager.enableDepthTest();
GlStateManager.popMatrix();
}
// And render the cursor;
int tx = terminal.getCursorX(), ty = terminal.getCursorY();
if( terminal.getCursorBlink() && FrameInfo.getGlobalCursorBlink() &&
tx >= 0 && ty >= 0 && tx < termWidth && ty < termHeight )
{
TextBuffer cursorColour = new TextBuffer( "0123456789abcdef".charAt( terminal.getTextColour() ), 1 );
fontRenderer.drawString(
new TextBuffer( '_', 1 ), MARGIN + FONT_WIDTH * tx, MARGIN + FONT_HEIGHT * ty,
cursorColour, null, 0, 0, greyscale, palette
);
}
}
}
GlStateManager.enableLighting();
private static void renderTexture( BufferBuilder builder, int x, int y, int textureX, int textureY, int width, int height, float r, float g, float b )
{
renderTexture( builder, x, y, textureX, textureY, width, height, width, height, r, g, b );
}
private static void renderTexture( BufferBuilder builder, int x, int y, int textureX, int textureY, int width, int height, int textureWidth, int textureHeight, float r, float g, float b )
{
float scale = 1 / 255.0f;
builder.pos( x, y + height, 0 ).tex( textureX * scale, (textureY + textureHeight) * scale ).color( r, g, b, 1.0f ).endVertex();
builder.pos( x + width, y + height, 0 ).tex( (textureX + textureWidth) * scale, (textureY + textureHeight) * scale ).color( r, g, b, 1.0f ).endVertex();
builder.pos( x + width, y, 0 ).tex( (textureX + textureWidth) * scale, textureY * scale ).color( r, g, b, 1.0f ).endVertex();
builder.pos( x, y, 0 ).tex( textureX * scale, textureY * scale ).color( r, g, b, 1.0f ).endVertex();
}
}

View File

@@ -94,7 +94,7 @@ public final class ModelTransformer
private final Point3f[] before = new Point3f[4];
private final Point3f[] after = new Point3f[4];
public NormalAwareTransformer( IVertexConsumer parent, Matrix4f positionMatrix, Matrix4f normalMatrix )
NormalAwareTransformer( IVertexConsumer parent, Matrix4f positionMatrix, Matrix4f normalMatrix )
{
super( parent );
this.positionMatrix = positionMatrix;

View File

@@ -0,0 +1,117 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.client.render;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.shared.peripheral.monitor.TileMonitor;
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.entity.player.EntityPlayer;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.world.World;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.client.event.DrawBlockHighlightEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
import org.lwjgl.opengl.GL11;
import java.util.EnumSet;
import static net.minecraft.util.EnumFacing.*;
@Mod.EventBusSubscriber( modid = ComputerCraft.MOD_ID, value = Dist.CLIENT )
public final class MonitorHighlightRenderer
{
private static final float EXPAND = 0.002f;
private MonitorHighlightRenderer()
{
}
@SubscribeEvent
public static void drawHighlight( DrawBlockHighlightEvent event )
{
if( event.getTarget().type != RayTraceResult.Type.BLOCK || event.getPlayer().isSneaking() ) return;
World world = event.getPlayer().getEntityWorld();
BlockPos pos = event.getTarget().getBlockPos();
TileEntity tile = world.getTileEntity( pos );
if( !(tile instanceof TileMonitor) ) return;
TileMonitor monitor = (TileMonitor) tile;
event.setCanceled( true );
// Determine which sides are part of the external faces of the monitor, and so which need to be rendered.
EnumSet<EnumFacing> faces = EnumSet.allOf( EnumFacing.class );
EnumFacing front = monitor.getFront();
faces.remove( front );
if( monitor.getXIndex() != 0 ) faces.remove( monitor.getRight().getOpposite() );
if( monitor.getXIndex() != monitor.getWidth() - 1 ) faces.remove( monitor.getRight() );
if( monitor.getYIndex() != 0 ) faces.remove( monitor.getDown().getOpposite() );
if( monitor.getYIndex() != monitor.getHeight() - 1 ) faces.remove( monitor.getDown() );
GlStateManager.enableBlend();
GlStateManager.blendFuncSeparate( GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA, GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ZERO );
GlStateManager.lineWidth( Math.max( 2.5F, (float) Minecraft.getInstance().mainWindow.getFramebufferWidth() / 1920.0F * 2.5F ) );
GlStateManager.disableTexture2D();
GlStateManager.depthMask( false );
GlStateManager.pushMatrix();
EntityPlayer player = event.getPlayer();
double x = player.lastTickPosX + (player.posX - player.lastTickPosX) * event.getPartialTicks();
double y = player.lastTickPosY + (player.posY - player.lastTickPosY) * event.getPartialTicks();
double z = player.lastTickPosZ + (player.posZ - player.lastTickPosZ) * event.getPartialTicks();
GlStateManager.translated( -x + pos.getX(), -y + pos.getY(), -z + pos.getZ() );
Tessellator tessellator = Tessellator.getInstance();
BufferBuilder buffer = tessellator.getBuffer();
buffer.begin( GL11.GL_LINES, DefaultVertexFormats.POSITION_COLOR );
// I wish I could think of a better way to do this
if( faces.contains( NORTH ) || faces.contains( WEST ) ) line( buffer, 0, 0, 0, UP );
if( faces.contains( SOUTH ) || faces.contains( WEST ) ) line( buffer, 0, 0, 1, UP );
if( faces.contains( NORTH ) || faces.contains( EAST ) ) line( buffer, 1, 0, 0, UP );
if( faces.contains( SOUTH ) || faces.contains( EAST ) ) line( buffer, 1, 0, 1, UP );
if( faces.contains( NORTH ) || faces.contains( DOWN ) ) line( buffer, 0, 0, 0, EAST );
if( faces.contains( SOUTH ) || faces.contains( DOWN ) ) line( buffer, 0, 0, 1, EAST );
if( faces.contains( NORTH ) || faces.contains( UP ) ) line( buffer, 0, 1, 0, EAST );
if( faces.contains( SOUTH ) || faces.contains( UP ) ) line( buffer, 0, 1, 1, EAST );
if( faces.contains( WEST ) || faces.contains( DOWN ) ) line( buffer, 0, 0, 0, SOUTH );
if( faces.contains( EAST ) || faces.contains( DOWN ) ) line( buffer, 1, 0, 0, SOUTH );
if( faces.contains( WEST ) || faces.contains( UP ) ) line( buffer, 0, 1, 0, SOUTH );
if( faces.contains( EAST ) || faces.contains( UP ) ) line( buffer, 1, 1, 0, SOUTH );
tessellator.draw();
GlStateManager.popMatrix();
GlStateManager.depthMask( true );
GlStateManager.enableTexture2D();
GlStateManager.disableBlend();
}
private static void line( BufferBuilder buffer, int x, int y, int z, EnumFacing direction )
{
double minX = x == 0 ? -EXPAND : 1 + EXPAND;
double minY = y == 0 ? -EXPAND : 1 + EXPAND;
double minZ = z == 0 ? -EXPAND : 1 + EXPAND;
buffer.pos( minX, minY, minZ ).color( 0, 0, 0, 0.4f ).endVertex();
buffer.pos(
minX + direction.getXOffset() * (1 + EXPAND * 2),
minY + direction.getYOffset() * (1 + EXPAND * 2),
minZ + direction.getZOffset() * (1 + EXPAND * 2)
).color( 0, 0, 0, 0.4f ).endVertex();
}
}

View File

@@ -11,6 +11,7 @@ import dan200.computercraft.shared.peripheral.modem.wired.BlockCable;
import dan200.computercraft.shared.peripheral.modem.wired.CableModemVariant;
import dan200.computercraft.shared.peripheral.modem.wired.CableShapes;
import dan200.computercraft.shared.peripheral.modem.wired.TileCable;
import dan200.computercraft.shared.util.WorldUtil;
import net.minecraft.block.Block;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.Minecraft;
@@ -25,10 +26,10 @@ import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.util.BlockRenderLayer;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.util.math.shapes.VoxelShape;
import net.minecraft.world.World;
import net.minecraftforge.client.ForgeHooksClient;
import net.minecraftforge.client.MinecraftForgeClient;
import net.minecraftforge.client.model.data.EmptyModelData;
import org.lwjgl.opengl.GL11;
import javax.annotation.Nonnull;
@@ -60,8 +61,7 @@ public class TileEntityCableRenderer extends TileEntityRenderer<TileCable>
Block block = state.getBlock();
if( block != ComputerCraft.Blocks.cable ) return;
VoxelShape shape = CableShapes.getModemShape( state );
state = te.hasModem() && shape.getBoundingBox().grow( 0.02, 0.02, 0.02 ).contains( hit.hitVec.subtract( pos.getX(), pos.getY(), pos.getZ() ) )
state = WorldUtil.isVecInside( CableShapes.getModemShape( state ), hit.hitVec.subtract( pos.getX(), pos.getY(), pos.getZ() ) )
? block.getDefaultState().with( BlockCable.MODEM, state.get( BlockCable.MODEM ) )
: state.with( BlockCable.MODEM, CableModemVariant.None );
@@ -81,7 +81,7 @@ public class TileEntityCableRenderer extends TileEntityRenderer<TileCable>
mc.getBlockRendererDispatcher().getBlockModelRenderer().renderModel(
world,
ForgeHooksClient.getDamageModel( model, breakingTexture, state, world, pos ),
state, pos, buffer, true, random, state.getPositionRandom( pos )
state, pos, buffer, true, random, state.getPositionRandom( pos ), EmptyModelData.INSTANCE
);
ForgeHooksClient.setRenderLayer( BlockRenderLayer.SOLID );

View File

@@ -31,6 +31,7 @@ import net.minecraft.util.EnumFacing;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.Vec3d;
import net.minecraftforge.client.ForgeHooksClient;
import net.minecraftforge.client.model.data.EmptyModelData;
import net.minecraftforge.client.model.pipeline.LightUtil;
import org.apache.commons.lang3.tuple.Pair;
import org.lwjgl.opengl.GL11;
@@ -197,10 +198,10 @@ public class TileEntityTurtleRenderer extends TileEntityRenderer<TileTurtle>
Random random = new Random( 0 );
Tessellator tessellator = Tessellator.getInstance();
rendererDispatcher.textureManager.bindTexture( TextureMap.LOCATION_BLOCKS_TEXTURE );
renderQuads( tessellator, model.getQuads( state, null, random ), tints );
renderQuads( tessellator, model.getQuads( state, null, random, EmptyModelData.INSTANCE ), tints );
for( EnumFacing facing : DirectionUtil.FACINGS )
{
renderQuads( tessellator, model.getQuads( state, facing, random ), tints );
renderQuads( tessellator, model.getQuads( state, facing, random, EmptyModelData.INSTANCE ), tints );
}
}

View File

@@ -70,7 +70,10 @@ public final class TurtleModelLoader implements ICustomModelLoader
{
private final ResourceLocation family;
private TurtleModel( ResourceLocation family ) {this.family = family;}
private TurtleModel( ResourceLocation family )
{
this.family = family;
}
@Nonnull
@Override

View File

@@ -9,10 +9,11 @@ package dan200.computercraft.client.render;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.renderer.model.BakedQuad;
import net.minecraft.client.renderer.model.IBakedModel;
import net.minecraft.client.renderer.model.ItemCameraTransforms;
import net.minecraft.client.renderer.model.ItemOverrideList;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.util.EnumFacing;
import net.minecraftforge.client.model.data.EmptyModelData;
import net.minecraftforge.client.model.data.IModelData;
import javax.annotation.Nonnull;
import javax.vecmath.Matrix4f;
@@ -44,7 +45,15 @@ public class TurtleMultiModel implements IBakedModel
@Nonnull
@Override
@Deprecated
public List<BakedQuad> getQuads( IBlockState state, EnumFacing side, @Nonnull Random rand )
{
return getQuads( state, side, rand, EmptyModelData.INSTANCE );
}
@Nonnull
@Override
public List<BakedQuad> getQuads( IBlockState state, EnumFacing side, @Nonnull Random rand, @Nonnull IModelData data )
{
if( side != null )
{
@@ -61,14 +70,10 @@ public class TurtleMultiModel implements IBakedModel
private List<BakedQuad> buildQuads( IBlockState state, EnumFacing side, Random rand )
{
ArrayList<BakedQuad> quads = new ArrayList<>();
ModelTransformer.transformQuadsTo( quads, m_baseModel.getQuads( state, side, rand ), m_generalTransform );
ModelTransformer.transformQuadsTo( quads, m_baseModel.getQuads( state, side, rand, EmptyModelData.INSTANCE ), m_generalTransform );
if( m_overlayModel != null )
{
ModelTransformer.transformQuadsTo( quads, m_overlayModel.getQuads( state, side, rand ), m_generalTransform );
}
if( m_overlayModel != null )
{
ModelTransformer.transformQuadsTo( quads, m_overlayModel.getQuads( state, side, rand ), m_generalTransform );
ModelTransformer.transformQuadsTo( quads, m_overlayModel.getQuads( state, side, rand, EmptyModelData.INSTANCE ), m_generalTransform );
}
if( m_leftUpgradeModel != null )
{
@@ -78,7 +83,7 @@ public class TurtleMultiModel implements IBakedModel
upgradeTransform = new Matrix4f( m_generalTransform );
upgradeTransform.mul( m_leftUpgradeTransform );
}
ModelTransformer.transformQuadsTo( quads, m_leftUpgradeModel.getQuads( state, side, rand ), upgradeTransform );
ModelTransformer.transformQuadsTo( quads, m_leftUpgradeModel.getQuads( state, side, rand, EmptyModelData.INSTANCE ), upgradeTransform );
}
if( m_rightUpgradeModel != null )
{
@@ -88,7 +93,7 @@ public class TurtleMultiModel implements IBakedModel
upgradeTransform = new Matrix4f( m_generalTransform );
upgradeTransform.mul( m_rightUpgradeTransform );
}
ModelTransformer.transformQuadsTo( quads, m_rightUpgradeModel.getQuads( state, side, rand ), upgradeTransform );
ModelTransformer.transformQuadsTo( quads, m_rightUpgradeModel.getQuads( state, side, rand, EmptyModelData.INSTANCE ), upgradeTransform );
}
quads.trimToSize();
return quads;
@@ -122,7 +127,7 @@ public class TurtleMultiModel implements IBakedModel
@Nonnull
@Override
@Deprecated
public ItemCameraTransforms getItemCameraTransforms()
public net.minecraft.client.renderer.model.ItemCameraTransforms getItemCameraTransforms()
{
return m_baseModel.getItemCameraTransforms();
}

View File

@@ -21,6 +21,7 @@ import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.ResourceLocation;
import net.minecraft.world.World;
import net.minecraftforge.client.model.data.IModelData;
import org.apache.commons.lang3.tuple.Pair;
import javax.annotation.Nonnull;
@@ -167,11 +168,20 @@ public class TurtleSmartItemModel implements IBakedModel
@Nonnull
@Override
@Deprecated
public List<BakedQuad> getQuads( IBlockState state, EnumFacing facing, @Nonnull Random rand )
{
return familyModel.getQuads( state, facing, rand );
}
@Nonnull
@Override
@Deprecated
public List<BakedQuad> getQuads( IBlockState state, EnumFacing facing, @Nonnull Random rand, @Nonnull IModelData data )
{
return familyModel.getQuads( state, facing, rand, data );
}
@Override
public boolean isAmbientOcclusion()
{

View File

@@ -6,13 +6,13 @@
package dan200.computercraft.core.apis;
import com.google.common.base.Preconditions;
import dan200.computercraft.api.lua.ILuaAPIFactory;
import javax.annotation.Nonnull;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.Objects;
public final class ApiFactories
{
@@ -25,7 +25,7 @@ public final class ApiFactories
public static synchronized void register( @Nonnull ILuaAPIFactory factory )
{
Preconditions.checkNotNull( factory, "provider cannot be null" );
Objects.requireNonNull( factory, "provider cannot be null" );
factories.add( factory );
}

View File

@@ -6,7 +6,6 @@
package dan200.computercraft.core.apis;
import com.google.common.base.Preconditions;
import dan200.computercraft.api.filesystem.IMount;
import dan200.computercraft.api.filesystem.IWritableMount;
import dan200.computercraft.api.peripheral.IComputerAccess;
@@ -121,7 +120,7 @@ public abstract class ComputerAccess implements IComputerAccess
@Override
public void queueEvent( @Nonnull final String event, final Object[] arguments )
{
Preconditions.checkNotNull( event, "event cannot be null" );
Objects.requireNonNull( event, "event cannot be null" );
m_environment.queueEvent( event, arguments );
}

View File

@@ -43,9 +43,7 @@ public class FSAPI implements ILuaAPI
@Override
public String[] getNames()
{
return new String[] {
"fs"
};
return new String[] { "fs" };
}
@Override

View File

@@ -42,9 +42,7 @@ public class HTTPAPI implements ILuaAPI
@Override
public String[] getNames()
{
return new String[] {
"http"
};
return new String[] { "http" };
}
@Override
@@ -83,6 +81,7 @@ public class HTTPAPI implements ILuaAPI
}
@Override
@SuppressWarnings( "resource" )
public Object[] callMethod( @Nonnull ILuaContext context, int method, @Nonnull Object[] args ) throws LuaException
{
switch( method )
@@ -95,7 +94,7 @@ public class HTTPAPI implements ILuaAPI
if( args.length >= 1 && args[0] instanceof Map )
{
Map<?, ?> options = (Map) args[0];
Map<?, ?> options = (Map<?, ?>) args[0];
address = getStringField( options, "url" );
postString = optStringField( options, "body", null );
headerTable = optTableField( options, "headers", Collections.emptyMap() );
@@ -135,7 +134,6 @@ public class HTTPAPI implements ILuaAPI
try
{
URI uri = HttpRequest.checkUri( address );
HttpRequest request = new HttpRequest( requests, m_apiEnvironment, address, postString, headers, binary, redirect );
long requestBody = request.body().readableBytes() + HttpRequest.getHeaderSize( headers );

View File

@@ -8,6 +8,7 @@ package dan200.computercraft.core.apis;
import dan200.computercraft.api.peripheral.IPeripheral;
import dan200.computercraft.api.peripheral.IWorkMonitor;
import dan200.computercraft.core.computer.ComputerSide;
import dan200.computercraft.core.computer.IComputerEnvironment;
import dan200.computercraft.core.filesystem.FileSystem;
import dan200.computercraft.core.terminal.Terminal;
@@ -18,16 +19,10 @@ import javax.annotation.Nullable;
public interface IAPIEnvironment
{
String[] SIDE_NAMES = new String[] {
"bottom", "top", "back", "front", "right", "left",
};
int SIDE_COUNT = 6;
@FunctionalInterface
interface IPeripheralChangeListener
{
void onPeripheralChanged( int side, @Nullable IPeripheral newPeripheral );
void onPeripheralChanged( ComputerSide side, @Nullable IPeripheral newPeripheral );
}
int getComputerID();
@@ -49,22 +44,22 @@ public interface IAPIEnvironment
void queueEvent( String event, Object[] args );
void setOutput( int side, int output );
void setOutput( ComputerSide side, int output );
int getOutput( int side );
int getOutput( ComputerSide side );
int getInput( int side );
int getInput( ComputerSide side );
void setBundledOutput( int side, int output );
void setBundledOutput( ComputerSide side, int output );
int getBundledOutput( int side );
int getBundledOutput( ComputerSide side );
int getBundledInput( int side );
int getBundledInput( ComputerSide side );
void setPeripheralChangeListener( @Nullable IPeripheralChangeListener listener );
@Nullable
IPeripheral getPeripheral( int side );
IPeripheral getPeripheral( ComputerSide side );
String getLabel();

View File

@@ -10,6 +10,7 @@ package dan200.computercraft.core.apis;
* This exists purely to ensure binary compatibility.
*
* @see dan200.computercraft.api.lua.ILuaAPI
* @deprecated Use the version in the public API. Only exists for compatibility with CCEmuX.
*/
@Deprecated
public interface ILuaAPI extends dan200.computercraft.api.lua.ILuaAPI

View File

@@ -0,0 +1,281 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.core.apis;
import dan200.computercraft.api.lua.LuaException;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatterBuilder;
import java.time.format.TextStyle;
import java.time.temporal.*;
import java.util.HashMap;
import java.util.Map;
import java.util.function.LongUnaryOperator;
final class LuaDateTime
{
private LuaDateTime()
{
}
static void format( DateTimeFormatterBuilder formatter, String format, ZoneOffset offset ) throws LuaException
{
for( int i = 0; i < format.length(); )
{
char c;
switch( c = format.charAt( i++ ) )
{
case '\n':
formatter.appendLiteral( '\n' );
break;
default:
formatter.appendLiteral( c );
break;
case '%':
if( i >= format.length() ) break;
switch( c = format.charAt( i++ ) )
{
default:
throw new LuaException( "bad argument #1: invalid conversion specifier '%" + c + "'" );
case '%':
formatter.appendLiteral( '%' );
break;
case 'a':
formatter.appendText( ChronoField.DAY_OF_WEEK, TextStyle.SHORT );
break;
case 'A':
formatter.appendText( ChronoField.DAY_OF_WEEK, TextStyle.FULL );
break;
case 'b':
case 'h':
formatter.appendText( ChronoField.MONTH_OF_YEAR, TextStyle.SHORT );
break;
case 'B':
formatter.appendText( ChronoField.MONTH_OF_YEAR, TextStyle.FULL );
break;
case 'c':
format( formatter, "%a %b %e %H:%M:%S %Y", offset );
break;
case 'C':
formatter.appendValueReduced( CENTURY, 2, 2, 0 );
break;
case 'd':
formatter.appendValue( ChronoField.DAY_OF_MONTH, 2 );
break;
case 'D':
case 'x':
format( formatter, "%m/%d/%y", offset );
break;
case 'e':
formatter.padNext( 2 ).appendValue( ChronoField.DAY_OF_MONTH );
break;
case 'F':
format( formatter, "%Y-%m-%d", offset );
break;
case 'g':
formatter.appendValueReduced( IsoFields.WEEK_BASED_YEAR, 2, 2, 0 );
break;
case 'G':
formatter.appendValue( IsoFields.WEEK_BASED_YEAR );
break;
case 'H':
formatter.appendValue( ChronoField.HOUR_OF_DAY, 2 );
break;
case 'I':
formatter.appendValue( ChronoField.HOUR_OF_AMPM );
break;
case 'j':
formatter.appendValue( ChronoField.DAY_OF_YEAR, 3 );
break;
case 'm':
formatter.appendValue( ChronoField.MONTH_OF_YEAR, 2 );
break;
case 'M':
formatter.appendValue( ChronoField.MINUTE_OF_HOUR, 2 );
break;
case 'n':
formatter.appendLiteral( '\n' );
break;
case 'p':
formatter.appendText( ChronoField.AMPM_OF_DAY );
break;
case 'r':
format( formatter, "%I:%M:%S %p", offset );
break;
case 'R':
format( formatter, "%H:%M", offset );
break;
case 'S':
formatter.appendValue( ChronoField.SECOND_OF_MINUTE, 2 );
break;
case 't':
formatter.appendLiteral( '\t' );
break;
case 'T':
case 'X':
format( formatter, "%H:%M:%S", offset );
break;
case 'u':
formatter.appendValue( ChronoField.DAY_OF_WEEK );
break;
case 'U':
formatter.appendValue( ChronoField.ALIGNED_WEEK_OF_YEAR, 2 );
break;
case 'V':
formatter.appendValue( IsoFields.WEEK_OF_WEEK_BASED_YEAR, 2 );
break;
case 'w':
formatter.appendValue( ZERO_WEEK );
break;
case 'W':
formatter.appendValue( WeekFields.ISO.weekOfYear(), 2 );
break;
case 'y':
formatter.appendValueReduced( ChronoField.YEAR, 2, 2, 0 );
break;
case 'Y':
formatter.appendValue( ChronoField.YEAR );
break;
case 'z':
formatter.appendOffset( "+HHMM", "+0000" );
break;
case 'Z':
formatter.appendChronologyId();
break;
}
}
}
}
static long fromTable( Map<?, ?> table ) throws LuaException
{
int year = getField( table, "year", -1 );
int month = getField( table, "month", -1 );
int day = getField( table, "day", -1 );
int hour = getField( table, "hour", 12 );
int minute = getField( table, "min", 12 );
int second = getField( table, "sec", 12 );
LocalDateTime time = LocalDateTime.of( year, month, day, hour, minute, second );
Boolean isDst = getBoolField( table, "isdst" );
if( isDst != null )
{
boolean requireDst = isDst;
for( ZoneOffset possibleOffset : ZoneOffset.systemDefault().getRules().getValidOffsets( time ) )
{
Instant instant = time.toInstant( possibleOffset );
if( possibleOffset.getRules().getDaylightSavings( instant ).isZero() == requireDst )
{
return instant.getEpochSecond();
}
}
}
ZoneOffset offset = ZoneOffset.systemDefault().getRules().getOffset( time );
return time.toInstant( offset ).getEpochSecond();
}
static Map<String, ?> toTable( TemporalAccessor date, ZoneId offset, Instant instant )
{
HashMap<String, Object> table = new HashMap<>( 9 );
table.put( "year", date.getLong( ChronoField.YEAR ) );
table.put( "month", date.getLong( ChronoField.MONTH_OF_YEAR ) );
table.put( "day", date.getLong( ChronoField.DAY_OF_MONTH ) );
table.put( "hour", date.getLong( ChronoField.HOUR_OF_DAY ) );
table.put( "min", date.getLong( ChronoField.MINUTE_OF_HOUR ) );
table.put( "sec", date.getLong( ChronoField.SECOND_OF_MINUTE ) );
table.put( "wday", date.getLong( WeekFields.SUNDAY_START.dayOfWeek() ) );
table.put( "yday", date.getLong( ChronoField.DAY_OF_YEAR ) );
table.put( "isdst", offset.getRules().isDaylightSavings( instant ) );
return table;
}
private static int getField( Map<?, ?> table, String field, int def ) throws LuaException
{
Object value = table.get( field );
if( value instanceof Number ) return ((Number) value).intValue();
if( def < 0 ) throw new LuaException( "field \"" + field + "\" missing in date table" );
return def;
}
private static Boolean getBoolField( Map<?, ?> table, String field ) throws LuaException
{
Object value = table.get( field );
if( value instanceof Boolean || value == null ) return (Boolean) value;
throw new LuaException( "field \"" + field + "\" missing in date table" );
}
private static final TemporalField CENTURY = map( ChronoField.YEAR, ValueRange.of( 0, 6 ), x -> (x / 100) % 100 );
private static final TemporalField ZERO_WEEK = map( WeekFields.SUNDAY_START.dayOfWeek(), ValueRange.of( 0, 6 ), x -> x - 1 );
private static TemporalField map( TemporalField field, ValueRange range, LongUnaryOperator convert )
{
return new TemporalField()
{
private final ValueRange range = ValueRange.of( 0, 99 );
@Override
public TemporalUnit getBaseUnit()
{
return field.getBaseUnit();
}
@Override
public TemporalUnit getRangeUnit()
{
return field.getRangeUnit();
}
@Override
public ValueRange range()
{
return range;
}
@Override
public boolean isDateBased()
{
return field.isDateBased();
}
@Override
public boolean isTimeBased()
{
return field.isTimeBased();
}
@Override
public boolean isSupportedBy( TemporalAccessor temporal )
{
return field.isSupportedBy( temporal );
}
@Override
public ValueRange rangeRefinedBy( TemporalAccessor temporal )
{
return range;
}
@Override
public long getFrom( TemporalAccessor temporal )
{
return convert.applyAsLong( temporal.getLong( field ) );
}
@Override
@SuppressWarnings( "unchecked" )
public <R extends Temporal> R adjustInto( R temporal, long newValue )
{
return (R) temporal.with( field, newValue );
}
};
}
}

View File

@@ -12,6 +12,11 @@ import dan200.computercraft.api.lua.LuaException;
import dan200.computercraft.shared.util.StringUtil;
import javax.annotation.Nonnull;
import java.time.Instant;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatterBuilder;
import java.util.*;
import static dan200.computercraft.core.apis.ArgumentHelper.*;
@@ -31,9 +36,9 @@ public class OSAPI implements ILuaAPI
private static class Timer
{
public int m_ticksLeft;
int m_ticksLeft;
public Timer( int ticksLeft )
Timer( int ticksLeft )
{
m_ticksLeft = ticksLeft;
}
@@ -41,10 +46,10 @@ public class OSAPI implements ILuaAPI
private static class Alarm implements Comparable<Alarm>
{
public final double m_time;
public final int m_day;
final double m_time;
final int m_day;
public Alarm( double time, int day )
Alarm( double time, int day )
{
m_time = time;
m_day = day;
@@ -73,9 +78,7 @@ public class OSAPI implements ILuaAPI
@Override
public String[] getNames()
{
return new String[] {
"os"
};
return new String[] { "os" };
}
@Override
@@ -184,11 +187,12 @@ public class OSAPI implements ILuaAPI
"day",
"cancelTimer",
"cancelAlarm",
"epoch"
"epoch",
"date",
};
}
private float getTimeForCalendar( Calendar c )
private static float getTimeForCalendar( Calendar c )
{
float time = c.get( Calendar.HOUR_OF_DAY );
time += c.get( Calendar.MINUTE ) / 60.0f;
@@ -196,7 +200,7 @@ public class OSAPI implements ILuaAPI
return time;
}
private int getDayForCalendar( Calendar c )
private static int getDayForCalendar( Calendar c )
{
GregorianCalendar g = c instanceof GregorianCalendar ? (GregorianCalendar) c : new GregorianCalendar();
int year = c.get( Calendar.YEAR );
@@ -209,7 +213,7 @@ public class OSAPI implements ILuaAPI
return day;
}
private long getEpochForCalendar( Calendar c )
private static long getEpochForCalendar( Calendar c )
{
return c.getTime().getTime();
}
@@ -282,6 +286,9 @@ public class OSAPI implements ILuaAPI
case 11:
{
// time
Object value = args.length > 0 ? args[0] : null;
if( value instanceof Map ) return new Object[] { LuaDateTime.fromTable( (Map<?, ?>) value ) };
String param = optString( args, 0, "ingame" );
switch( param.toLowerCase( Locale.ROOT ) )
{
@@ -355,9 +362,8 @@ public class OSAPI implements ILuaAPI
}
return null;
}
case 15:
case 15: // epoch
{
// epoch
String param = optString( args, 0, "ingame" );
switch( param.toLowerCase( Locale.ROOT ) )
{
@@ -377,14 +383,39 @@ public class OSAPI implements ILuaAPI
// Get in-game epoch
synchronized( m_alarms )
{
return new Object[] {
m_day * 86400000 + (int) (m_time * 3600000.0f)
};
return new Object[] { m_day * 86400000 + (int) (m_time * 3600000.0f) };
}
default:
throw new LuaException( "Unsupported operation" );
}
}
case 16: // date
{
String format = optString( args, 0, "%c" );
long time = optLong( args, 1, Instant.now().getEpochSecond() );
Instant instant = Instant.ofEpochSecond( time );
ZonedDateTime date;
ZoneOffset offset;
if( format.startsWith( "!" ) )
{
offset = ZoneOffset.UTC;
date = ZonedDateTime.ofInstant( instant, offset );
format = format.substring( 1 );
}
else
{
ZoneId id = ZoneId.systemDefault();
offset = id.getRules().getOffset( instant );
date = ZonedDateTime.ofInstant( instant, id );
}
if( format.equals( "*t" ) ) return new Object[] { LuaDateTime.toTable( date, offset, instant ) };
DateTimeFormatterBuilder formatter = new DateTimeFormatterBuilder();
LuaDateTime.format( formatter, format, offset );
return new Object[] { formatter.toFormatter( Locale.ROOT ).format( date ) };
}
default:
return null;
}

View File

@@ -12,6 +12,7 @@ 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.ComputerSide;
import dan200.computercraft.core.tracking.TrackingField;
import javax.annotation.Nonnull;
@@ -35,7 +36,7 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange
private Map<String, Integer> m_methodMap;
private boolean m_attached;
public PeripheralWrapper( IPeripheral peripheral, String side )
PeripheralWrapper( IPeripheral peripheral, String side )
{
super( m_environment );
m_side = side;
@@ -245,32 +246,33 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange
// IPeripheralChangeListener
@Override
public void onPeripheralChanged( int side, IPeripheral newPeripheral )
public void onPeripheralChanged( ComputerSide side, IPeripheral newPeripheral )
{
synchronized( m_peripherals )
{
if( m_peripherals[side] != null )
int index = side.ordinal();
if( m_peripherals[index] != null )
{
// Queue a detachment
final PeripheralWrapper wrapper = m_peripherals[side];
final PeripheralWrapper wrapper = m_peripherals[index];
if( wrapper.isAttached() ) wrapper.detach();
// Queue a detachment event
m_environment.queueEvent( "peripheral_detach", new Object[] { IAPIEnvironment.SIDE_NAMES[side] } );
m_environment.queueEvent( "peripheral_detach", new Object[] { side.getName() } );
}
// Assign the new peripheral
m_peripherals[side] = newPeripheral == null ? null
: new PeripheralWrapper( newPeripheral, IAPIEnvironment.SIDE_NAMES[side] );
m_peripherals[index] = newPeripheral == null ? null
: new PeripheralWrapper( newPeripheral, side.getName() );
if( m_peripherals[side] != null )
if( m_peripherals[index] != null )
{
// Queue an attachment
final PeripheralWrapper wrapper = m_peripherals[side];
final PeripheralWrapper wrapper = m_peripherals[index];
if( m_running && !wrapper.isAttached() ) wrapper.attach();
// Queue an attachment event
m_environment.queueEvent( "peripheral", new Object[] { IAPIEnvironment.SIDE_NAMES[side] } );
m_environment.queueEvent( "peripheral", new Object[] { side.getName() } );
}
}
}
@@ -280,9 +282,7 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange
@Override
public String[] getNames()
{
return new String[] {
"peripheral"
};
return new String[] { "peripheral" };
}
@Override
@@ -324,7 +324,7 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange
"isPresent",
"getType",
"getMethods",
"call"
"call",
};
}
@@ -337,16 +337,13 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange
{
// isPresent
boolean present = false;
int side = parseSide( args );
if( side >= 0 )
ComputerSide side = ComputerSide.valueOfInsensitive( getString( args, 0 ) );
if( side != null )
{
synchronized( m_peripherals )
{
PeripheralWrapper p = m_peripherals[side];
if( p != null )
{
present = true;
}
PeripheralWrapper p = m_peripherals[side.ordinal()];
if( p != null ) present = true;
}
}
return new Object[] { present };
@@ -354,21 +351,13 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange
case 1:
{
// getType
String type = null;
int side = parseSide( args );
if( side >= 0 )
ComputerSide side = ComputerSide.valueOfInsensitive( getString( args, 0 ) );
if( side != null )
{
synchronized( m_peripherals )
{
PeripheralWrapper p = m_peripherals[side];
if( p != null )
{
type = p.getType();
}
}
if( type != null )
{
return new Object[] { type };
PeripheralWrapper p = m_peripherals[side.ordinal()];
if( p != null ) return new Object[] { p.getType() };
}
}
return null;
@@ -377,12 +366,12 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange
{
// getMethods
String[] methods = null;
int side = parseSide( args );
if( side >= 0 )
ComputerSide side = ComputerSide.valueOfInsensitive( getString( args, 0 ) );
if( side != null )
{
synchronized( m_peripherals )
{
PeripheralWrapper p = m_peripherals[side];
PeripheralWrapper p = m_peripherals[side.ordinal()];
if( p != null )
{
methods = p.getMethods();
@@ -403,16 +392,16 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange
case 3:
{
// call
int side = parseSide( args );
ComputerSide side = ComputerSide.valueOfInsensitive( getString( args, 0 ) );
String methodName = getString( args, 1 );
Object[] methodArgs = Arrays.copyOfRange( args, 2, args.length );
if( side >= 0 )
if( side != null )
{
PeripheralWrapper p;
synchronized( m_peripherals )
{
p = m_peripherals[side];
p = m_peripherals[side.ordinal()];
}
if( p != null )
{
@@ -425,19 +414,4 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange
return null;
}
}
// Privates
private int parseSide( Object[] args ) throws LuaException
{
String side = getString( args, 0 );
for( int n = 0; n < IAPIEnvironment.SIDE_NAMES.length; n++ )
{
if( side.equals( IAPIEnvironment.SIDE_NAMES[n] ) )
{
return n;
}
}
return -1;
}
}

View File

@@ -9,6 +9,7 @@ package dan200.computercraft.core.apis;
import dan200.computercraft.api.lua.ILuaAPI;
import dan200.computercraft.api.lua.ILuaContext;
import dan200.computercraft.api.lua.LuaException;
import dan200.computercraft.core.computer.ComputerSide;
import javax.annotation.Nonnull;
import java.util.HashMap;
@@ -28,9 +29,7 @@ public class RedstoneAPI implements ILuaAPI
@Override
public String[] getNames()
{
return new String[] {
"rs", "redstone"
};
return new String[] { "rs", "redstone" };
}
@Nonnull
@@ -64,56 +63,40 @@ public class RedstoneAPI implements ILuaAPI
{
// getSides
Map<Object, Object> table = new HashMap<>();
for( int i = 0; i < IAPIEnvironment.SIDE_NAMES.length; i++ )
for( int i = 0; i < ComputerSide.NAMES.length; i++ )
{
table.put( i + 1, IAPIEnvironment.SIDE_NAMES[i] );
table.put( i + 1, ComputerSide.NAMES[i] );
}
return new Object[] { table };
}
case 1:
{
// setOutput
int side = parseSide( args );
ComputerSide side = parseSide( args );
boolean output = getBoolean( args, 1 );
m_environment.setOutput( side, output ? 15 : 0 );
return null;
}
case 2:
{
// getOutput
int side = parseSide( args );
return new Object[] { m_environment.getOutput( side ) > 0 };
}
case 3:
{
// getInput
int side = parseSide( args );
return new Object[] { m_environment.getInput( side ) > 0 };
}
case 2: // getOutput
return new Object[] { m_environment.getOutput( parseSide( args ) ) > 0 };
case 3: // getInput
return new Object[] { m_environment.getInput( parseSide( args ) ) > 0 };
case 4:
{
// setBundledOutput
int side = parseSide( args );
ComputerSide side = parseSide( args );
int output = getInt( args, 1 );
m_environment.setBundledOutput( side, output );
return null;
}
case 5:
{
// getBundledOutput
int side = parseSide( args );
return new Object[] { m_environment.getBundledOutput( side ) };
}
case 6:
{
// getBundledInput
int side = parseSide( args );
return new Object[] { m_environment.getBundledInput( side ) };
}
case 5: // getBundledOutput
return new Object[] { m_environment.getBundledOutput( parseSide( args ) ) };
case 6: // getBundledInput
return new Object[] { m_environment.getBundledInput( parseSide( args ) ) };
case 7:
{
// testBundledInput
int side = parseSide( args );
ComputerSide side = parseSide( args );
int mask = getInt( args, 1 );
int input = m_environment.getBundledInput( side );
return new Object[] { (input & mask) == mask };
@@ -122,7 +105,7 @@ public class RedstoneAPI implements ILuaAPI
case 9:
{
// setAnalogOutput/setAnalogueOutput
int side = parseSide( args );
ComputerSide side = parseSide( args );
int output = getInt( args, 1 );
if( output < 0 || output > 15 )
{
@@ -132,34 +115,20 @@ public class RedstoneAPI implements ILuaAPI
return null;
}
case 10:
case 11:
{
// getAnalogOutput/getAnalogueOutput
int side = parseSide( args );
return new Object[] { m_environment.getOutput( side ) };
}
case 11: // getAnalogOutput/getAnalogueOutput
return new Object[] { m_environment.getOutput( parseSide( args ) ) };
case 12:
case 13:
{
// getAnalogInput/getAnalogueInput
int side = parseSide( args );
return new Object[] { m_environment.getInput( side ) };
}
case 13: // getAnalogInput/getAnalogueInput
return new Object[] { m_environment.getInput( parseSide( args ) ) };
default:
return null;
}
}
private static int parseSide( Object[] args ) throws LuaException
private static ComputerSide parseSide( Object[] args ) throws LuaException
{
String side = getString( args, 0 );
for( int n = 0; n < IAPIEnvironment.SIDE_NAMES.length; n++ )
{
if( side.equals( IAPIEnvironment.SIDE_NAMES[n] ) )
{
return n;
}
}
throw new LuaException( "Invalid side." );
ComputerSide side = ComputerSide.valueOfInsensitive( getString( args, 0 ) );
if( side == null ) throw new LuaException( "Invalid side." );
return side;
}
}

View File

@@ -33,9 +33,7 @@ public class TermAPI implements ILuaAPI
@Override
public String[] getNames()
{
return new String[] {
"term"
};
return new String[] { "term" };
}
@Nonnull
@@ -89,9 +87,7 @@ public class TermAPI implements ILuaAPI
public static Object[] encodeColour( int colour ) throws LuaException
{
return new Object[] {
1 << colour
};
return new Object[] { 1 << colour };
}
public static void setColour( Terminal terminal, int colour, double r, double g, double b )

View File

@@ -212,6 +212,7 @@ public class BinaryReadableHandle extends HandleGeneric
}
}
case 3: // close
checkOpen();
close();
return null;
case 4: // seek

View File

@@ -95,6 +95,7 @@ public class BinaryWritableHandle extends HandleGeneric
return null;
}
case 2: // close
checkOpen();
close();
return null;
case 3: // seek

View File

@@ -152,6 +152,7 @@ public class EncodedReadableHandle extends HandleGeneric
return null;
}
case 3: // close
checkOpen();
close();
return null;
default:

View File

@@ -93,6 +93,7 @@ public class EncodedWritableHandle extends HandleGeneric
return null;
}
case 3: // close
checkOpen();
close();
return null;
default:

View File

@@ -37,8 +37,13 @@ public abstract class HandleGeneric implements ILuaObject
protected final void close()
{
m_open = false;
IoUtil.closeQuietly( m_closable );
m_closable = null;
Closeable closeable = m_closable;
if( closeable != null )
{
IoUtil.closeQuietly( closeable );
m_closable = null;
}
}
/**

View File

@@ -72,7 +72,8 @@ public abstract class Resource<T extends Resource<T>> implements Closeable
*/
protected void dispose()
{
@SuppressWarnings( "unchecked" ) T thisT = (T) this;
@SuppressWarnings( "unchecked" )
T thisT = (T) this;
limiter.release( thisT );
}
@@ -95,7 +96,8 @@ public abstract class Resource<T extends Resource<T>> implements Closeable
public boolean queue( Consumer<T> task )
{
@SuppressWarnings( "unchecked" ) T thisT = (T) this;
@SuppressWarnings( "unchecked" )
T thisT = (T) this;
return limiter.queue( thisT, () -> task.accept( thisT ) );
}

View File

@@ -24,6 +24,7 @@ import java.io.Closeable;
import java.util.Arrays;
import static dan200.computercraft.core.apis.ArgumentHelper.optBoolean;
import static dan200.computercraft.core.apis.http.websocket.Websocket.CLOSE_EVENT;
import static dan200.computercraft.core.apis.http.websocket.Websocket.MESSAGE_EVENT;
public class WebsocketHandle implements ILuaObject, Closeable
@@ -53,15 +54,18 @@ public class WebsocketHandle implements ILuaObject, Closeable
switch( method )
{
case 0: // receive
checkOpen();
while( true )
{
checkOpen();
Object[] event = context.pullEvent( MESSAGE_EVENT );
if( event.length >= 3 && Objects.equal( event[1], websocket.address() ) )
Object[] event = context.pullEvent( null );
if( event.length >= 3 && Objects.equal( event[0], MESSAGE_EVENT ) && Objects.equal( event[1], websocket.address() ) )
{
return Arrays.copyOfRange( event, 2, event.length );
}
else if( event.length >= 2 && Objects.equal( event[0], CLOSE_EVENT ) && Objects.equal( event[1], websocket.address() ) && closed )
{
return null;
}
}
case 1: // send

View File

@@ -338,7 +338,7 @@ final class ComputerExecutor
}
}
private FileSystem createFileSystem()
IWritableMount getRootMount()
{
if( rootMount == null )
{
@@ -347,11 +347,15 @@ final class ComputerExecutor
computer.getComputerEnvironment().getComputerSpaceLimit()
);
}
return rootMount;
}
private FileSystem createFileSystem()
{
FileSystem filesystem = null;
try
{
filesystem = new FileSystem( "hdd", rootMount );
filesystem = new FileSystem( "hdd", getRootMount() );
IMount romMount = getRomMount();
if( romMount == null )

View File

@@ -0,0 +1,59 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.core.computer;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/**
* A side on a computer. Unlike {@link net.minecraft.util.EnumFacing}, this is relative to the direction the computer is
* facing..
*/
public enum ComputerSide
{
BOTTOM( "bottom" ),
TOP( "top" ),
BACK( "back" ),
FRONT( "front" ),
RIGHT( "right" ),
LEFT( "left" );
public static final String[] NAMES = new String[] { "bottom", "top", "back", "front", "right", "left" };
public static final int COUNT = 6;
private static final ComputerSide[] VALUES = values();
private final String name;
ComputerSide( String name )
{
this.name = name;
}
@Nonnull
public static ComputerSide valueOf( int side )
{
return VALUES[side];
}
@Nullable
public static ComputerSide valueOfInsensitive( @Nonnull String name )
{
for( ComputerSide side : VALUES )
{
if( side.name.equalsIgnoreCase( name ) ) return side;
}
return null;
}
public String getName()
{
return name;
}
}

View File

@@ -26,12 +26,12 @@ import javax.annotation.Nullable;
*/
public class ComputerSystem extends ComputerAccess implements IComputerSystem
{
private final IAPIEnvironment m_environment;
private final IAPIEnvironment environment;
ComputerSystem( IAPIEnvironment environment )
{
super( environment );
this.m_environment = environment;
this.environment = environment;
}
@Nonnull
@@ -45,7 +45,7 @@ public class ComputerSystem extends ComputerAccess implements IComputerSystem
@Override
public IFileSystem getFileSystem()
{
FileSystem fs = m_environment.getFileSystem();
FileSystem fs = environment.getFileSystem();
return fs == null ? null : fs.getMountWrapper();
}
@@ -53,6 +53,6 @@ public class ComputerSystem extends ComputerAccess implements IComputerSystem
@Override
public String getLabel()
{
return m_environment.getLabel();
return environment.getLabel();
}
}

View File

@@ -133,7 +133,6 @@ public final class ComputerThread
synchronized( threadLock )
{
running = true;
if( monitor == null || !monitor.isAlive() ) (monitor = monitorFactory.newThread( new Monitor() )).start();
if( runners == null )
{
@@ -158,6 +157,8 @@ public final class ComputerThread
runnerFactory.newThread( runners[i] = new TaskRunner() ).start();
}
}
if( monitor == null || !monitor.isAlive() ) (monitor = monitorFactory.newThread( new Monitor() )).start();
}
}
@@ -368,7 +369,16 @@ public final class ComputerThread
{
TaskRunner runner = currentRunners[i];
// If we've no runner, skip.
if( runner == null ) continue;
if( runner == null || runner.owner == null || !runner.owner.isAlive() )
{
if( !running ) continue;
// Mark the old runner as dead and start a new one.
ComputerCraft.log.warn( "Previous runner ({}) has crashed, restarting!",
runner != null && runner.owner != null ? runner.owner.getName() : runner );
if( runner != null ) runner.running = false;
runnerFactory.newThread( runners[i] = new TaskRunner() ).start();
}
// If the runner has no work, skip
ComputerExecutor executor = runner.currentExecutor.get();
@@ -492,7 +502,7 @@ public final class ComputerThread
{
executor.work();
}
catch( Exception e )
catch( Exception | LinkageError | VirtualMachineError e )
{
ComputerCraft.log.error( "Error running task on computer #" + executor.getComputer().getID(), e );
}

View File

@@ -41,17 +41,17 @@ public final class Environment implements IAPIEnvironment
private final Computer computer;
private boolean internalOutputChanged = false;
private final int[] internalOutput = new int[SIDE_COUNT];
private final int[] internalBundledOutput = new int[SIDE_COUNT];
private final int[] internalOutput = new int[ComputerSide.COUNT];
private final int[] internalBundledOutput = new int[ComputerSide.COUNT];
private final int[] externalOutput = new int[SIDE_COUNT];
private final int[] externalBundledOutput = new int[SIDE_COUNT];
private final int[] externalOutput = new int[ComputerSide.COUNT];
private final int[] externalBundledOutput = new int[ComputerSide.COUNT];
private boolean inputChanged = false;
private final int[] input = new int[SIDE_COUNT];
private final int[] bundledInput = new int[SIDE_COUNT];
private final int[] input = new int[ComputerSide.COUNT];
private final int[] bundledInput = new int[ComputerSide.COUNT];
private final IPeripheral[] peripherals = new IPeripheral[SIDE_COUNT];
private final IPeripheral[] peripherals = new IPeripheral[ComputerSide.COUNT];
private IPeripheralChangeListener peripheralListener = null;
Environment( Computer computer )
@@ -111,85 +111,89 @@ public final class Environment implements IAPIEnvironment
}
@Override
public int getInput( int side )
public int getInput( ComputerSide side )
{
return input[side];
return input[side.ordinal()];
}
@Override
public int getBundledInput( int side )
public int getBundledInput( ComputerSide side )
{
return bundledInput[side];
return bundledInput[side.ordinal()];
}
@Override
public void setOutput( int side, int output )
public void setOutput( ComputerSide side, int output )
{
int index = side.ordinal();
synchronized( internalOutput )
{
if( internalOutput[side] != output )
if( internalOutput[index] != output )
{
internalOutput[side] = output;
internalOutput[index] = output;
internalOutputChanged = true;
}
}
}
@Override
public int getOutput( int side )
public int getOutput( ComputerSide side )
{
synchronized( internalOutput )
{
return computer.isOn() ? internalOutput[side] : 0;
return computer.isOn() ? internalOutput[side.ordinal()] : 0;
}
}
@Override
public void setBundledOutput( int side, int output )
public void setBundledOutput( ComputerSide side, int output )
{
int index = side.ordinal();
synchronized( internalOutput )
{
if( internalBundledOutput[side] != output )
if( internalBundledOutput[index] != output )
{
internalBundledOutput[side] = output;
internalBundledOutput[index] = output;
internalOutputChanged = true;
}
}
}
@Override
public int getBundledOutput( int side )
public int getBundledOutput( ComputerSide side )
{
synchronized( internalOutput )
{
return computer.isOn() ? internalBundledOutput[side] : 0;
return computer.isOn() ? internalBundledOutput[side.ordinal()] : 0;
}
}
public int getExternalRedstoneOutput( int side )
public int getExternalRedstoneOutput( ComputerSide side )
{
return computer.isOn() ? externalOutput[side] : 0;
return computer.isOn() ? externalOutput[side.ordinal()] : 0;
}
public int getExternalBundledRedstoneOutput( int side )
public int getExternalBundledRedstoneOutput( ComputerSide side )
{
return computer.isOn() ? externalBundledOutput[side] : 0;
return computer.isOn() ? externalBundledOutput[side.ordinal()] : 0;
}
public void setRedstoneInput( int side, int level )
public void setRedstoneInput( ComputerSide side, int level )
{
if( input[side] != level )
int index = side.ordinal();
if( input[index] != level )
{
input[side] = level;
input[index] = level;
inputChanged = true;
}
}
public void setBundledRedstoneInput( int side, int combination )
public void setBundledRedstoneInput( ComputerSide side, int combination )
{
if( bundledInput[side] != combination )
int index = side.ordinal();
if( bundledInput[index] != combination )
{
bundledInput[side] = combination;
bundledInput[index] = combination;
inputChanged = true;
}
}
@@ -222,7 +226,7 @@ public final class Environment implements IAPIEnvironment
boolean changed = false;
for( int i = 0; i < SIDE_COUNT; i++ )
for( int i = 0; i < ComputerSide.COUNT; i++ )
{
if( externalOutput[i] != internalOutput[i] )
{
@@ -255,24 +259,25 @@ public final class Environment implements IAPIEnvironment
}
@Override
public IPeripheral getPeripheral( int side )
public IPeripheral getPeripheral( ComputerSide side )
{
synchronized( peripherals )
{
return peripherals[side];
return peripherals[side.ordinal()];
}
}
public void setPeripheral( int side, IPeripheral peripheral )
public void setPeripheral( ComputerSide side, IPeripheral peripheral )
{
synchronized( peripherals )
{
IPeripheral existing = peripherals[side];
int index = side.ordinal();
IPeripheral existing = peripherals[index];
if( (existing == null && peripheral != null) ||
(existing != null && peripheral == null) ||
(existing != null && !existing.equals( peripheral )) )
{
peripherals[side] = peripheral;
peripherals[index] = peripheral;
if( peripheralListener != null ) peripheralListener.onPeripheralChanged( side, peripheral );
}
}

View File

@@ -134,7 +134,7 @@ public final class MainThread
// Of course, we'll go over the MAX_TICK_TIME most of the time, but eventually that overrun will accumulate
// and we'll skip a whole tick - bringing the average back down again.
currentTick++;
budget += Math.min( budget + ComputerCraft.maxMainGlobalTime, ComputerCraft.maxMainGlobalTime );
budget = Math.min( budget + ComputerCraft.maxMainGlobalTime, ComputerCraft.maxMainGlobalTime );
canExecute = budget > 0;
// Cool down any warm computers.

View File

@@ -224,7 +224,7 @@ final class MainThreadExecutor implements IWorkMonitor
{
state = State.COOLING;
currentTick = MainThread.currentTick();
budget += Math.min( budget + ComputerCraft.maxMainComputerTime, ComputerCraft.maxMainComputerTime );
budget = Math.min( budget + ComputerCraft.maxMainComputerTime, ComputerCraft.maxMainComputerTime );
if( budget < ComputerCraft.maxMainComputerTime ) return false;
state = State.COOL;

View File

@@ -6,6 +6,7 @@
package dan200.computercraft.core.filesystem;
import dan200.computercraft.api.filesystem.FileOperationException;
import dan200.computercraft.api.filesystem.IMount;
import javax.annotation.Nonnull;
@@ -95,7 +96,7 @@ public class ComboMount implements IMount
}
else
{
throw new IOException( "/" + path + ": Not a directory" );
throw new FileOperationException( path, "Not a directory" );
}
}
@@ -110,7 +111,7 @@ public class ComboMount implements IMount
return part.getSize( path );
}
}
throw new IOException( "/" + path + ": No such file" );
throw new FileOperationException( path, "No such file" );
}
@Nonnull
@@ -126,7 +127,7 @@ public class ComboMount implements IMount
return part.openForRead( path );
}
}
throw new IOException( "/" + path + ": No such file" );
throw new FileOperationException( path, "No such file" );
}
@Nonnull
@@ -141,6 +142,6 @@ public class ComboMount implements IMount
return part.openChannelForRead( path );
}
}
throw new IOException( "/" + path + ": No such file" );
throw new FileOperationException( path, "No such file" );
}
}

View File

@@ -6,6 +6,7 @@
package dan200.computercraft.core.filesystem;
import dan200.computercraft.api.filesystem.FileOperationException;
import dan200.computercraft.api.filesystem.IMount;
import javax.annotation.Nonnull;
@@ -44,7 +45,7 @@ public class EmptyMount implements IMount
@Deprecated
public InputStream openForRead( @Nonnull String path ) throws IOException
{
throw new IOException( "/" + path + ": No such file" );
throw new FileOperationException( path, "No such file" );
}
@Nonnull
@@ -52,6 +53,6 @@ public class EmptyMount implements IMount
@Deprecated
public ReadableByteChannel openChannelForRead( @Nonnull String path ) throws IOException
{
throw new IOException( "/" + path + ": No such file" );
throw new FileOperationException( path, "No such file" );
}
}

View File

@@ -7,6 +7,7 @@
package dan200.computercraft.core.filesystem;
import com.google.common.collect.Sets;
import dan200.computercraft.api.filesystem.FileOperationException;
import dan200.computercraft.api.filesystem.IWritableMount;
import javax.annotation.Nonnull;
@@ -167,12 +168,12 @@ public class FileMount implements IWritableMount
{
if( !created() )
{
if( !path.isEmpty() ) throw new IOException( "/" + path + ": Not a directory" );
if( !path.isEmpty() ) throw new FileOperationException( path, "Not a directory" );
return;
}
File file = getRealPath( path );
if( !file.exists() || !file.isDirectory() ) throw new IOException( "/" + path + ": Not a directory" );
if( !file.exists() || !file.isDirectory() ) throw new FileOperationException( path, "Not a directory" );
String[] paths = file.list();
for( String subPath : paths )
@@ -194,7 +195,7 @@ public class FileMount implements IWritableMount
if( file.exists() ) return file.isDirectory() ? 0 : file.length();
}
throw new IOException( "/" + path + ": No such file" );
throw new FileOperationException( path, "No such file" );
}
@Nonnull
@@ -208,7 +209,7 @@ public class FileMount implements IWritableMount
if( file.exists() && !file.isDirectory() ) return new FileInputStream( file );
}
throw new IOException( "/" + path + ": No such file" );
throw new FileOperationException( path, "No such file" );
}
@Nonnull
@@ -221,7 +222,7 @@ public class FileMount implements IWritableMount
if( file.exists() && !file.isDirectory() ) return FileChannel.open( file.toPath(), READ_OPTIONS );
}
throw new IOException( "/" + path + ": No such file" );
throw new FileOperationException( path, "No such file" );
}
// IWritableMount implementation
@@ -233,7 +234,7 @@ public class FileMount implements IWritableMount
File file = getRealPath( path );
if( file.exists() )
{
if( !file.isDirectory() ) throw new IOException( "/" + path + ": File exists" );
if( !file.isDirectory() ) throw new FileOperationException( path, "File exists" );
return;
}
@@ -247,7 +248,7 @@ public class FileMount implements IWritableMount
if( getRemainingSpace() < dirsToCreate * MINIMUM_FILE_SIZE )
{
throw new IOException( "/" + path + ": Out of space" );
throw new FileOperationException( path, "Out of space" );
}
if( file.mkdirs() )
@@ -256,14 +257,14 @@ public class FileMount implements IWritableMount
}
else
{
throw new IOException( "/" + path + ": Access denied" );
throw new FileOperationException( path, "Access denied" );
}
}
@Override
public void delete( @Nonnull String path ) throws IOException
{
if( path.isEmpty() ) throw new IOException( "/" + path + ": Access denied" );
if( path.isEmpty() ) throw new FileOperationException( path, "Access denied" );
if( created() )
{
@@ -319,7 +320,7 @@ public class FileMount implements IWritableMount
{
create();
File file = getRealPath( path );
if( file.exists() && file.isDirectory() ) throw new IOException( "/" + path + ": Cannot write to directory" );
if( file.exists() && file.isDirectory() ) throw new FileOperationException( path, "Cannot write to directory" );
if( file.exists() )
{
@@ -327,7 +328,7 @@ public class FileMount implements IWritableMount
}
else if( getRemainingSpace() < MINIMUM_FILE_SIZE )
{
throw new IOException( "/" + path + ": Out of space" );
throw new FileOperationException( path, "Out of space" );
}
m_usedSpace += MINIMUM_FILE_SIZE;
@@ -340,12 +341,12 @@ public class FileMount implements IWritableMount
{
if( !created() )
{
throw new IOException( "/" + path + ": No such file" );
throw new FileOperationException( path, "No such file" );
}
File file = getRealPath( path );
if( !file.exists() ) throw new IOException( "/" + path + ": No such file" );
if( file.isDirectory() ) throw new IOException( "/" + path + ": Cannot write to directory" );
if( !file.exists() ) throw new FileOperationException( path, "No such file" );
if( file.isDirectory() ) throw new FileOperationException( path, "Cannot write to directory" );
// Allowing seeking when appending is not recommended, so we use a separate channel.
return new WritableCountingChannel(

View File

@@ -8,6 +8,7 @@ package dan200.computercraft.core.filesystem;
import com.google.common.io.ByteStreams;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.api.filesystem.FileOperationException;
import dan200.computercraft.api.filesystem.IFileSystem;
import dan200.computercraft.api.filesystem.IMount;
import dan200.computercraft.api.filesystem.IWritableMount;
@@ -45,7 +46,7 @@ public class FileSystem
m_writableMount = null;
}
public MountWrapper( String label, String location, IWritableMount mount )
MountWrapper( String label, String location, IWritableMount mount )
{
this( label, location, (IMount) mount );
m_writableMount = mount;
@@ -107,7 +108,7 @@ public class FileSystem
}
catch( IOException e )
{
throw new FileSystemException( e.getMessage() );
throw localExceptionOf( e );
}
}
@@ -122,12 +123,12 @@ public class FileSystem
}
else
{
throw new FileSystemException( "/" + path + ": Not a directory" );
throw localExceptionOf( path, "Not a directory" );
}
}
catch( IOException e )
{
throw new FileSystemException( e.getMessage() );
throw localExceptionOf( e );
}
}
@@ -149,12 +150,12 @@ public class FileSystem
}
else
{
throw new FileSystemException( "/" + path + ": No such file" );
throw localExceptionOf( path, "No such file" );
}
}
catch( IOException e )
{
throw new FileSystemException( e.getMessage() );
throw localExceptionOf( e );
}
}
@@ -169,12 +170,12 @@ public class FileSystem
}
else
{
throw new FileSystemException( "/" + path + ": No such file" );
throw localExceptionOf( path, "No such file" );
}
}
catch( IOException e )
{
throw new FileSystemException( e.getMessage() );
throw localExceptionOf( e );
}
}
@@ -182,19 +183,14 @@ public class FileSystem
public void makeDirectory( String path ) throws FileSystemException
{
if( m_writableMount == null )
{
throw new FileSystemException( "/" + path + ": Access denied" );
}
if( m_writableMount == null ) throw exceptionOf( path, "Access denied" );
path = toLocal( path );
try
{
path = toLocal( path );
if( m_mount.exists( path ) )
{
if( !m_mount.isDirectory( path ) )
{
throw new FileSystemException( "/" + path + ": File exists" );
}
if( !m_mount.isDirectory( path ) ) throw localExceptionOf( path, "File exists" );
}
else
{
@@ -203,16 +199,14 @@ public class FileSystem
}
catch( IOException e )
{
throw new FileSystemException( e.getMessage() );
throw localExceptionOf( e );
}
}
public void delete( String path ) throws FileSystemException
{
if( m_writableMount == null )
{
throw new FileSystemException( "/" + path + ": Access denied" );
}
if( m_writableMount == null ) throw exceptionOf( path, "Access denied" );
try
{
path = toLocal( path );
@@ -227,22 +221,20 @@ public class FileSystem
}
catch( IOException e )
{
throw new FileSystemException( e.getMessage() );
throw localExceptionOf( e );
}
}
public WritableByteChannel openForWrite( String path ) throws FileSystemException
{
if( m_writableMount == null )
{
throw new FileSystemException( "/" + path + ": Access denied" );
}
if( m_writableMount == null ) throw exceptionOf( path, "Access denied" );
path = toLocal( path );
try
{
path = toLocal( path );
if( m_mount.exists( path ) && m_mount.isDirectory( path ) )
{
throw new FileSystemException( "/" + path + ": Cannot write to directory" );
throw localExceptionOf( path, "Cannot write to directory" );
}
else
{
@@ -263,19 +255,17 @@ public class FileSystem
}
catch( IOException e )
{
throw new FileSystemException( e.getMessage() );
throw localExceptionOf( e );
}
}
public WritableByteChannel openForAppend( String path ) throws FileSystemException
{
if( m_writableMount == null )
{
throw new FileSystemException( "/" + path + ": Access denied" );
}
if( m_writableMount == null ) throw exceptionOf( path, "Access denied" );
path = toLocal( path );
try
{
path = toLocal( path );
if( !m_mount.exists( path ) )
{
if( !path.isEmpty() )
@@ -290,7 +280,7 @@ public class FileSystem
}
else if( m_mount.isDirectory( path ) )
{
throw new FileSystemException( "/" + path + ": Cannot write to directory" );
throw localExceptionOf( path, "Cannot write to directory" );
}
else
{
@@ -303,16 +293,36 @@ public class FileSystem
}
catch( IOException e )
{
throw new FileSystemException( e.getMessage() );
throw localExceptionOf( e );
}
}
// private members
private String toLocal( String path )
{
return FileSystem.toLocal( path, m_location );
}
private FileSystemException localExceptionOf( IOException e )
{
if( !m_location.isEmpty() && e instanceof FileOperationException )
{
FileOperationException ex = (FileOperationException) e;
if( ex.getFilename() != null ) return localExceptionOf( ex.getFilename(), ex.getMessage() );
}
return new FileSystemException( e.getMessage() );
}
private FileSystemException localExceptionOf( String path, String message )
{
if( !m_location.isEmpty() ) path = path.isEmpty() ? m_location : m_location + "/" + path;
return exceptionOf( path, message );
}
private static FileSystemException exceptionOf( String path, String message )
{
return new FileSystemException( "/" + path + ": " + message );
}
}
private final FileSystemWrapperMount m_wrapper = new FileSystemWrapperMount( this );
@@ -769,7 +779,7 @@ public class FileSystem
// Clean the path or illegal characters.
final char[] specialChars = new char[] {
'"', ':', '<', '>', '?', '|' // Sorted by ascii value (important)
'"', ':', '<', '>', '?', '|', // Sorted by ascii value (important)
};
StringBuilder cleanName = new StringBuilder();

View File

@@ -9,6 +9,7 @@ package dan200.computercraft.core.filesystem;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.io.ByteStreams;
import dan200.computercraft.api.filesystem.FileOperationException;
import dan200.computercraft.api.filesystem.IMount;
import dan200.computercraft.core.apis.handles.ArrayByteChannel;
import dan200.computercraft.shared.util.IoUtil;
@@ -69,7 +70,7 @@ public class JarMount implements IMount
// Cleanup any old mounts. It's unlikely that there will be any, but it's best to be safe.
cleanup();
if( !jarFile.exists() || jarFile.isDirectory() ) throw new FileNotFoundException();
if( !jarFile.exists() || jarFile.isDirectory() ) throw new FileNotFoundException( "Cannot find " + jarFile );
// Open the zip file
try
@@ -85,14 +86,14 @@ public class JarMount implements IMount
if( zip.getEntry( subPath ) == null )
{
zip.close();
throw new IOException( "Zip does not contain path" );
throw new FileNotFoundException( "Zip does not contain path" );
}
// We now create a weak reference to this mount. This is automatically added to the appropriate queue.
new MountReference( this );
// Read in all the entries
root = new FileEntry( "" );
root = new FileEntry();
Enumeration<? extends ZipEntry> zipEntries = zip.entries();
while( zipEntries.hasMoreElements() )
{
@@ -139,7 +140,7 @@ public class JarMount implements IMount
FileEntry nextEntry = lastEntry.children.get( part );
if( nextEntry == null || !nextEntry.isDirectory() )
{
lastEntry.children.put( part, nextEntry = new FileEntry( part ) );
lastEntry.children.put( part, nextEntry = new FileEntry() );
}
lastEntry = nextEntry;
@@ -166,7 +167,7 @@ public class JarMount implements IMount
public void list( @Nonnull String path, @Nonnull List<String> contents ) throws IOException
{
FileEntry file = get( path );
if( file == null || !file.isDirectory() ) throw new IOException( "/" + path + ": Not a directory" );
if( file == null || !file.isDirectory() ) throw new FileOperationException( path, "Not a directory" );
file.list( contents );
}
@@ -176,7 +177,7 @@ public class JarMount implements IMount
{
FileEntry file = get( path );
if( file != null ) return file.size;
throw new IOException( "/" + path + ": No such file" );
throw new FileOperationException( path, "No such file" );
}
@Nonnull
@@ -218,22 +219,15 @@ public class JarMount implements IMount
}
}
throw new IOException( "/" + path + ": No such file" );
throw new FileOperationException( path, "No such file" );
}
private static class FileEntry
{
final String name;
String path;
long size;
Map<String, FileEntry> children;
FileEntry( String name )
{
this.name = name;
}
void setup( ZipEntry entry )
{
path = entry.getName();

View File

@@ -14,7 +14,6 @@ import dan200.computercraft.core.apis.handles.ArrayByteChannel;
import net.minecraft.resources.IReloadableResourceManager;
import net.minecraft.resources.IResource;
import net.minecraft.resources.IResourceManager;
import net.minecraft.resources.IResourceManagerReloadListener;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.resource.IResourceType;
import net.minecraftforge.resource.ISelectiveResourceReloadListener;
@@ -171,7 +170,7 @@ public class ResourceMount implements IMount
{
total += read;
read = s.read( TEMP_BUFFER );
} while( read > 0 );
} while ( read > 0 );
return file.size = total;
}
@@ -241,7 +240,7 @@ public class ResourceMount implements IMount
}
/**
* A {@link IResourceManagerReloadListener} which reloads any associated mounts.
* A {@link ISelectiveResourceReloadListener} which reloads any associated mounts.
*
* While people should really be keeping a permanent reference to this, some people construct it every
* method call, so let's make this as small as possible.

View File

@@ -242,7 +242,7 @@ public class CobaltLuaMachine implements ILuaMachine
}
catch( InterruptedException e )
{
throw new OrphanedThread();
throw new InterruptedError( e );
}
catch( LuaException e )
{
@@ -550,7 +550,7 @@ public class CobaltLuaMachine implements ILuaMachine
{
if( ComputerCraft.logPeripheralErrors ) ComputerCraft.log.error( "Error running task", t );
m_computer.queueEvent( "task_complete", new Object[] {
taskID, false, "Java Exception Thrown: " + t
taskID, false, "Java Exception Thrown: " + t,
} );
}
};

View File

@@ -8,7 +8,7 @@ package dan200.computercraft.core.terminal;
public class TextBuffer
{
public char[] m_text;
private final char[] m_text;
public TextBuffer( char c, int length )
{

View File

@@ -6,7 +6,6 @@
package dan200.computercraft.shared;
import com.google.common.base.Preconditions;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.api.redstone.IBundledRedstoneProvider;
import dan200.computercraft.shared.common.DefaultBundledRedstoneProvider;
@@ -16,6 +15,7 @@ import net.minecraft.world.World;
import javax.annotation.Nonnull;
import java.util.LinkedHashSet;
import java.util.Objects;
import java.util.Set;
public final class BundledRedstone
@@ -26,7 +26,7 @@ public final class BundledRedstone
public static synchronized void register( @Nonnull IBundledRedstoneProvider provider )
{
Preconditions.checkNotNull( provider, "provider cannot be null" );
Objects.requireNonNull( provider, "provider cannot be null" );
providers.add( provider );
}

View File

@@ -44,8 +44,8 @@ public final class Config
private static ConfigValue<Boolean> logComputerErrors;
private static ConfigValue<Integer> computerThreads;
private static ConfigValue<Long> maxMainGlobalTime;
private static ConfigValue<Long> maxMainComputerTime;
private static ConfigValue<Integer> maxMainGlobalTime;
private static ConfigValue<Integer> maxMainComputerTime;
private static ConfigValue<Boolean> httpEnabled;
private static ConfigValue<Boolean> httpWebsocketEnabled;
@@ -54,8 +54,8 @@ public final class Config
private static ConfigValue<Integer> httpTimeout;
private static ConfigValue<Integer> httpMaxRequests;
private static ConfigValue<Long> httpMaxDownload;
private static ConfigValue<Long> httpMaxUpload;
private static ConfigValue<Integer> httpMaxDownload;
private static ConfigValue<Integer> httpMaxUpload;
private static ConfigValue<Integer> httpMaxWebsockets;
private static ConfigValue<Integer> httpMaxWebsocketMessage;
@@ -134,13 +134,13 @@ public final class Config
.comment( "The maximum time that can be spent executing tasks in a single tick, in milliseconds.\n" +
"Note, we will quite possibly go over this limit, as there's no way to tell how long a will take " +
"- this aims to be the upper bound of the average time." )
.defineInRange( "max_main_global_time", TimeUnit.NANOSECONDS.toMillis( ComputerCraft.maxMainGlobalTime ), 1, Long.MAX_VALUE );
.defineInRange( "max_main_global_time", (int) TimeUnit.NANOSECONDS.toMillis( ComputerCraft.maxMainGlobalTime ), 1, Integer.MAX_VALUE );
maxMainComputerTime = builder
.comment( "The ideal maximum time a computer can execute for in a tick, in milliseconds.\n" +
"Note, we will quite possibly go over this limit, as there's no way to tell how long a will take " +
"- this aims to be the upper bound of the average time." )
.defineInRange( "max_main_computer_time", TimeUnit.NANOSECONDS.toMillis( ComputerCraft.maxMainComputerTime ), 1, Long.MAX_VALUE );
.defineInRange( "max_main_computer_time", (int) TimeUnit.NANOSECONDS.toMillis( ComputerCraft.maxMainComputerTime ), 1, Integer.MAX_VALUE );
builder.pop();
}
@@ -180,11 +180,11 @@ public final class Config
httpMaxDownload = builder
.comment( "The maximum size (in bytes) that a computer can download in a single request. Note that responses may receive more data than allowed, but this data will not be returned to the client." )
.defineInRange( "max_download", ComputerCraft.httpMaxDownload, 0, Long.MAX_VALUE );
.defineInRange( "max_download", (int) ComputerCraft.httpMaxDownload, 0, Integer.MAX_VALUE );
httpMaxUpload = builder
.comment( "The maximum size (in bytes) that a computer can upload in a single request. This includes headers and POST text." )
.defineInRange( "max_upload", ComputerCraft.httpMaxUpload, 0, Long.MAX_VALUE );
.defineInRange( "max_upload", (int) ComputerCraft.httpMaxUpload, 0, Integer.MAX_VALUE );
httpMaxWebsockets = builder
.comment( "The number of websockets a computer can have open at one time. Set to 0 for unlimited." )

View File

@@ -11,8 +11,8 @@ import com.mojang.brigadier.arguments.StringArgumentType;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.api.peripheral.IPeripheral;
import dan200.computercraft.core.apis.IAPIEnvironment;
import dan200.computercraft.core.computer.Computer;
import dan200.computercraft.core.computer.ComputerSide;
import dan200.computercraft.core.tracking.ComputerTracker;
import dan200.computercraft.core.tracking.Tracking;
import dan200.computercraft.core.tracking.TrackingContext;
@@ -118,12 +118,12 @@ public final class CommandComputerCraft
table.row( header( "Position" ), linkPosition( context.getSource(), computer ) );
table.row( header( "Family" ), text( computer.getFamily().toString() ) );
for( int i = 0; i < 6; i++ )
for( ComputerSide side : ComputerSide.values() )
{
IPeripheral peripheral = computer.getPeripheral( i );
IPeripheral peripheral = computer.getPeripheral( side );
if( peripheral != null )
{
table.row( header( "Peripheral " + IAPIEnvironment.SIDE_NAMES[i] ), text( peripheral.getType() ) );
table.row( header( "Peripheral " + side.getName() ), text( peripheral.getType() ) );
}
}

View File

@@ -16,7 +16,7 @@ public final class Exceptions
public static final DynamicCommandExceptionType COMPUTER_ARG_NONE = translated1( "argument.computercraft.computer.no_matching" );
public static final Dynamic2CommandExceptionType COMPUTER_ARG_MANY = translated2( "argument.computercraft.computer.many_matching" );
public static final DynamicCommandExceptionType TRACKING_FIELD_ARG_NONE = translated1( "argument.computercraft.tacking_field.no_field" );
public static final DynamicCommandExceptionType TRACKING_FIELD_ARG_NONE = translated1( "argument.computercraft.tracking_field.no_field" );
static final SimpleCommandExceptionType NOT_TRACKING_EXCEPTION = translated( "commands.computercraft.track.stop.not_enabled" );
static final SimpleCommandExceptionType NO_TIMINGS_EXCEPTION = translated( "commands.computercraft.track.dump.no_timings" );

View File

@@ -7,7 +7,6 @@
package dan200.computercraft.shared.common;
import net.minecraft.block.Block;
import net.minecraft.block.ITileEntityProvider;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.tileentity.TileEntity;
@@ -23,7 +22,7 @@ import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.Random;
public abstract class BlockGeneric extends Block implements ITileEntityProvider
public abstract class BlockGeneric extends Block
{
private final TileEntityType<? extends TileGeneric> type;
@@ -55,7 +54,6 @@ public abstract class BlockGeneric extends Block implements ITileEntityProvider
@Override
@Deprecated
@SuppressWarnings( "deprecation" )
public final void neighborChanged( IBlockState state, World world, BlockPos pos, Block neighbourBlock, BlockPos neighbourPos )
{
TileEntity tile = world.getTileEntity( pos );
@@ -77,9 +75,15 @@ public abstract class BlockGeneric extends Block implements ITileEntityProvider
if( te instanceof TileGeneric ) ((TileGeneric) te).blockTick();
}
@Override
public boolean hasTileEntity( IBlockState state )
{
return true;
}
@Nullable
@Override
public TileEntity createNewTileEntity( @Nonnull IBlockReader world )
public TileEntity createTileEntity( @Nonnull IBlockState state, @Nonnull IBlockReader world )
{
return type.create();
}

View File

@@ -49,9 +49,7 @@ public class CommandAPI implements ILuaAPI
@Override
public String[] getNames()
{
return new String[] {
"commands"
};
return new String[] { "commands" };
}
@Nonnull
@@ -64,7 +62,7 @@ public class CommandAPI implements ILuaAPI
"list",
"getBlockPosition",
"getBlockInfos",
"getBlockInfo"
"getBlockInfo",
};
}

View File

@@ -6,6 +6,7 @@
package dan200.computercraft.shared.computer.blocks;
import dan200.computercraft.core.computer.ComputerSide;
import dan200.computercraft.shared.common.BlockGeneric;
import dan200.computercraft.shared.common.IBundledRedstoneBlock;
import dan200.computercraft.shared.computer.core.ComputerFamily;
@@ -65,9 +66,8 @@ public abstract class BlockComputerBase<T extends TileComputerBase> extends Bloc
ServerComputer computer = computerEntity.getServerComputer();
if( computer == null ) return 0;
EnumFacing localSide = computerEntity.remapToLocalSide( incomingSide.getOpposite() );
return computerEntity.isRedstoneBlockedOnSide( localSide ) ? 0 :
computer.getRedstoneOutput( localSide.getIndex() );
ComputerSide localSide = computerEntity.remapToLocalSide( incomingSide.getOpposite() );
return computer.getRedstoneOutput( localSide );
}
@Nonnull
@@ -88,11 +88,7 @@ public abstract class BlockComputerBase<T extends TileComputerBase> extends Bloc
@Override
public boolean getBundledRedstoneConnectivity( World world, BlockPos pos, EnumFacing side )
{
TileEntity entity = world.getTileEntity( pos );
if( !(entity instanceof TileComputerBase) ) return false;
TileComputerBase computerEntity = (TileComputerBase) entity;
return !computerEntity.isRedstoneBlockedOnSide( computerEntity.remapToLocalSide( side ) );
return true;
}
@Override
@@ -105,9 +101,8 @@ public abstract class BlockComputerBase<T extends TileComputerBase> extends Bloc
ServerComputer computer = computerEntity.getServerComputer();
if( computer == null ) return 0;
EnumFacing localSide = computerEntity.remapToLocalSide( side );
return computerEntity.isRedstoneBlockedOnSide( localSide ) ? 0 :
computer.getBundledRedstoneOutput( localSide.getIndex() );
ComputerSide localSide = computerEntity.remapToLocalSide( side );
return computer.getBundledRedstoneOutput( localSide );
}
@Nonnull

View File

@@ -7,6 +7,7 @@
package dan200.computercraft.shared.computer.blocks;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.core.computer.ComputerSide;
import dan200.computercraft.shared.computer.core.ComputerFamily;
import dan200.computercraft.shared.computer.core.ComputerState;
import dan200.computercraft.shared.computer.core.ServerComputer;
@@ -95,8 +96,12 @@ public class TileComputer extends TileComputerBase
}
@Override
protected EnumFacing remapLocalSide( EnumFacing localSide )
protected ComputerSide remapLocalSide( ComputerSide localSide )
{
return localSide.getAxis() == EnumFacing.Axis.X ? localSide.getOpposite() : localSide;
// For legacy reasons, computers invert the meaning of "left" and "right". A computer's front is facing
// towards you, but a turtle's front is facing the other way.
if( localSide == ComputerSide.RIGHT ) return ComputerSide.LEFT;
if( localSide == ComputerSide.LEFT ) return ComputerSide.RIGHT;
return localSide;
}
}

View File

@@ -9,6 +9,7 @@ package dan200.computercraft.shared.computer.blocks;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.api.peripheral.IPeripheral;
import dan200.computercraft.api.peripheral.IPeripheralTile;
import dan200.computercraft.core.computer.ComputerSide;
import dan200.computercraft.shared.BundledRedstone;
import dan200.computercraft.shared.Peripherals;
import dan200.computercraft.shared.common.TileGeneric;
@@ -19,7 +20,10 @@ import dan200.computercraft.shared.computer.core.ServerComputer;
import dan200.computercraft.shared.util.DirectionUtil;
import dan200.computercraft.shared.util.RedstoneUtil;
import joptsimple.internal.Strings;
import net.minecraft.block.BlockRedstoneWire;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.init.Blocks;
import net.minecraft.init.Items;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
@@ -31,6 +35,7 @@ import net.minecraft.util.ITickable;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.text.TextComponentString;
import net.minecraft.world.World;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
@@ -198,24 +203,19 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT
m_on = m_startOn = nbt.getBoolean( NBT_ON );
}
protected boolean isPeripheralBlockedOnSide( EnumFacing localSide )
{
return false;
}
protected boolean isRedstoneBlockedOnSide( EnumFacing localSide )
protected boolean isPeripheralBlockedOnSide( ComputerSide localSide )
{
return false;
}
protected abstract EnumFacing getDirection();
protected EnumFacing remapToLocalSide( EnumFacing globalSide )
protected ComputerSide remapToLocalSide( EnumFacing globalSide )
{
return remapLocalSide( DirectionUtil.toLocal( getDirection(), globalSide ) );
}
protected EnumFacing remapLocalSide( EnumFacing localSide )
protected ComputerSide remapLocalSide( ComputerSide localSide )
{
return localSide;
}
@@ -223,18 +223,36 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT
private void updateSideInput( ServerComputer computer, EnumFacing dir, BlockPos offset )
{
EnumFacing offsetSide = dir.getOpposite();
EnumFacing localDir = remapToLocalSide( dir );
if( !isRedstoneBlockedOnSide( localDir ) )
{
computer.setRedstoneInput( localDir.getIndex(), getWorld().getRedstonePower( offset, dir ) );
computer.setBundledRedstoneInput( localDir.getIndex(), BundledRedstone.getOutput( getWorld(), offset, offsetSide ) );
}
ComputerSide localDir = remapToLocalSide( dir );
computer.setRedstoneInput( localDir, getRedstoneInput( world, offset, dir ) );
computer.setBundledRedstoneInput( localDir, BundledRedstone.getOutput( getWorld(), offset, offsetSide ) );
if( !isPeripheralBlockedOnSide( localDir ) )
{
computer.setPeripheral( localDir.getIndex(), Peripherals.getPeripheral( getWorld(), offset, offsetSide ) );
computer.setPeripheral( localDir, Peripherals.getPeripheral( getWorld(), offset, offsetSide ) );
}
}
/**
* Gets the redstone input for an adjacent block
*
* @param world The world we exist in
* @param pos The position of the neighbour
* @param side The side we are reading from
* @return The effective redstone power
* @see net.minecraft.block.BlockRedstoneDiode#calculateInputStrength(World, BlockPos, IBlockState)
*/
protected static int getRedstoneInput( World world, BlockPos pos, EnumFacing side )
{
int power = world.getRedstonePower( pos, side );
if( power >= 15 ) return power;
IBlockState neighbour = world.getBlockState( pos );
return neighbour.getBlock() == Blocks.REDSTONE_WIRE
? Math.max( power, neighbour.get( BlockRedstoneWire.POWER ) )
: power;
}
public void updateInput()
{
if( getWorld() == null || getWorld().isRemote ) return;
@@ -257,7 +275,6 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT
ServerComputer computer = getServerComputer();
if( computer == null ) return;
// Find the appropriate side and update.
BlockPos pos = computer.getPosition();
for( EnumFacing dir : DirectionUtil.FACINGS )
{
@@ -268,6 +285,9 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT
break;
}
}
// If the position is not any adjacent one, update all inputs.
updateInput();
}
public void updateOutput()

View File

@@ -11,9 +11,9 @@ import java.util.HashMap;
import java.util.Map;
import java.util.Random;
public class ComputerRegistry<TComputer extends IComputer>
public class ComputerRegistry<T extends IComputer>
{
private Map<Integer, TComputer> m_computers;
private Map<Integer, T> m_computers;
private int m_nextUnusedInstanceID;
private int m_sessionID;
@@ -33,12 +33,12 @@ public class ComputerRegistry<TComputer extends IComputer>
return m_nextUnusedInstanceID++;
}
public Collection<TComputer> getComputers()
public Collection<T> getComputers()
{
return m_computers.values();
}
public TComputer get( int instanceID )
public T get( int instanceID )
{
if( instanceID >= 0 )
{
@@ -55,7 +55,7 @@ public class ComputerRegistry<TComputer extends IComputer>
return m_computers.containsKey( instanceID );
}
public void add( int instanceID, TComputer computer )
public void add( int instanceID, T computer )
{
if( m_computers.containsKey( instanceID ) )
{

View File

@@ -14,6 +14,7 @@ import dan200.computercraft.api.lua.ILuaAPI;
import dan200.computercraft.api.peripheral.IPeripheral;
import dan200.computercraft.core.apis.IAPIEnvironment;
import dan200.computercraft.core.computer.Computer;
import dan200.computercraft.core.computer.ComputerSide;
import dan200.computercraft.core.computer.IComputerEnvironment;
import dan200.computercraft.shared.common.ServerTerminal;
import dan200.computercraft.shared.network.NetworkHandler;
@@ -172,10 +173,14 @@ public class ServerComputer extends ServerTerminal implements IComputer, IComput
// Send terminal state to clients who are currently interacting with the computer.
MinecraftServer server = ServerLifecycleHooks.getCurrentServer();
NetworkMessage packet = createTerminalPacket();
NetworkMessage packet = null;
for( EntityPlayer player : server.getPlayerList().getPlayers() )
{
if( isInteracting( player ) ) NetworkHandler.sendToPlayer( player, packet );
if( isInteracting( player ) )
{
if( packet == null ) packet = createTerminalPacket();
NetworkHandler.sendToPlayer( player, packet );
}
}
}
}
@@ -261,22 +266,22 @@ public class ServerComputer extends ServerTerminal implements IComputer, IComput
m_computer.queueEvent( event, arguments );
}
public int getRedstoneOutput( int side )
public int getRedstoneOutput( ComputerSide side )
{
return m_computer.getEnvironment().getExternalRedstoneOutput( side );
}
public void setRedstoneInput( int side, int level )
public void setRedstoneInput( ComputerSide side, int level )
{
m_computer.getEnvironment().setRedstoneInput( side, level );
}
public int getBundledRedstoneOutput( int side )
public int getBundledRedstoneOutput( ComputerSide side )
{
return m_computer.getEnvironment().getExternalBundledRedstoneOutput( side );
}
public void setBundledRedstoneInput( int side, int combination )
public void setBundledRedstoneInput( ComputerSide side, int combination )
{
m_computer.getEnvironment().setBundledRedstoneInput( side, combination );
}
@@ -286,12 +291,12 @@ public class ServerComputer extends ServerTerminal implements IComputer, IComput
m_computer.addApi( api );
}
public void setPeripheral( int side, IPeripheral peripheral )
public void setPeripheral( ComputerSide side, IPeripheral peripheral )
{
m_computer.getEnvironment().setPeripheral( side, peripheral );
}
public IPeripheral getPeripheral( int side )
public IPeripheral getPeripheral( ComputerSide side )
{
return m_computer.getEnvironment().getPeripheral( side );
}

View File

@@ -1,9 +1,8 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2018. Do not distribute without permission.
* Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.shared.integration.charset;
import dan200.computercraft.shared.common.TileGeneric;

View File

@@ -1,9 +1,8 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2018. Do not distribute without permission.
* Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.shared.integration.charset;
import dan200.computercraft.api.redstone.IBundledRedstoneProvider;

View File

@@ -1,9 +1,8 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2018. Do not distribute without permission.
* Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.shared.integration.charset;
import dan200.computercraft.ComputerCraft;

View File

@@ -10,8 +10,10 @@ import dan200.computercraft.ComputerCraft;
import dan200.computercraft.api.ComputerCraftAPI;
import dan200.computercraft.api.peripheral.IPeripheral;
import dan200.computercraft.api.peripheral.IPeripheralTile;
import dan200.computercraft.shared.peripheral.common.TilePeripheralBase;
import dan200.computercraft.shared.peripheral.modem.wireless.TileAdvancedModem;
import dan200.computercraft.shared.peripheral.modem.wireless.TileWirelessModem;
import dan200.computercraft.shared.peripheral.monitor.TileMonitor;
import mcmultipart.api.addon.IMCMPAddon;
import mcmultipart.api.addon.MCMPAddon;
import mcmultipart.api.container.IMultipartContainer;
@@ -52,7 +54,7 @@ public class MCMPIntegration implements IMCMPAddon
public void registerParts( IMultipartRegistry registry )
{
// Setup all parts
register( registry, ComputerCraft.Blocks.peripheral, new PartNormalModem() );
register( registry, ComputerCraft.Blocks.peripheral, new PartPeripheral() );
register( registry, ComputerCraft.Blocks.advancedModem, new PartAdvancedModem() );
// Subscribe to capability events
@@ -83,8 +85,11 @@ public class MCMPIntegration implements IMCMPAddon
public static void attach( AttachCapabilitiesEvent<TileEntity> event )
{
TileEntity tile = event.getObject();
if( tile instanceof TileAdvancedModem || tile instanceof TileWirelessModem )
if( tile instanceof TileAdvancedModem || tile instanceof TileWirelessModem
|| tile instanceof TilePeripheralBase || tile instanceof TileMonitor )
{
// We need to attach to modems (obviously), but also any other tile created by BlockPeripheral. Otherwise
// IMultipart.convertToMultipartTile will error.
event.addCapability( CAPABILITY_KEY, new BasicMultipart( tile ) );
}
}
@@ -94,7 +99,10 @@ public class MCMPIntegration implements IMCMPAddon
private final TileEntity tile;
private IMultipartTile wrapped;
private BasicMultipart( TileEntity tile ) {this.tile = tile;}
private BasicMultipart( TileEntity tile )
{
this.tile = tile;
}
@Override
public boolean hasCapability( @Nonnull Capability<?> capability, @Nullable EnumFacing facing )

View File

@@ -10,6 +10,7 @@ import dan200.computercraft.ComputerCraft;
import dan200.computercraft.shared.peripheral.common.BlockPeripheral;
import dan200.computercraft.shared.peripheral.common.BlockPeripheralVariant;
import mcmultipart.api.multipart.IMultipart;
import mcmultipart.api.slot.EnumCenterSlot;
import mcmultipart.api.slot.EnumFaceSlot;
import mcmultipart.api.slot.IPartSlot;
import net.minecraft.block.Block;
@@ -20,34 +21,41 @@ import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;
public class PartNormalModem implements IMultipart
import javax.annotation.Nonnull;
public class PartPeripheral implements IMultipart
{
@Override
public IPartSlot getSlotForPlacement( World world, BlockPos pos, IBlockState state, EnumFacing facing, float hitX, float hitY, float hitZ, EntityLivingBase placer )
{
return EnumFaceSlot.fromFace( getFacing( state ) );
return getSlot( state );
}
@Override
public IPartSlot getSlotFromWorld( IBlockAccess world, BlockPos pos, IBlockState state )
{
return EnumFaceSlot.fromFace( getFacing( state ) );
return getSlot( state );
}
private EnumFacing getFacing( IBlockState state )
@Nonnull
private static IPartSlot getSlot( IBlockState state )
{
BlockPeripheralVariant type = state.getValue( BlockPeripheral.VARIANT );
if( type == BlockPeripheralVariant.WirelessModemUpOn || type == BlockPeripheralVariant.WirelessModemUpOff )
{
return EnumFacing.UP;
return EnumFaceSlot.UP;
}
else if( type == BlockPeripheralVariant.WirelessModemDownOn || type == BlockPeripheralVariant.WirelessModemDownOff )
{
return EnumFacing.UP;
return EnumFaceSlot.DOWN;
}
else if( type == BlockPeripheralVariant.WirelessModemOff || type == BlockPeripheralVariant.WirelessModemOn )
{
return EnumFaceSlot.fromFace( state.getValue( BlockPeripheral.FACING ) );
}
else
{
return state.getValue( BlockPeripheral.FACING );
return EnumCenterSlot.CENTER;
}
}

View File

@@ -52,7 +52,7 @@ public class CommandBlockPeripheral implements IPeripheral
{
case 0: // getCommand
return context.executeMainThreadTask( () -> new Object[] {
m_commandBlock.getCommandBlockLogic().getCommand()
m_commandBlock.getCommandBlockLogic().getCommand(),
} );
case 1:
{

View File

@@ -50,7 +50,7 @@ public class DiskDrivePeripheral implements IPeripheral
"playAudio",
"stopAudio",
"ejectDisk",
"getDiskID"
"getDiskID",
};
}

View File

@@ -62,7 +62,7 @@ public final class TileDiskDrive extends TileGeneric implements DefaultInventory
@Nonnull
private ItemStack m_diskStack = ItemStack.EMPTY;
private final LazyOptional<IItemHandlerModifiable> m_itemCap = LazyOptional.of( () -> new InvWrapper( this ) );
private LazyOptional<IItemHandlerModifiable> itemHandlerCap;
private IMount m_diskMount = null;
private boolean m_recordQueued = false;
@@ -82,6 +82,17 @@ public final class TileDiskDrive extends TileGeneric implements DefaultInventory
if( m_recordPlaying ) stopRecord();
}
@Override
protected void invalidateCaps()
{
super.invalidateCaps();
if( itemHandlerCap != null )
{
itemHandlerCap.invalidate();
itemHandlerCap = null;
}
}
@Override
public boolean onActivate( EntityPlayer player, EnumHand hand, EnumFacing side, float hitX, float hitY, float hitZ )
{
@@ -540,7 +551,11 @@ public final class TileDiskDrive extends TileGeneric implements DefaultInventory
@Override
public <T> LazyOptional<T> getCapability( @Nonnull Capability<T> cap, @Nullable final EnumFacing side )
{
if( cap == ITEM_HANDLER_CAPABILITY ) return m_itemCap.cast();
if( cap == ITEM_HANDLER_CAPABILITY )
{
if( itemHandlerCap == null ) itemHandlerCap = LazyOptional.of( () -> new InvWrapper( this ) );
return itemHandlerCap.cast();
}
return super.getCapability( cap, side );
}

View File

@@ -73,7 +73,7 @@ public abstract class ModemPeripheral implements IPeripheral, IPacketSender, IPa
for( IComputerAccess computer : m_computers )
{
computer.queueEvent( "modem_message", new Object[] {
computer.getAttachmentName(), packet.getChannel(), packet.getReplyChannel(), packet.getPayload(), distance
computer.getAttachmentName(), packet.getChannel(), packet.getReplyChannel(), packet.getPayload(), distance,
} );
}
}
@@ -89,7 +89,7 @@ public abstract class ModemPeripheral implements IPeripheral, IPacketSender, IPa
for( IComputerAccess computer : m_computers )
{
computer.queueEvent( "modem_message", new Object[] {
computer.getAttachmentName(), packet.getChannel(), packet.getReplyChannel(), packet.getPayload()
computer.getAttachmentName(), packet.getChannel(), packet.getReplyChannel(), packet.getPayload(),
} );
}
}

View File

@@ -86,7 +86,7 @@ public class BlockCable extends BlockGeneric implements WaterloggableBlock
{
if( !state.get( CABLE ) ) return false;
if( state.get( MODEM ).getFacing() == direction ) return true;
return ComputerCraftAPI.getWiredElementAt( world, pos.offset( direction ), direction.getOpposite() ) != null;
return ComputerCraftAPI.getWiredElementAt( world, pos.offset( direction ), direction.getOpposite() ).isPresent();
}
@Nonnull
@@ -113,8 +113,7 @@ public class BlockCable extends BlockGeneric implements WaterloggableBlock
ItemStack item;
IBlockState newState;
VoxelShape bb = CableShapes.getModemShape( state );
if( WorldUtil.isVecInside( bb, hit.hitVec.subtract( pos.getX(), pos.getY(), pos.getZ() ) ) )
if( WorldUtil.isVecInside( CableShapes.getModemShape( state ), hit.hitVec.subtract( pos.getX(), pos.getY(), pos.getZ() ) ) )
{
newState = state.with( MODEM, CableModemVariant.None );
item = new ItemStack( ComputerCraft.Items.wiredModem );
@@ -161,9 +160,7 @@ public class BlockCable extends BlockGeneric implements WaterloggableBlock
if( modem == null ) return new ItemStack( ComputerCraft.Items.cable );
// We've a modem and cable, so try to work out which one we're interacting with
TileEntity tile = world.getTileEntity( pos );
return tile instanceof TileCable && hit != null &&
CableShapes.getModemShape( state ).getBoundingBox().contains( hit.hitVec.subtract( pos.getX(), pos.getY(), pos.getZ() ) )
return hit != null && WorldUtil.isVecInside( CableShapes.getModemShape( state ), hit.hitVec.subtract( pos.getX(), pos.getY(), pos.getZ() ) )
? new ItemStack( ComputerCraft.Items.wiredModem )
: new ItemStack( ComputerCraft.Items.cable );
@@ -202,21 +199,6 @@ public class BlockCable extends BlockGeneric implements WaterloggableBlock
return getFluidState( state ).getBlockState();
}
if( side == state.get( MODEM ).getFacing() && !state.isValidPosition( world, pos ) )
{
if( !state.get( CABLE ) ) return getFluidState( state ).getBlockState();
/* TODO:
TileEntity entity = world.getTileEntity( pos );
if( entity instanceof TileCable )
{
entity.modemChanged();
entity.connectionsChanged();
}
*/
state = state.with( MODEM, CableModemVariant.None );
}
return state.with( CONNECTIONS.get( side ), doesConnectVisually( state, world, pos, side ) );
}

View File

@@ -35,6 +35,7 @@ import net.minecraft.util.text.TextComponentTranslation;
import net.minecraft.world.World;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.common.util.NonNullConsumer;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
@@ -90,7 +91,7 @@ public class TileCable extends TileGeneric implements IPeripheralTile
private boolean m_connectionsFormed = false;
private final WiredModemElement m_cable = new CableElement();
private LazyOptional<IWiredElement> m_cableCapability = LazyOptional.of( () -> m_cable );
private LazyOptional<IWiredElement> elementCap;
private final IWiredNode m_node = m_cable.getNode();
private final WiredModemPeripheral m_modem = new WiredModemPeripheral(
new ModemState( () -> TickScheduler.schedule( this ) ),
@@ -113,6 +114,8 @@ public class TileCable extends TileGeneric implements IPeripheralTile
}
};
private final NonNullConsumer<LazyOptional<IWiredElement>> connectedNodeChanged = x -> connectionsChanged();
public TileCable()
{
super( FACTORY );
@@ -152,6 +155,17 @@ public class TileCable extends TileGeneric implements IPeripheralTile
onRemove();
}
@Override
protected void invalidateCaps()
{
super.invalidateCaps();
if( elementCap != null )
{
elementCap.invalidate();
elementCap = null;
}
}
@Override
public void onLoad()
{
@@ -322,18 +336,20 @@ public class TileCable extends TileGeneric implements IPeripheralTile
BlockPos offset = current.offset( facing );
if( !world.isBlockLoaded( offset ) ) continue;
IWiredElement element = ComputerCraftAPI.getWiredElementAt( world, offset, facing.getOpposite() );
if( element == null ) continue;
LazyOptional<IWiredElement> element = ComputerCraftAPI.getWiredElementAt( world, offset, facing.getOpposite() );
if( !element.isPresent() ) continue;
element.addListener( connectedNodeChanged );
IWiredNode node = element.orElseThrow( NullPointerException::new ).getNode();
if( BlockCable.canConnectIn( state, facing ) )
{
// If we can connect to it then do so
m_node.connectTo( element.getNode() );
m_node.connectTo( node );
}
else if( m_node.getNetwork() == element.getNode().getNetwork() )
else if( m_node.getNetwork() == node.getNetwork() )
{
// Otherwise if we're on the same network then attempt to void it.
m_node.disconnectFrom( element.getNode() );
m_node.disconnectFrom( node );
}
}
}
@@ -341,9 +357,11 @@ public class TileCable extends TileGeneric implements IPeripheralTile
void modemChanged()
{
// Tell anyone who cares that the connection state has changed
// TODO: Be more restrictive about this.
m_cableCapability.invalidate();
m_cableCapability = LazyOptional.of( () -> m_cable );
if( elementCap != null )
{
elementCap.invalidate();
elementCap = null;
}
if( getWorld().isRemote ) return;
@@ -405,8 +423,9 @@ public class TileCable extends TileGeneric implements IPeripheralTile
{
if( capability == CapabilityWiredElement.CAPABILITY )
{
return !m_destroyed && BlockCable.canConnectIn( getBlockState(), facing )
? m_cableCapability.cast() : LazyOptional.empty();
if( m_destroyed || !BlockCable.canConnectIn( getBlockState(), facing ) ) return LazyOptional.empty();
if( elementCap == null ) elementCap = LazyOptional.of( () -> m_cable );
return elementCap.cast();
}
return super.getCapability( capability, facing );
@@ -418,7 +437,7 @@ public class TileCable extends TileGeneric implements IPeripheralTile
return !m_destroyed && hasModem() && side == getDirection() ? m_modem : null;
}
public boolean hasCable()
boolean hasCable()
{
return getBlockState().get( BlockCable.CABLE );
}
@@ -428,7 +447,7 @@ public class TileCable extends TileGeneric implements IPeripheralTile
return getBlockState().get( BlockCable.MODEM ) != CableModemVariant.None;
}
boolean canAttachPeripheral()
private boolean canAttachPeripheral()
{
return hasCable() && hasModem();
}

View File

@@ -8,7 +8,7 @@ package dan200.computercraft.shared.peripheral.modem.wired;
import com.google.common.base.Objects;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.ComputerCraftAPIImpl;
import dan200.computercraft.api.ComputerCraftAPI;
import dan200.computercraft.api.network.wired.IWiredElement;
import dan200.computercraft.api.network.wired.IWiredNode;
import dan200.computercraft.api.peripheral.IPeripheral;
@@ -33,6 +33,7 @@ import net.minecraft.util.text.TextComponentTranslation;
import net.minecraft.world.World;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.common.util.NonNullConsumer;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
@@ -105,10 +106,10 @@ public class TileWiredModemFull extends TileGeneric implements IPeripheralTile
private final ModemState m_modemState = new ModemState( () -> TickScheduler.schedule( this ) );
private final WiredModemElement m_element = new FullElement( this );
private final LazyOptional<WiredModemElement> m_elementCap = LazyOptional.of( () -> m_element );
private LazyOptional<IWiredElement> elementCap;
private final IWiredNode m_node = m_element.getNode();
private int m_state = 0;
private final NonNullConsumer<LazyOptional<IWiredElement>> connectedNodeChanged = x -> connectionsChanged();
public TileWiredModemFull()
{
@@ -143,6 +144,17 @@ public class TileWiredModemFull extends TileGeneric implements IPeripheralTile
doRemove();
}
@Override
protected void invalidateCaps()
{
super.invalidateCaps();
if( elementCap != null )
{
elementCap.invalidate();
elementCap = null;
}
}
@Override
public void remove()
{
@@ -275,11 +287,11 @@ public class TileWiredModemFull extends TileGeneric implements IPeripheralTile
BlockPos offset = current.offset( facing );
if( !world.isBlockLoaded( offset ) ) continue;
IWiredElement element = ComputerCraftAPIImpl.INSTANCE.getWiredElementAt( world, offset, facing.getOpposite() );
if( element == null ) continue;
LazyOptional<IWiredElement> element = ComputerCraftAPI.getWiredElementAt( world, offset, facing.getOpposite() );
if( !element.isPresent() ) continue;
// If we can connect to it then do so
m_node.connectTo( element.getNode() );
element.addListener( connectedNodeChanged );
m_node.connectTo( element.orElseThrow( NullPointerException::new ).getNode() );
}
}
@@ -350,7 +362,11 @@ public class TileWiredModemFull extends TileGeneric implements IPeripheralTile
@Override
public <T> LazyOptional<T> getCapability( @Nonnull Capability<T> capability, @Nullable EnumFacing facing )
{
if( capability == CapabilityWiredElement.CAPABILITY ) return m_elementCap.cast();
if( capability == CapabilityWiredElement.CAPABILITY )
{
if( elementCap == null ) elementCap = LazyOptional.of( () -> m_element );
return elementCap.cast();
}
return super.getCapability( capability, facing );
}

View File

@@ -277,7 +277,7 @@ public abstract class WiredModemPeripheral extends ModemPeripheral implements IW
private final String[] m_methods;
private final Map<String, Integer> m_methodMap;
public RemotePeripheralWrapper( WiredModemElement element, IPeripheral peripheral, IComputerAccess computer, String name )
RemotePeripheralWrapper( WiredModemElement element, IPeripheral peripheral, IComputerAccess computer, String name )
{
m_element = element;
m_peripheral = peripheral;

View File

@@ -8,6 +8,7 @@ package dan200.computercraft.shared.peripheral.modem.wireless;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.api.peripheral.IPeripheral;
import dan200.computercraft.api.peripheral.IPeripheralTile;
import dan200.computercraft.shared.common.TileGeneric;
import dan200.computercraft.shared.peripheral.modem.ModemPeripheral;
import dan200.computercraft.shared.peripheral.modem.ModemState;
@@ -22,8 +23,9 @@ import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public class TileWirelessModem extends TileGeneric
public class TileWirelessModem extends TileGeneric implements IPeripheralTile
{
public static final NamedBlockEntityType<TileWirelessModem> FACTORY_NORMAL = NamedBlockEntityType.create(
new ResourceLocation( ComputerCraft.MOD_ID, "wireless_modem_normal" ),
@@ -146,4 +148,13 @@ public class TileWirelessModem extends TileGeneric
getWorld().setBlockState( getPos(), state.with( BlockWirelessModem.ON, on ) );
}
}
@Nullable
@Override
public IPeripheral getPeripheral( @Nonnull EnumFacing side )
{
updateDirection();
return side == modemDirection ? modem : null;
}
}

View File

@@ -155,7 +155,7 @@ public class TileMonitor extends TileGeneric implements IPeripheralTile
for( IComputerAccess computer : monitor.m_computers )
{
computer.queueEvent( "monitor_resize", new Object[] {
computer.getAttachmentName()
computer.getAttachmentName(),
} );
}
}
@@ -321,7 +321,7 @@ public class TileMonitor extends TileGeneric implements IPeripheralTile
return getDirection().rotateYCCW();
}
private EnumFacing getDown()
public EnumFacing getDown()
{
EnumFacing orientation = getOrientation();
if( orientation == EnumFacing.NORTH ) return EnumFacing.UP;
@@ -625,7 +625,7 @@ public class TileMonitor extends TileGeneric implements IPeripheralTile
for( IComputerAccess computer : monitor.m_computers )
{
computer.queueEvent( "monitor_touch", new Object[] {
computer.getAttachmentName(), xCharPos, yCharPos
computer.getAttachmentName(), xCharPos, yCharPos,
} );
}
}

View File

@@ -61,8 +61,7 @@ public final class TilePrinter extends TileGeneric implements DefaultSidedInvent
ITextComponent customName;
private final NonNullList<ItemStack> m_inventory = NonNullList.withSize( 13, ItemStack.EMPTY );
private IItemHandlerModifiable m_itemHandlerAll = new InvWrapper( this );
private LazyOptional<IItemHandlerModifiable>[] m_itemHandlerSides;
private LazyOptional<IItemHandlerModifiable>[] itemHandlerCaps;
private final Terminal m_page = new Terminal( ItemPrintout.LINE_MAX_LENGTH, ItemPrintout.LINES_PER_PAGE );
private String m_pageTitle = "";
@@ -79,6 +78,22 @@ public final class TilePrinter extends TileGeneric implements DefaultSidedInvent
ejectContents();
}
@Override
protected void invalidateCaps()
{
super.invalidateCaps();
if( itemHandlerCaps != null )
{
for( int i = 0; i < itemHandlerCaps.length; i++ )
{
if( itemHandlerCaps[i] == null ) continue;
itemHandlerCaps[i].invalidate();
itemHandlerCaps[i] = null;
}
}
}
@Override
public boolean onActivate( EntityPlayer player, EnumHand hand, EnumFacing side, float hitX, float hitY, float hitZ )
{
@@ -516,7 +531,6 @@ public final class TilePrinter extends TileGeneric implements DefaultSidedInvent
getWorld().setBlockState( getPos(), state.with( BlockPrinter.TOP, top ).with( BlockPrinter.BOTTOM, bottom ) );
}
@SuppressWarnings( { "unchecked", "rawtypes" } )
@Nonnull
@Override
@@ -524,28 +538,16 @@ public final class TilePrinter extends TileGeneric implements DefaultSidedInvent
{
if( capability == ITEM_HANDLER_CAPABILITY )
{
LazyOptional<IItemHandlerModifiable>[] handlers = m_itemHandlerSides;
if( handlers == null ) handlers = m_itemHandlerSides = new LazyOptional[6];
LazyOptional<IItemHandlerModifiable>[] handlers = itemHandlerCaps;
if( handlers == null ) handlers = itemHandlerCaps = new LazyOptional[7];
LazyOptional<IItemHandlerModifiable> handler;
if( facing == null )
int index = facing == null ? 0 : 1 + facing.getIndex();
LazyOptional<IItemHandlerModifiable> handler = handlers[index];
if( handler == null )
{
int i = 6;
handler = handlers[i];
if( handler == null )
{
handler = handlers[i] = LazyOptional.of( () -> m_itemHandlerAll );
}
}
else
{
int i = facing.ordinal();
handler = handlers[i];
if( handler == null )
{
handler = handlers[i] = LazyOptional.of( () -> new SidedInvWrapper( this, facing ) );
}
handler = handlers[index] = facing == null
? LazyOptional.of( () -> new InvWrapper( this ) )
: LazyOptional.of( () -> new SidedInvWrapper( this, facing ) );
}
return handler.cast();

View File

@@ -59,8 +59,8 @@ public abstract class SpeakerPeripheral implements IPeripheral
public String[] getMethodNames()
{
return new String[] {
"playSound", // Plays sound at resourceLocator
"playNote" // Plays note
"playSound",
"playNote",
};
}

View File

@@ -35,9 +35,7 @@ public class PocketAPI implements ILuaAPI
@Override
public String[] getNames()
{
return new String[] {
"pocket"
};
return new String[] { "pocket" };
}
@Nonnull
@@ -46,7 +44,7 @@ public class PocketAPI implements ILuaAPI
{
return new String[] {
"equipBack",
"unequipBack"
"unequipBack",
};
}

View File

@@ -10,6 +10,7 @@ import dan200.computercraft.ComputerCraft;
import dan200.computercraft.api.peripheral.IPeripheral;
import dan200.computercraft.api.pocket.IPocketAccess;
import dan200.computercraft.api.pocket.IPocketUpgrade;
import dan200.computercraft.core.computer.ComputerSide;
import dan200.computercraft.shared.common.IColouredItem;
import dan200.computercraft.shared.computer.core.ComputerFamily;
import dan200.computercraft.shared.computer.core.ServerComputer;
@@ -123,14 +124,14 @@ public class PocketServerComputer extends ServerComputer implements IPocketAcces
public void invalidatePeripheral()
{
IPeripheral peripheral = m_upgrade == null ? null : m_upgrade.createPeripheral( this );
setPeripheral( 2, peripheral );
setPeripheral( ComputerSide.BACK, peripheral );
}
@Nonnull
@Override
public Map<ResourceLocation, IPeripheral> getUpgrades()
{
return m_upgrade == null ? Collections.emptyMap() : Collections.singletonMap( m_upgrade.getUpgradeID(), getPeripheral( 2 ) );
return m_upgrade == null ? Collections.emptyMap() : Collections.singletonMap( m_upgrade.getUpgradeID(), getPeripheral( ComputerSide.BACK ) );
}
public IPocketUpgrade getUpgrade()

View File

@@ -12,6 +12,7 @@ import dan200.computercraft.api.ComputerCraftAPI;
import dan200.computercraft.api.filesystem.IMount;
import dan200.computercraft.api.media.IMedia;
import dan200.computercraft.api.pocket.IPocketUpgrade;
import dan200.computercraft.core.computer.ComputerSide;
import dan200.computercraft.shared.PocketUpgrades;
import dan200.computercraft.shared.common.IColouredItem;
import dan200.computercraft.shared.computer.core.ClientComputer;
@@ -120,7 +121,7 @@ public class ItemPocketComputer extends Item implements IComputerItem, IMedia, I
// Update pocket upgrade
if( upgrade != null )
{
upgrade.update( computer, computer.getPeripheral( 2 ) );
upgrade.update( computer, computer.getPeripheral( ComputerSide.BACK ) );
}
}
}
@@ -149,7 +150,7 @@ public class ItemPocketComputer extends Item implements IComputerItem, IMedia, I
if( upgrade != null )
{
computer.updateValues( player, stack, upgrade );
stop = upgrade.onRightClick( world, computer, computer.getPeripheral( 2 ) );
stop = upgrade.onRightClick( world, computer, computer.getPeripheral( ComputerSide.BACK ) );
}
}

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