1
0
mirror of https://github.com/SquidDev-CC/CC-Tweaked synced 2025-10-23 01:47:38 +00:00

Compare commits

..

109 Commits

Author SHA1 Message Date
Jonathan Coates
f0ba1108d5 Merge branch 'mc-1.15.x' into mc-1.16.x 2021-05-20 19:03:56 +01:00
Jonathan Coates
5d0daf9b2d Remove dependencies from gradle 2021-05-20 19:03:30 +01:00
Jonathan Coates
8b8692ba53 Merge branch 'mc-1.15.x' into mc-1.16.x 2021-05-20 18:30:10 +01:00
Jonathan Coates
1f385f5b35 Bump version to 1.94.0 2021-05-20 18:29:57 +01:00
Jonathan Coates
34baa09b6c Set stack size when crafting coloured items
Fixes #793
2021-05-20 18:12:30 +01:00
Jonathan Coates
b21866fbff Merge pull request #794 from MCJack123/patch-7
Add the ability to call `cc.expect` directly
2021-05-20 09:23:28 +01:00
JackMacWindows
e0a288bcb9 Add the ability to call cc.expect directly 2021-05-19 20:14:13 -04:00
Jonathan Coates
4592534a18 Fix mount suggestion always being printed out 2021-05-18 09:44:11 +00:00
Lupus590
28165bfcd6 Add cc.expect.range (#790) 2021-05-17 17:49:48 +01:00
Jonathan Coates
953b94fd08 Add problem matchers for Github actions
- Add a basic problem matcher for illuaminate errors.
 - Add a script (tools/parse-reports.py) which parses the XML reports
   generated by checkstyle and junit, extracts source locations, and
   emits them in a manner which can be consumed by another set of
   matchers.

This should make it a little easier to see problems for folks who just
rely on CI to test things (though also, please don't do this if you can
help it).
2021-05-17 16:31:58 +00:00
Jonathan Coates
e10e30f82b Use a separate region for the bottom pocket computer border
This is definitely not a good solution, but it's probably the best we
can do right now given resizable computers are a thing.

Fixes #775, closes #776
2021-05-16 18:40:18 +01:00
Jonathan Coates
aeb1fa0e7e Optimise all textures
using "optipng -o7 -strip all". I ran this a few years ago and had some
issues, but aren't seeing any problems now. I don't know if this is a
graphics card change, or just optipng fixed some bugs.

These are fairly minimal changes, but hopefully save a few bytes!
2021-05-16 18:00:47 +01:00
Jonathan Coates
349a7543b0 Fix build failures
- Add license headers. Also check these during pre-commit.
 - Fix javadoc issue.
2021-05-15 21:27:48 +01:00
Jonathan Coates
3d589eda4a Expose GenericSource to the public API
- Remove the service provider code and require people to explicitly
   register these. This is definitely more ugly, but easier than people
   pulling in AutoService or similar!
 - Add an API for registering capabilities.
 - Expand the doc comments a little. Not sure how useful they'll be, but
   let's see!

There's still so much work to be done on this, but it's a "good enough"
first step.
2021-05-15 21:11:09 +01:00
Jonathan Coates
de646b66b6 Allow turtles to use compostors 2021-05-14 18:32:52 +01:00
Jonathan Coates
4f0d311df7 Add example to turtle.inspect
A pretty common but non-trivial API, so worth having something. Even if
not perfect.
2021-05-14 18:06:51 +01:00
Jonathan Coates
d6e3c9a7fa Add inventory.getItemLimit
Closes #781
2021-05-13 18:12:49 +01:00
Jonathan Coates
a7a724f134 Bump Cobalt version 2021-05-13 18:09:08 +01:00
Jonathan Coates
b0e30fdce1 Use lightGrey for folders on normal computers
This way we still get some differences between files and folders on
normal computers. I did try with just green, but I think the contrast is
too low.

Closes #656
2021-05-05 22:10:19 +01:00
Jonathan Coates
4e15afa254 Add tests for placing monitors from turtles (#691) 2021-05-05 21:49:25 +01:00
Jonathan Coates
84bac06178 Merge remote-tracking branch 'baeuric/mc-1.15.x' into mc-1.15.x 2021-05-05 21:46:47 +01:00
Jonathan Coates
1fecb995c9 Don't close file handles from ResourceMounts
Unlike short handles, we don't read these immediately, and so we can't
close it right away. Otherwise the file is considered empty!

Fixes SquidDev-CC/treasure-programs#1
2021-05-05 21:26:17 +01:00
Euric
99b719299c Defer monitor tile update when placed by another TE 2021-05-04 14:24:58 -07:00
Jonathan Coates
fb9590467d Add some examples to inventory methods
Closes #761. It's not perfect, but it's a little better. Maybe??
2021-05-04 19:23:35 +01:00
Jonathan Coates
bc8e090873 Simplify our overrides of load/loadstring
- Remove auto-prefixing of load/loadstring
 - Use Cobalt's normal load implementation, with a simple hook to
   set _ENV on the environment.
2021-05-04 18:30:28 +01:00
Jonathan Coates
cf0f67265f Correctly handle sparse arrays in cc.pretty
This also swaps the order we display mixed array/maps in, so that the
array part comes first. I think this is more sensible.

Closes #777
2021-05-04 18:05:56 +01:00
Jonathan Coates
53dd15a213 Clean up language scripts 2021-04-28 21:28:52 +01:00
Jonathan Coates
eb2d617ed8 Add a pre commit hook to lint code
This uses pre-commit [1] to check patches are well formed and run
several linters on them. We currently do some boring things (check files
are syntactically valid) as well as some project-specific ones:
 - Run illuaminate on the Lua files
 - Run checkstyle on Java

[1]: https://pre-commit.com/
2021-04-28 21:24:27 +01:00
Jonathan Coates
74dae4ec17 That's it, I'm adding pre-commit hooks 2021-04-28 08:19:09 +01:00
Jonathan Coates
abbc46877b Remove mavenLocal() repository
Hopefully should bump to the latest Cobalt version too
2021-04-28 08:05:58 +01:00
Jonathan Coates
3cb25b3525 Various VM tests
These are largely copied across from Cobalt's test suite, with some
minor tweaks. It actually exposed one bug in Cobalt, which is pretty
nice.

One interesting thing from the coroutine tests, is that Lua 5.4 (and
one assumes 5.2/5.3) doesn't allow yielding from within the error
handler of xpcall - I rather thought it might.

This doesn't add any of the PUC Lua tests yet - I got a little
distracted.

Also:
 - Allow skipping "keyword" tests, in the style of busted. This is
   implemented on the Java side for now.
 - Fix a bug with os.date("%I", _) not being 2 characters wide.
2021-04-27 22:25:46 +01:00
Jonathan Coates
f387730b88 Merge branch 'mc-1.15.x' into mc-1.16.x 2021-04-24 11:50:23 +01:00
Jonathan Coates
92b45b1868 Switch to using maven-publish
The old maven package is removed in Gradle 7.0. Instead, we publish to
squiddev.cc using WebDAV (ewww).
2021-04-24 11:26:04 +01:00
Jonathan Coates
003c7ec2e8 Fix Forge maven location
1.16 is going to be sad for a while, as I need to work out FG 4 woes.
2021-04-23 22:40:20 +01:00
Jonathan Coates
c45221a2d0 Fix checkstyle
This is gonna be 50% of my commits at this rate.
2021-04-13 13:03:26 +01:00
Jonathan Coates
8494ba8ce2 Improve UX when a resource mount cannot be found
- Add a full example of the docs. Hopefully is a little more explicit.
 - Print a warning when the mount is empty.

Closes #762
2021-04-13 13:01:28 +01:00
Jonathan Coates
058d63e77f Add citation to cc.pretty
ust to look extra pretentious.
2021-04-11 18:43:24 +01:00
Jonathan Coates
17b5bca443 Make the peripheral API examples a little clearer 2021-04-07 18:34:55 +01:00
Jonathan Coates
c3f5700494 Fix checkstyle
Today is not a good day apparently :D:.
2021-04-03 14:13:55 +01:00
Jonathan Coates
b17ff6daf0 Fix a couple of JEI issues
- Don't treat turtles/pocket computers with no upgrades as an "any"
   turtle. Otherwise getting the recipe of a crafty turtle shows the
   recipe of a normal turtle too.
 - Fix "get usage" of upgrade items not returning their recipes.
 - Fix NPEs inside JEI (closes #719)
2021-04-03 14:08:58 +01:00
Jonathan Coates
e8f5531a8c Fix checkstyle 2021-04-03 12:55:20 +01:00
Jonathan Coates
51d3b091da "Finish" documentation for several modules
- Add remaining docs for the turtle API
 - Add documentation for the fluid storage peripheral.
 - Enforce undocumented warning for most modules (only io and window
   remaining).

"Finish" in quotes, because these are clearly a long way from perfect.
I'm bad at writing docs, OK!
2021-04-03 12:45:54 +01:00
lily
9708dd6786 Fixed sortCoords for draw functions (#749) 2021-04-02 15:30:28 +01:00
Jonathan Coates
e48427dbbc Add documentation for io.setvbuf
Fixes #746.

Love how "good first issue" guarantees that nobody will do it. Not
actually true, and thank you for those people who have contributed!
2021-03-28 19:38:25 +01:00
Jonathan Coates
669b6d2d56 Merge pull request #742 from Wojbie/edit-fix
Fix missing `term.setCursorBlink(true)` in edit.lua
2021-03-19 16:48:34 +00:00
Wojbie
32d956bbe7 Fix missing term.setCursorBlink(true) in edit.lua 2021-03-19 16:07:20 +01:00
Ronan Hanley
3a147c78a8 Refactor and add tests for TextBuffer (#738) 2021-03-16 21:19:54 +00:00
Jonathan Coates
8c56b6a7be Merge branch 'mc-1.15.x' into mc-1.16.x 2021-03-12 09:26:15 +00:00
Jonathan Coates
66e42e0817 Bump version to 1.95.3 2021-03-12 09:19:16 +00:00
Jonathan Coates
0ee3d10fda Add User-Agent to Websockets
I think, haven't actually tested this :D:. Closes #730.
2021-03-12 09:14:52 +00:00
Jonathan Coates
ed0afc4068 Bump ForgeGradle version
Fixes #686
2021-03-12 08:59:31 +00:00
Wojbie
1f70ed6985 Make edit display errors/results of execution and handle require. (#723) 2021-02-23 20:50:19 +00:00
Weblate
8f3ea60c74 Translations for Portuguese (Brazil)
Co-authored-by: Matheus Medeiros Souza <mmedeiros.cbp@gmail.com>
2021-02-21 13:42:57 +00:00
Jonathan Coates
eb722a74cd Clarify the turtle.place docs a little
Closes #714
2021-02-20 20:19:22 +00:00
Jonathan Coates
1825f67eee Lazily load models in data generators
Fixes #701 (well, hopefully). Our BlockModelProvider is created when
running other mods' data generators (thought not run), which causes
issues as none of the models are considered as "existing files".
2021-02-13 13:02:24 +00:00
Jonathan Coates
975a994581 Fix missing method usages
Maybe one should do a full gradle build when doing major build c hanges
:D:.
2021-02-13 12:48:59 +00:00
Jonathan Coates
061514549d Bump Gradle/ForgeGradle version
This is definitely going to break the build (it shouldn't, but these
things always do). Anyway...

 - Use the new Java toolchain support, rather than requiring the user to
   install multiple Java versions.
 - Bump versions of several plugins.

We're sadly stuck on Gradle <7 for now, as they drop the old
maven-publish plugin, which drops SCP support.
2021-02-13 12:39:52 +00:00
Jonathan Coates
5e52429c23 Merge pull request #709 from SkyTheCodeMaster/patch-1
Fix `redstone.getBundledInput(side)` returning the output of said side.
2021-02-05 20:54:57 +00:00
SkyTheCodeMaster
396cf15a1f Fix redstone.getBundledInput(side) returning the output of said side. 2021-02-05 14:10:11 -05:00
Jonathan Coates
7514cf7320 Mark as compatible with 1.16.{4,5}
Closes #694
2021-01-24 21:23:29 +00:00
Jonathan Coates
1316d6a3c9 Migrate all examples to use tweaked.cc
Might as well, I've got the server capacity to spare. Hopefully.
2021-01-23 14:58:08 +00:00
Jonathan Coates
e1cbbe3628 Haven't been hoisted by this petard for a while
I really should move this to Gradle. Probably should just write my own
plugin at this point.
2021-01-19 21:33:05 +00:00
Jonathan Coates
6d367e08a3 ./gradlew checkstyleMain
Every time I forget to run this before pushing, I get very sad.
2021-01-19 21:15:18 +00:00
Jonathan Coates
eaa7359c8c Add a whole bunch of tests
Coverage graph goes woosh. Hopefully.

More importantly, all of these are historic regressions, so very much
worth tracking.
2021-01-19 20:02:45 +00:00
SquidDev
657ceda3af Switch back to reobfuscated name in RecordMedia
Fixes #688
2021-01-19 13:43:49 +00:00
JackMacWindows
a934e42219 Finish the rest of the event documentation (#683) 2021-01-19 09:20:52 +00:00
Jonathan Coates
1544749282 Defer sending monitor updates until tick end
We send monitor updates when a player starts watching a chunk. However,
the block/tile data has not been sent when this event is fired, and so
the packet is entirely ignored.

Instead, we now queue a "send this" task, which is then dispatched on
the next tick end.

I have memories of this working on 1.12, so either something changed in
an update or I'm a complete idiot. Both are possible.

Fixes #687
2021-01-18 22:20:48 +00:00
FensieRenaud
763bab80fa Serialise sparse arrays into JSON (#685) 2021-01-18 20:48:33 +00:00
FensieRenaud
417fda3019 Serialise sparse arrays into JSON (#685) 2021-01-18 16:44:39 +00:00
Jonathan Coates
444830cf2d Remove Grgit/jgit usage in build.gradle
The replacement is objectively worse. However, it supports Git
worktrees, which sadly jgit does not.

We really need to rewrite the build script to make it lazy so we're not
executing these commands every time.
2021-01-16 15:41:19 +00:00
Jonathan Coates
23bf33c454 Use mixins to construct the TestFunctionInfo class
There's some funky things going on here, but thankfully they're limited
to test code.
2021-01-16 12:40:00 +00:00
Jonathan Coates
0be030c497 Merge branch 'mc-1.15.x' into mc-1.16.x 2021-01-16 11:38:59 +00:00
Jonathan Coates
a3a9684505 Widen version range to include 1.16.5
Building against 1.16.4 for now to ensure we don't break it. Hopefully
we can bump this too once most people have migrated.

Will push a release tomorrow - don't want to be sorting out merge
conflicts at 23:30.
2021-01-15 23:26:01 +00:00
Jonathan Coates
c5694ea966 Merge branch 'mc-1.15.x' into mc-1.16.x 2021-01-09 19:25:33 +00:00
Jonathan Coates
7b476cb24b Remove usage of deprecated event constructor
This requires a Forge bump, but probably no harm in doing so anyway.
We're on an ancient (2nd Nov) version. Fixes #665.
2021-01-09 18:49:40 +00:00
Jonathan Coates
7ca261d763 Merge branch 'mc-1.15.x' into mc-1.16.x 2021-01-09 18:32:40 +00:00
Jonathan Coates
1edb7288b9 Merge branch 'mc-1.15.x' into mc-1.16.x 2021-01-06 22:39:54 +00:00
Jonathan Coates
4af5bcc0b0 Fix serveral 1.15 -> 1.16 issues
Well, strictly speaking some mapping changes.
2020-12-25 16:59:09 +00:00
Jonathan Coates
96c577482d Merge branch 'mc-1.15.x' into mc-1.16.x 2020-12-25 16:43:32 +00:00
SquidDev
61f8e97f6b Force the monitor depth blocker to be flushed
As explained in the comment, "built-in" rendering types are now manually
rendered ("finish"ed) before calling finish() on the main renderer. This
means our depth blocker hasn't actually been drawn (if a monitor is the
last TE to be rendered), and so blocks pass the depth test when they
shouldn't.

Fixes #599
2020-12-11 13:09:16 +00:00
SquidDev
c92f06cfd9 Bump deps to 1.16.4 2020-12-11 13:08:24 +00:00
Stephen Gibson
c9f3d315c0 Fix epoch documentation to use milliseconds (#580) 2020-11-13 14:32:49 +00:00
SquidDev
83df64e520 Merge branch 'mc-1.15.x' into mc-1.16.x 2020-11-07 12:46:10 +00:00
SquidDev
ab232bd689 Update to MC 1.16.4
Just some mapping changes really
2020-11-03 15:33:10 +00:00
SquidDev
5bf367af9f Merge branch 'mc-1.15.x' into mc-1.16.x 2020-10-23 17:45:11 +01:00
SquidDev
4766833cf2 Bump JEI/crafttweaker versions
In my defence, they weren't out when I started the 1.15 update.
2020-10-20 17:38:59 +01:00
SquidDev
71563a52ff Let's make this a proper release 2020-10-04 11:31:06 +01:00
SquidDev
0c6e7b5db5 Merge branch 'mc-1.15.x' into mc-1.16.x 2020-10-04 11:24:42 +01:00
SquidDev
72c1d451fe Mark the release as beta-quality 2020-09-12 10:47:19 +01:00
SquidDev
8b4a01df27 Update to Minecraft 1.16.3
I hope the Fabric folks now realise this is gonna be a race of who can
update first :p. Either way, this was a very easy update - only changes
were due to unrelated Forge changes.
2020-09-12 10:45:59 +01:00
SquidDev
d0a973fa46 Merge branch 'mc-1.15.x' into mc-1.16.x 2020-09-12 09:29:21 +01:00
SquidDev
26c12ac1a9 Bump version to 1.91.1 2020-09-04 17:29:35 +01:00
SquidDev
2c67849b35 Fix NPE when turtles interact with an entity
Closes #531
2020-08-27 17:17:03 +01:00
SquidDev
7809a2eddd Merge branch 'mc-1.15.x' into mc-1.16.x 2020-08-23 15:46:17 +01:00
SquidDev
e8e9294fdf Correctly check for success or consume
No, I don't really know what the difference is either :). Closes #518.
2020-08-22 19:28:02 +01:00
SquidDev
99581e1f40 Initial update to 1.16.2
Seems to load fine, but not done any proper testing.
2020-08-14 22:00:03 +01:00
SquidDev
29646a7f61 Bump version to 1.90.3 2020-07-27 19:07:06 +01:00
SquidDev
50d2712581 Resolve CC's save location to the world dir
Fixes #509
2020-07-27 19:04:57 +01:00
SquidDev
3093f882d8 Fix selected slot now showing in the turtle GUI 2020-07-27 18:37:07 +01:00
SquidDev
e5cf0d1c61 Update mappings 2020-07-27 18:26:42 +01:00
SquidDev
6b102a8142 Merge branch 'mc-1.15.x' into mc-1.16.x 2020-07-25 12:08:33 +01:00
SquidDev
c8a6888a2f Fix styles not being saved
Styles have been changed to be immutable, meaning that we were never
updating them! Fixes #499.
2020-07-25 11:19:04 +01:00
SquidDev
9ce33f8a3f Add back missing override of getPositionVec
This was removed in the initial update (46595e73df)
because I got terribly confused over mappings and I forgot to add it
back.

Fixes #505
2020-07-25 10:56:50 +01:00
SquidDev
a1dcd59d95 Update to latest Forge
Fixes #498
2020-07-18 15:11:57 +01:00
SquidDev
2a17585702 Merge branch 'mc-1.15.x' into mc-1.16.x 2020-07-18 12:24:49 +01:00
SquidDev
087c305b0d Fix non-inventory GUIs rendering labels 2020-07-18 12:17:02 +01:00
SquidDev
31764f6d65 Register various gold items as piglin_loved 2020-07-18 11:14:55 +01:00
SquidDev
4efde2b294 Merge branch 'mc-1.15.x' into mc-1.16.x 2020-07-18 10:34:29 +01:00
SquidDev
46595e73df Initial update to Minecraft 1.16.1
A lot is broken, but at least we can get in game:
 - GUIs render a whole bunch of additional "inventory" text, which we
   really don't want.
 - Computers load from the wrong location.
 - There's some issues with using Forge's tags from outside of JSON
   recipes. We need to work out why.
2020-07-11 20:36:10 +01:00
340 changed files with 7585 additions and 1423 deletions

View File

@@ -16,6 +16,3 @@ indent_size = 2
[*.yml]
indent_size = 2
[*.properties]
insert_final_newline = false

17
.github/matchers/checkstyle.json vendored Normal file
View File

@@ -0,0 +1,17 @@
{
"problemMatcher": [
{
"owner": "checkstyle",
"pattern": [
{
"regexp": "^([a-z]+) ([\\w./-]+):(\\d+):(\\d+): (.*)$",
"severity": 1,
"file": 2,
"line": 3,
"column": 4,
"message": 5
}
]
}
]
}

18
.github/matchers/illuaminate.json vendored Normal file
View File

@@ -0,0 +1,18 @@
{
"problemMatcher": [
{
"owner": "illuaminate",
"severity": "warning",
"pattern": [
{
"regexp": "^([\\w./-]+):\\[(\\d+):(\\d+)\\-(?:\\d+):(?:\\d+)\\]: (.*) \\[([a-z:-]+)\\]$",
"file": 1,
"line": 2,
"column": 3,
"message": 4,
"code": 5
}
]
}
]
}

15
.github/matchers/junit.json vendored Normal file
View File

@@ -0,0 +1,15 @@
{
"problemMatcher": [
{
"owner": "junit",
"pattern": [
{
"regexp": "^## ([\\w./-]+):(\\d+): (.*)$",
"file": 1,
"line": 2,
"message": 3
}
]
}
]
}

View File

@@ -23,10 +23,15 @@ jobs:
restore-keys: |
${{ runner.os }}-gradle-
- name: Disable Gradle daemon
run: |
mkdir -p ~/.gradle
echo "org.gradle.daemon=false" >> ~/.gradle/gradle.properties
- name: Build with Gradle
run: |
./gradlew assemble --no-daemon || ./gradlew assemble --no-daemon
./gradlew downloadAssets --no-daemon || ./gradlew downloadAssets --no-daemon
./gradlew assemble || ./gradlew assemble
./gradlew downloadAssets || ./gradlew downloadAssets
./gradlew build
- name: Upload Jar
@@ -36,18 +41,21 @@ jobs:
path: build/libs
- name: Upload Coverage
run: bash <(curl -s https://codecov.io/bash)
continue-on-error: true
uses: codecov/codecov-action@v1
- name: Generate Java documentation stubs
run: ./gradlew luaJavadoc --no-daemon
- name: Parse test reports
run: ./tools/parse-reports.py
if: ${{ failure() }}
- name: Lint Lua code
- name: Cache pre-commit
uses: actions/cache@v2
with:
path: ~/.cache/pre-commit
key: ${{ runner.os }}-pre-commit-${{ hashFiles('config/pre-commit/config.yml') }}
restore-keys: |
${{ runner.os }}-pre-commit-
- name: Run linters
run: |
test -d bin || mkdir bin
test -f bin/illuaminate || wget -q -Obin/illuaminate https://squiddev.cc/illuaminate/linux-x86-64/illuaminate
chmod +x bin/illuaminate
bin/illuaminate lint
- name: Check whitespace
run: python3 tools/check-lines.py
pip install pre-commit
pre-commit run --config config/pre-commit/config.yml --show-diff-on-failure --all --color=always

View File

@@ -51,18 +51,10 @@ illuaminate, which spits out our HTML.
For various reasons, getting the environment set up to build documentation can be pretty complex. I'd quite like to
automate this via Docker and/or nix in the future, but this needs to be done manually for now.
First, you will need JDK 9+ (in addition to JDK 8 which is required to build Minecraft itself). Sadly our version of
Gradle doesn't support multiple toolchains, and so you need to install this yourself.
Gradle needs to be told about this JDK via the `JAVA_HOME_11_X64` environment variable or adding `java11Home` to
`~/.gradle/gradle.properties`. On my system this looks like:
```properties
java11Home=/usr/lib/jvm/java-11-openjdk/
```
If you just want to build the documentation stubs for linting, this is enough. However, if you want to build the full
website, you will also need to install a few Node packages by running `npm ci`.
This tooling is only needed if you need to build the whole website. If you just want to generate the Lua stubs, you can
skp this section.
- Install Node/npm and install our Node packages with `npm ci`.
- Install [illuaminate][illuaminate-usage] as described above.
#### Building documentation
Gradle should be your entrypoint to building most documentation. There's two tasks which are of interest:
@@ -73,7 +65,7 @@ Gradle should be your entrypoint to building most documentation. There's two tas
#### Writing documentation
illuaminate's documentation system is not currently documented (somewhat ironic), but is _largely_ the same as
[ldoc][ldoc]. Documentation comments are written in Markdown,
[ldoc][ldoc]. Documentation comments are written in Markdown,
Our markdown engine does _not_ support GitHub flavoured markdown, and so does not support all the features one might
expect (such as tables). It is very much recommended that you build and preview the docs locally first.
@@ -85,18 +77,18 @@ entire test suite (and some additional bits of verification).
Before we get into writing tests, it's worth mentioning the various test suites that CC: Tweaked has:
- "Core" Java (`./src/test/java`): These test core bits of the mod which don't require any Minecraft interaction.
This includes the `@LuaFunction` system, file system code, etc...
These tests are run by `./gradlew test`.
- CraftOS (`./src/test/resources/test-rom/`): These tests are written in Lua, and ensure the Lua environment, libraries
and programs work as expected. These are (generally) written to be able to be run on emulators too, to provide some
sort of compliance test.
These tests are run by the '"Core" Java' test suite, and so are also run with `./gradlew test`.
- In-game (`./src/test/java/dan200/computercraft/ingame/`): These tests are run on an actual Minecraft server, using
[the same system Mojang do][mc-test]. The aim of these is to test in-game behaviour of blocks and peripherals.
These are run by `./gradlew testInGame`.
## CraftOS tests

14
LICENSE
View File

@@ -19,14 +19,14 @@ Mod: The mod code designated by the present license, in source form, binary
form, as obtained standalone, as part of a wider distribution or resulting from
the compilation of the original or modified sources.
Dependency: Code required for the mod to work properly. This includes
Dependency: Code required for the mod to work properly. This includes
dependencies required to compile the code as well as any file or modification
that is explicitly or implicitly required for the mod to be working.
1. Scope
--------
The present license is granted to any user of the mod. As a prerequisite,
The present license is granted to any user of the mod. As a prerequisite,
a user must own a legally acquired copy of Minecraft
2. Liability
@@ -41,13 +41,13 @@ or misuse of this mod fall on the user.
3. Play rights
--------------
The user is allowed to install this mod on a Minecraft client or server and to play
The user is allowed to install this mod on a Minecraft client or server and to play
without restriction.
4. Modification rights
----------------------
The user has the right to decompile the source code, look at either the
The user has the right to decompile the source code, look at either the
decompiled version or the original source code, and to modify it.
5. Distribution of original or modified copy rights
@@ -61,10 +61,10 @@ include:
- patch to its source or binary files
- any copy of a portion of its binary source files
The user is allowed to redistribute this mod partially, in totality, or
The user is allowed to redistribute this mod partially, in totality, or
included in a distribution.
When distributing binary files, the user must provide means to obtain its
When distributing binary files, the user must provide means to obtain its
entire set of sources or modified sources at no cost.
All distributions of this mod must remain licensed under the CCPL.
@@ -92,7 +92,7 @@ must be made available at no cost and remain licensed under the CCPL.
---------------
If you choose to contribute code or assets to be included in this mod, you
agree that, if added to to the main repository at
agree that, if added to to the main repository at
https://github.com/dan200/ComputerCraft, your contributions will be covered by
this license, and that Daniel Ratcliffe will retain the right to re-license the
mod, including your contributions, in part or in whole, under other licenses.

View File

@@ -4,37 +4,48 @@ buildscript {
mavenCentral()
maven {
name = "forge"
url = "https://files.minecraftforge.net/maven"
url = "https://maven.minecraftforge.net"
}
maven {
name = "Sponge (Mixin)"
url = "https://repo.spongepowered.org/repository/maven-public/"
content { includeGroup "org.spongepowered" }
}
}
dependencies {
classpath 'com.google.code.gson:gson:2.8.1'
classpath 'net.minecraftforge.gradle:ForgeGradle:3.0.190'
classpath 'net.minecraftforge.gradle:ForgeGradle:4.1.9'
classpath 'net.sf.proguard:proguard-gradle:6.1.0beta2'
classpath 'org.ajoberstar.grgit:grgit-gradle:3.0.0'
classpath 'org.spongepowered:mixingradle:0.7-SNAPSHOT'
}
}
plugins {
id "checkstyle"
id "jacoco"
id "maven-publish"
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"
id "com.matthewprenger.cursegradle" version "1.4.0"
id "com.github.breadmoirai.github-release" version "2.2.12"
id "org.jetbrains.kotlin.jvm" version "1.3.72"
}
apply plugin: 'net.minecraftforge.gradle'
apply plugin: 'org.ajoberstar.grgit'
apply plugin: 'maven-publish'
apply plugin: 'maven'
apply plugin: 'org.spongepowered.mixin'
version = mod_version
group = "org.squiddev"
archivesBaseName = "cc-tweaked-${mc_version}"
sourceCompatibility = targetCompatibility = compileJava.sourceCompatibility = compileJava.targetCompatibility = '1.8'
java {
toolchain {
languageVersion = JavaLanguageVersion.of(8)
}
withSourcesJar()
withJavadocJar()
}
minecraft {
runs {
@@ -79,6 +90,10 @@ minecraft {
testServer {
workingDirectory project.file('test-files/server')
parent runs.server
properties 'mixin.env.disableRefMap': 'true'
arg "-mixin.config=cctest.mixin.json"
arg "--nogui"
mods {
cctest {
@@ -88,11 +103,15 @@ minecraft {
}
}
mappings channel: 'official', version: project.mc_version
mappings channel: 'official', version: mc_version
accessTransformer file('src/main/resources/META-INF/accesstransformer.cfg')
}
mixin {
add sourceSets.test, "cctest.refmap.json"
}
sourceSets {
main.resources {
srcDir 'src/generated/resources'
@@ -110,7 +129,6 @@ repositories {
configurations {
shade
compile.extendsFrom shade
deployerJars
cctJavadoc
}
@@ -119,15 +137,12 @@ dependencies {
minecraft "net.minecraftforge:forge:${mc_version}-${forge_version}"
compileOnly fg.deobf("mezz.jei:jei-1.15.2:6.0.0.3:api")
compileOnly fg.deobf("com.blamejared.crafttweaker:CraftTweaker-1.15.2:6.0.0.9")
compileOnly fg.deobf("mezz.jei:jei-1.16.4:7.6.0.58:api")
compileOnly fg.deobf("com.blamejared.crafttweaker:CraftTweaker-1.16.4:7.0.0.63")
runtimeOnly fg.deobf("mezz.jei:jei-1.15.2:6.0.0.3")
runtimeOnly fg.deobf("mezz.jei:jei-1.16.4:7.6.0.58")
compileOnly 'com.google.auto.service:auto-service:1.0-rc7'
annotationProcessor 'com.google.auto.service:auto-service:1.0-rc7'
shade 'org.squiddev:Cobalt:0.5.1-SNAPSHOT'
shade 'org.squiddev:Cobalt:0.5.2-SNAPSHOT'
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.7.0'
testImplementation 'org.junit.jupiter:junit-jupiter-params:5.7.0'
@@ -136,10 +151,9 @@ dependencies {
testImplementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.3.72'
testImplementation 'org.jetbrains.kotlin:kotlin-reflect:1.3.72'
testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.8'
testAnnotationProcessor 'org.spongepowered:mixin:0.8.2:processor'
deployerJars "org.apache.maven.wagon:wagon-ssh:3.0.0"
cctJavadoc 'cc.tweaked:cct-javadoc:1.3.0'
cctJavadoc 'cc.tweaked:cct-javadoc:1.4.0'
}
// Compile tasks
@@ -158,17 +172,14 @@ task luaJavadoc(type: Javadoc) {
options.docletpath = configurations.cctJavadoc.files as List
options.doclet = "cc.tweaked.javadoc.LuaDoclet"
options.noTimestamp = false
// Attempt to run under Java 11 (any Java >= 9 will work though).
if(System.getProperty("java.version").startsWith("1.")
&& (System.getenv("JAVA_HOME_11_X64") != null || project.hasProperty("java11Home"))) {
executable = "${System.getenv("JAVA_HOME_11_X64") ?: project.property("java11Home")}/bin/javadoc"
javadocTool = javaToolchains.javadocToolFor {
languageVersion = JavaLanguageVersion.of(11)
}
}
jar {
dependsOn javadoc
manifest {
attributes(["Specification-Title": "computercraft",
"Specification-Vendor": "SquidDev",
@@ -179,10 +190,6 @@ jar {
"Implementation-Timestamp": new Date().format("yyyy-MM-dd'T'HH:mm:ssZ")])
}
from (sourceSets.main.allSource) {
include "dan200/computercraft/api/**/*.java"
}
from configurations.shade.collect { it.isDirectory() ? it : zipTree(it) }
}
@@ -200,7 +207,6 @@ 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
task proguard(type: ProGuardTask, dependsOn: jar) {
@@ -253,16 +259,15 @@ processResources {
def hash = 'none'
Set<String> contributors = []
try {
def grgit = Grgit.open(dir: '.')
hash = grgit.head().id
hash = ["git", "-C", projectDir, "rev-parse", "HEAD"].execute().text.trim()
def blacklist = ['GitHub', 'dan200', 'Daniel Ratcliffe']
grgit.log().each {
if (!blacklist.contains(it.author.name)) contributors.add(it.author.name)
if (!blacklist.contains(it.committer.name)) contributors.add(it.committer.name)
["git", "-C", projectDir, "log", "--format=tformat:%an%n%cn"].execute().text.split('\n').each {
if (!blacklist.contains(it)) contributors.add(it)
}
} catch(Exception ignored) { }
} catch(Exception e) {
e.printStackTrace()
}
inputs.property "commithash", hash
from(sourceSets.main.resources.srcDirs) {
@@ -483,8 +488,8 @@ tasks.register('jacocoTestInGameReport', JacocoReport.class).configure {
it.dependsOn('testInGame')
it.executionData(new File(buildDir, 'jacoco/testInGame.exec'))
it.setSourceDirectories(project.files(sourceSets.main.allJava.srcDirs))
it.setClassDirectories(project.files(new File(buildDir, 'jacocoClassDump/testInGame')))
it.sourceDirectories.from(sourceSets.main.allJava.srcDirs)
it.classDirectories.from(new File(buildDir, 'jacocoClassDump/testInGame'))
it.reports {
xml.enabled true
@@ -546,56 +551,56 @@ curseforge {
relations {
incompatible "computercraft"
}
addGameVersion '1.16.4'
addGameVersion '1.16.5'
}
}
tasks.withType(GenerateModuleMetadata) {
// We can't generate metadata as that includes Forge as a dependency.
enabled = false
}
publishing {
publications {
mavenJava(MavenPublication) {
maven(MavenPublication) {
from components.java
// artifact sourceJar
pom {
name = 'CC: Tweaked'
description = 'CC: Tweaked is a fork of ComputerCraft, adding programmable computers, turtles and more to Minecraft.'
url = 'https://github.com/SquidDev-CC/CC-Tweaked'
scm {
url = 'https://github.com/SquidDev-CC/CC-Tweaked.git'
}
issueManagement {
system = 'github'
url = 'https://github.com/SquidDev-CC/CC-Tweaked/issues'
}
licenses {
license {
name = 'ComputerCraft Public License, Version 1.0'
url = 'https://github.com/SquidDev-CC/CC-Tweaked/blob/mc-1.15.x/LICENSE'
}
}
withXml { asNode().remove(asNode().get("dependencies")) }
}
}
}
}
uploadArchives {
repositories {
if(project.hasProperty('mavenUploadUrl')) {
mavenDeployer {
configuration = configurations.deployerJars
repository(url: project.property('mavenUploadUrl')) {
authentication(
userName: project.property('mavenUploadUser'),
privateKey: project.property('mavenUploadKey'))
}
pom.project {
name 'CC: Tweaked'
packaging 'jar'
description 'CC: Tweaked is a fork of ComputerCraft, adding programmable computers, turtles and more to Minecraft.'
url 'https://github.com/SquidDev-CC/CC-Tweaked'
scm {
url 'https://github.com/SquidDev-CC/CC-Tweaked.git'
}
issueManagement {
system 'github'
url 'https://github.com/SquidDev-CC/CC-Tweaked/issues'
}
licenses {
license {
name 'ComputerCraft Public License, Version 1.0'
url 'https://github.com/SquidDev-CC/CC-Tweaked/blob/master/LICENSE'
distribution 'repo'
}
}
}
pom.whenConfigured { pom ->
pom.dependencies.clear()
if (project.hasProperty("mavenUser")) {
maven {
name = "SquidDev"
url = "https://squiddev.cc/maven"
credentials {
username = project.property("mavenUser") as String
password = project.property("mavenPass") as String
}
}
}
@@ -606,22 +611,27 @@ githubRelease {
token project.hasProperty('githubApiKey') ? project.githubApiKey : ''
owner 'SquidDev-CC'
repo 'CC-Tweaked'
try {
targetCommitish = Grgit.open(dir: '.').branch.current().name
} catch(Exception ignored) { }
targetCommitish.set(project.provider({
try {
return ["git", "-C", projectDir, "rev-parse", "--abbrev-ref", "HEAD"].execute().text.trim()
} catch (Exception e) {
e.printStackTrace()
}
return "master"
}))
tagName "v${mc_version}-${mod_version}"
releaseName "[${mc_version}] ${mod_version}"
body {
body.set(project.provider({
"## " + new File(projectDir, "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"]
def uploadTasks = ["publish", "curseforge", "githubRelease"]
uploadTasks.forEach { tasks.getByName(it).dependsOn checkRelease }
task uploadAll(dependsOn: uploadTasks) {

View File

@@ -2488,4 +2488,4 @@
</option>
</inspection_tool>
</profile>
</component>
</component>

View File

@@ -58,4 +58,4 @@
<option name="CONTINUATION_INDENT_SIZE" value="4" />
</indentOptions>
</codeStyleSettings>
</code_scheme>
</code_scheme>

View File

@@ -0,0 +1,55 @@
# See https://pre-commit.com for more information
# See https://pre-commit.com/hooks.html for more hooks
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v3.2.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-merge-conflict
# Quick syntax checkers
- id: check-xml
- id: check-yaml
- id: check-toml
- id: check-json
exclude: "tsconfig\\.json$"
- repo: https://github.com/editorconfig-checker/editorconfig-checker.python
rev: 2.3.5
hooks:
- id: editorconfig-checker
args: ['-disable-indentation']
exclude: "^(.*\\.(bat)|LICENSE)$"
- repo: local
hooks:
- id: checkstyle
name: Check Java codestyle
files: ".*\\.java$"
language: system
entry: ./gradlew checkstyleMain checkstyleTest
pass_filenames: false
require_serial: true
- id: license
name: Check Java license headers
files: ".*\\.java$"
language: system
entry: ./gradlew licenseFormat
pass_filenames: false
require_serial: true
- id: illuaminate
name: Check Lua code
files: ".*\\.(lua|java|md)"
language: script
entry: config/pre-commit/illuaminate-lint.sh
pass_filenames: false
require_serial: true
exclude: |
(?x)^(
src/generated|
src/test/resources/test-rom/data/json-parsing/|
src/test/server-files/|
config/idea/
)

View File

@@ -0,0 +1,16 @@
#!/usr/bin/env sh
set -e
test -d bin || mkdir bin
test -f bin/illuaminate || curl -s -obin/illuaminate https://squiddev.cc/illuaminate/linux-x86-64/illuaminate
chmod +x bin/illuaminate
if [ -n ${GITHUB_ACTIONS+x} ]; then
# Register a problem matcher (see https://github.com/actions/toolkit/blob/master/docs/problem-matchers.md)
# for illuaminate.
echo "::add-matcher::.github/matchers/illuaminate.json"
trap 'echo "::remove-matcher owner=illuaminate::"' EXIT
fi
./gradlew luaJavadoc
bin/illuaminate lint

21
doc/events/alarm.md Normal file
View File

@@ -0,0 +1,21 @@
---
module: [kind=event] alarm
see: os.setAlarm To start an alarm.
---
The @{timer} event is fired when an alarm started with @{os.setAlarm} completes.
## Return Values
1. @{string}: The event name.
2. @{number}: The ID of the alarm that finished.
## Example
Starts a timer and then prints its ID:
```lua
local alarmID = os.setAlarm(os.time() + 0.05)
local event, id
repeat
event, id = os.pullEvent("alarm")
until id == alarmID
print("Alarm with ID " .. id .. " was fired")
```

View File

@@ -0,0 +1,18 @@
---
module: [kind=event] computer_command
---
The @{computer_command} event is fired when the `/computercraft queue` command is run for the current computer.
## Return Values
1. @{string}: The event name.
... @{string}: The arguments passed to the command.
## Example
Prints the contents of messages sent:
```lua
while true do
local event = {os.pullEvent("computer_command")}
print("Received message:", table.unpack(event, 2))
end
```

19
doc/events/disk.md Normal file
View File

@@ -0,0 +1,19 @@
---
module: [kind=event] disk
see: disk_eject For the event sent when a disk is removed.
---
The @{disk} event is fired when a disk is inserted into an adjacent or networked disk drive.
## Return Values
1. @{string}: The event name.
2. @{string}: The side of the disk drive that had a disk inserted.
## Example
Prints a message when a disk is inserted:
```lua
while true do
local event, side = os.pullEvent("disk")
print("Inserted a disk on side " .. side)
end
```

19
doc/events/disk_eject.md Normal file
View File

@@ -0,0 +1,19 @@
---
module: [kind=event] disk_eject
see: disk For the event sent when a disk is inserted.
---
The @{disk_eject} event is fired when a disk is removed from an adjacent or networked disk drive.
## Return Values
1. @{string}: The event name.
2. @{string}: The side of the disk drive that had a disk removed.
## Example
Prints a message when a disk is removed:
```lua
while true do
local event, side = os.pullEvent("disk_eject")
print("Removed a disk on side " .. side)
end
```

14
doc/events/http_check.md Normal file
View File

@@ -0,0 +1,14 @@
---
module: [kind=event] http_check
see: http.checkURLAsync To check a URL asynchronously.
---
The @{http_check} event is fired when a URL check finishes.
This event is normally handled inside @{http.checkURL}, but it can still be seen when using @{http.checkURLAsync}.
## Return Values
1. @{string}: The event name.
2. @{string}: The URL requested to be checked.
3. @{boolean}: Whether the check succeeded.
4. @{string|nil}: If the check failed, a reason explaining why the check failed.

View File

@@ -0,0 +1,39 @@
---
module: [kind=event] http_failure
see: http.request To send an HTTP request.
---
The @{http_failure} event is fired when an HTTP request fails.
This event is normally handled inside @{http.get} and @{http.post}, but it can still be seen when using @{http.request}.
## Return Values
1. @{string}: The event name.
2. @{string}: The URL of the site requested.
3. @{string}: An error describing the failure.
4. @{http.Response|nil}: A response handle if the connection succeeded, but the server's response indicated failure.
## Example
Prints an error why the website cannot be contacted:
```lua
local myURL = "https://does.not.exist.tweaked.cc"
http.request(myURL)
local event, url, err
repeat
event, url, err = os.pullEvent("http_failure")
until url == myURL
print("The URL " .. url .. " could not be reached: " .. err)
```
Prints the contents of a webpage that does not exist:
```lua
local myURL = "https://tweaked.cc/this/does/not/exist"
http.request(myURL)
local event, url, err, handle
repeat
event, url, err, handle = os.pullEvent("http_failure")
until url == myURL
print("The URL " .. url .. " could not be reached: " .. err)
print(handle.getResponseCode())
handle.close()
```

View File

@@ -0,0 +1,27 @@
---
module: [kind=event] http_success
see: http.request To make an HTTP request.
---
The @{http_success} event is fired when an HTTP request returns successfully.
This event is normally handled inside @{http.get} and @{http.post}, but it can still be seen when using @{http.request}.
## Return Values
1. @{string}: The event name.
2. @{string}: The URL of the site requested.
3. @{http.Response}: The handle for the response text.
## Example
Prints the content of a website (this may fail if the request fails):
```lua
local myURL = "https://tweaked.cc/"
http.request(myURL)
local event, url, handle
repeat
event, url, handle = os.pullEvent("http_success")
until url == myURL
print("Contents of " .. url .. ":")
print(handle.readAll())
handle.close()
```

View File

@@ -11,16 +11,16 @@ If the button pressed represented a printable character, then the @{key} event w
event. If you are consuming text input, use a @{char} event instead!
## Return values
1. [`string`]: The event name.
2. [`number`]: The numerical key value of the key pressed.
3. [`boolean`]: Whether the key event was generated while holding the key (@{true}), rather than pressing it the first time (@{false}).
1. @{string}: The event name.
2. @{number}: The numerical key value of the key pressed.
3. @{boolean}: Whether the key event was generated while holding the key (@{true}), rather than pressing it the first time (@{false}).
## Example
Prints each key when the user presses it, and if the key is being held.
```lua
while true do
local event, key, is_held = os.pullEvent("key")
local event, key, is_held = os.pullEvent("key")
print(("%s held=%s"):format(keys.getName(key), is_held))
end
```

View File

@@ -0,0 +1,22 @@
---
module: [kind=event] modem_message
---
The @{modem_message} event is fired when a message is received on an open channel on any modem.
## Return Values
1. @{string}: The event name.
2. @{string}: The side of the modem that received the message.
3. @{number}: The channel that the message was sent on.
4. @{number}: The reply channel set by the sender.
5. @{any}: The message as sent by the sender.
6. @{number}: The distance between the sender and the receiver, in blocks (decimal).
## Example
Prints a message when one is sent:
```lua
while true do
local event, side, channel, replyChannel, message, distance = os.pullEvent("modem_message")
print(("Message received on side %s on channel %d (reply to %d) from %f blocks away with message %s"):format(side, channel, replyChannel, distance, tostring(message)))
end
```

View File

@@ -0,0 +1,18 @@
---
module: [kind=event] monitor_resize
---
The @{monitor_resize} event is fired when an adjacent or networked monitor's size is changed.
## Return Values
1. @{string}: The event name.
2. @{string}: The side or network ID of the monitor that resized.
## Example
Prints a message when a monitor is resized:
```lua
while true do
local event, side = os.pullEvent("monitor_resize")
print("The monitor on side " .. side .. " was resized.")
end
```

View File

@@ -0,0 +1,20 @@
---
module: [kind=event] monitor_touch
---
The @{monitor_touch} event is fired when an adjacent or networked Advanced Monitor is right-clicked.
## Return Values
1. @{string}: The event name.
2. @{string}: The side or network ID of the monitor that was touched.
3. @{number}: The X coordinate of the touch, in characters.
4. @{number}: The Y coordinate of the touch, in characters.
## Example
Prints a message when a monitor is touched:
```lua
while true do
local event, side, x, y = os.pullEvent("monitor_touch")
print("The monitor on side " .. side .. " was touched at (" .. x .. ", " .. y .. ")")
end
```

View File

@@ -20,5 +20,3 @@ while true do
print(("The mouse button %s was dragged at %d, %d"):format(button, x, y))
end
```

View File

@@ -19,6 +19,3 @@ while true do
print(("The mouse button %s was released at %d, %d"):format(button, x, y))
end
```
[`string`]: string
[`number`]: number

18
doc/events/paste.md Normal file
View File

@@ -0,0 +1,18 @@
---
module: [kind=event] paste
---
The @{paste} event is fired when text is pasted into the computer through Ctrl-V (or ⌘V on Mac).
## Return values
1. @{string}: The event name.
2. @{string} The text that was pasted.
## Example
Prints pasted text:
```lua
while true do
local event, text = os.pullEvent("paste")
print('"' .. text .. '" was pasted')
end
```

19
doc/events/peripheral.md Normal file
View File

@@ -0,0 +1,19 @@
---
module: [kind=event] peripheral
see: peripheral_detach For the event fired when a peripheral is detached.
---
The @{peripheral} event is fired when a peripheral is attached on a side or to a modem.
## Return Values
1. @{string}: The event name.
2. @{string}: The side the peripheral was attached to.
## Example
Prints a message when a peripheral is attached:
```lua
while true do
local event, side = os.pullEvent("peripheral")
print("A peripheral was attached on side " .. side)
end
```

View File

@@ -0,0 +1,19 @@
---
module: [kind=event] peripheral_detach
see: peripheral For the event fired when a peripheral is attached.
---
The @{peripheral_detach} event is fired when a peripheral is detached from a side or from a modem.
## Return Values
1. @{string}: The event name.
2. @{string}: The side the peripheral was detached from.
## Example
Prints a message when a peripheral is detached:
```lua
while true do
local event, side = os.pullEvent("peripheral_detach")
print("A peripheral was detached on side " .. side)
end
```

View File

@@ -0,0 +1,30 @@
---
module: [kind=event] rednet_message
see: modem_message For raw modem messages sent outside of Rednet.
see: rednet.receive To wait for a Rednet message with an optional timeout and protocol filter.
---
The @{rednet_message} event is fired when a message is sent over Rednet.
This event is usually handled by @{rednet.receive}, but it can also be pulled manually.
@{rednet_message} events are sent by @{rednet.run} in the top-level coroutine in response to @{modem_message} events. A @{rednet_message} event is always preceded by a @{modem_message} event. They are generated inside CraftOS rather than being sent by the ComputerCraft machine.
## Return Values
1. @{string}: The event name.
2. @{number}: The ID of the sending computer.
3. @{any}: The message sent.
4. @{string|nil}: The protocol of the message, if provided.
## Example
Prints a message when one is sent:
```lua
while true do
local event, sender, message, protocol = os.pullEvent("rednet_message")
if protocol ~= nil then
print("Received message from " .. sender .. " with protocol " .. protocol .. " and message " .. tostring(message))
else
print("Received message from " .. sender .. " with message " .. tostring(message))
end
end
```

14
doc/events/redstone.md Normal file
View File

@@ -0,0 +1,14 @@
---
module: [kind=event] redstone
---
The @{redstone} event is fired whenever any redstone inputs on the computer change.
## Example
Prints a message when a redstone input changes:
```lua
while true do
os.pullEvent("redstone")
print("A redstone input has changed!")
end
```

View File

@@ -0,0 +1,28 @@
---
module: [kind=event] task_complete
see: commands.execAsync To run a command which fires a task_complete event.
---
The @{task_complete} event is fired when an asynchronous task completes. This is usually handled inside the function call that queued the task; however, functions such as @{commands.execAsync} return immediately so the user can wait for completion.
## Return Values
1. @{string}: The event name.
2. @{number}: The ID of the task that completed.
3. @{boolean}: Whether the command succeeded.
4. @{string}: If the command failed, an error message explaining the failure. (This is not present if the command succeeded.)
...: Any parameters returned from the command.
## Example
Prints the results of an asynchronous command:
```lua
local taskID = commands.execAsync("say Hello")
local event
repeat
event = {os.pullEvent("task_complete")}
until event[2] == taskID
if event[3] == true then
print("Task " .. event[2] .. " succeeded:", table.unpack(event, 4))
else
print("Task " .. event[2] .. " failed: " .. event[4])
end
```

15
doc/events/term_resize.md Normal file
View File

@@ -0,0 +1,15 @@
---
module: [kind=event] term_resize
---
The @{term_resize} event is fired when the main terminal is resized, mainly when a new tab is opened or closed in @{multishell}.
## Example
Prints :
```lua
while true do
os.pullEvent("term_resize")
local w, h = term.getSize()
print("The term was resized to (" .. w .. ", " .. h .. ")")
end
```

25
doc/events/terminate.md Normal file
View File

@@ -0,0 +1,25 @@
---
module: [kind=event] terminate
---
The @{terminate} event is fired when <kbd>Ctrl-T</kbd> is held down.
This event is normally handled by @{os.pullEvent}, and will not be returned. However, @{os.pullEventRaw} will return this event when fired.
@{terminate} will be sent even when a filter is provided to @{os.pullEventRaw}. When using @{os.pullEventRaw} with a filter, make sure to check that the event is not @{terminate}.
## Example
Prints a message when Ctrl-T is held:
```lua
while true do
local event = os.pullEventRaw("terminate")
if event == "terminate" then print("Terminate requested!") end
end
```
Exits when Ctrl-T is held:
```lua
while true do
os.pullEvent()
end
```

21
doc/events/timer.md Normal file
View File

@@ -0,0 +1,21 @@
---
module: [kind=event] timer
see: os.startTimer To start a timer.
---
The @{timer} event is fired when a timer started with @{os.startTimer} completes.
## Return Values
1. @{string}: The event name.
2. @{number}: The ID of the timer that finished.
## Example
Starts a timer and then prints its ID:
```lua
local timerID = os.startTimer(2)
local event, id
repeat
event, id = os.pullEvent("timer")
until id == timerID
print("Timer with ID " .. id .. " was fired")
```

View File

@@ -0,0 +1,14 @@
---
module: [kind=event] turtle_inventory
---
The @{turtle_inventory} event is fired when a turtle's inventory is changed.
## Example
Prints a message when the inventory is changed:
```lua
while true do
os.pullEvent("turtle_inventory")
print("The inventory was changed.")
end
```

View File

@@ -0,0 +1,21 @@
---
module: [kind=event] websocket_closed
---
The @{websocket_closed} event is fired when an open WebSocket connection is closed.
## Return Values
1. @{string}: The event name.
2. @{string}: The URL of the WebSocket that was closed.
## Example
Prints a message when a WebSocket is closed (this may take a minute):
```lua
local myURL = "wss://example.tweaked.cc/echo"
local ws = http.websocket(myURL)
local event, url
repeat
event, url = os.pullEvent("websocket_closed")
until url == myURL
print("The WebSocket at " .. url .. " was closed.")
```

View File

@@ -0,0 +1,25 @@
---
module: [kind=event] websocket_failure
see: http.websocketAsync To send an HTTP request.
---
The @{websocket_failure} event is fired when a WebSocket connection request fails.
This event is normally handled inside @{http.websocket}, but it can still be seen when using @{http.websocketAsync}.
## Return Values
1. @{string}: The event name.
2. @{string}: The URL of the site requested.
3. @{string}: An error describing the failure.
## Example
Prints an error why the website cannot be contacted:
```lua
local myURL = "wss://example.tweaked.cc/not-a-websocket"
http.websocketAsync(myURL)
local event, url, err
repeat
event, url, err = os.pullEvent("websocket_failure")
until url == myURL
print("The URL " .. url .. " could not be reached: " .. err)
```

View File

@@ -0,0 +1,26 @@
---
module: [kind=event] websocket_message
---
The @{websocket_message} event is fired when a message is received on an open WebSocket connection.
This event is normally handled by @{http.Websocket.receive}, but it can also be pulled manually.
## Return Values
1. @{string}: The event name.
2. @{string}: The URL of the WebSocket.
3. @{string}: The contents of the message.
## Example
Prints a message sent by a WebSocket:
```lua
local myURL = "wss://example.tweaked.cc/echo"
local ws = http.websocket(myURL)
ws.send("Hello!")
local event, url, message
repeat
event, url, message = os.pullEvent("websocket_message")
until url == myURL
print("Received message from " .. url .. " with contents " .. message)
ws.close()
```

View File

@@ -0,0 +1,28 @@
---
module: [kind=event] websocket_success
see: http.websocketAsync To open a WebSocket asynchronously.
---
The @{websocket_success} event is fired when a WebSocket connection request returns successfully.
This event is normally handled inside @{http.websocket}, but it can still be seen when using @{http.websocketAsync}.
## Return Values
1. @{string}: The event name.
2. @{string}: The URL of the site.
3. @{http.Websocket}: The handle for the WebSocket.
## Example
Prints the content of a website (this may fail if the request fails):
```lua
local myURL = "wss://example.tweaked.cc/echo"
http.websocketAsync(myURL)
local event, url, handle
repeat
event, url, handle = os.pullEvent("websocket_success")
until url == myURL
print("Connected to " .. url)
handle.send("Hello!")
print(handle.receive())
handle.close()
```

View File

@@ -58,10 +58,10 @@ function request(...) end
-- @treturn string A message detailing why the request failed.
-- @treturn Response|nil The failing http response, if available.
--
-- @usage Make a request to [example.computercraft.cc](https://example.computercraft.cc),
-- @usage Make a request to [example.tweaked.cc](https://example.tweaked.cc),
-- and print the returned page.
-- ```lua
-- local request = http.get("https://example.computercraft.cc")
-- local request = http.get("https://example.tweaked.cc")
-- print(request.readAll())
-- -- => HTTP is working!
-- request.close()
@@ -123,7 +123,7 @@ function checkURLAsync(url) end
--
-- @usage
-- ```lua
-- print(http.checkURL("https://example.computercraft.cc/"))
-- print(http.checkURL("https://example.tweaked.cc/"))
-- -- => true
-- print(http.checkURL("http://localhost/"))
-- -- => false Domain not permitted

View File

@@ -1 +1,13 @@
--[[- Craft a recipe based on the turtle's inventory.
The turtle's inventory should set up like a crafting grid. For instance, to
craft sticks, slots 1 and 5 should contain sticks. _All_ other slots should be
empty, including those outside the crafting "grid".
@tparam[opt=64] number limit The maximum number of crafting steps to run.
@throws When limit is less than 1 or greater than 64.
@treturn[1] true If crafting succeeds.
@treturn[2] false If crafting fails.
@treturn string A string describing why crafting failed.
]]
function craft(limit) end

View File

@@ -1,6 +1,6 @@
# Mod properties
mod_version=1.95.2
mod_version=1.96.0
# Minecraft properties (update mods.toml when changing)
mc_version=1.15.2
forge_version=31.1.41
mc_version=1.16.4
forge_version=35.1.16

Binary file not shown.

View File

@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.9-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.2-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

53
gradlew vendored
View File

@@ -1,5 +1,21 @@
#!/usr/bin/env sh
#
# Copyright 2015 the original author or authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
##############################################################################
##
## Gradle start up script for UN*X
@@ -28,7 +44,7 @@ APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
@@ -66,6 +82,7 @@ esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
@@ -109,10 +126,11 @@ if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
# For Cygwin or MSYS, switch paths to Windows format before running java
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
@@ -138,19 +156,19 @@ if $cygwin ; then
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
i=`expr $i + 1`
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
0) set -- ;;
1) set -- "$args0" ;;
2) set -- "$args0" "$args1" ;;
3) set -- "$args0" "$args1" "$args2" ;;
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
@@ -159,14 +177,9 @@ save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=$(save "$@")
APP_ARGS=`save "$@"`
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
cd "$(dirname "$0")"
fi
exec "$JAVACMD" "$@"

43
gradlew.bat vendored
View File

@@ -1,3 +1,19 @@
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@@ -13,15 +29,18 @@ if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
if "%ERRORLEVEL%" == "0" goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
@@ -35,7 +54,7 @@ goto fail
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
if exist "%JAVA_EXE%" goto execute
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
@@ -45,28 +64,14 @@ echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end
@rem End local scope for the variables with windows NT shell

View File

@@ -88,27 +88,16 @@
;; Suppress warnings for currently undocumented modules.
(at
(; Java APIs
/doc/stub/http.lua
/doc/stub/os.lua
/doc/stub/turtle.lua
/doc/stub/global.lua
; Java generated APIs
/build/docs/luaJavadoc/turtle.lua
; Peripherals
/build/docs/luaJavadoc/drive.lua
/build/docs/luaJavadoc/speaker.lua
/build/docs/luaJavadoc/printer.lua
; Generic peripherals
/build/docs/luaJavadoc/fluid_storage.lua
; Lua APIs
(; Lua APIs
/src/main/resources/*/computercraft/lua/rom/apis/io.lua
/src/main/resources/*/computercraft/lua/rom/apis/window.lua)
(linters -doc:undocumented -doc:undocumented-arg -doc:undocumented-return))
;; Suppress warnings for the BIOS using its own deprecated members for now.
(at /src/main/resources/*/computercraft/lua/bios.lua
;; Suppress warnings for various APIs using its own deprecated members.
(at
(/src/main/resources/*/computercraft/lua/bios.lua
/src/main/resources/*/computercraft/lua/rom/apis/turtle/turtle.lua)
(linters -var:deprecated))
(at /src/test/resources/test-rom

View File

@@ -0,0 +1,10 @@
{
"replace": false,
"values": [
"computercraft:computer_advanced",
"computercraft:turtle_advanced",
"computercraft:wireless_modem_advanced",
"computercraft:pocket_computer_advanced",
"computercraft:monitor_advanced"
]
}

View File

@@ -8,7 +8,6 @@ package dan200.computercraft;
import dan200.computercraft.api.turtle.event.TurtleAction;
import dan200.computercraft.core.apis.http.options.Action;
import dan200.computercraft.core.apis.http.options.AddressRule;
import dan200.computercraft.core.asm.GenericSource;
import dan200.computercraft.shared.Config;
import dan200.computercraft.shared.Registry;
import dan200.computercraft.shared.computer.core.ClientComputerRegistry;
@@ -17,7 +16,6 @@ import dan200.computercraft.shared.peripheral.monitor.MonitorRenderer;
import dan200.computercraft.shared.pocket.peripherals.PocketModem;
import dan200.computercraft.shared.pocket.peripherals.PocketSpeaker;
import dan200.computercraft.shared.turtle.upgrades.*;
import dan200.computercraft.shared.util.ServiceUtil;
import net.minecraftforge.fml.common.Mod;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@@ -117,6 +115,5 @@ public final class ComputerCraft
{
Config.setup();
Registry.setup();
GenericSource.setup( () -> ServiceUtil.loadServicesForge( GenericSource.class ) );
}
}

View File

@@ -8,6 +8,7 @@ package dan200.computercraft;
import dan200.computercraft.api.ComputerCraftAPI.IComputerCraftAPI;
import dan200.computercraft.api.filesystem.IMount;
import dan200.computercraft.api.filesystem.IWritableMount;
import dan200.computercraft.api.lua.GenericSource;
import dan200.computercraft.api.lua.ILuaAPIFactory;
import dan200.computercraft.api.media.IMediaProvider;
import dan200.computercraft.api.network.IPacketNetwork;
@@ -18,9 +19,11 @@ import dan200.computercraft.api.pocket.IPocketUpgrade;
import dan200.computercraft.api.redstone.IBundledRedstoneProvider;
import dan200.computercraft.api.turtle.ITurtleUpgrade;
import dan200.computercraft.core.apis.ApiFactories;
import dan200.computercraft.core.asm.GenericMethod;
import dan200.computercraft.core.filesystem.FileMount;
import dan200.computercraft.core.filesystem.ResourceMount;
import dan200.computercraft.shared.*;
import dan200.computercraft.shared.peripheral.generic.GenericPeripheralProvider;
import dan200.computercraft.shared.peripheral.modem.wireless.WirelessNetwork;
import dan200.computercraft.shared.util.IDAssigner;
import dan200.computercraft.shared.wired.WiredNode;
@@ -31,6 +34,7 @@ import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IBlockReader;
import net.minecraft.world.World;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.fml.ModList;
import net.minecraftforge.fml.server.ServerLifecycleHooks;
@@ -54,7 +58,7 @@ public final class ComputerCraftAPIImpl implements IComputerCraftAPI
public static InputStream getResourceFile( String domain, String subPath )
{
IReloadableResourceManager manager = ServerLifecycleHooks.getCurrentServer().getResources();
IReloadableResourceManager manager = (IReloadableResourceManager) ServerLifecycleHooks.getCurrentServer().getDataPackRegistries().getResourceManager();
try
{
return manager.getResource( new ResourceLocation( domain, subPath ) ).getInputStream();
@@ -97,7 +101,7 @@ public final class ComputerCraftAPIImpl implements IComputerCraftAPI
@Override
public IMount createResourceMount( @Nonnull String domain, @Nonnull String subPath )
{
IReloadableResourceManager manager = ServerLifecycleHooks.getCurrentServer().getResources();
IReloadableResourceManager manager = (IReloadableResourceManager) ServerLifecycleHooks.getCurrentServer().getDataPackRegistries().getResourceManager();
ResourceMount mount = ResourceMount.get( domain, subPath, manager );
return mount.exists( "" ) ? mount : null;
}
@@ -108,6 +112,18 @@ public final class ComputerCraftAPIImpl implements IComputerCraftAPI
Peripherals.register( provider );
}
@Override
public void registerGenericSource( @Nonnull GenericSource source )
{
GenericMethod.register( source );
}
@Override
public void registerGenericCapability( @Nonnull Capability<?> capability )
{
GenericPeripheralProvider.addCapability( capability );
}
@Override
public void registerTurtleUpgrade( @Nonnull ITurtleUpgrade upgrade )
{

View File

@@ -7,6 +7,7 @@ package dan200.computercraft.api;
import dan200.computercraft.api.filesystem.IMount;
import dan200.computercraft.api.filesystem.IWritableMount;
import dan200.computercraft.api.lua.GenericSource;
import dan200.computercraft.api.lua.ILuaAPIFactory;
import dan200.computercraft.api.media.IMedia;
import dan200.computercraft.api.media.IMediaProvider;
@@ -23,6 +24,7 @@ import net.minecraft.util.Direction;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IBlockReader;
import net.minecraft.world.World;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.util.LazyOptional;
import javax.annotation.Nonnull;
@@ -98,7 +100,9 @@ public final class ComputerCraftAPI
* resource folder onto a computer's file system.
*
* The files in this mount will be a combination of files in all mod jar, and data packs that contain
* resources with the same domain and path.
* resources with the same domain and path. For instance, ComputerCraft's resources are stored in
* "/data/computercraft/lua/rom". We construct a mount for that with
* {@code createResourceMount("computercraft", "lua/rom")}.
*
* @param domain The domain under which to look for resources. eg: "mymod".
* @param subPath The subPath under which to look for resources. eg: "lua/myfiles".
@@ -114,7 +118,7 @@ public final class ComputerCraftAPI
}
/**
* Registers a peripheral provider to convert blocks into {@link IPeripheral} implementations.
* rers a peripheral provider to convert blocks into {@link IPeripheral} implementations.
*
* @param provider The peripheral provider to register.
* @see IPeripheral
@@ -125,6 +129,28 @@ public final class ComputerCraftAPI
getInstance().registerPeripheralProvider( provider );
}
/**
* Registers a method source for generic peripherals.
*
* @param source The method source to register.
* @see GenericSource
*/
public static void registerGenericSource( @Nonnull GenericSource source )
{
getInstance().registerGenericSource( source );
}
/**
* Registers a capability that can be used by generic peripherals.
*
* @param capability The capability to register.
* @see GenericSource
*/
public static void registerGenericCapability( @Nonnull Capability<?> capability )
{
getInstance().registerGenericCapability( capability );
}
/**
* Registers a new turtle turtle for use in ComputerCraft. After calling this,
* users should be able to craft Turtles with your new turtle. It is recommended to call
@@ -256,6 +282,10 @@ public final class ComputerCraftAPI
void registerPeripheralProvider( @Nonnull IPeripheralProvider provider );
void registerGenericSource( @Nonnull GenericSource source );
void registerGenericCapability( @Nonnull Capability<?> capability );
void registerTurtleUpgrade( @Nonnull ITurtleUpgrade upgrade );
void registerBundledRedstoneProvider( @Nonnull IBundledRedstoneProvider provider );

View File

@@ -6,11 +6,11 @@
package dan200.computercraft.api.client;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.TransformationMatrix;
import net.minecraft.client.renderer.model.IBakedModel;
import net.minecraft.client.renderer.model.ModelManager;
import net.minecraft.client.renderer.model.ModelResourceLocation;
import net.minecraft.item.ItemStack;
import net.minecraft.util.math.vector.TransformationMatrix;
import javax.annotation.Nonnull;
import java.util.Objects;

View File

@@ -0,0 +1,60 @@
/*
* This file is part of the public ComputerCraft API - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only.
* For help using the API, and posting your mods, visit the forums at computercraft.info.
*/
package dan200.computercraft.api.lua;
import dan200.computercraft.api.ComputerCraftAPI;
import dan200.computercraft.api.peripheral.IPeripheral;
import dan200.computercraft.api.peripheral.IPeripheralProvider;
import dan200.computercraft.core.asm.LuaMethod;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.items.IItemHandler;
import javax.annotation.Nonnull;
/**
* A generic source of {@link LuaMethod} functions.
*
* Unlike normal objects ({@link IDynamicLuaObject} or {@link IPeripheral}), methods do not target this object but
* instead are defined as {@code static} and accept their target as the first parameter. This allows you to inject
* methods onto objects you do not own, as well as declaring methods for a specific "trait" (for instance, a
* {@link Capability}).
*
* Currently the "generic peripheral" system is incompatible with normal peripherals. Normal {@link IPeripheralProvider}
* or {@link IPeripheral} implementations take priority. Tile entities which use this system are given a peripheral name
* determined by their id, rather than any peripheral provider. This will hopefully change in the future, once a suitable
* design has been established.
*
* For example, the main CC: Tweaked mod defines a generic source for inventories, which works on {@link IItemHandler}s:
*
* <pre>{@code
* public class InventoryMethods implements GenericSource {
* \@LuaFunction( mainThread = true )
* public static int size(IItemHandler inventory) {
* return inventory.getSlots();
* }
*
* // ...
* }
* }</pre>
*
* @see ComputerCraftAPI#registerGenericSource(GenericSource)
* @see ComputerCraftAPI#registerGenericCapability(Capability) New capabilities (those not built into Forge) must be
* explicitly given to the generic peripheral system, as there is no way to enumerate all capabilities.
*/
public interface GenericSource
{
/**
* A unique identifier for this generic source.
*
* This is currently unused, but may be used in the future to allow disabling specific sources. It is recommended
* to return an identifier using your mod's ID.
*
* @return This source's identifier.
*/
@Nonnull
ResourceLocation id();
}

View File

@@ -5,7 +5,7 @@
*/
package dan200.computercraft.api.network;
import net.minecraft.util.math.Vec3d;
import net.minecraft.util.math.vector.Vector3d;
import net.minecraft.world.World;
import javax.annotation.Nonnull;
@@ -29,7 +29,7 @@ public interface IPacketReceiver
* @return The receiver's position.
*/
@Nonnull
Vec3d getPosition();
Vector3d getPosition();
/**
* Get the maximum distance this receiver can send and receive messages.

View File

@@ -5,7 +5,7 @@
*/
package dan200.computercraft.api.network;
import net.minecraft.util.math.Vec3d;
import net.minecraft.util.math.vector.Vector3d;
import net.minecraft.world.World;
import javax.annotation.Nonnull;
@@ -29,7 +29,7 @@ public interface IPacketSender
* @return The sender's position.
*/
@Nonnull
Vec3d getPosition();
Vector3d getPosition();
/**
* Get some sort of identification string for this sender. This does not strictly need to be unique, but you

View File

@@ -13,7 +13,7 @@ import net.minecraft.inventory.IInventory;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.util.Direction;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
import net.minecraft.util.math.vector.Vector3d;
import net.minecraft.world.World;
import net.minecraftforge.items.IItemHandlerModifiable;
@@ -67,7 +67,7 @@ public interface ITurtleAccess
* @see #getVisualYaw(float)
*/
@Nonnull
Vec3d getVisualPosition( float f );
Vector3d getVisualPosition( float f );
/**
* Returns the yaw the turtle is facing when it is rendered.

View File

@@ -12,14 +12,12 @@ import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.FontRenderer;
import net.minecraft.client.gui.NewChatGui;
import net.minecraft.client.gui.RenderComponentsUtil;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.text.TextFormatting;
import org.apache.commons.lang3.StringUtils;
import javax.annotation.Nullable;
import java.util.List;
public class ClientTableFormatter implements TableFormatter
{
@@ -57,7 +55,7 @@ public class ClientTableFormatter implements TableFormatter
@Override
public int getWidth( ITextComponent component )
{
return renderer().width( component.getColoredString() );
return renderer().width( component );
}
@Override
@@ -66,10 +64,11 @@ public class ClientTableFormatter implements TableFormatter
Minecraft mc = Minecraft.getInstance();
NewChatGui chat = mc.gui.getChat();
// Trim the text if it goes over the allowed length
int maxWidth = MathHelper.floor( chat.getWidth() / chat.getScale() );
List<ITextComponent> list = RenderComponentsUtil.wrapComponents( component, maxWidth, mc.font, false, false );
if( !list.isEmpty() ) chat.addMessage( list.get( 0 ), id );
// TODO: Trim the text if it goes over the allowed length
// int maxWidth = MathHelper.floor( chat.getChatWidth() / chat.getScale() );
// List<ITextProperties> list = RenderComponentsUtil.wrapComponents( component, maxWidth, mc.fontRenderer );
// if( !list.isEmpty() ) chat.printChatMessageWithOptionalDeletion( list.get( 0 ), id );
chat.addMessage( component, id );
}
@Override

View File

@@ -13,10 +13,14 @@ import dan200.computercraft.core.terminal.TextBuffer;
import dan200.computercraft.shared.util.Colour;
import dan200.computercraft.shared.util.Palette;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.*;
import net.minecraft.client.renderer.IRenderTypeBuffer;
import net.minecraft.client.renderer.RenderState;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.client.renderer.vertex.VertexFormat;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.vector.Matrix4f;
import net.minecraft.util.math.vector.TransformationMatrix;
import org.lwjgl.opengl.GL11;
import javax.annotation.Nonnull;

View File

@@ -5,6 +5,7 @@
*/
package dan200.computercraft.client.gui;
import com.mojang.blaze3d.matrix.MatrixStack;
import com.mojang.blaze3d.systems.RenderSystem;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.client.gui.widgets.WidgetTerminal;
@@ -21,6 +22,8 @@ import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.util.text.ITextComponent;
import org.lwjgl.glfw.GLFW;
import javax.annotation.Nonnull;
import static dan200.computercraft.client.render.ComputerBorderRenderer.BORDER;
import static dan200.computercraft.client.render.ComputerBorderRenderer.MARGIN;
@@ -120,7 +123,7 @@ public final class GuiComputer<T extends ContainerComputerBase> extends Containe
}
@Override
public void renderBg( float partialTicks, int mouseX, int mouseY )
public void renderBg( @Nonnull MatrixStack stack, float partialTicks, int mouseX, int mouseY )
{
// Draw terminal
terminal.draw( terminalWrapper.getX(), terminalWrapper.getY() );
@@ -135,11 +138,10 @@ public final class GuiComputer<T extends ContainerComputerBase> extends Containe
}
@Override
public void render( int mouseX, int mouseY, float partialTicks )
public void render( @Nonnull MatrixStack stack, int mouseX, int mouseY, float partialTicks )
{
renderBackground();
super.render( mouseX, mouseY, partialTicks );
renderTooltip( mouseX, mouseY );
super.render( stack, mouseX, mouseY, partialTicks );
renderTooltip( stack, mouseX, mouseY );
}
@Override
@@ -148,4 +150,10 @@ public final class GuiComputer<T extends ContainerComputerBase> extends Containe
return (getFocused() != null && getFocused().mouseDragged( x, y, button, deltaX, deltaY ))
|| super.mouseDragged( x, y, button, deltaX, deltaY );
}
@Override
protected void renderLabels( @Nonnull MatrixStack transform, int mouseX, int mouseY )
{
// Skip rendering labels.
}
}

View File

@@ -5,6 +5,7 @@
*/
package dan200.computercraft.client.gui;
import com.mojang.blaze3d.matrix.MatrixStack;
import com.mojang.blaze3d.systems.RenderSystem;
import dan200.computercraft.shared.peripheral.diskdrive.ContainerDiskDrive;
import net.minecraft.client.gui.screen.inventory.ContainerScreen;
@@ -12,6 +13,8 @@ import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.text.ITextComponent;
import javax.annotation.Nonnull;
public class GuiDiskDrive extends ContainerScreen<ContainerDiskDrive>
{
private static final ResourceLocation BACKGROUND = new ResourceLocation( "computercraft", "textures/gui/disk_drive.png" );
@@ -22,26 +25,18 @@ public class GuiDiskDrive extends ContainerScreen<ContainerDiskDrive>
}
@Override
protected void renderLabels( int mouseX, int mouseY )
{
String title = this.title.getColoredString();
font.draw( title, (imageWidth - font.width( title )) / 2.0f, 6, 0x404040 );
font.draw( title, 8, imageHeight - 96 + 2, 0x404040 );
}
@Override
protected void renderBg( float partialTicks, int mouseX, int mouseY )
protected void renderBg( @Nonnull MatrixStack transform, float partialTicks, int mouseX, int mouseY )
{
RenderSystem.color4f( 1.0F, 1.0F, 1.0F, 1.0F );
minecraft.getTextureManager().bind( BACKGROUND );
blit( leftPos, topPos, 0, 0, imageWidth, imageHeight );
blit( transform, leftPos, topPos, 0, 0, imageWidth, imageHeight );
}
@Override
public void render( int mouseX, int mouseY, float partialTicks )
public void render( @Nonnull MatrixStack transform, int mouseX, int mouseY, float partialTicks )
{
renderBackground();
super.render( mouseX, mouseY, partialTicks );
renderTooltip( mouseX, mouseY );
renderBackground( transform );
super.render( transform, mouseX, mouseY, partialTicks );
renderTooltip( transform, mouseX, mouseY );
}
}

View File

@@ -5,14 +5,16 @@
*/
package dan200.computercraft.client.gui;
import com.mojang.blaze3d.matrix.MatrixStack;
import com.mojang.blaze3d.systems.RenderSystem;
import dan200.computercraft.shared.peripheral.printer.ContainerPrinter;
import net.minecraft.client.gui.screen.inventory.ContainerScreen;
import net.minecraft.client.resources.I18n;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.text.ITextComponent;
import javax.annotation.Nonnull;
public class GuiPrinter extends ContainerScreen<ContainerPrinter>
{
private static final ResourceLocation BACKGROUND = new ResourceLocation( "computercraft", "textures/gui/printer.png" );
@@ -22,29 +24,29 @@ public class GuiPrinter extends ContainerScreen<ContainerPrinter>
super( container, player, title );
}
@Override
protected void renderLabels( int mouseX, int mouseY )
/*@Override
protected void drawGuiContainerForegroundLayer( int mouseX, int mouseY )
{
String title = getTitle().getColoredString();
font.draw( title, (imageWidth - font.width( title )) / 2.0f, 6, 0x404040 );
font.draw( I18n.get( "container.inventory" ), 8, imageHeight - 96 + 2, 0x404040 );
}
String title = getTitle().getFormattedText();
font.drawString( title, (xSize - font.getStringWidth( title )) / 2.0f, 6, 0x404040 );
font.drawString( I18n.format( "container.inventory" ), 8, ySize - 96 + 2, 0x404040 );
}*/
@Override
protected void renderBg( float partialTicks, int mouseX, int mouseY )
protected void renderBg( @Nonnull MatrixStack transform, float partialTicks, int mouseX, int mouseY )
{
RenderSystem.color4f( 1.0F, 1.0F, 1.0F, 1.0F );
minecraft.getTextureManager().bind( BACKGROUND );
blit( leftPos, topPos, 0, 0, imageWidth, imageHeight );
blit( transform, leftPos, topPos, 0, 0, imageWidth, imageHeight );
if( getMenu().isPrinting() ) blit( leftPos + 34, topPos + 21, 176, 0, 25, 45 );
if( getMenu().isPrinting() ) blit( transform, leftPos + 34, topPos + 21, 176, 0, 25, 45 );
}
@Override
public void render( int mouseX, int mouseY, float partialTicks )
public void render( @Nonnull MatrixStack stack, int mouseX, int mouseY, float partialTicks )
{
renderBackground();
super.render( mouseX, mouseY, partialTicks );
renderTooltip( mouseX, mouseY );
renderBackground( stack );
super.render( stack, mouseX, mouseY, partialTicks );
renderTooltip( stack, mouseX, mouseY );
}
}

View File

@@ -5,6 +5,7 @@
*/
package dan200.computercraft.client.gui;
import com.mojang.blaze3d.matrix.MatrixStack;
import com.mojang.blaze3d.systems.RenderSystem;
import dan200.computercraft.core.terminal.TextBuffer;
import dan200.computercraft.shared.common.ContainerHeldItem;
@@ -12,18 +13,17 @@ import dan200.computercraft.shared.media.items.ItemPrintout;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.screen.inventory.ContainerScreen;
import net.minecraft.client.renderer.IRenderTypeBuffer;
import net.minecraft.client.renderer.Matrix4f;
import net.minecraft.client.renderer.TransformationMatrix;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.util.math.vector.Matrix4f;
import net.minecraft.util.text.ITextComponent;
import org.lwjgl.glfw.GLFW;
import javax.annotation.Nonnull;
import static dan200.computercraft.client.render.PrintoutRenderer.*;
public class GuiPrintout extends ContainerScreen<ContainerHeldItem>
{
private static final Matrix4f IDENTITY = TransformationMatrix.identity().getMatrix();
private final boolean book;
private final int pages;
private final TextBuffer[] text;
@@ -91,27 +91,33 @@ public class GuiPrintout extends ContainerScreen<ContainerHeldItem>
}
@Override
public void renderBg( float partialTicks, int mouseX, int mouseY )
protected void renderBg( @Nonnull MatrixStack transform, float partialTicks, int mouseX, int mouseY )
{
// Draw the printout
RenderSystem.color4f( 1.0f, 1.0f, 1.0f, 1.0f );
RenderSystem.enableDepthTest();
IRenderTypeBuffer.Impl renderer = Minecraft.getInstance().renderBuffers().bufferSource();
drawBorder( IDENTITY, renderer, leftPos, topPos, getBlitOffset(), page, pages, book );
drawText( IDENTITY, renderer, leftPos + X_TEXT_MARGIN, topPos + Y_TEXT_MARGIN, ItemPrintout.LINES_PER_PAGE * page, text, colours );
Matrix4f matrix = transform.last().pose();
drawBorder( matrix, renderer, leftPos, topPos, getBlitOffset(), page, pages, book );
drawText( matrix, renderer, leftPos + X_TEXT_MARGIN, topPos + Y_TEXT_MARGIN, ItemPrintout.LINES_PER_PAGE * page, text, colours );
renderer.endBatch();
}
@Override
public void render( int mouseX, int mouseY, float partialTicks )
public void render( @Nonnull MatrixStack stack, int mouseX, int mouseY, float partialTicks )
{
// We must take the background further back in order to not overlap with our printed pages.
setBlitOffset( getBlitOffset() - 1 );
renderBackground();
renderBackground( stack );
setBlitOffset( getBlitOffset() + 1 );
super.render( mouseX, mouseY, partialTicks );
renderTooltip( mouseX, mouseY );
super.render( stack, mouseX, mouseY, partialTicks );
}
@Override
protected void renderLabels( @Nonnull MatrixStack transform, int mouseX, int mouseY )
{
// Skip rendering labels.
}
}

View File

@@ -5,6 +5,7 @@
*/
package dan200.computercraft.client.gui;
import com.mojang.blaze3d.matrix.MatrixStack;
import com.mojang.blaze3d.systems.RenderSystem;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.client.gui.widgets.WidgetTerminal;
@@ -18,6 +19,8 @@ import net.minecraft.util.ResourceLocation;
import net.minecraft.util.text.ITextComponent;
import org.lwjgl.glfw.GLFW;
import javax.annotation.Nonnull;
public class GuiTurtle extends ContainerScreen<ContainerTurtle>
{
private static final ResourceLocation BACKGROUND_NORMAL = new ResourceLocation( ComputerCraft.MOD_ID, "textures/gui/turtle_normal.png" );
@@ -92,41 +95,38 @@ public class GuiTurtle extends ContainerScreen<ContainerTurtle>
return super.keyPressed( key, scancode, modifiers );
}
private void drawSelectionSlot( boolean advanced )
{
// Draw selection slot
int slot = container.getSelectedSlot();
if( slot >= 0 )
{
RenderSystem.color4f( 1.0F, 1.0F, 1.0F, 1.0F );
int slotX = slot % 4;
int slotY = slot / 4;
minecraft.getTextureManager().bind( advanced ? BACKGROUND_ADVANCED : BACKGROUND_NORMAL );
blit( leftPos + ContainerTurtle.TURTLE_START_X - 2 + slotX * 18, topPos + ContainerTurtle.PLAYER_START_Y - 2 + slotY * 18, 0, 217, 24, 24 );
}
}
@Override
protected void renderBg( float partialTicks, int mouseX, int mouseY )
protected void renderBg( @Nonnull MatrixStack transform, float partialTicks, int mouseX, int mouseY )
{
// Draw term
boolean advanced = family == ComputerFamily.ADVANCED;
ResourceLocation texture = family == ComputerFamily.ADVANCED ? BACKGROUND_ADVANCED : BACKGROUND_NORMAL;
terminal.draw( terminalWrapper.getX(), terminalWrapper.getY() );
// Draw border/inventory
RenderSystem.color4f( 1.0F, 1.0F, 1.0F, 1.0F );
minecraft.getTextureManager().bind( advanced ? BACKGROUND_ADVANCED : BACKGROUND_NORMAL );
blit( leftPos, topPos, 0, 0, imageWidth, imageHeight );
minecraft.getTextureManager().bind( texture );
blit( transform, leftPos, topPos, 0, 0, imageWidth, imageHeight );
drawSelectionSlot( advanced );
// Draw selection slot
int slot = container.getSelectedSlot();
if( slot >= 0 )
{
int slotX = slot % 4;
int slotY = slot / 4;
blit( transform,
leftPos + ContainerTurtle.TURTLE_START_X - 2 + slotX * 18,
topPos + ContainerTurtle.PLAYER_START_Y - 2 + slotY * 18,
0, 217, 24, 24
);
}
}
@Override
public void render( int mouseX, int mouseY, float partialTicks )
public void render( @Nonnull MatrixStack stack, int mouseX, int mouseY, float partialTicks )
{
renderBackground();
super.render( mouseX, mouseY, partialTicks );
renderTooltip( mouseX, mouseY );
renderBackground( stack );
super.render( stack, mouseX, mouseY, partialTicks );
renderTooltip( stack, mouseX, mouseY );
}
@Override
@@ -135,4 +135,10 @@ public class GuiTurtle extends ContainerScreen<ContainerTurtle>
return (getFocused() != null && getFocused().mouseDragged( x, y, button, deltaX, deltaY ))
|| super.mouseDragged( x, y, button, deltaX, deltaY );
}
@Override
protected void renderLabels( @Nonnull MatrixStack transform, int mouseX, int mouseY )
{
// Skip rendering labels.
}
}

View File

@@ -11,13 +11,19 @@ import dan200.computercraft.client.render.TileEntityMonitorRenderer;
import dan200.computercraft.client.render.TileEntityTurtleRenderer;
import dan200.computercraft.client.render.TurtlePlayerRenderer;
import dan200.computercraft.shared.Registry;
import dan200.computercraft.shared.common.IColouredItem;
import dan200.computercraft.shared.computer.inventory.ContainerComputer;
import dan200.computercraft.shared.computer.inventory.ContainerViewComputer;
import dan200.computercraft.shared.peripheral.monitor.ClientMonitor;
import dan200.computercraft.shared.pocket.inventory.ContainerPocketComputer;
import dan200.computercraft.shared.pocket.items.ItemPocketComputer;
import net.minecraft.client.gui.ScreenManager;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.RenderTypeLookup;
import net.minecraft.item.IItemPropertyGetter;
import net.minecraft.item.Item;
import net.minecraft.item.ItemModelsProperties;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.event.world.WorldEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
@@ -26,6 +32,8 @@ import net.minecraftforge.fml.client.registry.RenderingRegistry;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent;
import java.util.function.Supplier;
@Mod.EventBusSubscriber( modid = ComputerCraft.MOD_ID, value = Dist.CLIENT, bus = Mod.EventBusSubscriber.Bus.MOD )
public final class ComputerCraftProxyClient
{
@@ -49,6 +57,25 @@ public final class ComputerCraftProxyClient
ClientRegistry.bindTileEntityRenderer( Registry.ModTiles.TURTLE_ADVANCED.get(), TileEntityTurtleRenderer::new );
RenderingRegistry.registerEntityRenderingHandler( Registry.ModEntities.TURTLE_PLAYER.get(), TurtlePlayerRenderer::new );
registerItemProperty( "state",
( stack, world, player ) -> ItemPocketComputer.getState( stack ).ordinal(),
Registry.ModItems.POCKET_COMPUTER_NORMAL, Registry.ModItems.POCKET_COMPUTER_ADVANCED
);
registerItemProperty( "state",
( stack, world, player ) -> IColouredItem.getColourBasic( stack ) != -1 ? 1 : 0,
Registry.ModItems.POCKET_COMPUTER_NORMAL, Registry.ModItems.POCKET_COMPUTER_ADVANCED
);
}
@SafeVarargs
private static void registerItemProperty( String name, IItemPropertyGetter getter, Supplier<? extends Item>... items )
{
ResourceLocation id = new ResourceLocation( ComputerCraft.MOD_ID, name );
for( Supplier<? extends Item> item : items )
{
ItemModelsProperties.register( item.get(), id, getter );
}
}
private static void registerContainers()

View File

@@ -14,14 +14,14 @@ import dan200.computercraft.shared.peripheral.modem.wired.CableShapes;
import dan200.computercraft.shared.util.WorldUtil;
import net.minecraft.block.BlockState;
import net.minecraft.client.renderer.ActiveRenderInfo;
import net.minecraft.client.renderer.Matrix4f;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.WorldRenderer;
import net.minecraft.entity.Entity;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.BlockRayTraceResult;
import net.minecraft.util.math.Vec3d;
import net.minecraft.util.math.shapes.VoxelShape;
import net.minecraft.util.math.vector.Matrix4f;
import net.minecraft.util.math.vector.Vector3d;
import net.minecraft.world.World;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.client.event.DrawHighlightEvent;
@@ -63,7 +63,7 @@ public final class CableHighlightRenderer
? CableShapes.getModemShape( state )
: CableShapes.getCableShape( state );
Vec3d cameraPos = info.getPosition();
Vector3d cameraPos = info.getPosition();
double xOffset = pos.getX() - cameraPos.x();
double yOffset = pos.getY() - cameraPos.y();
double zOffset = pos.getZ() - cameraPos.z();

View File

@@ -10,10 +10,10 @@ import com.mojang.blaze3d.vertex.IVertexBuilder;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.shared.computer.core.ComputerFamily;
import net.minecraft.client.renderer.BufferBuilder;
import net.minecraft.client.renderer.Matrix4f;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.vector.Matrix4f;
import org.lwjgl.opengl.GL11;
import javax.annotation.Nonnull;
@@ -47,7 +47,10 @@ public class ComputerBorderRenderer
private static final int CORNER_LEFT_X = BORDER;
private static final int CORNER_RIGHT_X = CORNER_LEFT_X + BORDER;
private static final int BORDER_RIGHT_X = 36;
private static final int GAP = 4;
private static final int LIGHT_BORDER_Y = 56;
private static final int LIGHT_CORNER_Y = 80;
public static final int LIGHT_HEIGHT = 8;
private static final float TEX_SCALE = 1 / 256.0f;
@@ -101,15 +104,15 @@ public class ComputerBorderRenderer
public static void render( Matrix4f transform, IVertexBuilder buffer, int x, int y, int z, int width, int height, float r, float g, float b )
{
render( transform, buffer, x, y, z, width, height, 0, r, g, b );
render( transform, buffer, x, y, z, width, height, false, r, g, b );
}
public static void render( Matrix4f transform, IVertexBuilder buffer, int x, int y, int z, int width, int height, int borderHeight, float r, float g, float b )
public static void render( Matrix4f transform, IVertexBuilder buffer, int x, int y, int z, int width, int height, boolean withLight, float r, float g, float b )
{
new ComputerBorderRenderer( transform, buffer, z, r, g, b ).doRender( x, y, width, height, borderHeight );
new ComputerBorderRenderer( transform, buffer, z, r, g, b ).doRender( x, y, width, height, withLight );
}
public void doRender( int x, int y, int width, int height, int bottomHeight )
public void doRender( int x, int y, int width, int height, boolean withLight )
{
int endX = x + width;
int endY = y + height;
@@ -125,28 +128,18 @@ public class ComputerBorderRenderer
// Bottom bar. We allow for drawing a stretched version, which allows for additional elements (such as the
// pocket computer's lights).
if( bottomHeight <= 0 )
if( withLight )
{
renderTexture( x, endY, 0, LIGHT_BORDER_Y, endX - x, BORDER + LIGHT_HEIGHT, BORDER, BORDER + LIGHT_HEIGHT );
renderTexture( x - BORDER, endY, CORNER_LEFT_X, LIGHT_CORNER_Y, BORDER, BORDER + LIGHT_HEIGHT );
renderTexture( endX, endY, CORNER_RIGHT_X, LIGHT_CORNER_Y, BORDER, BORDER + LIGHT_HEIGHT );
}
else
{
renderLine( x, endY, 0, BORDER, endX - x, BORDER );
renderCorner( x - BORDER, endY, CORNER_LEFT_X, CORNER_BOTTOM_Y );
renderCorner( endX, endY, CORNER_RIGHT_X, CORNER_BOTTOM_Y );
}
else
{
// 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( x - BORDER, endY, CORNER_LEFT_X, CORNER_BOTTOM_Y, BORDER, BORDER / 2 );
renderTexture( x, endY, 0, BORDER, width, BORDER / 2, BORDER, BORDER / 2 );
renderTexture( endX, endY, CORNER_RIGHT_X, CORNER_BOTTOM_Y, BORDER, BORDER / 2 );
renderTexture( x - BORDER, endY + BORDER / 2, CORNER_LEFT_X, CORNER_BOTTOM_Y + GAP, BORDER, bottomHeight, BORDER, GAP );
renderTexture( x, endY + BORDER / 2, 0, BORDER + GAP, width, bottomHeight, BORDER, GAP );
renderTexture( endX, endY + BORDER / 2, CORNER_RIGHT_X, CORNER_BOTTOM_Y + GAP, BORDER, bottomHeight, BORDER, GAP );
renderTexture( x - BORDER, endY + bottomHeight + BORDER / 2, CORNER_LEFT_X, CORNER_BOTTOM_Y + BORDER / 2, BORDER, BORDER / 2 );
renderTexture( x, endY + bottomHeight + BORDER / 2, 0, BORDER + BORDER / 2, width, BORDER / 2 );
renderTexture( endX, endY + bottomHeight + BORDER / 2, CORNER_RIGHT_X, CORNER_BOTTOM_Y + BORDER / 2, BORDER, BORDER / 2 );
}
}
private void renderCorner( int x, int y, int u, int v )

View File

@@ -10,12 +10,12 @@ import net.minecraft.client.Minecraft;
import net.minecraft.client.entity.player.AbstractClientPlayerEntity;
import net.minecraft.client.renderer.FirstPersonRenderer;
import net.minecraft.client.renderer.IRenderTypeBuffer;
import net.minecraft.client.renderer.Vector3f;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.util.Hand;
import net.minecraft.util.HandSide;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.vector.Vector3f;
public abstract class ItemMapLikeRenderer
{

View File

@@ -15,9 +15,13 @@ import dan200.computercraft.shared.computer.core.ComputerFamily;
import dan200.computercraft.shared.pocket.items.ItemPocketComputer;
import dan200.computercraft.shared.util.Colour;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.*;
import net.minecraft.client.renderer.BufferBuilder;
import net.minecraft.client.renderer.IRenderTypeBuffer;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.item.ItemStack;
import net.minecraft.util.math.vector.Matrix4f;
import net.minecraft.util.math.vector.Vector3f;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.client.event.RenderHandEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
@@ -26,8 +30,7 @@ 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.render.ComputerBorderRenderer.BORDER;
import static dan200.computercraft.client.render.ComputerBorderRenderer.MARGIN;
import static dan200.computercraft.client.render.ComputerBorderRenderer.*;
/**
* Emulates map rendering for pocket computers.
@@ -35,8 +38,6 @@ import static dan200.computercraft.client.render.ComputerBorderRenderer.MARGIN;
@Mod.EventBusSubscriber( modid = ComputerCraft.MOD_ID, value = Dist.CLIENT )
public final class ItemPocketRenderer extends ItemMapLikeRenderer
{
private static final int LIGHT_HEIGHT = 8;
private static final ItemPocketRenderer INSTANCE = new ItemPocketRenderer();
private ItemPocketRenderer()
@@ -127,7 +128,7 @@ public final class ItemPocketRenderer extends ItemMapLikeRenderer
BufferBuilder buffer = tessellator.getBuilder();
buffer.begin( GL11.GL_QUADS, DefaultVertexFormats.POSITION_COLOR_TEX );
ComputerBorderRenderer.render( transform, buffer, 0, 0, 0, width, height, LIGHT_HEIGHT, r, g, b );
ComputerBorderRenderer.render( transform, buffer, 0, 0, 0, width, height, true, r, g, b );
tessellator.end();
}

View File

@@ -9,9 +9,9 @@ import com.mojang.blaze3d.matrix.MatrixStack;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.shared.media.items.ItemPrintout;
import net.minecraft.client.renderer.IRenderTypeBuffer;
import net.minecraft.client.renderer.Matrix4f;
import net.minecraft.client.renderer.Vector3f;
import net.minecraft.item.ItemStack;
import net.minecraft.util.math.vector.Matrix4f;
import net.minecraft.util.math.vector.Vector3f;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.client.event.RenderHandEvent;
import net.minecraftforge.client.event.RenderItemInFrameEvent;

View File

@@ -9,12 +9,12 @@ import com.mojang.blaze3d.matrix.MatrixStack;
import com.mojang.blaze3d.vertex.IVertexBuilder;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.shared.peripheral.monitor.TileMonitor;
import net.minecraft.client.renderer.Matrix4f;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.Direction;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
import net.minecraft.util.math.vector.Matrix4f;
import net.minecraft.util.math.vector.Vector3d;
import net.minecraft.world.World;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.client.event.DrawHighlightEvent;
@@ -61,7 +61,7 @@ public final class MonitorHighlightRenderer
if( monitor.getYIndex() != monitor.getHeight() - 1 ) faces.remove( monitor.getDown() );
MatrixStack transformStack = event.getMatrix();
Vec3d cameraPos = event.getInfo().getPosition();
Vector3d cameraPos = event.getInfo().getPosition();
transformStack.pushPose();
transformStack.translate( pos.getX() - cameraPos.x(), pos.getY() - cameraPos.y(), pos.getZ() - cameraPos.z() );

View File

@@ -11,8 +11,8 @@ import com.mojang.blaze3d.systems.RenderSystem;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.client.gui.FixedWidthFontRenderer;
import dan200.computercraft.shared.util.Palette;
import net.minecraft.client.renderer.Matrix4f;
import net.minecraft.client.renderer.texture.TextureUtil;
import net.minecraft.util.math.vector.Matrix4f;
import org.lwjgl.BufferUtils;
import org.lwjgl.opengl.GL13;
import org.lwjgl.opengl.GL20;

View File

@@ -10,11 +10,11 @@ import dan200.computercraft.client.gui.FixedWidthFontRenderer;
import dan200.computercraft.core.terminal.TextBuffer;
import dan200.computercraft.shared.util.Palette;
import net.minecraft.client.renderer.IRenderTypeBuffer;
import net.minecraft.client.renderer.Matrix4f;
import net.minecraft.client.renderer.RenderState;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.vector.Matrix4f;
import org.lwjgl.opengl.GL11;
import static dan200.computercraft.client.gui.FixedWidthFontRenderer.FONT_HEIGHT;

View File

@@ -24,6 +24,9 @@ import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.client.renderer.vertex.VertexBuffer;
import net.minecraft.util.Direction;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.vector.Matrix4f;
import net.minecraft.util.math.vector.TransformationMatrix;
import net.minecraft.util.math.vector.Vector3f;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL13;
import org.lwjgl.opengl.GL20;
@@ -141,6 +144,10 @@ public class TileEntityMonitorRenderer extends TileEntityRenderer<TileMonitor>
(float) (xSize + 2 * TileMonitor.RENDER_MARGIN), (float) -(ySize + TileMonitor.RENDER_MARGIN * 2)
);
// Force a flush of the blocker. WorldRenderer.updateCameraAndRender will "finish" all the built-in
// buffers before calling renderer.finish, which means the blocker isn't actually rendered at that point!
renderer.getBuffer( RenderType.solid() );
transform.popPose();
}

View File

@@ -19,8 +19,6 @@ import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.FontRenderer;
import net.minecraft.client.renderer.Atlases;
import net.minecraft.client.renderer.IRenderTypeBuffer;
import net.minecraft.client.renderer.Matrix4f;
import net.minecraft.client.renderer.Vector3f;
import net.minecraft.client.renderer.model.BakedQuad;
import net.minecraft.client.renderer.model.IBakedModel;
import net.minecraft.client.renderer.model.ModelManager;
@@ -31,7 +29,9 @@ import net.minecraft.util.Direction;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.BlockRayTraceResult;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.util.math.Vec3d;
import net.minecraft.util.math.vector.Matrix4f;
import net.minecraft.util.math.vector.Vector3d;
import net.minecraft.util.math.vector.Vector3f;
import net.minecraftforge.client.model.data.EmptyModelData;
import javax.annotation.Nonnull;
@@ -99,7 +99,7 @@ public class TileEntityTurtleRenderer extends TileEntityRenderer<TileTurtle>
transform.pushPose();
// Setup the transform.
Vec3d offset = turtle.getRenderOffset( partialTicks );
Vector3d offset = turtle.getRenderOffset( partialTicks );
float yaw = turtle.getRenderYaw( partialTicks );
transform.translate( offset.x, offset.y, offset.z );

View File

@@ -57,16 +57,16 @@ public final class TurtleModelLoader implements IModelLoader<TurtleModelLoader.T
}
@Override
public Collection<Material> getTextures( IModelConfiguration owner, Function<ResourceLocation, IUnbakedModel> modelGetter, Set<Pair<String, String>> missingTextureErrors )
public Collection<RenderMaterial> getTextures( IModelConfiguration owner, Function<ResourceLocation, IUnbakedModel> modelGetter, Set<Pair<String, String>> missingTextureErrors )
{
Set<Material> materials = new HashSet<>();
Set<RenderMaterial> materials = new HashSet<>();
materials.addAll( modelGetter.apply( family ).getMaterials( modelGetter, missingTextureErrors ) );
materials.addAll( modelGetter.apply( COLOUR_TURTLE_MODEL ).getMaterials( modelGetter, missingTextureErrors ) );
return materials;
}
@Override
public IBakedModel bake( IModelConfiguration owner, ModelBakery bakery, Function<Material, TextureAtlasSprite> spriteGetter, IModelTransform transform, ItemOverrideList overrides, ResourceLocation modelLocation )
public IBakedModel bake( IModelConfiguration owner, ModelBakery bakery, Function<RenderMaterial, TextureAtlasSprite> spriteGetter, IModelTransform transform, ItemOverrideList overrides, ResourceLocation modelLocation )
{
return new TurtleSmartItemModel(
bakery.getBakedModel( family, transform, spriteGetter ),

View File

@@ -7,12 +7,12 @@ package dan200.computercraft.client.render;
import dan200.computercraft.api.client.TransformedModel;
import net.minecraft.block.BlockState;
import net.minecraft.client.renderer.TransformationMatrix;
import net.minecraft.client.renderer.model.BakedQuad;
import net.minecraft.client.renderer.model.IBakedModel;
import net.minecraft.client.renderer.model.ItemOverrideList;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.util.Direction;
import net.minecraft.util.math.vector.TransformationMatrix;
import net.minecraftforge.client.model.data.EmptyModelData;
import net.minecraftforge.client.model.data.IModelData;
import net.minecraftforge.client.model.pipeline.BakedQuadBuilder;

View File

@@ -15,14 +15,14 @@ import dan200.computercraft.shared.util.Holiday;
import dan200.computercraft.shared.util.HolidayUtil;
import net.minecraft.block.BlockState;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.TransformationMatrix;
import net.minecraft.client.renderer.model.*;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.world.ClientWorld;
import net.minecraft.entity.LivingEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.util.Direction;
import net.minecraft.util.ResourceLocation;
import net.minecraft.world.World;
import net.minecraft.util.math.vector.TransformationMatrix;
import net.minecraftforge.client.model.data.IModelData;
import javax.annotation.Nonnull;
@@ -109,7 +109,7 @@ public class TurtleSmartItemModel implements IBakedModel
{
@Nonnull
@Override
public IBakedModel resolve( @Nonnull IBakedModel originalModel, @Nonnull ItemStack stack, @Nullable World world, @Nullable LivingEntity entity )
public IBakedModel resolve( @Nonnull IBakedModel originalModel, @Nonnull ItemStack stack, @Nullable ClientWorld world, @Nullable LivingEntity entity )
{
ItemTurtle turtle = (ItemTurtle) stack.getItem();
int colour = turtle.getColour( stack );

View File

@@ -14,6 +14,7 @@ import dan200.computercraft.core.apis.http.*;
import dan200.computercraft.core.apis.http.request.HttpRequest;
import dan200.computercraft.core.apis.http.websocket.Websocket;
import io.netty.handler.codec.http.DefaultHttpHeaders;
import io.netty.handler.codec.http.HttpHeaderNames;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.HttpMethod;
@@ -179,7 +180,7 @@ public class HTTPAPI implements ILuaAPI
}
@Nonnull
private static HttpHeaders getHeaders( @Nonnull Map<?, ?> headerTable ) throws LuaException
private HttpHeaders getHeaders( @Nonnull Map<?, ?> headerTable ) throws LuaException
{
HttpHeaders headers = new DefaultHttpHeaders();
for( Map.Entry<?, ?> entry : headerTable.entrySet() )
@@ -197,6 +198,11 @@ public class HTTPAPI implements ILuaAPI
}
}
}
if( !headers.contains( HttpHeaderNames.USER_AGENT ) )
{
headers.set( HttpHeaderNames.USER_AGENT, apiEnvironment.getComputerEnvironment().getUserAgent() );
}
return headers;
}
}

View File

@@ -89,7 +89,7 @@ final class LuaDateTime
formatter.appendValue( ChronoField.HOUR_OF_DAY, 2 );
break;
case 'I':
formatter.appendValue( ChronoField.HOUR_OF_AMPM );
formatter.appendValue( ChronoField.HOUR_OF_AMPM, 2 );
break;
case 'j':
formatter.appendValue( ChronoField.DAY_OF_YEAR, 3 );

View File

@@ -191,7 +191,7 @@ public class RedstoneAPI implements ILuaAPI
@LuaFunction
public final int getBundledInput( ComputerSide side )
{
return environment.getBundledOutput( side );
return environment.getBundledInput( side );
}
/**

View File

@@ -80,10 +80,6 @@ public final class HttpRequestHandler extends SimpleChannelInboundHandler<HttpOb
{
request.headers().set( HttpHeaderNames.ACCEPT_CHARSET, "UTF-8" );
}
if( !request.headers().contains( HttpHeaderNames.USER_AGENT ) )
{
request.headers().set( HttpHeaderNames.USER_AGENT, this.request.environment().getComputerEnvironment().getUserAgent() );
}
request.headers().set( HttpHeaderNames.HOST, uri.getPort() < 0 ? uri.getHost() : uri.getHost() + ":" + uri.getPort() );
request.headers().set( HttpHeaderNames.CONNECTION, HttpHeaderValues.CLOSE );

View File

@@ -58,10 +58,10 @@ public class HttpResponseHandle implements ObjectSource
* If multiple headers are sent with the same name, they will be combined with a comma.
*
* @return The response's headers.
* @cc.usage Make a request to [example.computercraft.cc](https://example.computercraft.cc), and print the
* @cc.usage Make a request to [example.tweaked.cc](https://example.tweaked.cc), and print the
* returned headers.
* <pre>{@code
* local request = http.get("https://example.computercraft.cc")
* local request = http.get("https://example.tweaked.cc")
* print(textutils.serialize(request.getResponseHeaders()))
* -- => {
* -- [ "Content-Type" ] = "text/plain; charset=utf8",

View File

@@ -11,10 +11,7 @@ import com.google.common.cache.LoadingCache;
import com.google.common.primitives.Primitives;
import com.google.common.reflect.TypeToken;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.api.lua.IArguments;
import dan200.computercraft.api.lua.LuaException;
import dan200.computercraft.api.lua.LuaFunction;
import dan200.computercraft.api.lua.MethodResult;
import dan200.computercraft.api.lua.*;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Type;
@@ -111,7 +108,7 @@ public final class Generator<T>
addMethod( methods, method, annotation, instance );
}
for( GenericSource.GenericMethod method : GenericSource.GenericMethod.all() )
for( GenericMethod method : GenericMethod.all() )
{
if( !method.target.isAssignableFrom( klass ) ) continue;

View File

@@ -0,0 +1,90 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.core.asm;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.api.lua.GenericSource;
import dan200.computercraft.api.lua.LuaFunction;
import javax.annotation.Nonnull;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
/**
* A generic method is a method belonging to a {@link GenericSource} with a known target.
*/
public class GenericMethod
{
final Method method;
final LuaFunction annotation;
final Class<?> target;
private static final List<GenericSource> sources = new ArrayList<>();
private static List<GenericMethod> cache;
GenericMethod( Method method, LuaFunction annotation, Class<?> target )
{
this.method = method;
this.annotation = annotation;
this.target = target;
}
/**
* Find all public static methods annotated with {@link LuaFunction} which belong to a {@link GenericSource}.
*
* @return All available generic methods.
*/
static List<GenericMethod> all()
{
if( cache != null ) return cache;
return cache = sources.stream()
.flatMap( x -> Arrays.stream( x.getClass().getDeclaredMethods() ) )
.map( method ->
{
LuaFunction annotation = method.getAnnotation( LuaFunction.class );
if( annotation == null ) return null;
if( !Modifier.isStatic( method.getModifiers() ) )
{
ComputerCraft.log.error( "GenericSource method {}.{} should be static.", method.getDeclaringClass(), method.getName() );
return null;
}
Type[] types = method.getGenericParameterTypes();
if( types.length == 0 )
{
ComputerCraft.log.error( "GenericSource method {}.{} has no parameters.", method.getDeclaringClass(), method.getName() );
return null;
}
Class<?> target = Reflect.getRawType( method, types[0], false );
if( target == null ) return null;
return new GenericMethod( method, annotation, target );
} )
.filter( Objects::nonNull )
.collect( Collectors.toList() );
}
public static synchronized void register( @Nonnull GenericSource source )
{
Objects.requireNonNull( source, "Source cannot be null" );
if( cache != null )
{
ComputerCraft.log.warn( "Registering a generic source {} after cache has been built. This source will be ignored.", cache );
}
sources.add( source );
}
}

View File

@@ -1,120 +0,0 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.core.asm;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.api.lua.LuaFunction;
import dan200.computercraft.shared.peripheral.generic.GenericPeripheralProvider;
import dan200.computercraft.shared.util.ServiceUtil;
import net.minecraft.util.ResourceLocation;
import javax.annotation.Nonnull;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* A generic source of {@link LuaMethod} functions. This allows for injecting methods onto objects you do not own.
*
* Unlike conventional Lua objects, the annotated methods should be {@code static}, with their target as the first
* parameter.
*
* This is used by the generic peripheral system ({@link GenericPeripheralProvider}) to provide methods for arbitrary
* tile entities. Eventually this'll be be exposed in the public API. Until it is stabilised, it will remain in this
* package - do not use it in external mods!
*/
public interface GenericSource
{
/**
* A unique identifier for this generic source. This may be used in the future to allow disabling specific sources.
*
* @return This source's identifier.
*/
@Nonnull
ResourceLocation id();
/**
* Register a stream of generic sources.
*
* @param sources The source of generic methods.
* @see ServiceUtil For ways to load this. Sadly {@link java.util.ServiceLoader} is broken under Forge, but we don't
* want to add a hard-dep on Forge within core either.
*/
static void setup( Supplier<Stream<GenericSource>> sources )
{
GenericMethod.sources = sources;
}
/**
* A generic method is a method belonging to a {@link GenericSource} with a known target.
*/
class GenericMethod
{
final Method method;
final LuaFunction annotation;
final Class<?> target;
static Supplier<Stream<GenericSource>> sources;
private static List<GenericMethod> cache;
GenericMethod( Method method, LuaFunction annotation, Class<?> target )
{
this.method = method;
this.annotation = annotation;
this.target = target;
}
/**
* Find all public static methods annotated with {@link LuaFunction} which belong to a {@link GenericSource}.
*
* @return All available generic methods.
*/
static List<GenericMethod> all()
{
if( cache != null ) return cache;
if( sources == null )
{
ComputerCraft.log.warn( "Getting GenericMethods without a provider" );
return cache = Collections.emptyList();
}
return cache = sources.get()
.flatMap( x -> Arrays.stream( x.getClass().getDeclaredMethods() ) )
.map( method ->
{
LuaFunction annotation = method.getAnnotation( LuaFunction.class );
if( annotation == null ) return null;
if( !Modifier.isStatic( method.getModifiers() ) )
{
ComputerCraft.log.error( "GenericSource method {}.{} should be static.", method.getDeclaringClass(), method.getName() );
return null;
}
Type[] types = method.getGenericParameterTypes();
if( types.length == 0 )
{
ComputerCraft.log.error( "GenericSource method {}.{} has no parameters.", method.getDeclaringClass(), method.getName() );
return null;
}
Class<?> target = Reflect.getRawType( method, types[0], false );
if( target == null ) return null;
return new GenericMethod( method, annotation, target );
} )
.filter( Objects::nonNull )
.collect( Collectors.toList() );
}
}
}

View File

@@ -12,6 +12,7 @@ import com.google.common.io.ByteStreams;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.api.filesystem.IMount;
import dan200.computercraft.core.apis.handles.ArrayByteChannel;
import dan200.computercraft.shared.util.IoUtil;
import net.minecraft.resources.IReloadableResourceManager;
import net.minecraft.resources.IResource;
import net.minecraft.resources.IResourceManager;
@@ -103,9 +104,13 @@ public final class ResourceMount implements IMount
private void load()
{
boolean hasAny = false;
String existingNamespace = null;
FileEntry newRoot = new FileEntry( new ResourceLocation( namespace, subPath ) );
for( ResourceLocation file : manager.listResources( subPath, s -> true ) )
{
existingNamespace = file.getNamespace();
if( !file.getNamespace().equals( namespace ) ) continue;
String localPath = FileSystem.toLocal( file.getPath(), subPath );
@@ -114,6 +119,15 @@ public final class ResourceMount implements IMount
}
root = hasAny ? newRoot : null;
if( !hasAny )
{
ComputerCraft.log.warn( "Cannot find any files under /data/{}/{} for resource mount.", namespace, subPath );
if( existingNamespace != null )
{
ComputerCraft.log.warn( "There are files under /data/{}/{} though. Did you get the wrong namespace?", existingNamespace, subPath );
}
}
}
private FileEntry get( String path )
@@ -231,11 +245,20 @@ public final class ResourceMount implements IMount
byte[] contents = CONTENTS_CACHE.getIfPresent( file );
if( contents != null ) return new ArrayByteChannel( contents );
try( InputStream stream = manager.getResource( file.identifier ).getInputStream() )
try
{
InputStream stream = manager.getResource( file.identifier ).getInputStream();
if( stream.available() > MAX_CACHED_SIZE ) return Channels.newChannel( stream );
contents = ByteStreams.toByteArray( stream );
try
{
contents = ByteStreams.toByteArray( stream );
}
finally
{
IoUtil.closeQuietly( stream );
}
CONTENTS_CACHE.put( file, contents );
return new ArrayByteChannel( contents );
}

View File

@@ -12,46 +12,12 @@ public class TextBuffer
public TextBuffer( char c, int length )
{
text = new char[length];
for( int i = 0; i < length; i++ )
{
text[i] = c;
}
this.fill( c );
}
public TextBuffer( String text )
{
this( text, 1 );
}
public TextBuffer( String text, int repetitions )
{
int textLength = text.length();
this.text = new char[textLength * repetitions];
for( int i = 0; i < repetitions; i++ )
{
for( int j = 0; j < textLength; j++ )
{
this.text[j + i * textLength] = text.charAt( j );
}
}
}
public TextBuffer( TextBuffer text )
{
this( text, 1 );
}
public TextBuffer( TextBuffer text, int repetitions )
{
int textLength = text.length();
this.text = new char[textLength * repetitions];
for( int i = 0; i < repetitions; i++ )
{
for( int j = 0; j < textLength; j++ )
{
this.text[j + i * textLength] = text.charAt( j );
}
}
this.text = text.toCharArray();
}
public int length()
@@ -59,39 +25,16 @@ public class TextBuffer
return text.length;
}
public String read()
{
return read( 0, text.length );
}
public String read( int start )
{
return read( start, text.length );
}
public String read( int start, int end )
{
start = Math.max( start, 0 );
end = Math.min( end, text.length );
int textLength = Math.max( end - start, 0 );
return new String( text, start, textLength );
}
public void write( String text )
{
write( text, 0, text.length() );
write( text, 0 );
}
public void write( String text, int start )
{
write( text, start, start + text.length() );
}
public void write( String text, int start, int end )
{
int pos = start;
start = Math.max( start, 0 );
end = Math.min( end, pos + text.length() );
int end = Math.min( start + text.length(), pos + text.length() );
end = Math.min( end, this.text.length );
for( int i = start; i < end; i++ )
{
@@ -101,23 +44,10 @@ public class TextBuffer
public void write( TextBuffer text )
{
write( text, 0, text.length() );
}
public void write( TextBuffer text, int start )
{
write( text, start, start + text.length() );
}
public void write( TextBuffer text, int start, int end )
{
int pos = start;
start = Math.max( start, 0 );
end = Math.min( end, pos + text.length() );
end = Math.min( end, this.text.length );
for( int i = start; i < end; i++ )
int end = Math.min( text.length(), this.text.length );
for( int i = 0; i < end; i++ )
{
this.text[i] = text.charAt( i - pos );
this.text[i] = text.charAt( i );
}
}
@@ -126,11 +56,6 @@ public class TextBuffer
fill( c, 0, text.length );
}
public void fill( char c, int start )
{
fill( c, start, text.length );
}
public void fill( char c, int start, int end )
{
start = Math.max( start, 0 );
@@ -141,52 +66,6 @@ public class TextBuffer
}
}
public void fill( String text )
{
fill( text, 0, this.text.length );
}
public void fill( String text, int start )
{
fill( text, start, this.text.length );
}
public void fill( String text, int start, int end )
{
int pos = start;
start = Math.max( start, 0 );
end = Math.min( end, this.text.length );
int textLength = text.length();
for( int i = start; i < end; i++ )
{
this.text[i] = text.charAt( (i - pos) % textLength );
}
}
public void fill( TextBuffer text )
{
fill( text, 0, this.text.length );
}
public void fill( TextBuffer text, int start )
{
fill( text, start, this.text.length );
}
public void fill( TextBuffer text, int start, int end )
{
int pos = start;
start = Math.max( start, 0 );
end = Math.min( end, this.text.length );
int textLength = text.length();
for( int i = start; i < end; i++ )
{
this.text[i] = text.charAt( (i - pos) % textLength );
}
}
public char charAt( int i )
{
return text[i];

View File

@@ -16,19 +16,18 @@ import net.minecraft.data.DataGenerator;
import net.minecraft.util.Direction;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.client.model.generators.*;
import net.minecraftforge.common.data.ExistingFileHelper;
import javax.annotation.Nonnull;
public class BlockModelProvider extends BlockStateProvider
{
private final ModelFile monitorBase;
private final ModelFile orientable;
private ModelFile monitorBase;
private ModelFile orientable;
public BlockModelProvider( DataGenerator generator, ExistingFileHelper existingFileHelper )
{
super( generator, ComputerCraft.MOD_ID, existingFileHelper );
monitorBase = models().getExistingFile( new ResourceLocation( ComputerCraft.MOD_ID, "block/monitor_base" ) );
orientable = models().getExistingFile( new ResourceLocation( "block/orientable" ) );
}
@Nonnull
@@ -41,6 +40,9 @@ public class BlockModelProvider extends BlockStateProvider
@Override
protected void registerStatesAndModels()
{
monitorBase = models().getExistingFile( new ResourceLocation( ComputerCraft.MOD_ID, "block/monitor_base" ) );
orientable = models().getExistingFile( new ResourceLocation( "block/orientable" ) );
registerMonitors( Registry.ModBlocks.MONITOR_NORMAL.get() );
registerMonitors( Registry.ModBlocks.MONITOR_ADVANCED.get() );

View File

@@ -22,7 +22,7 @@ public class Generators
DataGenerator generator = event.getGenerator();
generator.addProvider( new Recipes( generator ) );
generator.addProvider( new LootTables( generator ) );
generator.addProvider( new Tags( generator ) );
generator.addProvider( new Tags( generator, event.getExistingFileHelper() ) );
generator.addProvider( new BlockModelProvider( generator, event.getExistingFileHelper() ) );
}
}

View File

@@ -12,11 +12,11 @@ import dan200.computercraft.ComputerCraft;
import net.minecraft.data.DataGenerator;
import net.minecraft.data.DirectoryCache;
import net.minecraft.data.IDataProvider;
import net.minecraft.loot.LootParameterSets;
import net.minecraft.loot.LootTable;
import net.minecraft.loot.LootTableManager;
import net.minecraft.loot.ValidationTracker;
import net.minecraft.util.ResourceLocation;
import net.minecraft.world.storage.loot.LootParameterSets;
import net.minecraft.world.storage.loot.LootTable;
import net.minecraft.world.storage.loot.LootTableManager;
import net.minecraft.world.storage.loot.ValidationTracker;
import javax.annotation.Nonnull;
import java.io.IOException;

View File

@@ -13,10 +13,10 @@ import dan200.computercraft.shared.data.PlayerCreativeLootCondition;
import dan200.computercraft.shared.proxy.ComputerCraftProxyCommon;
import net.minecraft.block.Block;
import net.minecraft.data.DataGenerator;
import net.minecraft.loot.*;
import net.minecraft.loot.conditions.Alternative;
import net.minecraft.loot.conditions.SurvivesExplosion;
import net.minecraft.util.ResourceLocation;
import net.minecraft.world.storage.loot.*;
import net.minecraft.world.storage.loot.conditions.Alternative;
import net.minecraft.world.storage.loot.conditions.SurvivesExplosion;
import net.minecraftforge.fml.RegistryObject;
import java.util.function.BiConsumer;
@@ -77,9 +77,9 @@ public class LootTables extends LootTableProvider
.setRolls( ConstantRange.exactly( 1 ) )
.add( DynamicLootEntry.dynamicEntry( new ResourceLocation( ComputerCraft.MOD_ID, "computer" ) ) )
.when( Alternative.alternative(
BlockNamedEntityLootCondition.builder(),
HasComputerIdLootCondition.builder(),
PlayerCreativeLootCondition.builder().invert()
BlockNamedEntityLootCondition.BUILDER,
HasComputerIdLootCondition.BUILDER,
PlayerCreativeLootCondition.BUILDER.invert()
) )
).build() );
}

View File

@@ -22,7 +22,7 @@ import net.minecraft.advancements.criterion.ItemPredicate;
import net.minecraft.block.Blocks;
import net.minecraft.data.*;
import net.minecraft.item.*;
import net.minecraft.tags.Tag;
import net.minecraft.tags.ITag;
import net.minecraft.util.IItemProvider;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.common.Tags;
@@ -62,7 +62,7 @@ public class Recipes extends RecipeProvider
.requires( Items.PAPER )
.requires( DyeItem.byColor( ofColour( colour ) ) )
.group( "computercraft:disk" )
.unlocks( "has_drive", inventoryChange( Registry.ModBlocks.DISK_DRIVE.get() ) )
.unlockedBy( "has_drive", inventoryChange( Registry.ModBlocks.DISK_DRIVE.get() ) )
.save( RecipeWrapper.wrap(
ImpostorShapelessRecipe.SERIALIZER, add,
x -> x.putInt( IColouredItem.NBT_COLOUR, colour.getHex() )
@@ -92,7 +92,7 @@ public class Recipes extends RecipeProvider
.pattern( "#T" )
.define( '#', base.getItem() )
.define( 'T', upgrade.getCraftingItem().getItem() )
.unlocks( "has_items",
.unlockedBy( "has_items",
inventoryChange( base.getItem(), upgrade.getCraftingItem().getItem() ) )
.save(
RecipeWrapper.wrap( ImpostorRecipe.SERIALIZER, add, result.getTag() ),
@@ -127,7 +127,7 @@ public class Recipes extends RecipeProvider
.pattern( "P" )
.define( '#', base.getItem() )
.define( 'P', upgrade.getCraftingItem().getItem() )
.unlocks( "has_items",
.unlockedBy( "has_items",
inventoryChange( base.getItem(), upgrade.getCraftingItem().getItem() ) )
.save(
RecipeWrapper.wrap( ImpostorRecipe.SERIALIZER, add, result.getTag() ),
@@ -148,8 +148,8 @@ public class Recipes extends RecipeProvider
.pattern( " # " )
.define( '#', Tags.Items.STONE )
.define( 'R', Tags.Items.DUSTS_REDSTONE )
.unlocks( "has_computer", inventoryChange( CCTags.COMPUTER ) )
.unlocks( "has_modem", inventoryChange( CCTags.COMPUTER ) )
.unlockedBy( "has_computer", inventoryChange( CCTags.COMPUTER ) )
.unlockedBy( "has_modem", inventoryChange( CCTags.COMPUTER ) )
.save( add );
ShapedRecipeBuilder
@@ -160,7 +160,7 @@ public class Recipes extends RecipeProvider
.define( '#', Tags.Items.STONE )
.define( 'R', Tags.Items.DUSTS_REDSTONE )
.define( 'G', Tags.Items.GLASS_PANES )
.unlocks( "has_redstone", inventoryChange( Tags.Items.DUSTS_REDSTONE ) )
.unlockedBy( "has_redstone", inventoryChange( Tags.Items.DUSTS_REDSTONE ) )
.save( add );
ShapedRecipeBuilder
@@ -171,7 +171,7 @@ public class Recipes extends RecipeProvider
.define( '#', Tags.Items.INGOTS_GOLD )
.define( 'R', Tags.Items.DUSTS_REDSTONE )
.define( 'G', Tags.Items.GLASS_PANES )
.unlocks( "has_components", inventoryChange( Items.REDSTONE, Items.GOLD_INGOT ) )
.unlockedBy( "has_components", inventoryChange( Items.REDSTONE, Items.GOLD_INGOT ) )
.save( add );
ShapedRecipeBuilder
@@ -182,7 +182,7 @@ public class Recipes extends RecipeProvider
.define( '#', Tags.Items.INGOTS_GOLD )
.define( 'R', Blocks.COMMAND_BLOCK )
.define( 'G', Tags.Items.GLASS_PANES )
.unlocks( "has_components", inventoryChange( Blocks.COMMAND_BLOCK ) )
.unlockedBy( "has_components", inventoryChange( Blocks.COMMAND_BLOCK ) )
.save( add );
ShapedRecipeBuilder
@@ -192,7 +192,7 @@ public class Recipes extends RecipeProvider
.pattern( "#R#" )
.define( '#', Tags.Items.STONE )
.define( 'R', Tags.Items.DUSTS_REDSTONE )
.unlocks( "has_computer", inventoryChange( CCTags.COMPUTER ) )
.unlockedBy( "has_computer", inventoryChange( CCTags.COMPUTER ) )
.save( add );
ShapedRecipeBuilder
@@ -202,7 +202,7 @@ public class Recipes extends RecipeProvider
.pattern( "###" )
.define( '#', Tags.Items.STONE )
.define( 'G', Tags.Items.GLASS_PANES )
.unlocks( "has_computer", inventoryChange( CCTags.COMPUTER ) )
.unlockedBy( "has_computer", inventoryChange( CCTags.COMPUTER ) )
.save( add );
ShapedRecipeBuilder
@@ -212,7 +212,7 @@ public class Recipes extends RecipeProvider
.pattern( "###" )
.define( '#', Tags.Items.INGOTS_GOLD )
.define( 'G', Tags.Items.GLASS_PANES )
.unlocks( "has_computer", inventoryChange( CCTags.COMPUTER ) )
.unlockedBy( "has_computer", inventoryChange( CCTags.COMPUTER ) )
.save( add );
ShapedRecipeBuilder
@@ -223,8 +223,8 @@ public class Recipes extends RecipeProvider
.define( '#', Tags.Items.STONE )
.define( 'A', Items.GOLDEN_APPLE )
.define( 'G', Tags.Items.GLASS_PANES )
.unlocks( "has_computer", inventoryChange( CCTags.COMPUTER ) )
.unlocks( "has_apple", inventoryChange( Items.GOLDEN_APPLE ) )
.unlockedBy( "has_computer", inventoryChange( CCTags.COMPUTER ) )
.unlockedBy( "has_apple", inventoryChange( Items.GOLDEN_APPLE ) )
.save( add );
ShapedRecipeBuilder
@@ -235,8 +235,8 @@ public class Recipes extends RecipeProvider
.define( '#', Tags.Items.INGOTS_GOLD )
.define( 'A', Items.GOLDEN_APPLE )
.define( 'G', Tags.Items.GLASS_PANES )
.unlocks( "has_computer", inventoryChange( CCTags.COMPUTER ) )
.unlocks( "has_apple", inventoryChange( Items.GOLDEN_APPLE ) )
.unlockedBy( "has_computer", inventoryChange( CCTags.COMPUTER ) )
.unlockedBy( "has_apple", inventoryChange( Items.GOLDEN_APPLE ) )
.save( add );
ShapedRecipeBuilder
@@ -247,7 +247,7 @@ public class Recipes extends RecipeProvider
.define( '#', Tags.Items.STONE )
.define( 'R', Tags.Items.DUSTS_REDSTONE )
.define( 'D', Tags.Items.DYES )
.unlocks( "has_computer", inventoryChange( CCTags.COMPUTER ) )
.unlockedBy( "has_computer", inventoryChange( CCTags.COMPUTER ) )
.save( add );
ShapedRecipeBuilder
@@ -258,7 +258,7 @@ public class Recipes extends RecipeProvider
.define( '#', Tags.Items.STONE )
.define( 'N', Blocks.NOTE_BLOCK )
.define( 'R', Tags.Items.DUSTS_REDSTONE )
.unlocks( "has_computer", inventoryChange( CCTags.COMPUTER ) )
.unlockedBy( "has_computer", inventoryChange( CCTags.COMPUTER ) )
.save( add );
ShapedRecipeBuilder
@@ -268,19 +268,19 @@ public class Recipes extends RecipeProvider
.pattern( "###" )
.define( '#', Tags.Items.STONE )
.define( 'R', Tags.Items.DUSTS_REDSTONE )
.unlocks( "has_computer", inventoryChange( CCTags.COMPUTER ) )
.unlocks( "has_cable", inventoryChange( Registry.ModItems.CABLE.get() ) )
.unlockedBy( "has_computer", inventoryChange( CCTags.COMPUTER ) )
.unlockedBy( "has_cable", inventoryChange( Registry.ModItems.CABLE.get() ) )
.save( add );
ShapelessRecipeBuilder
.shapeless( Registry.ModBlocks.WIRED_MODEM_FULL.get() )
.requires( Registry.ModItems.WIRED_MODEM.get() )
.unlocks( "has_modem", inventoryChange( CCTags.WIRED_MODEM ) )
.unlockedBy( "has_modem", inventoryChange( CCTags.WIRED_MODEM ) )
.save( add, new ResourceLocation( ComputerCraft.MOD_ID, "wired_modem_full_from" ) );
ShapelessRecipeBuilder
.shapeless( Registry.ModItems.WIRED_MODEM.get() )
.requires( Registry.ModBlocks.WIRED_MODEM_FULL.get() )
.unlocks( "has_modem", inventoryChange( CCTags.WIRED_MODEM ) )
.unlockedBy( "has_modem", inventoryChange( CCTags.WIRED_MODEM ) )
.save( add, new ResourceLocation( ComputerCraft.MOD_ID, "wired_modem_full_to" ) );
ShapedRecipeBuilder
@@ -290,7 +290,7 @@ public class Recipes extends RecipeProvider
.pattern( "###" )
.define( '#', Tags.Items.STONE )
.define( 'E', Tags.Items.ENDER_PEARLS )
.unlocks( "has_computer", inventoryChange( CCTags.COMPUTER ) )
.unlockedBy( "has_computer", inventoryChange( CCTags.COMPUTER ) )
.save( add );
ShapedRecipeBuilder
@@ -300,8 +300,8 @@ public class Recipes extends RecipeProvider
.pattern( "###" )
.define( '#', Tags.Items.INGOTS_GOLD )
.define( 'E', Items.ENDER_EYE )
.unlocks( "has_computer", inventoryChange( CCTags.COMPUTER ) )
.unlocks( "has_wireless", inventoryChange( Registry.ModBlocks.WIRELESS_MODEM_NORMAL.get() ) )
.unlockedBy( "has_computer", inventoryChange( CCTags.COMPUTER ) )
.unlockedBy( "has_wireless", inventoryChange( Registry.ModBlocks.WIRELESS_MODEM_NORMAL.get() ) )
.save( add );
}
@@ -310,13 +310,13 @@ public class Recipes extends RecipeProvider
return DyeColor.byId( 15 - colour.ordinal() );
}
private static InventoryChangeTrigger.Instance inventoryChange( Tag<Item> stack )
private static InventoryChangeTrigger.Instance inventoryChange( ITag<Item> stack )
{
return InventoryChangeTrigger.Instance.hasItem( ItemPredicate.Builder.item().of( stack ).build() );
return InventoryChangeTrigger.Instance.hasItems( ItemPredicate.Builder.item().of( stack ).build() );
}
private static InventoryChangeTrigger.Instance inventoryChange( IItemProvider... stack )
{
return InventoryChangeTrigger.Instance.hasItem( stack );
return InventoryChangeTrigger.Instance.hasItems( stack );
}
}

View File

@@ -7,46 +7,55 @@ package dan200.computercraft.data;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.shared.Registry;
import net.minecraft.data.BlockTagsProvider;
import net.minecraft.data.DataGenerator;
import net.minecraft.data.ItemTagsProvider;
import net.minecraft.item.Item;
import net.minecraft.tags.ITag;
import net.minecraft.tags.ItemTags;
import net.minecraft.tags.Tag;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.common.data.ExistingFileHelper;
import static dan200.computercraft.data.Tags.CCTags.*;
public class Tags extends ItemTagsProvider
{
private static final ITag.INamedTag<Item> PIGLIN_LOVED = ItemTags.PIGLIN_LOVED;
public static class CCTags
{
public static final Tag<Item> COMPUTER = item( "computer" );
public static final Tag<Item> TURTLE = item( "turtle" );
public static final Tag<Item> WIRED_MODEM = item( "wired_modem" );
public static final Tag<Item> MONITOR = item( "monitor" );
public static final ITag.INamedTag<Item> COMPUTER = item( "computer" );
public static final ITag.INamedTag<Item> TURTLE = item( "turtle" );
public static final ITag.INamedTag<Item> WIRED_MODEM = item( "wired_modem" );
public static final ITag.INamedTag<Item> MONITOR = item( "monitor" );
}
public Tags( DataGenerator generator )
public Tags( DataGenerator generator, ExistingFileHelper helper )
{
super( generator );
super( generator, new BlockTagsProvider( generator, ComputerCraft.MOD_ID, helper ), ComputerCraft.MOD_ID, helper );
}
@Override
protected void addTags()
{
tag( COMPUTER )
.add( Registry.ModItems.COMPUTER_NORMAL.get() )
.add( Registry.ModItems.COMPUTER_ADVANCED.get() )
.add( Registry.ModItems.COMPUTER_COMMAND.get() );
tag( COMPUTER ).add(
Registry.ModItems.COMPUTER_NORMAL.get(),
Registry.ModItems.COMPUTER_ADVANCED.get(),
Registry.ModItems.COMPUTER_COMMAND.get()
);
tag( TURTLE ).add( Registry.ModItems.TURTLE_NORMAL.get(), Registry.ModItems.TURTLE_ADVANCED.get() );
tag( WIRED_MODEM ).add( Registry.ModItems.WIRED_MODEM.get(), Registry.ModItems.WIRED_MODEM_FULL.get() );
tag( MONITOR )
.add( Registry.ModItems.MONITOR_NORMAL.get() )
.add( Registry.ModItems.MONITOR_ADVANCED.get() );
tag( MONITOR ).add( Registry.ModItems.MONITOR_NORMAL.get(), Registry.ModItems.MONITOR_ADVANCED.get() );
tag( PIGLIN_LOVED ).add(
Registry.ModItems.COMPUTER_ADVANCED.get(), Registry.ModItems.TURTLE_ADVANCED.get(),
Registry.ModItems.WIRELESS_MODEM_ADVANCED.get(), Registry.ModItems.POCKET_COMPUTER_ADVANCED.get(),
Registry.ModItems.MONITOR_ADVANCED.get()
);
}
private static Tag<Item> item( String name )
private static ITag.INamedTag<Item> item( String name )
{
return new ItemTags.Wrapper( new ResourceLocation( ComputerCraft.MOD_ID, name ) );
return ItemTags.bind( new ResourceLocation( ComputerCraft.MOD_ID, name ).toString() );
}
}

View File

@@ -56,6 +56,7 @@ import dan200.computercraft.shared.util.CreativeTabMain;
import dan200.computercraft.shared.util.FixedPointTileEntityType;
import dan200.computercraft.shared.util.ImpostorRecipe;
import dan200.computercraft.shared.util.ImpostorShapelessRecipe;
import net.minecraft.block.AbstractBlock;
import net.minecraft.block.Block;
import net.minecraft.block.material.Material;
import net.minecraft.entity.EntityClassification;
@@ -92,21 +93,21 @@ public final class Registry
public static final class ModBlocks
{
static final DeferredRegister<Block> BLOCKS = new DeferredRegister<>( ForgeRegistries.BLOCKS, ComputerCraft.MOD_ID );
static final DeferredRegister<Block> BLOCKS = DeferredRegister.create( ForgeRegistries.BLOCKS, ComputerCraft.MOD_ID );
private static Block.Properties properties()
private static AbstractBlock.Properties properties()
{
return Block.Properties.of( Material.STONE ).strength( 2 );
return AbstractBlock.Properties.of( Material.STONE ).strength( 2 );
}
private static Block.Properties turtleProperties()
private static AbstractBlock.Properties turtleProperties()
{
return Block.Properties.of( Material.STONE ).strength( 2.5f );
return AbstractBlock.Properties.of( Material.STONE ).strength( 2.5f );
}
private static Block.Properties modemProperties()
private static AbstractBlock.Properties modemProperties()
{
return Block.Properties.of( Material.STONE ).strength( 1.5f );
return AbstractBlock.Properties.of( Material.STONE ).strength( 1.5f );
}
public static final RegistryObject<BlockComputer> COMPUTER_NORMAL = BLOCKS.register( "computer_normal",
@@ -115,7 +116,7 @@ public final class Registry
() -> new BlockComputer( properties(), ComputerFamily.ADVANCED, ModTiles.COMPUTER_ADVANCED ) );
public static final RegistryObject<BlockComputer> COMPUTER_COMMAND = BLOCKS.register( "computer_command", () -> new BlockComputer(
Block.Properties.of( Material.STONE ).strength( -1, 6000000.0F ),
AbstractBlock.Properties.of( Material.STONE ).strength( -1, 6000000.0F ),
ComputerFamily.COMMAND, ModTiles.COMPUTER_COMMAND
) );
@@ -145,7 +146,7 @@ public final class Registry
public static class ModTiles
{
static final DeferredRegister<TileEntityType<?>> TILES = new DeferredRegister<>( ForgeRegistries.TILE_ENTITIES, ComputerCraft.MOD_ID );
static final DeferredRegister<TileEntityType<?>> TILES = DeferredRegister.create( ForgeRegistries.TILE_ENTITIES, ComputerCraft.MOD_ID );
private static <T extends TileEntity> RegistryObject<TileEntityType<T>> ofBlock( RegistryObject<? extends Block> block, Function<TileEntityType<T>, T> factory )
{
@@ -183,7 +184,7 @@ public final class Registry
public static final class ModItems
{
static final DeferredRegister<Item> ITEMS = new DeferredRegister<>( ForgeRegistries.ITEMS, ComputerCraft.MOD_ID );
static final DeferredRegister<Item> ITEMS = DeferredRegister.create( ForgeRegistries.ITEMS, ComputerCraft.MOD_ID );
private static Item.Properties properties()
{
@@ -245,7 +246,7 @@ public final class Registry
{
// Upgrades
ComputerCraft.TurtleUpgrades.wirelessModemNormal = new TurtleModem( false, new ResourceLocation( ComputerCraft.MOD_ID, "wireless_modem_normal" ) );
TurtleUpgrades.register( ComputerCraft.TurtleUpgrades.wirelessModemNormal );
ComputerCraftAPI.registerTurtleUpgrade( ComputerCraft.TurtleUpgrades.wirelessModemNormal );
ComputerCraft.TurtleUpgrades.wirelessModemAdvanced = new TurtleModem( true, new ResourceLocation( ComputerCraft.MOD_ID, "wireless_modem_advanced" ) );
ComputerCraftAPI.registerTurtleUpgrade( ComputerCraft.TurtleUpgrades.wirelessModemAdvanced );
@@ -281,7 +282,7 @@ public final class Registry
public static class ModEntities
{
static final DeferredRegister<EntityType<?>> ENTITIES = new DeferredRegister<>( ForgeRegistries.ENTITIES, ComputerCraft.MOD_ID );
static final DeferredRegister<EntityType<?>> ENTITIES = DeferredRegister.create( ForgeRegistries.ENTITIES, ComputerCraft.MOD_ID );
public static final RegistryObject<EntityType<TurtlePlayer>> TURTLE_PLAYER = ENTITIES.register( "turtle_player", () ->
EntityType.Builder.<TurtlePlayer>createNothing( EntityClassification.MISC )
@@ -293,7 +294,7 @@ public final class Registry
public static class ModContainers
{
static final DeferredRegister<ContainerType<?>> CONTAINERS = new DeferredRegister<>( ForgeRegistries.CONTAINERS, ComputerCraft.MOD_ID );
static final DeferredRegister<ContainerType<?>> CONTAINERS = DeferredRegister.create( ForgeRegistries.CONTAINERS, ComputerCraft.MOD_ID );
public static final RegistryObject<ContainerType<ContainerComputer>> COMPUTER = CONTAINERS.register( "computer",
() -> ContainerData.toType( ComputerContainerData::new, ContainerComputer::new ) );

View File

@@ -11,6 +11,7 @@ import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.server.MinecraftServer;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraft.world.server.ServerWorld;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
@@ -20,13 +21,12 @@ public final class TurtlePermissions
public static boolean isBlockEnterable( World world, BlockPos pos, PlayerEntity player )
{
MinecraftServer server = world.getServer();
return server == null || world.isClientSide || !server.isUnderSpawnProtection( world, pos, player );
return server == null || world.isClientSide || (world instanceof ServerWorld && !server.isUnderSpawnProtection( (ServerWorld) world, pos, player ));
}
public static boolean isBlockEditable( World world, BlockPos pos, PlayerEntity player )
{
MinecraftServer server = world.getServer();
return server == null || world.isClientSide || !server.isUnderSpawnProtection( world, pos, player );
return isBlockEnterable( world, pos, player );
}
@SubscribeEvent

View File

@@ -30,6 +30,7 @@ import net.minecraft.inventory.container.Container;
import net.minecraft.inventory.container.INamedContainerProvider;
import net.minecraft.network.play.server.SPlayerPositionLookPacket;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.text.IFormattableTextComponent;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.text.StringTextComponent;
import net.minecraft.util.text.TranslationTextComponent;
@@ -283,7 +284,7 @@ public final class CommandComputerCraft
private static ITextComponent linkComputer( CommandSource source, ServerComputer serverComputer, int computerId )
{
ITextComponent out = new StringTextComponent( "" );
IFormattableTextComponent out = new StringTextComponent( "" );
// Append the computer instance
if( serverComputer == null )

View File

@@ -12,6 +12,7 @@ import net.minecraft.client.Minecraft;
import net.minecraft.command.CommandSource;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.text.StringTextComponent;
import net.minecraft.util.text.Style;
import net.minecraft.util.text.TranslationTextComponent;
import net.minecraft.util.text.event.ClickEvent;
import net.minecraft.util.text.event.HoverEvent;
@@ -57,10 +58,8 @@ public final class CommandCopy
public static ITextComponent createCopyText( String text )
{
StringTextComponent name = new StringTextComponent( text );
name.getStyle()
.setClickEvent( new ClickEvent( ClickEvent.Action.RUN_COMMAND, PREFIX + text ) )
.setHoverEvent( new HoverEvent( HoverEvent.Action.SHOW_TEXT, new TranslationTextComponent( "gui.computercraft.tooltip.copy" ) ) );
return name;
return new StringTextComponent( text ).withStyle( Style.EMPTY
.withClickEvent( new ClickEvent( ClickEvent.Action.RUN_COMMAND, PREFIX + text ) )
.withHoverEvent( new HoverEvent( HoverEvent.Action.SHOW_TEXT, new TranslationTextComponent( "gui.computercraft.tooltip.copy" ) ) ) );
}
}

View File

@@ -13,6 +13,7 @@ import com.mojang.brigadier.context.CommandContext;
import com.mojang.brigadier.tree.CommandNode;
import com.mojang.brigadier.tree.LiteralCommandNode;
import net.minecraft.command.CommandSource;
import net.minecraft.util.text.IFormattableTextComponent;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.text.StringTextComponent;
import net.minecraft.util.text.TextFormatting;
@@ -173,7 +174,7 @@ public final class HelpingArgumentBuilder extends LiteralArgumentBuilder<Command
temp.addChild( node );
String usage = dispatcher.getSmartUsage( temp, context.getSource() ).get( node ).substring( node.getName().length() );
ITextComponent output = new StringTextComponent( "" )
IFormattableTextComponent output = new StringTextComponent( "" )
.append( coloured( "/" + command + usage, HEADER ) )
.append( " " )
.append( coloured( translate( "commands." + id + ".synopsis" ), SYNOPSIS ) )
@@ -189,8 +190,8 @@ public final class HelpingArgumentBuilder extends LiteralArgumentBuilder<Command
output.append( "\n" );
ITextComponent component = coloured( child.getName(), NAME );
component.getStyle().setClickEvent( new ClickEvent(
IFormattableTextComponent component = coloured( child.getName(), NAME );
component.getStyle().withClickEvent( new ClickEvent(
ClickEvent.Action.SUGGEST_COMMAND,
"/" + command + " " + child.getName()
) );

View File

@@ -19,37 +19,35 @@ public final class ChatHelpers
private ChatHelpers() {}
public static ITextComponent coloured( String text, TextFormatting colour )
public static IFormattableTextComponent coloured( String text, TextFormatting colour )
{
ITextComponent component = new StringTextComponent( text == null ? "" : text );
component.getStyle().setColor( colour );
return new StringTextComponent( text == null ? "" : text ).withStyle( colour );
}
public static <T extends IFormattableTextComponent> T coloured( T component, TextFormatting colour )
{
component.withStyle( colour );
return component;
}
public static <T extends ITextComponent> T coloured( T component, TextFormatting colour )
{
component.getStyle().setColor( colour );
return component;
}
public static ITextComponent text( String text )
public static IFormattableTextComponent text( String text )
{
return new StringTextComponent( text == null ? "" : text );
}
public static ITextComponent translate( String text )
public static IFormattableTextComponent translate( String text )
{
return new TranslationTextComponent( text == null ? "" : text );
}
public static ITextComponent translate( String text, Object... args )
public static IFormattableTextComponent translate( String text, Object... args )
{
return new TranslationTextComponent( text == null ? "" : text, args );
}
public static ITextComponent list( ITextComponent... children )
public static IFormattableTextComponent list( ITextComponent... children )
{
ITextComponent component = new StringTextComponent( "" );
IFormattableTextComponent component = new StringTextComponent( "" );
for( ITextComponent child : children )
{
component.append( child );
@@ -57,31 +55,31 @@ public final class ChatHelpers
return component;
}
public static ITextComponent position( BlockPos pos )
public static IFormattableTextComponent position( BlockPos pos )
{
if( pos == null ) return translate( "commands.computercraft.generic.no_position" );
return translate( "commands.computercraft.generic.position", pos.getX(), pos.getY(), pos.getZ() );
}
public static ITextComponent bool( boolean value )
public static IFormattableTextComponent bool( boolean value )
{
return value
? coloured( translate( "commands.computercraft.generic.yes" ), TextFormatting.GREEN )
: coloured( translate( "commands.computercraft.generic.no" ), TextFormatting.RED );
}
public static ITextComponent link( ITextComponent component, String command, ITextComponent toolTip )
public static IFormattableTextComponent link( IFormattableTextComponent component, String command, ITextComponent toolTip )
{
Style style = component.getStyle();
if( style.getColor() == null ) style.setColor( TextFormatting.YELLOW );
style.setClickEvent( new ClickEvent( ClickEvent.Action.RUN_COMMAND, command ) );
style.setHoverEvent( new HoverEvent( HoverEvent.Action.SHOW_TEXT, toolTip ) );
if( style.getColor() == null ) style = style.withColor( TextFormatting.YELLOW );
style = style.withClickEvent( new ClickEvent( ClickEvent.Action.RUN_COMMAND, command ) );
style = style.withHoverEvent( new HoverEvent( HoverEvent.Action.SHOW_TEXT, toolTip ) );
return component;
return component.setStyle( style );
}
public static ITextComponent header( String text )
public static IFormattableTextComponent header( String text )
{
return coloured( text, HEADER );
}

View File

@@ -79,7 +79,10 @@ public final class ColourableRecipe extends SpecialRecipe
}
if( colourable.isEmpty() ) return ItemStack.EMPTY;
return ((IColouredItem) colourable.getItem()).withColour( colourable, tracker.getColour() );
ItemStack stack = ((IColouredItem) colourable.getItem()).withColour( colourable, tracker.getColour() );
stack.setCount( 1 );
return stack;
}
@Override

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