1
0
mirror of https://github.com/SquidDev-CC/CC-Tweaked synced 2025-10-15 05:57:38 +00:00

Compare commits

...

125 Commits

Author SHA1 Message Date
Jonathan Coates
1f3b781a1d Merge branch 'mc-1.16.x' into mc-1.18.x 2023-02-14 10:10:50 +00:00
Jonathan Coates
d7305fb975 Bump CC:T to 1.101.2
Yes, it was the shiny parse errors, and not the steady accumulation of
bugs which made me finally do a version bump.
2023-02-14 10:00:24 +00:00
Jonathan Coates
9b3cadf57c Cherry pick several changes back from 1.19.3
The main purpose of this is to backport the improved parse/runtime
errors to older versions. I think they're sufficiently useful that we
should try to make it as widely available as possible.

We've been running them for a week now on SC3 and the released version
and not seen any issues, so I think it's probably stable enough.

This is a pretty lazy commit: I ended up copying the whole ROM over and
then picking up a few other related changes along the way.

 - Trim spaces from file paths (b8fce1eecc)

 - Correctly format 12AM/PM with
   %I (9f48395596)

 - Fix http.request and htpt.websocketAsync not handling a few failure
   edge-cases correctly (3b42f22a4f).

 - Move the internal modules into the main package path, hidden under
   cc.internal (34a31abd9c).

 - Gather code coverage in Java instead of
   Lua (28a55349a9).

 - Make error messages in edit more
   obvious (8cfbfe7ceb).

 - Make mcfly's test methods global. This means we don't need to pass
   stub everywhere (7335a892b5).

 - Improve runtime and parse errors. This comes from numerous commits,
   but chiefly a12b405acf, and
   5502412181.

 - Hide the internal redirect methods in
   multishell (33b6f38339).

Note this does /not/ include the shebang changes (sorry Emma!). I've
tried to avoid adding any user-controllable features, mostly because I
don't know how to handle the versioning otherwise :).
2023-02-14 09:45:03 +00:00
Jonathan Coates
68f6fa9343 Fall back to the default item when rendering non-turtles
Closes #1328. This isn't an actual fix - I have no clue what's going on
there - but it should be less crashy.
2023-02-09 12:45:20 +00:00
Jonathan Coates
58f2c0bd71 Update Cobalt to fix yielding inside __len
Closes #1307
2023-01-26 10:09:09 +00:00
Jonathan Coates
b46ad62424 Send the original rednet message to the current computer
We were incorrectly enquing the modem payload, not the underlying rednet
message.

Closes #1308.
2023-01-21 08:25:13 +00:00
Jonathan Coates
12f2f854a6 Include the licences of our dependencies in the credits
I feel like we should have been doing this from the beginning. Love to
uncompliant for 11 years :/.
2023-01-07 12:04:56 +00:00
Jonathan Coates
4078a2dcba Clamp speaker volume again
Looks like this was removed in b048b6666d.
2023-01-01 13:59:58 +00:00
Jonathan Coates
0ad12eeab6 Fix computer upgrade recipes
Fixes #1272
2022-12-26 09:32:02 +00:00
Jonathan Coates
68a5081740 Bump Cobalt version
See #1248 and #1249
2022-12-21 16:01:54 +00:00
Jonathan Coates
5e701f73d6 Use the correct import path in import.lua
Backported from 1.19.3
2022-12-14 21:52:32 +00:00
Jonathan Coates
0db32bd0fe Merge branch 'mc-1.16.x' into mc-1.18.x 2022-11-02 09:55:10 +00:00
Jonathan Coates
1d3ecb551d Improvee changelog 2022-11-02 07:58:31 +00:00
Jonathan Coates
aefda6a381 Fix a couple of issues with the release process
Only way to test these is in prod, alas :D:
2022-11-01 21:53:05 +00:00
Jonathan Coates
11ac865877 Merge branch 'mc-1.16.x' into mc-1.18.x 2022-11-01 20:07:15 +00:00
Jonathan Coates
6b93fafc46 Bump CC:T to 1.101.0
These version numbers are very hard to type correctly.
2022-11-01 20:01:21 +00:00
Jonathan Coates
1acb8441ec Add a couple of tests for file autocompletion 2022-11-01 19:22:07 +00:00
Ivo Leal
4b0988768d Add include_hidden option to fs.complete (#1194) 2022-11-01 14:50:15 +00:00
Jonathan Coates
f528046535 Add a whole bunch of missing @since annotations 2022-10-31 20:09:47 +00:00
Jonathan Coates
93f747fb54 Fix incorrect reboot tooltip
This tooltip was a) using the wrong text and b) incorrect anyway!
Rebooting an off computer does nothing, rather than turning it on.
2022-10-31 20:08:50 +00:00
Jonathan Coates
5d4c34fbac Merge branch 'mc-1.16.x' into mc-1.18.x 2022-10-31 18:03:39 +00:00
Jonathan Coates
4c5b3a6ee5 Clear Origin header on websockets
Technically this removes Sec-Websocket-Origin, as that's what the
current version of Netty uses. We'll need to change this on 1.18+.

Closes ##1197.
2022-10-31 17:46:02 +00:00
Jonathan Coates
7701b343fb Make PartialOptions immutable
- Switch to using OptionalInt/OptionalLong instead of @Nullable
   Long/Integers. I know IntelliJ complains, but it avoids the risk of
   implicit unboxing.

 - Instead of mutating PartialOptions, we now define a merge() function
   which returns the new options. This simplifies the logic in
   AddressRule a whole bunch.
2022-10-31 09:13:40 +00:00
Jonathan Coates
14cb97cba1 Sort NBT when writing
This should fix the worst cases of #1196.
2022-10-30 16:47:26 +00:00
Jonathan Coates
1490ca8624 Bump Cobalt version
Adds debug.getregistry() support
2022-10-30 16:39:25 +00:00
Jonathan Coates
f5b89982de Don't unnecessarily scroll in edit run wrapper (#1195) 2022-10-30 15:17:33 +00:00
Jonathan Coates
1a87175ae7 Be a little more rigorous in KotlinLuaMachine's threading 2022-10-30 11:44:01 +00:00
Jonathan Coates
c4184a33bc Rewrite our gametest system
This is a noisier diff than I'd like as this is just a direct copy from
the multi-loader branch.

 - Rename "ingame" package to "gametest"

 - Don't chain GameTestSequence methods - it's actually much cleaner if
   we just use Kotlin's implicit this syntax.

 - Use our work in 71f81e1201 to write
   computer tests using Kotlin instead of Lua. This means all the logic
   is in one place, which is nice!

 - Add a couple more tests for some of the more error-prone bits of
   functionality.
2022-10-30 10:50:16 +00:00
Jonathan Coates
b3702fed78 Remove all Minecraft references from the core package
This is an initial step before refactoring this into a separate module.
It's definitely not complete - there's a lot of work needed to remove
referneces to the main ComputerCraft class for instance - but is a
useful first step.
2022-10-30 09:20:26 +00:00
Jonathan Coates
38b2c944f3 Merge branch 'mc-1.16.x' into mc-1.18.x 2022-10-30 08:49:52 +00:00
Jonathan Coates
5ee5b11995 Fix month and day names under Java 17
I still don't really understand why the ROOT locale is wrong here, but
there we go. We'll need to remember to uncomment the tests on the 1.18
branch!

Also add some code to map tests back to their definition side. Alas,
this only links to the file right now, not the correct line :/.
2022-10-29 23:54:35 +01:00
Jonathan Coates
b2d2153258 Add several missing version annotations
I probably need to add this to the pre-release checklist. Don't think
there's a good way to automate this :(
2022-10-29 22:49:45 +01:00
Jonathan Coates
3d6ef0cf96 Fix peripheral API using the wrong methods 2022-10-29 22:47:57 +01:00
Jonathan Coates
71f81e1201 Move some test support code into testFixtues
This offers very few advantages now, but helps support the following in
the future:

 - Reuse test support code across multiple projects (useful for
   multi-loader).
 - Allow using test fixture code in testMod. We've got a version of our
   gametest which use Kotlin instead of Lua for asserting computer
   behaviour.

We can't use java-test-fixtures here for Forge reasons, so have to roll
our own version. Alas.

 - Add an ILuaMachine implementation which runs Kotlin coroutines
   instead. We can use this for testing asynchronous APIs. This also
   replaces the FakeComputerManager.

 - Move most things in the .support module to .test.core. We need to use
   a separate package in order to cope with Java 9 modules (again,
   thanks Forge).
2022-10-29 18:17:02 +01:00
Jonathan Coates
1e88d37004 Add peripheral_hub type for wired-modem-like peripherals (#1193)
This allows other mods to create wired-modem alike blocks, which expose
peripherals on the wired network, without having to reimplement the main
modem interface.

This is not currently documented, but a peripheral_hub should provide
the following methods:

 - isPresentRemote
 - getTypeRemote
 - hasTypeRemote
 - getMethodsRemote
 - callRemote
2022-10-29 16:03:05 +01:00
Jonathan Coates
97387556fe Handle file transfers inside CraftOS (#1190)
- Add a new file_transfer event. This has the signature
   "file_transfer", TransferredFiles.

   TransferredFiles has a single method getFiles(), which returns a list
   of all transferred files.

 - Add a new "import" program which waits for a file_transfer event and
   writes files to the current directory.

 - If a file_transfer event is not handled (i.e. its getFiles() method
   is not called) within 5 seconds on the client, we display a toast
   informing the user on how to upload a file.
2022-10-29 12:01:23 +01:00
Jonathan Coates
1f910ee2ba Use a separate object for tracking TickScheduler state
This allows us to use non-TileGeneric block entities. This is a clever
trick which will help us later!
2022-10-28 23:40:55 +01:00
Jonathan Coates
158850be09 Some Java-17ification
I might just stick on 1.18 for the rest of these refactors. Porting
across the mojmap boundary is painful.
2022-10-25 22:58:31 +01:00
Jonathan Coates
be827a21db Merge branch 'mc-1.16.x' into mc-1.18.x
I dare say there's going to be some bugs with this. I was as careful as
I could be, but yikes it was nasty.
2022-10-25 22:38:26 +01:00
Jonathan Coates
562f224c01 Refactor out our JEI plugin into reusable components
Pretty useless right now, but either useful for CC:R or our eventual
multi-loader support.
2022-10-25 19:26:44 +01:00
Jonathan Coates
f45614175a Some improvements to Javadoc publishing
- Use <p> everywhere. This is uglier, but also technically more
   correct. This requires a version bump to cct-javadoc, and will give
   me a massive headache when merging.

 - Link against the existing OpenJDK docs.
2022-10-25 19:17:55 +01:00
Jonathan Coates
af7af615c7 Correctly shut down computer threads
We now wait for workers to terminate when closing the computer thread.

I'll be honest, I'm not happy with this code. Multi-threading is really
hard to get right, and I can't say I'm convinced this is especially well
behaved. I did look at trying to model this in TLA+, but in the end
decided it wasn't worth it.

In the future we probably want to split ComputerExecutor into two
objects, where one is our entry in the ComputerThread queue (and so
holds timing information) while the other is responsible for actual
execution.
2022-10-25 09:32:32 +01:00
Jonathan Coates
8171578e80 Some minor build system improvements
- Correctly handle Git commands failing. We need an actual default
   value, not just null!

 - Use run/ and build/tmp/ for temporary test locations, not
   /test-files.
2022-10-24 19:21:09 +01:00
Jonathan Coates
f4e542b4db Use our global logger instead of per-class ones
No slf4j available for 1.16.5, and I'll forget if I depend on
log4j.
2022-10-23 16:13:08 +01:00
Jonathan Coates
3e3bc8d4b1 Fix a whole bunch of GH action issues
- Switch over to the Gradle GH action. Not expecting massive changes,
   but might provide some better caching.

 - Bump some GH action versions.

 - Fix a Java 8 compatability issue in our build scripts.
2022-10-22 21:36:52 +01:00
Jonathan Coates
b48f590b92 Merge branch 'feature/gradle-vice' into mc-1.16.x
The hills are alive with the sound of build scripts!
2022-10-22 21:13:50 +01:00
Jonathan Coates
6ab90dc30d Convert build script to Kotlin
- Add a new Node plugin. This automatically installs npm dependencies
   and provides a "NpxExecToDir" to dir task. This allows us to make the
   doc website task dependencies a little nicer, by simply chaining
   tasks together, rather than doing dependsOn + `input.files(the other
   task output)`.

 - Switch over to CurseForgeGradle from CurseGradle. The latter is
   super clunky to use in non-Groovy languages.

 - Copy our Modrinth description body to our repo, and add support for
   syncing it. We'll still have to do CF manually I think.
2022-10-22 21:09:08 +01:00
Jonathan Coates
0cfdd7b5e9 Move some more build logic to buildSrc
Look, I don't enjoy having 600 LOC long build.gradle files, it's just
very easy to do! This at least moves some of the complexity elsewhere,
so the build script is a little more declarative.
2022-10-22 20:47:47 +01:00
Jonathan Coates
af5d816798 Use spotless for enforcing licenses
It's more verbose as the default license plugin doesn't support multiple
license headers. However, it also gives us some other goodies (namely
formatting Kotlin and removing unused imports), so worth doing.
2022-10-22 18:19:51 +01:00
Jonathan Coates
57cf6084e2 Manage ComputerThread's lifecycle in ComputerContext
This converts ComputerThread from a singleton into a proper object,
which is setup when starting a computer, and tore down when the
ComputerContext is closed.

While this is mostly for conceptual elegance, it does offer some
concrete benefits:
 - You can now adjust the thread count without restarting the whole
   game (just leaving and rentering the world). Though, alas, no effect
   on servers.
 - We can run multiple ComputerThreads in parallel, which makes it much
   easier to run tests in parallel. This allows us to remove our rather
   silly IsolatedRunner test helper.
2022-10-22 14:36:25 +01:00
Jonathan Coates
e9cde9e1bf Refactor out main thread tasks into an interface
Computers now use a MainThreadScheduler to construct a
MainThreadScheduler.Executor, which is used to submit tasks. Our
previous (singleton) MainThread and MainThreadExecutor now implement
these interfaces.

The main purpose of this is to better manage the lifetime of the server
thread tasks. We've had at least one bug caused by us failing to reset
its state, so good to avoid those! This also allows us to use a fake
implementation in tests where we don't expect main thread tasks to run.

As we're now passing a bunch of arguments into our Computer, we bundle
the "global" ones into ComputerContext (which now also includes the Lua
machine factory!). This definitely isn't the nicest API, so we might
want to rethink this one day.
2022-10-22 14:13:06 +01:00
Jonathan Coates
68da044ff2 Merge branch 'feature/new-metrics' into mc-1.16.x 2022-10-22 12:21:41 +01:00
Jonathan Coates
18d9993fa7 Merge branch 'feature/more-datagen' into mc-1.16.x 2022-10-22 12:04:07 +01:00
Jonathan Coates
0c3de1087e Switch to vanilla's model data generators
In some ways this isn't as nice as the Forge version (requires ATs,
doesn't check texture/model existence). However, it's more multi-loader
friendly and in some cases has much less boilerplate.

Blockstate JSON files are incredibly verbose, so we add a custom JSON
pretty printer which writes things in a slightly more compact manner.

This also changes how turtle upgrades are loaded - we now support
standard ResourceLocations (so computercraft:blocks/some_turtle_upgrade)
as well as ModelResourceLocations (computercraft:items/some_turtle_upgrade#inventory).
I don't think any resource packs need to touch our upgrades, but
apologies if this breaks anything.
2022-10-22 11:55:30 +01:00
Jonathan Coates
ff89e5feeb Some datagen improvements
- Convert remaining recipes over to datagen.

 - Switch loot tables to use vanilla's loot table generator. It's
   honestly not too different, just the earlier system confused me too
   much :).

Alas, a positive diff because the JSON is so verbose. I've got a really
nice patch which makes the JSON more compact, but alas the Mixin doesn't
apply on 1.16 :(.
2022-10-22 10:50:10 +01:00
Jonathan Coates
0b26ab366d Rewrite the metrics system
- Remove TrackingField and replace it with a Metric abstract class.
   This has two concrete subclasses - Counter and Event. Events carry an
   additional piece of data each time it is observed, such as HTTP
   response size.

 - Computers now accept a MetricsObserver, which tracks metrics for this
   particular computer. This allows us to decouple Computer classes and
   metrics information. The concrete MetricsObserver class we use within
   Minecraft exposes the ServerComputer directly, so we no longer need to
   do the awkward mapping and lookups!

 - The /computercraft command can now do aggregates (count, avg, max)
   over all Event metrics. This removes the need for special handling of
   computer and server time.

There's also a small number of changes in removing the coupling between
Computer and some of its dependencies (ILuaMachine, MainThreadExecutor).
This makes some future refactorings easier, I promise!
2022-10-22 01:35:13 +01:00
Jonathan Coates
cb9731306c Give up on ComputerThreadTest being accurate
It's just too timing dependent right now. I'd like to fix this in the
future, but doing so is hard.
2022-10-22 00:42:21 +01:00
Jonathan Coates
5d833ac634 Expose getters for the detail registry too (#1188) 2022-10-22 00:42:07 +01:00
Jonathan Coates
9db3e6d2a0 Load the CC API with services loaders
This is a little odd (it's more complex for one!), but means we can
reuse the internal API interface in other classes, which is useful for
the data provider refactor I'm about to do.

This is much nicer in Java 17 :D (records, ServiceLoader.stream()),
but such is the perils of still targetting 1.16.
2022-10-21 23:50:44 +01:00
Jonathan Coates
1e703f1b07 Fix several off-by-one issues in UploadFileMessage
We now fuzz UploadFileMessage, generating random files and checking they
round-trip correctly.

The joy of having a long-lasting refactor branch with an absolutely
massive diff, is that you end up spotting bugs, and then it's a massive
pain to merge the fix back into trunk!
2022-10-21 23:10:18 +01:00
Jonathan Coates
b663028f42 Start work on curtailing our global state
The last 4 or 5 commits have simplified things. I can now have some
unnecessary complexity as a treat!

This is some initial work on better tying the lifecycle of
computers (and ComputerCraft) related state to the lifecycle of the
current Minecraft server.

 - Move server-wide methods in IComputerEnvironment (such as creating
   resource mounts) into a separate interface.
 - Add a new ServerContext class, which now holds the ID Assigner,
   server computer registry, and some other tiny bits and bobs. This can
   only be accessed by ServerContect.get(MinecraftServer), forcing
   slightly better discipline for how we use these globals.

This does allow us to nuke some of the ugliest bits in IDAssigner. Even
if it makes things much longer!
2022-10-21 21:02:24 +01:00
Jonathan Coates
cee60cdb5b Require computers to have a fixed ID
Moves ID assigning out of the Computer class and into wherever we
construct the ServerComputer (so in computer blocks and pocket computer
items).

This is definitely not perfect - it'd be nice to make ServerComputers
more responsible for managing the lifecycle of computers (so assigning
ids, handling auto-starting, etc...), but I've not found a good way to
handle this yet!
2022-10-21 19:51:41 +01:00
Jonathan Coates
695ef0542a Don't store a mutable array in Colour
It's kinda bad form, and we no longer need it anyway!
2022-10-21 19:07:58 +01:00
Jonathan Coates
c0d20b72c9 Remove ClientTerminal/ServerTerminal
They bring very little to the table now that computers do their own
thing! This also helps simplify the code in ServerMonitor a bit - turns
out we had two "dirty" flags in the implementation!
2022-10-21 19:00:29 +01:00
Jonathan Coates
cf05ab1db1 Store colour support in the Terminal
Previously we stored it alongside the terminal. While this makes sense -
it's not a property of the terminal itself, it ends up duplicating code
in a bunch of places.

We now track the colour flag on the terminal itself. This allows us to
simplify a couple of things:

 - The palette now also knows whether it supports colours or not, and so
   performs greyscale conversion. This means we no longer need to thread
   a "greyscale" flag throughout terminal rendering.

 - Remove isColour() getters from a whole load of
   places (TerminalMethods, ServerTerminal, IComputerEnvironment).
2022-10-21 18:26:57 +01:00
Jonathan Coates
c49547b962 Remove ClientComputer
Historically CC has maintained two computer registries; one on the
server (which runs the actual computer) and one on the client (which
stores the terminal and some small bits of additional data).

This means when a user opens the computer UI, we send the terminal
contents and store it in the client computer registry. We then send the
instance id alongside the "open container" packet, which is used to look
up the client computer (and thus terminal) in our client-side registry.

This patch makes the computer menu syncing behaviour more consistent
with vanilla. The initial terminal contents is sent alongside the "open
container" packet, and subsequent terminal changes apply /just/ to the
open container. Computer on/off state is synced via a vanilla
ContainerData/IIntArray.

Likewise, sending user input to the server now targets the open
container, rather than an arbitrary instance id.

The one remaining usage of ClientComputer is for pocket computers. For
these, we still need to sync the current on/off/blinking state and the
pocket computer light.

We don't need the full ClientComputer interface for this case (after
all, you can't send input to a pocket computer someone else is
holding!). This means we can tear out ClientComputer and
ClientComputerRegistry, replacing it with a much simpler
ClientPocketComputers store.

This in turn allows the following changes:

 - Remove IComputer, as we no longer need to abstract over client and
   server computers.

 - Likewise, we can merge ComputerRegistry into the server
   registry. This commit also cleans up the handling of instance IDs a
   little bit: ServerComputers are now responsible for generating their
   ID and adding/removing themselves from the registry.

 - As the client-side terminal will never be null, we can remove a whole
   bunch of null checks throughout the codebase.

 - As the terminal is available immediately, we don't need to explicitly
   pass in terminal sizes to the computer GUIs. This means we're no
   longer reliant on those config values on the client side!

 - Remove the "request computer state" packet. Pocket computers now
   store which players need to know the computer state, automatically
   sending data when a new player starts tracking the computer.
2022-10-21 18:17:43 +01:00
Jonathan Coates
9ed5ebb868 Merge branch 'mc-1.16.x' into mc-1.18.x 2022-10-12 08:32:03 +01:00
Jonathan Coates
a9b74dc979 Make IRC links https 2022-10-09 11:22:24 +01:00
Jonathan Coates
12b8a0393f Dump Cobalt's internal state on timeouts
Closes #1180
2022-10-09 11:22:16 +01:00
Jonathan Coates
cbfd83c2ba Merge pull request #1182 from Quezler/patch-2
Add all but 3 of the missing dutch translations
2022-10-08 20:54:34 +01:00
Patrick 'Quezler' Mounier
8564c1e54b Add all but 3 of the missing dutch translations 2022-10-08 21:00:58 +02:00
Jonathan Coates
08895cdecc Merge branch 'mc-1.16.x' into mc-1.18.x 2022-10-01 12:36:09 +01:00
Jonathan Coates
5be290a1e2 Bump version to 1.100.10
One more version and then it's a palendrome! Sort of.
2022-10-01 12:33:06 +01:00
Jonathan Coates
371f931140 Always add HTTP programs to the path (#1172) 2022-09-30 09:00:07 +00:00
Jonathan Coates
da5956e943 Make the sidebar a little wider
I was going to do something productive tonight, but then this happened.

Whatever, I'm retired, I'm allowed to make my entire existence just
adding 50px to things. Heck, maybe I'll do the same tomorrow too.
2022-09-29 22:21:38 +01:00
Jonathan Coates
e7533f2353 Improve community links a little 2022-09-29 22:01:51 +01:00
roland-a
0b7fbcde53 Send block updates to client when the turtle moves #1167 (#1170)
Fixes #1167
2022-09-29 17:49:02 +00:00
Jonathan Coates
c3b7302108 Remove some unused arguments in LuaDateTime
See comments in #1157
2022-09-11 15:03:09 +01:00
Jonathan Coates
61ac48c99f Mention audio formats in speaker help
Closes #1133. I'm not super happy about any of the versions proposed
there, but I think this is better than nothing.

Co-authored-by: JackMacWindows <jackmacwindowslinux@gmail.com>
2022-09-11 14:57:45 +01:00
Jonathan Coates
d22e138413 Fix numerous off-by-one errors in help program
We clamped various values to the height of the screen, rather than the
height of the content box (height-1). We didn't notice this most of the
time as the last line of a file is empty - it only really mattered when
a file was the same height as the computer's screen.

We now do the following:
 - Strip the trailing new line from a file when reading.
 - Replace most usages of height with height-1.
2022-09-11 14:57:34 +01:00
Jonathan Coates
ba64e06ca7 Use a Gradle plugin to download illuaminate
Previously illumainate required manual users to manually download it and
place it in ./bin/. This is both inconvenient for the user, and makes it
hard to ensure people are running the "right" version.

We now provide a small Gradle plugin which registers illuaminate as a
ependency, downloading the appropriate (now versioned!) file. This also
theoretically supports Macs, though I don't have access to one to test
this.

This enables the following changes:

 - The Lua lint script has been converted to a Gradle task (./gradle
   lintLua).

 - illuaminateDocs now uses a task definition with an explicit output
   directory. We can now consume this output as an input to another
   task, and get a task dependency implicitly.

 - Move the pre-commit config into the root of the tree. We can now use
   the default GitHub action to run our hooks.

 - Simplify CONTRIBUTING.md a little bit. Hopefully it's less
   intimidating now.
2022-09-11 14:11:33 +01:00
Jonathan Coates
db8c979a06 Merge pull request #1156 from IvoLeal72/patch-1
Fixed usage example of textuils.pagedTabulate
2022-08-28 16:41:40 +01:00
Ivo Leal
9d18487dc5 Fixed usage example of textuils.pagedTabulate 2022-08-28 15:24:47 +01:00
Jonathan Coates
feb7681c9c Add some missing test timeouts 2022-07-30 18:14:43 +01:00
Jonathan Coates
ad4a2aa68d Mirror Oculus with our maven
In some ways it's probably less reliable than modrinth, but let's be
consistent here.
2022-07-30 17:56:56 +01:00
Jonathan Coates
4228011b84 Support Occulus shaders
This is mostly copied from the work Toad and I did for CC:R.

Instead of not writing to the depth buffer when rendering terminals, we
now render terminal forgrounds with a small glPolygonOffset (or an
emulation of it where not possible). This removes the need for custom
render types, while still avoiding z-fighting between the terminal
foreground and background.

The VBO monitors backend now uses Iris's TextVertexSink API when
available: Iris overwrites the vertex format for RenderType.text, and so
we need to use this API to avoid rendering garbage.

Performance is maybe a little worse than before (<3ms) and definitely
worse than CC:R. Unfortunately we can't do our upload batching as that
conflicts with Optifine's patches - instead we need to maintain two
separate VBOs. This is a bit slower, but not so bad it's unworkable.
2022-07-30 12:15:04 +01:00
Jonathan Coates
bd19fdf350 Merge branch 'mc-1.16.x' into mc-1.18.x 2022-07-28 09:43:06 +01:00
Jonathan Coates
e2041f7438 Bump version to 1.100.9 2022-07-27 08:25:31 +01:00
Jonathan Coates
d61202e2b8 Fix location of language file 2022-07-27 07:52:05 +01:00
Weblate
6ce88a7dcf Translations for Norwegian Bokmål
Co-authored-by: Erlend <erlend.bergersen@sandnesskolen.no>
2022-07-26 13:17:57 +00:00
Weblate
5d65b3e654 Added translation for Norwegian Bokmål
Co-authored-by: Erlend <erlend.bergersen@sandnesskolen.no>
2022-07-24 15:45:46 +00:00
Erlend
abf857f864 Clearify GPS documentation note (#1139) 2022-07-22 20:27:27 +00:00
Jonathan Coates
ebef3117f2 Update npm packages 2022-07-21 20:38:44 +01:00
Jonathan Coates
b28c1ac8e0 Test various time locales exist
Not clear if we can really test their behaviour too much.

See 69b211b4fb.
2022-07-21 09:44:40 +01:00
Jonathan Coates
69b211b4fb Fix name of "ingame" time locale
This has been here since 1.17 :D. Class rename gone wrong!
2022-07-21 09:44:36 +01:00
Jonathan Coates
48147fa61c Don't use MultiBufferSource for monitors
We're doing lots of weird OpenGL shenangins anyway, so it doesn't make
sense to use it. Instead just draw directly using the Tesselator
BufferBuilder.

This might improve compatiability with Sodium/Rubidium. Please don't let
me know if it doesn't though - I really don't want to have to deal with
it any more.
2022-07-16 22:07:23 +01:00
Jonathan Coates
ba976f9a16 Fix monitor depth blocker being too small
This allowed you to see transparent blocks through the bottom/right
margins of the monitor when using the VBO renderer.
2022-07-16 22:07:15 +01:00
Luiz Krüger
969feb4a1c ItemGroup info on getItemDetail (#1127) 2022-07-16 20:30:20 +00:00
JackMacWindows
bd5de11ad5 Add WAV support to speaker program (#1112) 2022-07-09 08:59:35 +01:00
Jonathan Coates
5366fcb9c8 Point people towards the http.rules config option
Rather than blanket disabling http with http.enabled. I think it's still
useful to keep the option around, but hopefully make it clearer what the
ramifications are.
2022-07-08 22:13:39 +01:00
Jonathan Coates
6335e77da6 Add a code of conduct
Been meaning to do this for years, woops.
2022-07-08 22:08:50 +01:00
heap-underflow
4cfd0a2d1c Fix off-by-1 error in generic inventory's getItemLimit() (#1131) 2022-07-08 07:44:13 +00:00
Jonathan Coates
be3a960273 Check for duplicate ids when registering channels
Should prevent #1130 occurring again. Possibly worth submitting a PR to
Forge for this too.
2022-07-08 08:27:37 +01:00
Jonathan Coates
f25a73b8f2 Fix packet ID conflict
Merge gone wrong I suspect. I should probably add a check for this.

Fixes #1130. Slightly embarassing that this has been around for 7
months.
2022-07-07 21:45:05 +01:00
Jonathan Coates
954254e7e4 Update Minecraft versions 2022-07-07 21:06:32 +01:00
Jonathan Coates
56f0e0674f Fix term.blit failing on substrings
Hahah. Serves me right for trying to optimise too much. Fixes #1123.
2022-07-02 16:47:43 +01:00
Jonathan Coates
4e438df9ad Update cct-javadoc
No longer warns about empty comments. Closes #1107.
2022-07-02 11:51:58 +01:00
Toad-Dev
51c3a9d8af Fix z-fighting on bold printout borders.
- Changed page background to render as one quad, instead of two halves.
- Set page background to a z-offset that is between zeroth (potentially
  bold border) and subsequent background pages. Bold borders were at the
  same z-offset before.
2022-07-02 11:24:40 +01:00
Jonathan Coates
d967730085 Run the JSX transformer without type checking
Makes it run about twice as fast. Still irritatingly slow, though really
want to avoid making it incremental or anything.
2022-07-02 10:12:47 +01:00
Lupus590
d6afee8deb Document setting up a gps constellation (#1070) 2022-07-02 10:09:38 +01:00
Jonathan Coates
41bddcab9f Use shorter mod version when publishing to Modrinth
i.e. 1.100.8 rather than 1.19-1.100.8.
2022-07-02 09:10:45 +01:00
Jonathan Coates
b8d7695392 Merge pull request #1126 from JohnnyIrvin/mc-1.16.x
Spelling error Turtle API
2022-07-01 21:13:18 +01:00
Johnny Irvin
b7fa4102df Fix spell err Turtle API Doc
* `throug` -> `through`
2022-07-01 09:19:11 -04:00
Jonathan Coates
d2f94f2653 Merge branch 'mc-1.16.x' into mc-1.18.x 2022-06-23 22:26:09 +01:00
Jonathan Coates
718111787c Also propogate the Java launcher when copying tasks
We removed the config which ran all JavaExec tasks with the given
launcher, so need to override this again.

A little abusrd that this isn't done by Gradle, but there we go.
2022-06-23 22:24:53 +01:00
Jonathan Coates
bb0e449560 Switch over to using SLF4J
No bearing on MC, but allows us to drop the depenedency in other
projects (CCEmuX, eval.tweaked.cc, etc...)

I'd quite like to spin the core into a separate project which doesn't
depend on MC at all, but not worth doing right now.
2022-06-23 20:57:24 +01:00
Jonathan Coates
ee495b3359 Merge branch 'mc-1.16.x' into mc-1.18.x 2022-06-23 20:53:37 +01:00
Jonathan Coates
d1e952770d Bump version to 1.100.8 2022-06-23 20:44:14 +01:00
Jonathan Coates
2d30208631 Avoid early creation of tasks
Notionally speeds up the build a little, though not really noticable in
practice.
2022-06-23 20:44:14 +01:00
Jonathan Coates
03f50f9298 _Actually_ publish an API jar 2022-06-21 07:28:15 +01:00
Jonathan Coates
1a0e3fc2fa Use the Gradle shadow plugin to shade deps
Just saves us from having to worry about conflicts with other mods which
bundle Cobalt. This might make the transition to Jar-in-Jar easier too -
not sure yet!

Also produce an API jar - fixes #1060.
2022-06-20 19:54:35 +01:00
Jonathan Coates
6d5b13dbbc Revert "Switch over to using SLF4J"
This reverts commit b7f698d6f7.

Apparently slf4j is on the classpath in dev but not in live. Will apply
this on 1.18 and later instead.
2022-06-20 19:52:23 +01:00
Jonathan Coates
f9f8233ef4 Some "improvements" to our Gradle script
- Switch to plugins { ... } imports for Forge (FG finally supports it!)

 - Use FG's new fg.component to clean up our Maven metadata instead. We
   also mark JEI as optional (using Gradle's registerFeature), which
   means we've no stray deps inside our POM any more.
2022-06-19 11:21:42 +01:00
Jonathan Coates
b7f698d6f7 Switch over to using SLF4J
No bearing on MC, but allows us to drop the depenedency in other
projects (CCEmuX, eval.tweaked.cc, etc...)

I'd quite like to spin the core into a separate project which doesn't
depend on MC at all, but not worth doing right now.
2022-06-19 11:10:53 +01:00
Jonathan Coates
93f3cd4a53 Fix lock code being null for newly placed blocks
This causes an NPE when serialising or opening printers and disk drives.
Fixes #1109
2022-06-16 07:56:54 +01:00
733 changed files with 20805 additions and 11310 deletions

View File

@@ -9,8 +9,8 @@ body:
description: What version of Minecraft are you using?
options:
- 1.16.x
- 1.17.x
- 1.18.x
- 1.19.x
validations:
required: true
- type: input

View File

@@ -1,8 +1,5 @@
blank_issues_enabled: false
contact_links:
- name: ComputerCraft Discord
url: https://discord.computercraft.cc
about: Get help on the ComputerCraft Discord.
- name: GitHub Discussions
url: https://github.com/cc-tweaked/CC-Tweaked/discussions
about: Or ask questions on GitHub Discussions.
about: Ask questions on GitHub Discussions.

View File

@@ -8,20 +8,19 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Clone repository
uses: actions/checkout@v3
- name: Set up Java 8
uses: actions/setup-java@v1
- name: Set up Java
uses: actions/setup-java@v3
with:
java-version: 8
java-version: 17
distribution: 'temurin'
- name: Cache gradle dependencies
uses: actions/cache@v2
- name: Setup Gradle
uses: gradle/gradle-build-action@v2
with:
path: ~/.gradle/caches
key: ${{ runner.os }}-gradle-${{ hashFiles('gradle.properties') }}
restore-keys: |
${{ runner.os }}-gradle-
cache-read-only: ${{ !startsWith(github.ref, 'refs/heads/mc-') }}
- name: Disable Gradle daemon
run: |
@@ -32,7 +31,7 @@ jobs:
run: |
./gradlew assemble || ./gradlew assemble
./gradlew downloadAssets || ./gradlew downloadAssets
xvfb-run ./gradlew build
./gradlew build
- name: Upload Jar
uses: actions/upload-artifact@v2
@@ -40,31 +39,12 @@ jobs:
name: CC-Tweaked
path: build/libs
- name: Upload Screnshots
uses: actions/upload-artifact@v2
with:
name: Screenshots
path: test-files/client/screenshots
if-no-files-found: ignore
retention-days: 5
if: failure()
- name: Upload Coverage
- name: Upload coverage
uses: codecov/codecov-action@v2
- name: Parse test reports
run: ./tools/parse-reports.py
if: ${{ failure() }}
- 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: |
pip install pre-commit
pre-commit run --config config/pre-commit/config.yml --show-diff-on-failure --all --color=always
uses: pre-commit/action@v3.0.0

View File

@@ -11,29 +11,19 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Clone repository
uses: actions/checkout@v3
- name: Set up Java 8
- name: Set up Java
uses: actions/setup-java@v1
with:
java-version: 8
java-version: 17
distribution: 'temurin'
- name: Cache gradle dependencies
uses: actions/cache@v2
- name: Setup Gradle
uses: gradle/gradle-build-action@v2
with:
path: ~/.gradle/caches
key: ${{ runner.os }}-gradle-${{ hashFiles('gradle.properties') }}
restore-keys: |
${{ runner.os }}-gradle-
- name: Setup illuaminate
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
- name: Setup node
run: npm ci
cache-read-only: ${{ !startsWith(github.ref, 'refs/heads/mc-') }}
- name: Build with Gradle
run: ./gradlew compileJava --no-daemon || ./gradlew compileJava --no-daemon

3
.gitignore vendored
View File

@@ -2,14 +2,15 @@
/classes
/logs
/build
/buildSrc/build
/out
/doc/out/
/node_modules
/.jqwik-database
# Runtime directories
/run
/run-*
/test-files
*.ipr
*.iws

View File

@@ -17,6 +17,6 @@ vscode:
tasks:
- name: Setup pre-commit hool
init: pre-commit install --config config/pre-commit/config.yml --allow-missing-config
init: pre-commit install --allow-missing-config
- name: Install npm packages
init: npm ci

View File

@@ -24,6 +24,13 @@ repos:
- repo: local
hooks:
- id: license
name: Spotless
files: ".*\\.(java|kt|kts)$"
language: system
entry: ./gradlew spotlessApply
pass_filenames: false
require_serial: true
- id: checkstyle
name: Check Java codestyle
files: ".*\\.java$"
@@ -31,18 +38,11 @@ repos:
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
language: system
entry: ./gradlew lintLua
pass_filenames: false
require_serial: true

133
CODE_OF_CONDUCT.md Normal file
View File

@@ -0,0 +1,133 @@
# Contributor Covenant Code of Conduct
## Our Pledge
We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, caste, color, religion, or sexual
identity and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.
## Our Standards
Examples of behavior that contributes to a positive environment for our
community include:
* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
* Focusing on what is best not just for us as individuals, but for the overall
community
Examples of unacceptable behavior include:
* The use of sexualized language or imagery, and sexual attention or advances of
any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or email address,
without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Enforcement Responsibilities
Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.
Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.
## Scope
This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at
"conduct AT squiddev DOT cc". All complaints will be reviewed and investigated
promptly and fairly.
All community leaders are obligated to respect the privacy and security of the
reporter of any incident.
## Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:
### 1. Correction
**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.
### 2. Warning
**Community Impact**: A violation through a single incident or series of
actions.
**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or permanent
ban.
### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.
**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within the
community.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.1, available at
[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].
Community Impact Guidelines were inspired by
[Mozilla's code of conduct enforcement ladder][Mozilla CoC].
For answers to common questions about this code of conduct, see the FAQ at
[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at
[https://www.contributor-covenant.org/translations][translations].
[homepage]: https://www.contributor-covenant.org
[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html
[Mozilla CoC]: https://github.com/mozilla/diversity
[FAQ]: https://www.contributor-covenant.org/faq
[translations]: https://www.contributor-covenant.org/translations

View File

@@ -39,40 +39,30 @@ are run whenever you submit a PR, it's often useful to run this before committin
- **[Checkstyle]:** Checks Java code to ensure it is consistently formatted. This can be run with `./gradlew build` or
`./gradle check`.
- **[illuaminate]:** Checks Lua code for semantic and styleistic issues. See [the usage section][illuaminate-usage] for
how to download and run it. You may need to generate the Java documentation stubs (see "Documentation" below) for all
lints to pass.
- **[illuaminate]:** Checks Lua code for semantic and styleistic issues. This can be run with `./gradlew lintLua`.
### Documentation
When writing documentation for [CC: Tweaked's documentation website][docs], it may be useful to build the documentation
and preview it yourself before submitting a PR.
Building all documentation is, sadly, a multi-stage process (though this is largely hidden by Gradle). First we need to
convert Java doc-comments into Lua ones, we also generate some Javascript to embed. All of this is then finally fed into
illuaminate, which spits out our HTML.
Our documentation generation pipeline is rather complex, and involves invoking several external tools. Most of this
complexity is hidden by Gradle, but you will need to perform some initial setup:
#### Setting up the tooling
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.
- Install [Node/npm][node].
- Run `npm ci` to install our Node dependencies.
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:
- `./gradlew luaJavadoc` - Generate documentation stubs for Java methods.
- `./gradlew docWebsite` - Generate the whole website (including Javascript pages). The resulting HTML is stored at
`./build/docs/site/`.
You can now run `./gradlew docWebsite`. This generates documentation from our Lua and Java code, writing the resulting
HTML into `./build/docs/site`.
#### 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,
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.
expect. It is recommended that you build and preview the docs locally first.
When iterating on documentation, you can get Gradle to rebuild the website every time a file changes by running
`./gradlew docWebsite -t`. This will take a couple of seconds to run, but definitely beats running it manually!
### Testing
Thankfully running tests is much simpler than running the documentation generator! `./gradlew check` will run the
@@ -90,11 +80,10 @@ Before we get into writing tests, it's worth mentioning the various test suites
These tests are run by the '"Core" Java' test suite, and so are also run with `./gradlew test`.
- In-game (`./src/testMod/java/dan200/computercraft/ingame/`): These tests are run on an actual Minecraft server and client,
using [the same system Mojang do][mc-test]. The aim of these is to test in-game behaviour of blocks and peripherals.
- In-game (`./src/testMod/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 testClient` and `./gradlew testServer`. You may want to run the client under `xvfb-run`
or similar when running in a headless environment.
These tests are run with `./gradlew runGametest`.
## CraftOS tests
CraftOS's tests are written using a test system called "mcfly", heavily inspired by [busted] (and thus RSpec). Groups of
@@ -107,9 +96,9 @@ asserts that your variable `foo` is equal to the expected value `"bar"`.
[community]: README.md#Community "Get in touch with the community."
[checkstyle]: https://checkstyle.org/
[illuaminate]: https://github.com/SquidDev/illuaminate/ "Illuaminate on GitHub"
[illuaminate-usage]: https://github.com/SquidDev/illuaminate/blob/master/README.md#usage "Installing Illuaminate"
[weblate]: https://i18n.tweaked.cc/projects/cc-tweaked/minecraft/ "CC: Tweaked weblate instance"
[docs]: https://tweaked.cc/ "CC: Tweaked documentation"
[ldoc]: http://stevedonovan.github.io/ldoc/ "ldoc, a Lua documentation generator."
[mc-test]: https://www.youtube.com/watch?v=vXaWOJTCYNg
[busted]: https://github.com/Olivine-Labs/busted "busted: Elegant Lua unit testing."
[node]: https://nodejs.org/en/ "Node.js"

View File

@@ -13,9 +13,8 @@ developing the mod, [check out the instructions here](CONTRIBUTING.md#developing
## Community
If you need help getting started with CC: Tweaked, want to show off your latest project, or just want to chat about
ComputerCraft we have a [forum](https://forums.computercraft.cc/) and [Discord guild](https://discord.computercraft.cc)!
There's also a fairly populated, albeit quiet [IRC channel](http://webchat.esper.net/?channels=computercraft), if that's
more your cup of tea.
ComputerCraft, do check out our [forum] and [GitHub discussions page][GitHub discussions]! There's also a fairly
populated, albeit quiet [IRC channel][irc], if that's more your cup of tea.
We also host fairly comprehensive documentation at [tweaked.cc](https://tweaked.cc/ "The CC: Tweaked website").
@@ -35,7 +34,8 @@ repositories {
}
dependencies {
implementation fg.deobf("org.squiddev:cc-tweaked-${mc_version}:${cct_version}")
compileOnly fg.deobf("org.squiddev:cc-tweaked-${mc_version}:${cct_version}:api")
runtimeOnly fg.deobf("org.squiddev:cc-tweaked-${mc_version}:${cct_version}")
}
```
@@ -51,3 +51,6 @@ the generated documentation [can be browsed online](https://tweaked.cc/javadoc/)
[modrinth]: https://modrinth.com/mod/gu7yAYhd "Download CC: Tweaked from Modrinth"
[forge]: https://files.minecraftforge.net/ "Download Minecraft Forge."
[ccrestitched]: https://www.curseforge.com/minecraft/mc-mods/cc-restitched "Download CC: Restitched from CurseForge"
[forum]: https://forums.computercraft.cc/
[GitHub Discussions]: https://github.com/cc-tweaked/CC-Tweaked/discussions
[IRC]: https://webchat.esper.net/?channels=computercraft "#computercraft on EsperNet"

View File

@@ -1,619 +0,0 @@
buildscript {
repositories {
mavenCentral()
maven { url = "https://maven.minecraftforge.net" }
maven { url = 'https://maven.parchmentmc.org' }
}
dependencies {
classpath 'net.minecraftforge.gradle:ForgeGradle:5.1.+'
classpath "org.spongepowered:mixingradle:0.7.+"
classpath 'org.parchmentmc:librarian:1.+'
}
}
plugins {
id "checkstyle"
id "jacoco"
id "maven-publish"
id "com.github.hierynomus.license" version "0.16.1"
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.6.0"
id "com.modrinth.minotaur" version "1.2.1"
}
apply plugin: 'net.minecraftforge.gradle'
apply plugin: "org.spongepowered.mixin"
apply plugin: 'org.parchmentmc.librarian.forgegradle'
version = mod_version
group = "org.squiddev"
archivesBaseName = "cc-tweaked-${mc_version}"
def javaVersion = JavaLanguageVersion.of(17)
java {
toolchain {
languageVersion = javaVersion
}
withSourcesJar()
withJavadocJar()
}
tasks.withType(JavaExec).configureEach {
javaLauncher = javaToolchains.launcherFor {
languageVersion = javaVersion
}
}
sourceSets {
main.resources {
srcDir 'src/generated/resources'
}
testMod {}
}
minecraft {
runs {
all {
lazyToken('minecraft_classpath') {
configurations.shade.copyRecursive().resolve().collect { it.absolutePath }.join(File.pathSeparator)
}
property 'forge.logging.markers', 'REGISTRIES'
property 'forge.logging.console.level', 'debug'
mods {
computercraft {
source sourceSets.main
}
}
arg "-mixin.config=computercraft.mixins.json"
}
client {
workingDirectory project.file('run')
}
server {
workingDirectory project.file("run/server")
arg "--nogui"
}
data {
workingDirectory project.file('run')
args '--mod', 'computercraft', '--all', '--output', file('src/generated/resources/'), '--existing', file('src/main/resources/')
}
testClient {
workingDirectory project.file('test-files/client')
parent runs.client
mods {
cctest {
source sourceSets.testMod
}
}
lazyToken('minecraft_classpath') {
(configurations.shade.copyRecursive().resolve() + configurations.testModExtra.copyRecursive().resolve())
.collect { it.absolutePath }
.join(File.pathSeparator)
}
}
gameTestServer {
workingDirectory project.file('test-files/server')
mods {
cctest {
source sourceSets.testMod
}
}
lazyToken('minecraft_classpath') {
(configurations.shade.copyRecursive().resolve() + configurations.testModExtra.copyRecursive().resolve())
.collect { it.absolutePath }
.join(File.pathSeparator)
}
}
}
mappings channel: 'parchment', version: "${mapping_version}-${mc_version}"
accessTransformer file('src/main/resources/META-INF/accesstransformer.cfg')
accessTransformer file('src/testMod/resources/META-INF/accesstransformer.cfg')
}
mixin {
add sourceSets.main, 'computercraft.mixins.refmap.json'
}
repositories {
mavenCentral()
maven {
name "SquidDev"
url "https://squiddev.cc/maven"
}
}
configurations {
shade
implementation.extendsFrom shade
cctJavadoc
testModExtra
testModImplementation.extendsFrom(testModExtra)
testModImplementation.extendsFrom(implementation)
}
dependencies {
checkstyle "com.puppycrawl.tools:checkstyle:8.45"
minecraft "net.minecraftforge:forge:${mc_version}-${forge_version}"
annotationProcessor 'org.spongepowered:mixin:0.8.4:processor'
compileOnly fg.deobf("mezz.jei:jei-1.18.2:9.4.1.116:api")
runtimeOnly fg.deobf("mezz.jei:jei-1.18.2:9.4.1.116")
shade 'org.squiddev:Cobalt:0.5.5'
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.7.0'
testImplementation 'org.junit.jupiter:junit-jupiter-params:5.7.0'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.7.0'
testImplementation 'org.hamcrest:hamcrest:2.2'
testImplementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.6.0'
testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2'
testModImplementation sourceSets.main.output
testModExtra('org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.6.0') {
exclude group: "org.jetbrains", module: "annotations"
}
cctJavadoc 'cc.tweaked:cct-javadoc:1.4.6'
}
// Compile tasks
compileTestModJava {
dependsOn(compileJava)
}
javadoc {
include "dan200/computercraft/api/**/*.java"
}
task luaJavadoc(type: Javadoc) {
description "Generates documentation for Java-side Lua functions."
group "documentation"
source = sourceSets.main.allJava
destinationDir = file("${project.docsDir}/luaJavadoc")
classpath = sourceSets.main.compileClasspath
options.docletpath = configurations.cctJavadoc.files as List
options.doclet = "cc.tweaked.javadoc.LuaDoclet"
options.noTimestamp = false
javadocTool = javaToolchains.javadocToolFor {
languageVersion = javaVersion
}
}
jar {
manifest {
attributes([
"Specification-Title" : "computercraft",
"Specification-Vendor" : "SquidDev",
"Specification-Version" : "1",
"Implementation-Title" : "CC: Tweaked",
"Implementation-Version" : "${mod_version}",
"Implementation-Vendor" : "SquidDev",
"Implementation-Timestamp": new Date().format("yyyy-MM-dd'T'HH:mm:ssZ")
,
"MixinConfigs" : "computercraft.mixins.json",
])
}
from configurations.shade.collect { it.isDirectory() ? it : zipTree(it) }
}
jar.finalizedBy('reobfJar')
[compileJava, compileTestJava, compileTestModJava].forEach {
it.configure {
options.compilerArgs << "-Xlint" << "-Xlint:-processing"
}
}
processResources {
def hash = 'none'
Set<String> contributors = []
try {
hash = ["git", "-C", projectDir, "rev-parse", "HEAD"].execute().text.trim()
def blacklist = ['GitHub', 'Daniel Ratcliffe', 'Weblate']
// Extract all authors, commiters and co-authors from the git log.
def authors = ["git", "-C", projectDir, "log", "--format=tformat:%an <%ae>%n%cn <%ce>%n%(trailers:key=Co-authored-by,valueonly)"]
.execute().text.readLines().unique()
// We now pass this through git's mailmap to de-duplicate some authors.
def remapAuthors = ["git", "check-mailmap", "--stdin"].execute()
remapAuthors.withWriter { stdin ->
if (stdin !instanceof BufferedWriter) stdin = new BufferedWriter(stdin)
authors.forEach {
if (it == "") return
if (!it.endsWith(">")) it += ">" // Some commits have broken Co-Authored-By lines!
stdin.writeLine(it)
}
stdin.close()
}
// And finally extract out the actual name.
def emailRegex = ~/^([^<]+) <.+>$/
remapAuthors.text.readLines().forEach {
def matcher = it =~ emailRegex
matcher.find()
def name = matcher.group(1)
if (!blacklist.contains(name)) contributors.add(name)
}
} catch (Exception e) {
e.printStackTrace()
}
inputs.property "commithash", hash
duplicatesStrategy = DuplicatesStrategy.INCLUDE
from(sourceSets.main.resources.srcDirs) {
include 'data/computercraft/lua/rom/help/credits.txt'
expand(
'gitcontributors': contributors.sort(false, String.CASE_INSENSITIVE_ORDER).join('\n')
)
}
from(sourceSets.main.resources.srcDirs) {
exclude 'data/computercraft/lua/rom/help/credits.txt'
}
}
sourcesJar {
duplicatesStrategy = DuplicatesStrategy.INCLUDE
}
// Web tasks
import com.hierynomus.gradle.license.tasks.LicenseCheck
import com.hierynomus.gradle.license.tasks.LicenseFormat
import com.modrinth.minotaur.TaskModrinthUpload
import org.apache.tools.ant.taskdefs.condition.Os
List<String> mkCommand(String command) {
return Os.isFamily(Os.FAMILY_WINDOWS) ? ["cmd", "/c", command] : ["sh", "-c", command]
}
task rollup(type: Exec) {
group = "build"
description = "Bundles JS into rollup"
inputs.files(fileTree("src/web")).withPropertyName("sources")
inputs.file("package-lock.json").withPropertyName("package-lock.json")
inputs.file("tsconfig.json").withPropertyName("Typescript config")
inputs.file("rollup.config.js").withPropertyName("Rollup config")
outputs.file("$buildDir/rollup/index.js").withPropertyName("output")
commandLine mkCommand('"node_modules/.bin/rollup" --config rollup.config.js')
}
task illuaminateDocs(type: Exec, dependsOn: [rollup, luaJavadoc]) {
group = "build"
description = "Generates docs using Illuaminate"
inputs.files(fileTree("doc")).withPropertyName("docs")
inputs.files(fileTree("src/main/resources/data/computercraft/lua/rom")).withPropertyName("lua rom")
inputs.file("illuaminate.sexp").withPropertyName("illuaminate.sexp")
inputs.dir("$buildDir/docs/luaJavadoc")
inputs.file("$buildDir/rollup/index.js").withPropertyName("scripts")
inputs.file("src/web/styles.css").withPropertyName("styles")
outputs.dir("$buildDir/docs/lua")
commandLine mkCommand('"bin/illuaminate" doc-gen')
}
task jsxDocs(type: Exec, dependsOn: [illuaminateDocs]) {
group = "build"
description = "Post-processes documentation to statically render some dynamic content."
inputs.files(fileTree("src/web")).withPropertyName("sources")
inputs.file("src/generated/export/index.json").withPropertyName("export")
inputs.file("package-lock.json").withPropertyName("package-lock.json")
inputs.file("tsconfig.json").withPropertyName("Typescript config")
inputs.files(fileTree("$buildDir/docs/lua"))
outputs.dir("$buildDir/docs/site")
commandLine mkCommand('"node_modules/.bin/ts-node" --esm src/web/transform.tsx')
}
task docWebsite(type: Copy, dependsOn: [jsxDocs]) {
from('doc') {
include 'logo.png'
include 'images/**'
}
from("$buildDir/rollup") {
exclude 'index.js'
}
from("$buildDir/docs/lua") {
exclude '**/*.html'
}
from("src/generated/export/items") {
into("images/items")
}
into "${project.docsDir}/site"
}
// Check tasks
test {
useJUnitPlatform()
testLogging {
events "skipped", "failed"
}
}
jacocoTestReport {
dependsOn('test')
reports {
xml.required = true
html.required = true
}
}
check.dependsOn jacocoTestReport
license {
mapping("java", "SLASHSTAR_STYLE")
strictCheck true
ext.year = Calendar.getInstance().get(Calendar.YEAR)
}
[licenseMain, licenseFormatMain].forEach {
it.configure {
include("**/*.java")
exclude("dan200/computercraft/api/**")
header file('config/license/main.txt')
}
}
[licenseTest, licenseFormatTest, licenseTestMod, licenseFormatTestMod].forEach {
it.configure {
include("**/*.java")
header file('config/license/main.txt')
}
}
gradle.projectsEvaluated {
tasks.withType(LicenseFormat) {
outputs.upToDateWhen { false }
}
}
task licenseAPI(type: LicenseCheck)
task licenseFormatAPI(type: LicenseFormat)
[licenseAPI, licenseFormatAPI].forEach {
it.configure {
source = sourceSets.main.java
include("dan200/computercraft/api/**")
header file('config/license/api.txt')
}
}
tasks.register("testServer", JavaExec.class).configure {
it.group('In-game tests')
it.description("Runs tests on a temporary Minecraft instance.")
it.dependsOn("prepareRunGameTestServer", "cleanTestServer", 'compileTestModJava')
// Copy from runTestServer. We do it in this slightly odd way as runTestServer
// isn't created until the task is configured (which is no good for us).
JavaExec exec = tasks.getByName("runGameTestServer")
exec.copyTo(it)
it.setClasspath(exec.getClasspath())
it.mainClass = exec.mainClass
it.setArgs(exec.getArgs())
// Jacoco and modlauncher don't play well together as the classes loaded in-game don't
// match up with those written to disk. We get Jacoco to dump all classes to disk, and
// use that when generating the report.
def coverageOut = new File(buildDir, "jacocoClassDump/testServer")
jacoco.applyTo(it)
it.jacoco.setIncludes(["dan200.computercraft.*"])
it.jacoco.setClassDumpDir(coverageOut)
it.outputs.dir(coverageOut)
// Older versions of modlauncher don't include a protection domain (and thus no code
// source). Jacoco skips such classes by default, so we need to explicitly include them.
it.jacoco.setIncludeNoLocationClasses(true)
}
tasks.register("jacocoTestServerReport", JacocoReport.class).configure {
it.group('In-game')
it.description("Generate coverage reports for testServer")
it.dependsOn("testServer")
it.executionData(new File(buildDir, "jacoco/testServer.exec"))
it.sourceDirectories.from(sourceSets.main.allJava.srcDirs)
it.classDirectories.from(new File(buildDir, "jacocoClassDump/testServer"))
it.reports {
xml.enabled true
html.enabled true
}
}
check.dependsOn("jacocoTestServerReport")
// Upload tasks
task checkRelease {
group "upload"
description "Verifies that everything is ready for a release"
inputs.property "version", mod_version
inputs.file("src/main/resources/data/computercraft/lua/rom/help/changelog.md")
inputs.file("src/main/resources/data/computercraft/lua/rom/help/whatsnew.md")
doLast {
def ok = true
// Check we're targetting the current version
def whatsnew = new File(projectDir, "src/main/resources/data/computercraft/lua/rom/help/whatsnew.md").readLines()
if (whatsnew[0] != "New features in CC: Tweaked $mod_version") {
ok = false
project.logger.error("Expected `whatsnew.md' to target $mod_version.")
}
// Check "read more" exists and trim it
def idx = whatsnew.findIndexOf { it == 'Type "help changelog" to see the full version history.' }
if (idx == -1) {
ok = false
project.logger.error("Must mention the changelog in whatsnew.md")
} else {
whatsnew = whatsnew.getAt(0..<idx)
}
// Check whatsnew and changelog match.
def versionChangelog = "# " + whatsnew.join("\n")
def changelog = new File(projectDir, "src/main/resources/data/computercraft/lua/rom/help/changelog.md").getText()
if (!changelog.startsWith(versionChangelog)) {
ok = false
project.logger.error("whatsnew and changelog are not in sync")
}
if (!ok) throw new IllegalStateException("Could not check release")
}
}
check.dependsOn checkRelease
def isStable = true
curseforge {
apiKey = project.hasProperty('curseForgeApiKey') ? project.curseForgeApiKey : ''
project {
id = '282001'
releaseType = isStable ? 'release' : 'alpha'
changelog = "Release notes can be found on the GitHub repository (https://github.com/cc-tweaked/CC-Tweaked/releases/tag/v${mc_version}-${mod_version})."
addGameVersion "${mc_version}"
}
}
tasks.register('publishModrinth', TaskModrinthUpload.class).configure {
dependsOn('assemble', 'reobfJar')
onlyIf {
project.hasProperty('modrinthApiKey')
}
token = project.hasProperty('modrinthApiKey') ? project.getProperty('modrinthApiKey') : ''
projectId = 'gu7yAYhd'
versionNumber = "${project.mc_version}-${project.mod_version}"
uploadFile = jar
versionType = isStable ? 'RELEASE' : 'ALPHA'
addGameVersion(project.mc_version)
changelog = "Release notes can be found on the [GitHub repository](https://github.com/cc-tweaked/CC-Tweaked/releases/tag/v${mc_version}-${mod_version})."
addLoader('forge')
}
tasks.withType(GenerateModuleMetadata) {
// We can't generate metadata as that includes Forge as a dependency.
enabled = false
}
publishing {
publications {
maven(MavenPublication) {
from components.java
pom {
name = 'CC: Tweaked'
description = 'CC: Tweaked is a fork of ComputerCraft, adding programmable computers, turtles and more to Minecraft.'
url = 'https://github.com/cc-tweaked/CC-Tweaked'
scm {
url = 'https://github.com/cc-tweaked/CC-Tweaked.git'
}
issueManagement {
system = 'github'
url = 'https://github.com/cc-tweaked/CC-Tweaked/issues'
}
licenses {
license {
name = 'ComputerCraft Public License, Version 1.0'
url = 'https://github.com/cc-tweaked/CC-Tweaked/blob/mc-1.15.x/LICENSE'
}
}
withXml { asNode().remove(asNode().get("dependencies")) }
}
}
}
repositories {
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
}
}
}
}
}
githubRelease {
token project.hasProperty('githubApiKey') ? project.githubApiKey : ''
owner 'cc-tweaked'
repo 'CC-Tweaked'
targetCommitish.set(project.provider({
def cmd = ["git", "rev-parse", "--abbrev-ref", "HEAD"]
println(cmd)
def proc = cmd.execute([], projectDir)
if (proc.waitFor() != 0) {
println(proc.err.text.trim())
throw new IllegalStateException("Executed with a non-0 exit code (${proc.exitValue()}).")
}
def branch = proc.text.trim()
if (branch == "") throw new IllegalStateException("Cannot determine branch")
return branch
}))
tagName "v${mc_version}-${mod_version}"
releaseName "[${mc_version}] ${mod_version}"
body.set(project.provider({
"## " + new File(projectDir, "src/main/resources/data/computercraft/lua/rom/help/whatsnew.md")
.readLines()
.takeWhile { it != 'Type "help changelog" to see the full version history.' }
.join("\n").trim()
}))
prerelease !isStable
}
def uploadTasks = ["publish", "curseforge", "publishModrinth", "githubRelease"]
uploadTasks.forEach { tasks.getByName(it).dependsOn checkRelease }
task uploadAll(dependsOn: uploadTasks) {
group "upload"
description "Uploads to all repositories (Maven, Curse, Modrinth, GitHub release)"
}

458
build.gradle.kts Normal file
View File

@@ -0,0 +1,458 @@
import cc.tweaked.gradle.*
import net.darkhax.curseforgegradle.TaskPublishCurseForge
import net.minecraftforge.gradle.common.util.RunConfig
plugins {
// Build
alias(libs.plugins.forgeGradle)
alias(libs.plugins.mixinGradle)
alias(libs.plugins.librarian)
alias(libs.plugins.shadow)
// Publishing
`maven-publish`
alias(libs.plugins.curseForgeGradle)
alias(libs.plugins.githubRelease)
alias(libs.plugins.minotaur)
// Utility
alias(libs.plugins.taskTree)
id("cc-tweaked.illuaminate")
id("cc-tweaked.node")
id("cc-tweaked.gametest")
id("cc-tweaked")
}
val isStable = true
val modVersion: String by extra
val mcVersion: String by extra
group = "org.squiddev"
version = modVersion
base.archivesName.set("cc-tweaked-$mcVersion")
java.registerFeature("extraMods") { usingSourceSet(sourceSets.main.get()) }
sourceSets {
main {
resources.srcDir("src/generated/resources")
}
}
minecraft {
runs {
// configureEach would be better, but we need to eagerly configure configs or otherwise the run task doesn't
// get set up properly.
all {
lazyToken("minecraft_classpath") {
configurations["shade"].copyRecursive().resolve().joinToString(File.pathSeparator) { it.absolutePath }
}
property("forge.logging.markers", "REGISTRIES")
property("forge.logging.console.level", "debug")
forceExit = false
mods.register("computercraft") { source(sourceSets.main.get()) }
}
val client by registering {
workingDirectory(file("run"))
}
val server by registering {
workingDirectory(file("run/server"))
arg("--nogui")
}
val data by registering {
workingDirectory(file("run"))
args(
"--mod",
"computercraft",
"--all",
"--output",
file("src/generated/resources/"),
"--existing",
file("src/main/resources/"),
)
property("cct.pretty-json", "true")
}
fun RunConfig.configureForGameTest() {
val old = lazyTokens.get("minecraft_classpath")
lazyToken("minecraft_classpath") {
// We do some terrible hacks here to basically find all things not already on the runtime classpath
// and add them. /Except/ for our source sets, as those need to load inside the Minecraft classpath.
val testMod = configurations["testModRuntimeClasspath"].resolve()
val implementation = configurations.runtimeClasspath.get().resolve()
val new = (testMod - implementation)
.asSequence()
.filter { it.isFile && !it.name.endsWith("-test-fixtures.jar") }
.map { it.absolutePath }
.joinToString(File.pathSeparator)
if (old == null) new else old.get() + File.pathSeparator + new
}
property("cctest.sources", file("src/testMod/resources/data/cctest").absolutePath)
arg("--mixin.config=computercraft-gametest.mixins.json")
mods.register("cctest") {
source(sourceSets["testMod"])
source(sourceSets["testFixtures"])
}
}
val testClient by registering {
workingDirectory(file("run/testClient"))
parent(client.get())
configureForGameTest()
}
val gameTestServer by registering {
workingDirectory(file("run/testServer"))
configureForGameTest()
property("forge.logging.console.level", "info")
}
}
mappings("parchment", "${libs.versions.parchmentMc.get()}-${libs.versions.parchment.get()}-$mcVersion")
accessTransformer(file("src/main/resources/META-INF/accesstransformer.cfg"))
}
mixin {
add(sourceSets.main.get(), "computercraft.mixins.refmap.json")
config("computercraft.mixins.json")
}
reobf {
register("shadowJar")
}
configurations {
val shade by registering { isTransitive = false }
implementation { extendsFrom(shade.get()) }
register("cctJavadoc")
}
dependencies {
minecraft("net.minecraftforge:forge:$mcVersion-${libs.versions.forge.get()}")
annotationProcessor("org.spongepowered:mixin:0.8.5:processor")
compileOnly(libs.jetbrainsAnnotations)
annotationProcessorEverywhere(libs.autoService)
"extraModsCompileOnly"(fg.deobf("mezz.jei:jei-1.18.2:9.4.1.116:api"))
"extraModsRuntimeOnly"(fg.deobf("mezz.jei:jei-1.18.2:9.4.1.116"))
"extraModsCompileOnly"(fg.deobf("maven.modrinth:oculus:1.18.2-1.2.5"))
"shade"(libs.cobalt)
testFixturesApi(libs.bundles.test)
testFixturesApi(libs.bundles.kotlin)
testImplementation(libs.bundles.test)
testImplementation(libs.bundles.kotlin)
testRuntimeOnly(libs.bundles.testRuntime)
"cctJavadoc"(libs.cctJavadoc)
}
illuaminate {
version.set(libs.versions.illuaminate)
}
// Compile tasks
tasks.javadoc {
include("dan200/computercraft/api/**/*.java")
(options as StandardJavadocDocletOptions).links("https://docs.oracle.com/en/java/javase/17/docs/api/")
}
val apiJar by tasks.registering(Jar::class) {
archiveClassifier.set("api")
from(sourceSets.main.get().output) {
include("dan200/computercraft/api/**/*")
}
}
tasks.assemble { dependsOn(apiJar) }
val luaJavadoc by tasks.registering(Javadoc::class) {
description = "Generates documentation for Java-side Lua functions."
group = JavaBasePlugin.DOCUMENTATION_GROUP
source(sourceSets.main.get().java)
setDestinationDir(buildDir.resolve("docs/luaJavadoc"))
classpath = sourceSets.main.get().compileClasspath
options.docletpath = configurations["cctJavadoc"].files.toList()
options.doclet = "cc.tweaked.javadoc.LuaDoclet"
(options as StandardJavadocDocletOptions).noTimestamp(false)
javadocTool.set(
javaToolchains.javadocToolFor {
languageVersion.set(cc.tweaked.gradle.CCTweakedPlugin.JAVA_VERSION)
},
)
}
tasks.processResources {
inputs.property("modVersion", modVersion)
inputs.property("forgeVersion", libs.versions.forge.get())
inputs.property("gitHash", cct.gitHash)
filesMatching("data/computercraft/lua/rom/help/credits.md") {
expand(mapOf("gitContributors" to cct.gitContributors.get().joinToString("\n")))
}
filesMatching("META-INF/mods.toml") {
expand(mapOf("forgeVersion" to libs.versions.forge.get(), "file" to mapOf("jarVersion" to modVersion)))
}
}
tasks.jar {
isReproducibleFileOrder = true
isPreserveFileTimestamps = false
finalizedBy("reobfJar")
archiveClassifier.set("slim")
manifest {
attributes(
"Specification-Title" to "computercraft",
"Specification-Vendor" to "SquidDev",
"Specification-Version" to "1",
"Implementation-Title" to "cctweaked",
"Implementation-Version" to modVersion,
"Implementation-Vendor" to "SquidDev",
)
}
}
tasks.shadowJar {
finalizedBy("reobfShadowJar")
archiveClassifier.set("")
configurations = listOf(project.configurations["shade"])
relocate("org.squiddev.cobalt", "cc.tweaked.internal.cobalt")
minimize()
}
tasks.assemble { dependsOn("shadowJar") }
// Web tasks
val rollup by tasks.registering(NpxExecToDir::class) {
group = LifecycleBasePlugin.BUILD_GROUP
description = "Bundles JS into rollup"
// Sources
inputs.files(fileTree("src/web")).withPropertyName("sources")
// Config files
inputs.file("tsconfig.json").withPropertyName("Typescript config")
inputs.file("rollup.config.js").withPropertyName("Rollup config")
// Output directory. Also defined in illuaminate.sexp and rollup.config.js
output.set(buildDir.resolve("rollup"))
args = listOf("rollup", "--config", "rollup.config.js")
}
val illuaminateDocs by tasks.registering(IlluaminateExecToDir::class) {
group = JavaBasePlugin.DOCUMENTATION_GROUP
description = "Generates docs using Illuaminate"
// Config files
inputs.file("illuaminate.sexp").withPropertyName("illuaminate.sexp")
// Sources
inputs.files(fileTree("doc")).withPropertyName("docs")
inputs.files(fileTree("src/main/resources/data/computercraft/lua")).withPropertyName("lua rom")
inputs.files(luaJavadoc)
// Additional assets
inputs.files(rollup)
inputs.file("src/web/styles.css").withPropertyName("styles")
// Output directory. Also defined in illuaminate.sexp and transform.tsx
output.set(buildDir.resolve("illuaminate"))
args = listOf("doc-gen")
}
val jsxDocs by tasks.registering(NpxExecToDir::class) {
group = JavaBasePlugin.DOCUMENTATION_GROUP
description = "Post-processes documentation to statically render some dynamic content."
// Config files
inputs.file("tsconfig.json").withPropertyName("Typescript config")
// Sources
inputs.files(fileTree("src/web")).withPropertyName("sources")
inputs.file("src/generated/export/index.json").withPropertyName("export")
inputs.files(illuaminateDocs)
// Output directory. Also defined in src/web/transform.tsx
output.set(buildDir.resolve("jsxDocs"))
args = listOf("ts-node", "-T", "--esm", "src/web/transform.tsx")
}
val docWebsite by tasks.registering(Copy::class) {
group = JavaBasePlugin.DOCUMENTATION_GROUP
description = "Assemble docs and assets together into the documentation website."
from(jsxDocs)
from("doc") {
include("logo.png")
include("images/**")
}
from(rollup) { exclude("index.js") }
from(illuaminateDocs) { exclude("**/*.html") }
from("src/generated/export/items") { into("images/items") }
into(buildDir.resolve("docs/site"))
}
// Check tasks
tasks.test {
systemProperty("cct.test-files", buildDir.resolve("tmp/testFiles").absolutePath)
}
val lintLua by tasks.registering(IlluaminateExec::class) {
group = JavaBasePlugin.VERIFICATION_GROUP
description = "Lint Lua (and Lua docs) with illuaminate"
// Config files
inputs.file("illuaminate.sexp").withPropertyName("illuaminate.sexp")
// Sources
inputs.files(fileTree("doc")).withPropertyName("docs")
inputs.files(fileTree("src/main/resources/data/computercraft/lua")).withPropertyName("lua rom")
inputs.files(luaJavadoc)
args = listOf("lint")
doFirst { if (System.getenv("GITHUB_ACTIONS") != null) println("::add-matcher::.github/matchers/illuaminate.json") }
doLast { if (System.getenv("GITHUB_ACTIONS") != null) println("::remove-matcher owner=illuaminate::") }
}
val runGametest by tasks.registering(JavaExec::class) {
group = LifecycleBasePlugin.VERIFICATION_GROUP
description = "Runs tests on a temporary Minecraft instance."
dependsOn("cleanRunGametest")
// Copy from runGameTestServer. We do it in this slightly odd way as runGameTestServer
// isn't created until the task is configured (which is no good for us).
val exec = tasks.getByName<JavaExec>("runGameTestServer")
dependsOn(exec.dependsOn)
exec.copyToFull(this)
}
cct.jacoco(runGametest)
tasks.check { dependsOn(runGametest) }
// Upload tasks
val checkChangelog by tasks.registering(CheckChangelog::class) {
version.set(modVersion)
whatsNew.set(file("src/main/resources/data/computercraft/lua/rom/help/whatsnew.md"))
changelog.set(file("src/main/resources/data/computercraft/lua/rom/help/changelog.md"))
}
tasks.check { dependsOn(checkChangelog) }
val publishCurseForge by tasks.registering(TaskPublishCurseForge::class) {
group = PublishingPlugin.PUBLISH_TASK_GROUP
description = "Upload artifacts to CurseForge"
apiToken = findProperty("curseForgeApiKey") ?: ""
enabled = apiToken != ""
val mainFile = upload("282001", tasks.shadowJar.get().archiveFile)
dependsOn(tasks.shadowJar) // Ughr.
mainFile.changelog = "Release notes can be found on the [GitHub repository](https://github.com/cc-tweaked/CC-Tweaked/releases/tag/v$mcVersion-$modVersion)."
mainFile.changelogType = "markdown"
mainFile.releaseType = if (isStable) "release" else "alpha"
mainFile.gameVersions.add(mcVersion)
}
tasks.publish { dependsOn(publishCurseForge) }
modrinth {
token.set(findProperty("modrinthApiKey") as String? ?: "")
projectId.set("gu7yAYhd")
versionNumber.set("$mcVersion-$modVersion")
versionName.set(modVersion)
versionType.set(if (isStable) "release" else "alpha")
uploadFile.set(tasks.shadowJar as Any)
gameVersions.add(mcVersion)
changelog.set("Release notes can be found on the [GitHub repository](https://github.com/cc-tweaked/CC-Tweaked/releases/tag/v$mcVersion-$modVersion).")
syncBodyFrom.set(provider { file("doc/mod-page.md").readText() })
}
tasks.publish { dependsOn(tasks.modrinth) }
githubRelease {
token(findProperty("githubApiKey") as String? ?: "")
owner.set("cc-tweaked")
repo.set("CC-Tweaked")
targetCommitish.set(cct.gitBranch)
tagName.set("v$mcVersion-$modVersion")
releaseName.set("[$mcVersion] $modVersion")
body.set(
provider {
"## " + file("src/main/resources/data/computercraft/lua/rom/help/whatsnew.md")
.readLines()
.takeWhile { it != "Type \"help changelog\" to see the full version history." }
.joinToString("\n").trim()
},
)
prerelease.set(!isStable)
}
tasks.publish { dependsOn(tasks.githubRelease) }
publishing {
publications {
register<MavenPublication>("maven") {
artifactId = base.archivesName.get()
from(components["java"])
artifact(apiJar)
fg.component(this)
pom {
name.set("CC: Tweaked")
description.set("CC: Tweaked is a fork of ComputerCraft, adding programmable computers, turtles and more to Minecraft.")
url.set("https://github.com/cc-tweaked/CC-Tweaked")
scm {
url.set("https://github.com/cc-tweaked/CC-Tweaked.git")
}
issueManagement {
system.set("github")
url.set("https://github.com/cc-tweaked/CC-Tweaked/issues")
}
licenses {
license {
name.set("ComputerCraft Public License, Version 1.0")
url.set("https://github.com/cc-tweaked/CC-Tweaked/blob/HEAD/LICENSE")
}
}
}
}
}
repositories {
maven("https://squiddev.cc/maven") {
name = "SquidDev"
credentials(PasswordCredentials::class)
}
}
}

33
buildSrc/build.gradle.kts Normal file
View File

@@ -0,0 +1,33 @@
plugins {
`java-gradle-plugin`
`kotlin-dsl`
}
repositories {
mavenCentral()
gradlePluginPortal()
}
dependencies {
implementation(libs.kotlin.plugin)
implementation(libs.spotless)
}
gradlePlugin {
plugins {
register("cc-tweaked") {
id = "cc-tweaked"
implementationClass = "cc.tweaked.gradle.CCTweakedPlugin"
}
register("cc-tweaked.illuaminate") {
id = "cc-tweaked.illuaminate"
implementationClass = "cc.tweaked.gradle.IlluaminatePlugin"
}
register("cc-tweaked.node") {
id = "cc-tweaked.node"
implementationClass = "cc.tweaked.gradle.NodePlugin"
}
}
}

View File

@@ -0,0 +1,7 @@
dependencyResolutionManagement {
versionCatalogs {
create("libs") {
from(files("../gradle/libs.versions.toml"))
}
}
}

View File

@@ -0,0 +1,53 @@
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
/**
* Sets up the configurations for writing game tests.
*
* See notes in [cc.tweaked.gradle.MinecraftConfigurations] for the general design behind these cursed ideas.
*/
plugins {
id("cc-tweaked.kotlin-convention")
id("cc-tweaked.java-convention")
}
val main = sourceSets.main.get()
// Both testMod and testFixtures inherit from the main classpath, just so we have access to Minecraft classes.
val testMod by sourceSets.creating {
compileClasspath += main.compileClasspath
runtimeClasspath += main.runtimeClasspath
}
configurations {
named(testMod.compileClasspathConfigurationName) {
shouldResolveConsistentlyWith(compileClasspath.get())
}
named(testMod.runtimeClasspathConfigurationName) {
shouldResolveConsistentlyWith(runtimeClasspath.get())
}
}
// Like the main test configurations, we're safe to depend on source set outputs.
dependencies {
add(testMod.implementationConfigurationName, main.output)
}
// Similar to java-test-fixtures, but tries to avoid putting the obfuscated jar on the classpath.
val testFixtures by sourceSets.creating {
compileClasspath += main.compileClasspath
}
java.registerFeature("testFixtures") {
usingSourceSet(testFixtures)
disablePublication()
}
dependencies {
add(testFixtures.implementationConfigurationName, main.output)
testImplementation(testFixtures(project))
add(testMod.implementationConfigurationName, testFixtures(project))
}

View File

@@ -0,0 +1,106 @@
import cc.tweaked.gradle.CCTweakedPlugin
import cc.tweaked.gradle.LicenseHeader
import com.diffplug.gradle.spotless.FormatExtension
import com.diffplug.spotless.LineEnding
import java.nio.charset.StandardCharsets
plugins {
`java-library`
jacoco
checkstyle
id("com.diffplug.spotless")
}
java {
toolchain {
languageVersion.set(CCTweakedPlugin.JAVA_VERSION)
}
withSourcesJar()
withJavadocJar()
}
repositories {
mavenCentral()
maven("https://squiddev.cc/maven") {
name = "SquidDev"
content {
includeGroup("org.squiddev")
includeGroup("cc.tweaked")
// Things we mirror
includeGroup("com.blamejared.crafttweaker")
includeGroup("commoble.morered")
includeGroup("maven.modrinth")
includeGroup("mezz.jei")
}
}
}
dependencies {
val libs = project.extensions.getByType<VersionCatalogsExtension>().named("libs")
checkstyle(libs.findLibrary("checkstyle").get())
}
// Configure default JavaCompile tasks with our arguments.
sourceSets.all {
tasks.named(compileJavaTaskName, JavaCompile::class.java) {
// Processing just gives us "No processor claimed any of these annotations", so skip that!
options.compilerArgs.addAll(listOf("-Xlint", "-Xlint:-processing"))
}
}
tasks.withType(JavaCompile::class.java).configureEach {
options.encoding = "UTF-8"
}
tasks.test {
finalizedBy("jacocoTestReport")
useJUnitPlatform()
testLogging {
events("skipped", "failed")
}
}
tasks.withType(JacocoReport::class.java).configureEach {
reports.xml.required.set(true)
reports.html.required.set(true)
}
spotless {
encoding = StandardCharsets.UTF_8
lineEndings = LineEnding.UNIX
fun FormatExtension.defaults() {
endWithNewline()
trimTrailingWhitespace()
indentWithSpaces(4)
}
val licenser = LicenseHeader.create(
api = file("config/license/api.txt"),
main = file("config/license/main.txt"),
)
java {
defaults()
addStep(licenser)
removeUnusedImports()
}
val ktlintConfig = mapOf(
"disabled_rules" to "no-wildcard-imports",
"ij_kotlin_allow_trailing_comma" to "true",
"ij_kotlin_allow_trailing_comma_on_call_site" to "true",
)
kotlinGradle {
defaults()
ktlint().editorConfigOverride(ktlintConfig)
}
kotlin {
defaults()
ktlint().editorConfigOverride(ktlintConfig)
}
}

View File

@@ -0,0 +1,21 @@
import cc.tweaked.gradle.CCTweakedPlugin
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins {
kotlin("jvm")
}
kotlin {
jvmToolchain {
languageVersion.set(CCTweakedPlugin.JAVA_VERSION)
}
}
tasks.withType(KotlinCompile::class.java).configureEach {
// So technically we shouldn't need to do this as the toolchain sets it above. However, the option only appears
// to be set when the task executes, so doesn't get picked up by IDEs.
kotlinOptions.jvmTarget = when {
CCTweakedPlugin.JAVA_VERSION.asInt() > 8 -> CCTweakedPlugin.JAVA_VERSION.toString()
else -> "1.${CCTweakedPlugin.JAVA_VERSION.asInt()}"
}
}

View File

@@ -0,0 +1,124 @@
package cc.tweaked.gradle
import org.gradle.api.NamedDomainObjectProvider
import org.gradle.api.Project
import org.gradle.api.attributes.TestSuiteType
import org.gradle.api.file.FileSystemOperations
import org.gradle.api.provider.Provider
import org.gradle.api.reporting.ReportingExtension
import org.gradle.api.tasks.JavaExec
import org.gradle.api.tasks.SourceSetContainer
import org.gradle.configurationcache.extensions.capitalized
import org.gradle.kotlin.dsl.get
import org.gradle.language.base.plugins.LifecycleBasePlugin
import org.gradle.testing.jacoco.plugins.JacocoCoverageReport
import org.gradle.testing.jacoco.plugins.JacocoPluginExtension
import org.gradle.testing.jacoco.plugins.JacocoTaskExtension
import org.gradle.testing.jacoco.tasks.JacocoReport
import java.io.BufferedWriter
import java.io.IOException
import java.io.OutputStreamWriter
import java.util.regex.Pattern
abstract class CCTweakedExtension(
private val project: Project,
private val fs: FileSystemOperations,
) {
/** Get the hash of the latest git commit. */
val gitHash: Provider<String> = gitProvider(project, "<no git hash>") {
ProcessHelpers.captureOut("git", "-C", project.projectDir.absolutePath, "rev-parse", "HEAD").trim()
}
/** Get the current git branch. */
val gitBranch: Provider<String> = gitProvider(project, "<no git branch>") {
ProcessHelpers.captureOut("git", "-C", project.projectDir.absolutePath, "rev-parse", "--abbrev-ref", "HEAD").trim()
}
/** Get a list of all contributors to the project. */
val gitContributors: Provider<List<String>> = gitProvider(project, listOf()) {
val authors: Set<String> = HashSet(
ProcessHelpers.captureLines(
"git", "-C", project.projectDir.absolutePath, "log",
"--format=tformat:%an <%ae>%n%cn <%ce>%n%(trailers:key=Co-authored-by,valueonly)",
),
)
val process = ProcessHelpers.startProcess("git", "check-mailmap", "--stdin")
BufferedWriter(OutputStreamWriter(process.outputStream)).use { writer ->
for (authorName in authors) {
var author = authorName
if (author.isEmpty()) continue
if (!author.endsWith(">")) author += ">" // Some commits have broken Co-Authored-By lines!
writer.write(author)
writer.newLine()
}
}
val contributors: MutableSet<String> = HashSet()
for (authorLine in ProcessHelpers.captureLines(process)) {
val matcher = EMAIL.matcher(authorLine)
matcher.find()
val name = matcher.group(1)
if (!IGNORED_USERS.contains(name)) contributors.add(name)
}
contributors.sortedWith(String.CASE_INSENSITIVE_ORDER)
}
fun jacoco(task: NamedDomainObjectProvider<JavaExec>) {
val classDump = project.buildDir.resolve("jacocoClassDump/${task.name}")
val reportTaskName = "jacoco${task.name.capitalized()}Report"
val jacoco = project.extensions.getByType(JacocoPluginExtension::class.java)
task.configure {
finalizedBy(reportTaskName)
doFirst("Clean class dump directory") { fs.delete { delete(classDump) } }
jacoco.applyTo(this)
extensions.configure(JacocoTaskExtension::class.java) {
includes = listOf("dan200.computercraft.*")
classDumpDir = classDump
// Older versions of modlauncher don't include a protection domain (and thus no code
// source). Jacoco skips such classes by default, so we need to explicitly include them.
isIncludeNoLocationClasses = true
}
}
project.tasks.register(reportTaskName, JacocoReport::class.java) {
group = LifecycleBasePlugin.VERIFICATION_GROUP
description = "Generates code coverage report for the ${task.name} task."
executionData(task.get())
classDirectories.from(classDump)
// Don't want to use sourceSets(...) here as we have a custom class directory.
val sourceSets = project.extensions.getByType(SourceSetContainer::class.java)
sourceDirectories.from(sourceSets["main"].allSource.sourceDirectories)
}
project.extensions.configure(ReportingExtension::class.java) {
reports.register("${task.name}CodeCoverageReport", JacocoCoverageReport::class.java) {
testType.set(TestSuiteType.INTEGRATION_TEST)
}
}
}
companion object {
private val EMAIL = Pattern.compile("^([^<]+) <.+>$")
private val IGNORED_USERS = setOf(
"GitHub", "Daniel Ratcliffe", "Weblate",
)
private fun <T> gitProvider(project: Project, default: T, supplier: () -> T): Provider<T> {
return project.provider {
try {
supplier()
} catch (e: IOException) {
project.logger.error("Cannot read Git repository: ${e.message}")
default
}
}
}
}
}

View File

@@ -0,0 +1,18 @@
package cc.tweaked.gradle
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.jvm.toolchain.JavaLanguageVersion
/**
* Configures projects to match a shared configuration.
*/
class CCTweakedPlugin : Plugin<Project> {
override fun apply(project: Project) {
project.extensions.create("cct", CCTweakedExtension::class.java)
}
companion object {
val JAVA_VERSION = JavaLanguageVersion.of(17)
}
}

View File

@@ -0,0 +1,65 @@
package cc.tweaked.gradle
import org.gradle.api.DefaultTask
import org.gradle.api.GradleException
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.provider.Property
import org.gradle.api.tasks.*
import org.gradle.language.base.plugins.LifecycleBasePlugin
import java.nio.charset.StandardCharsets
/**
* Checks the `changelog.md` and `whatsnew.md` files are well-formed.
*/
@CacheableTask
abstract class CheckChangelog : DefaultTask() {
init {
group = LifecycleBasePlugin.VERIFICATION_GROUP
description = "Verifies the changelog and whatsnew file are consistent."
}
@get:Input
abstract val version: Property<String>
@get:InputFile
@get:PathSensitive(PathSensitivity.NONE)
abstract val changelog: RegularFileProperty
@get:InputFile
@get:PathSensitive(PathSensitivity.NONE)
abstract val whatsNew: RegularFileProperty
@TaskAction
fun check() {
val version = version.get()
var ok = true
// Check we're targetting the current version
var whatsNew = whatsNew.get().asFile.readLines()
if (whatsNew[0] != "New features in CC: Tweaked $version") {
ok = false
logger.error("Expected `whatsnew.md' to target $version.")
}
// Check "read more" exists and trim it
val idx = whatsNew.indexOfFirst { it == "Type \"help changelog\" to see the full version history." }
if (idx == -1) {
ok = false
logger.error("Must mention the changelog in whatsnew.md")
} else {
whatsNew = whatsNew.slice(0 until idx)
}
// Check whatsnew and changelog match.
val expectedChangelog = sequenceOf("# ${whatsNew[0]}") + whatsNew.slice(1 until whatsNew.size).asSequence()
val changelog = changelog.get().asFile.readLines()
val mismatch = expectedChangelog.zip(changelog.asSequence()).filter { (a, b) -> a != b }.firstOrNull()
if (mismatch != null) {
ok = false
logger.error("whatsnew and changelog are not in sync")
}
if (!ok) throw GradleException("Could not check release")
}
}

View File

@@ -0,0 +1,73 @@
package cc.tweaked.gradle
import com.diffplug.spotless.FormatterFunc
import com.diffplug.spotless.FormatterStep
import com.diffplug.spotless.generic.LicenseHeaderStep
import java.io.File
import java.io.Serializable
import java.nio.charset.StandardCharsets
/**
* Similar to [LicenseHeaderStep], but supports multiple licenses.
*/
object LicenseHeader {
/**
* The current year to use in templates. Intentionally not dynamic to avoid failing the build.
*/
private const val YEAR = 2022
private val COMMENT = Regex("""^/\*(.*?)\*/\n?""", RegexOption.DOT_MATCHES_ALL)
fun create(api: File, main: File): FormatterStep = FormatterStep.createLazy(
"license",
{ Licenses(getTemplateText(api), getTemplateText(main)) },
{ state -> FormatterFunc.NeedsFile { contents, file -> formatFile(state, contents, file) } },
)
private fun getTemplateText(file: File): String =
file.readText().trim().replace("\${year}", "$YEAR")
private fun formatFile(licenses: Licenses, contents: String, file: File): String {
val license = getLicense(contents)
val expectedLicense = getExpectedLicense(licenses, file.parentFile)
return when {
license == null -> setLicense(expectedLicense, contents)
license.second != expectedLicense -> setLicense(expectedLicense, contents, license.first)
else -> contents
}
}
private fun getExpectedLicense(licenses: Licenses, root: File): String {
var file: File? = root
while (file != null) {
if (file.name == "api" && file.parentFile?.name == "computercraft") return licenses.api
file = file.parentFile
}
return licenses.main
}
private fun getLicense(contents: String): Pair<Int, String>? {
val match = COMMENT.find(contents) ?: return null
val license = match.groups[1]!!.value
.trim().lineSequence()
.map { it.trimStart(' ', '*') }
.joinToString("\n")
return Pair(match.range.last + 1, license)
}
private fun setLicense(license: String, contents: String, start: Int = 0): String {
val out = StringBuilder()
out.append("/*\n")
for (line in license.lineSequence()) out.append(" * ").append(line).append("\n")
out.append(" */\n")
out.append(contents, start, contents.length)
return out.toString()
}
private data class Licenses(val api: String, val main: String) : Serializable {
companion object {
private const val serialVersionUID: Long = 7741106448372435662L
}
}
}

View File

@@ -0,0 +1,11 @@
package cc.tweaked.gradle
import org.gradle.api.provider.Property
import org.gradle.api.tasks.AbstractExecTask
import org.gradle.api.tasks.OutputDirectory
import java.io.File
abstract class ExecToDir : AbstractExecTask<ExecToDir>(ExecToDir::class.java) {
@get:OutputDirectory
abstract val output: Property<File>
}

View File

@@ -0,0 +1,20 @@
package cc.tweaked.gradle
import org.gradle.api.artifacts.dsl.DependencyHandler
import org.gradle.api.tasks.JavaExec
fun DependencyHandler.annotationProcessorEverywhere(dep: Any) {
add("compileOnly", dep)
add("annotationProcessor", dep)
add("testCompileOnly", dep)
add("testAnnotationProcessor", dep)
}
fun JavaExec.copyToFull(spec: JavaExec) {
copyTo(spec)
spec.classpath = classpath
spec.mainClass.set(mainClass)
spec.javaLauncher.set(javaLauncher)
spec.args = args
}

View File

@@ -0,0 +1,121 @@
package cc.tweaked.gradle
import org.gradle.api.DefaultTask
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.Task
import org.gradle.api.artifacts.Dependency
import org.gradle.api.provider.Property
import org.gradle.api.provider.Provider
import org.gradle.api.tasks.AbstractExecTask
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.TaskAction
import java.io.File
abstract class IlluaminateExtension {
/** The version of illuaminate to use. */
abstract val version: Property<String>
/** The path to illuaminate. If not given, illuaminate will be downloaded automatically. */
abstract val file: Property<File>
}
class IlluaminatePlugin : Plugin<Project> {
override fun apply(project: Project) {
val extension = project.extensions.create("illuaminate", IlluaminateExtension::class.java)
extension.file.convention(setupDependency(project, extension.version))
project.tasks.register(SetupIlluaminate.NAME, SetupIlluaminate::class.java) {
file.set(extension.file.map { it.absolutePath })
}
}
/** Set up a repository for illuaminate and download our binary from it. */
private fun setupDependency(project: Project, version: Provider<String>): Provider<File> {
project.repositories.ivy {
name = "Illuaminate"
setUrl("https://squiddev.cc/illuaminate/bin/")
patternLayout {
artifact("[revision]/[artifact]-[ext]")
}
metadataSources {
artifact()
}
content {
includeModule("cc.squiddev", "illuaminate")
}
}
return version.map {
val dep = illuaminateArtifact(project, it)
val configuration = project.configurations.detachedConfiguration(dep)
configuration.isTransitive = false
configuration.resolve().single()
}
}
/** Define a dependency for illuaminate from a version number and the current operating system. */
private fun illuaminateArtifact(project: Project, version: String): Dependency {
val osName = System.getProperty("os.name").toLowerCase()
val (os, suffix) = when {
osName.contains("windows") -> Pair("windows", ".exe")
osName.contains("mac os") || osName.contains("darwin") -> Pair("macos", "")
osName.contains("linux") -> Pair("linux", "")
else -> error("Unsupported OS $osName for illuaminate")
}
val osArch = System.getProperty("os.arch").toLowerCase()
val arch = when {
osArch == "arm" || osArch.startsWith("aarch") -> error("Unsupported architecture '$osArch' for illuaminate")
osArch.contains("64") -> "x86_64"
else -> error("Unsupported architecture $osArch for illuaminate")
}
return project.dependencies.create(
mapOf(
"group" to "cc.squiddev",
"name" to "illuaminate",
"version" to version,
"ext" to "$os-$arch$suffix",
),
)
}
}
private val Task.illuaminatePath: String? // "?" needed to avoid overload ambiguity in setExecutable below.
get() = project.extensions.getByType(IlluaminateExtension::class.java).file.get().absolutePath
/** Prepares illuaminate for being run. This simply requests the dependency and then marks it as executable. */
abstract class SetupIlluaminate : DefaultTask() {
@get:Input
abstract val file: Property<String>
@TaskAction
fun setExecutable() {
val file = File(this.file.get())
if (file.canExecute()) {
didWork = false
return
}
file.setExecutable(true)
}
companion object {
const val NAME: String = "setupIlluaminate"
}
}
abstract class IlluaminateExec : AbstractExecTask<IlluaminateExec>(IlluaminateExec::class.java) {
init {
dependsOn(SetupIlluaminate.NAME)
executable = illuaminatePath
}
}
abstract class IlluaminateExecToDir : ExecToDir() {
init {
dependsOn(SetupIlluaminate.NAME)
executable = illuaminatePath
}
}

View File

@@ -0,0 +1,60 @@
package cc.tweaked.gradle
import org.gradle.api.DefaultTask
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.file.Directory
import org.gradle.api.file.DirectoryProperty
import org.gradle.api.provider.Provider
import org.gradle.api.tasks.*
import java.io.File
class NodePlugin : Plugin<Project> {
override fun apply(project: Project) {
val extension = project.extensions.create("node", NodeExtension::class.java)
project.tasks.register(NpmInstall.TASK_NAME, NpmInstall::class.java) {
projectRoot.convention(extension.projectRoot)
}
}
}
abstract class NodeExtension(project: Project) {
/** The directory containing `package-lock.json` and `node_modules/`. */
abstract val projectRoot: DirectoryProperty
init {
projectRoot.convention(project.layout.projectDirectory)
}
}
/** Installs node modules as dependencies. */
abstract class NpmInstall : DefaultTask() {
@get:Internal
abstract val projectRoot: DirectoryProperty
@get:InputFile
@get:PathSensitive(PathSensitivity.NONE)
val packageLock: Provider<File> = projectRoot.file("package-lock.json").map { it.asFile }
@get:OutputDirectory
val nodeModules: Provider<Directory> = projectRoot.dir("node_modules")
@TaskAction
fun install() {
project.exec {
commandLine("npm", "ci")
workingDir = projectRoot.get().asFile
}
}
companion object {
internal const val TASK_NAME: String = "npmInstall"
}
}
abstract class NpxExecToDir : ExecToDir() {
init {
dependsOn(NpmInstall.TASK_NAME)
executable = "npx"
}
}

View File

@@ -0,0 +1,35 @@
package cc.tweaked.gradle
import org.codehaus.groovy.runtime.ProcessGroovyMethods
import java.io.BufferedReader
import java.io.IOException
import java.io.InputStreamReader
import java.util.stream.Collectors
internal object ProcessHelpers {
fun startProcess(vararg command: String): Process {
// Something randomly passes in "GIT_DIR=" as an environment variable which clobbers everything else. Don't
// inherit the environment array!
return Runtime.getRuntime().exec(command, arrayOfNulls(0))
}
fun captureOut(vararg command: String): String {
val process = startProcess(*command)
val result = ProcessGroovyMethods.getText(process)
if (process.waitFor() != 0) throw IOException("Command exited with a non-0 status")
return result
}
fun captureLines(vararg command: String): List<String> {
return captureLines(startProcess(*command))
}
fun captureLines(process: Process): List<String> {
val out = BufferedReader(InputStreamReader(process.inputStream)).use { reader ->
reader.lines().filter { it.isNotEmpty() }.collect(Collectors.toList())
}
ProcessGroovyMethods.closeStreams(process)
if (process.waitFor() != 0) throw IOException("Command exited with a non-0 status")
return out
}
}

View File

@@ -78,7 +78,9 @@
<!-- Javadoc -->
<!-- TODO: Missing* checks for the dan200.computercraft.api package? -->
<module name="AtclauseOrder" />
<module name="AtclauseOrder">
<property name="tagOrder" value="@param, @return, @throws, @deprecated"/>
</module>
<module name="InvalidJavadocPosition" />
<module name="JavadocBlockTagLocation" />
<module name="JavadocMethod"/>
@@ -107,7 +109,9 @@
<module name="LocalFinalVariableName" />
<module name="LocalVariableName" />
<module name="MemberName" />
<module name="MethodName" />
<module name="MethodName">
<property name="format" value="^(computercraft\$)?[a-z][a-zA-Z0-9]*$" />
</module>
<module name="MethodTypeParameterName" />
<module name="PackageName">
<property name="format" value="^dan200\.computercraft(\.[a-z][a-z0-9]*)*" />
@@ -115,11 +119,6 @@
<module name="ParameterName" />
<module name="StaticVariableName">
<property name="format" value="^[a-z][a-zA-Z0-9]*|CAPABILITY(_[A-Z_]+)?$" />
<property name="applyToPrivate" value="false" />
</module>
<module name="StaticVariableName">
<property name="format" value="^(s_)?[a-z][a-zA-Z0-9]*|CAPABILITY(_[A-Z_]+)?$" />
<property name="applyToPrivate" value="true" />
</module>
<module name="TypeName" />

View File

@@ -1,16 +0,0 @@
#!/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

View File

@@ -0,0 +1,42 @@
---
module: [kind=event] file_transfer
since: 1.101.0
---
The @{file_transfer} event is queued when a user drags-and-drops a file on an open computer.
This event contains a single argument, that in turn has a single method @{TransferredFiles.getFiles|getFiles}. This
returns the list of files that are being transferred. Each file is a @{fs.BinaryReadHandle|binary file handle} with an
additional @{TransferredFile.getName|getName} method.
## Return values
1. @{string}: The event name
2. @{TransferredFiles}: The list of transferred files.
## Example
Waits for a user to drop files on top of the computer, then prints the list of files and the size of each file.
```lua
local _, files = os.pullEvent("file_transfer")
for _, file in ipairs(files.getFiles()) do
-- Seek to the end of the file to get its size, then go back to the beginning.
local size = file.seek("end")
file.seek("set", 0)
print(file.getName() .. " " .. file.getSize())
end
```
## Example
Save each transferred file to the computer's storage.
```lua
local _, files = os.pullEvent("file_transfer")
for _, file in ipairs(files.getFiles()) do
local handle = fs.open(file.getName(), "wb")
handle.write(file.readAll())
handle.close()
file.close()
end
```

90
doc/guides/gps_setup.md Normal file
View File

@@ -0,0 +1,90 @@
---
module: [kind=guide] gps_setup
---
# Setting up GPS
The @{gps} API allows computers and turtles to find their current position using wireless modems.
In order to use GPS, you'll need to set up multiple *GPS hosts*. These are computers running the special `gps host`
program, which tell other computers the host's position. Several hosts running together are known as a *GPS
constellation*.
In order to give the best results, a GPS constellation needs at least four computers. More than four GPS hosts per
constellation is redundant, but it does not cause problems.
## Building a GPS constellation
![An example GPS constellation.](/images/gps-constellation-example.png){.big-image}
We are going to build our GPS constellation as shown in the image above. You will need 4 computers and either 4 wireless
modems or 4 ender modems. Try not to mix ender and wireless modems together as you might get some odd behavior when your
requesting computers are out of range.
:::tip Ender modems vs wireless modems
Ender modems have a very large range, which makes them very useful for setting up GPS hosts. If you do this then you
will likely only need one GPS constellation for the whole dimension (such as the Overworld or Nether).
If you do use wireless modems then you may find that you need multiple GPS constellations to cover your needs.
A computer needs a wireless or ender modem and to be in range of a GPS constellation that is in the same dimension as it
to use the GPS API. The reason for this is that ComputerCraft mimics real-life GPS by making use of the distance
parameter of @{modem_message|modem messages} and some maths.
:::
Locate where you want to place your GPS constellation. You will need an area at least 6 blocks high, 6 blocks wide, and
6 blocks deep (6x6x6). If you are using wireless modems then you may want to build your constellation as high as you can
because high altitude boosts modem message range and thus the radius that your constellation covers.
The GPS constellation will only work when it is in a loaded chunk. If you want your constellation to always be
accessible, you may want to permanently load the chunk using a vanilla or modded chunk loader. Make sure that your 6x6x6
area fits in a single chunk to reduce the number of chunks that need to be kept loaded.
Let's get started building the constellation! Place your first computer in one of the corners of your 6x6x6. Remember
which computer this is as other computers need to be placed relative to it. Place the second computer 4 blocks above the
first. Go back to your first computer and place your third computer 5 blocks in front of your first computer, leaving 4
blocks of air between them. Finally for the fourth computer, go back to your first computer and place it 5 blocks right
of your first computer, leaving 4 blocks of air between them.
With all four computers placed within the 6x6x6, place one modem on top of each computer. You should have 4 modems and 4
computers all within your 6x6x6 where each modem is attached to a computer and each computer has a modem.
Currently your GPS constellation will not work, that's because each host is not aware that it's a GPS host. We will fix
this in the next section.
## Configuring the constellation
Now that the structure of your constellation is built, we need to configure each host in it.
Go back to the first computer that you placed and create a startup file, by running `edit startup`.
Type the following code into the file:
```lua
shell.run("gps", "host", x, y, z)
```
Escape from the computer GUI and then press <kbd>F3</kbd> to open Minecraft's debug screen and then look at the computer
(without opening the GUI). On the right of the screen about halfway down you should see an entry labeled `Targeted
Block`, the numbers correspond to the position of the block that you are looking at. Replace `x` with the first number,
`y` with the second number, and `z` with the third number.
For example, if I had a computer at x = 59, y = 5, z = -150, then my <kbd>F3</kbd> debug screen entry would be `Target
Block: 59, 5, -150` and I would change my startup file to this `shell.run("gps", "host", 59, 5, -150)`.
To hide Minecraft's debug screen, press <kbd>F3</kbd> again.
Create similar startup files for the other computers in your constellation, making sure to input the each computer's own
coordinates.
:::caution Modem messages come from the computer's position, not the modem's
Wireless modems transmit from the block that they are attached to *not* the block space that they occupy, the
coordinates that you input into your GPS host should be the position of the computer and not the position of the modem.
:::
Congratulations, your constellation is now fully set up! You can test it by placing another computer close by, placing a
wireless modem on it, and running the `gps locate` program (or calling the @{gps.locate} function).
:::info Why use Minecraft's coordinates?
CC doesn't care if you use Minecraft's coordinate system, so long as all of the GPS hosts with overlapping ranges use
the same reference point (requesting computers will get confused if hosts have different reference points). However,
using MC's coordinate system does provide a nice standard to adopt server-wide. It also is consistent with how command
computers get their location, they use MC's command system to get their block which returns that in MC's coordinate
system.
:::

View File

@@ -185,7 +185,7 @@ end
:::note Confused?
Don't worry if you don't understand this example. It's quite advanced, and does use some ideas that this guide doesn't
cover. That said, don't be afraid to ask on [Discord] or [IRC] either!
cover. That said, don't be afraid to ask on [GitHub Discussions] or [IRC] either!
:::
It's worth noting that the examples of audio processing we've mentioned here are about manipulating the _amplitude_ of
@@ -200,6 +200,5 @@ This is, I'm afraid, left as an exercise to the reader.
[PCM]: https://en.wikipedia.org/wiki/Pulse-code_modulation "Pulse-code Modulation - Wikipedia"
[Ring Buffer]: https://en.wikipedia.org/wiki/Circular_buffer "Circular buffer - Wikipedia"
[Sine Wave]: https://en.wikipedia.org/wiki/Sine_wave "Sine wave - Wikipedia"
[Discord]: https://discord.computercraft.cc "The Minecraft Computer Mods Discord"
[IRC]: http://webchat.esper.net/?channels=computercraft "IRC webchat on EsperNet"
[GitHub Discussions]: https://github.com/cc-tweaked/CC-Tweaked/discussions
[IRC]: https://webchat.esper.net/?channels=computercraft "#computercraft on EsperNet"

Binary file not shown.

After

Width:  |  Height:  |  Size: 331 KiB

View File

@@ -37,8 +37,7 @@ little daunting getting started. Thankfully, there's several fantastic tutorials
Once you're a little more familiar with the mod, the sidebar and links below provide more detailed documentation on the
various APIs and peripherals provided by the mod.
If you get stuck, do pop in to the [Minecraft Computer Mod Discord guild][discord] or ComputerCraft's
[IRC channel][irc].
If you get stuck, do [ask a question on GitHub][GitHub Discussions] or pop in to the ComputerCraft's [IRC channel][IRC].
## Get Involved
CC: Tweaked lives on [GitHub]. If you've got any ideas, feedback or bugs please do [create an issue][bug].
@@ -51,5 +50,5 @@ CC: Tweaked lives on [GitHub]. If you've got any ideas, feedback or bugs please
[forge]: https://files.minecraftforge.net/ "Download Minecraft Forge."
[ccrestitched]: https://www.curseforge.com/minecraft/mc-mods/cc-restitched "Download CC: Restitched from CurseForge"
[lua]: https://www.lua.org/ "Lua's main website"
[discord]: https://discord.computercraft.cc "The Minecraft Computer Mods Discord"
[irc]: http://webchat.esper.net/?channels=computercraft "IRC webchat on EsperNet"
[GitHub Discussions]: https://github.com/cc-tweaked/CC-Tweaked/discussions
[IRC]: https://webchat.esper.net/?channels=computercraft "#computercraft on EsperNet"

61
doc/mod-page.md Normal file
View File

@@ -0,0 +1,61 @@
# ![CC: Tweaked](https://tweaked.cc/logo.png)
CC: Tweaked is a mod for Minecraft which adds programmable computers, turtles and more to the game. A fork of the much-beloved [ComputerCraft], it continues its legacy with better performance, stability, and a wealth of new features.
**Fabric support is added by the [CC: Restitched][ccrestitched] project**
## Testimonials
> I'm not sure what that is [...] I don't know where that came from.
>
> \- [direwolf20, December 2020](https://youtu.be/D8Ue9I-SKeM?t=980)
> It is basically ComputerCraft. It has the turtles, and the computers, and writing Lua programs and all that stuff.
>
> \- [direwolf20, May 2022](https://youtu.be/7Ruq33XmQIQ?t=537)
## Features
Controlled using the [Lua programming language][lua], CC: Tweaked's computers provides all the tools you need to start
writing code and automating your Minecraft world.
![A ComputerCraft terminal open and ready to be programmed.](https://tweaked.cc/images/basic-terminal.png)
While computers are incredibly powerful, they're rather limited by their inability to move about. *Turtles* are the
solution here. They can move about the world, placing and breaking blocks, swinging a sword to protect you from zombies,
or whatever else you program them to!
![A turtle tunneling in Minecraft.](https://tweaked.cc/images/turtle.png)
Not all problems can be solved with a pickaxe though, and so CC: Tweaked also provides a bunch of additional peripherals
for your computers. You can play a tune with speakers, display text or images on a monitor, connect all your
computers together with modems, and much more.
Computers can now also interact with inventories such as chests, allowing you to build complex inventory and item
management systems.
![A chest's contents being read by a computer and displayed on a monitor.](https://tweaked.cc/images/peripherals.png)
## Getting Started
While ComputerCraft is lovely for both experienced programmers and for people who have never coded before, it can be a
little daunting getting started. Thankfully, there's several fantastic tutorials out there:
- [Direwolf20's ComputerCraft tutorials](https://www.youtube.com/watch?v=wrUHUhfCY5A "ComputerCraft Tutorial Episode 1 - HELP! and Hello World")
- [Sethbling's ComputerCraft series](https://www.youtube.com/watch?v=DSsx4VSe-Uk "Programming Tutorial with Minecraft Turtles -- Ep. 1: Intro to Turtles and If-Then-Else_End")
- [Lyqyd's Computer Basics 1](http://www.computercraft.info/forums2/index.php?/topic/15033-computer-basics-i/ "Computer Basics I")
Once you're a little more familiar with the mod, the [wiki](https://tweaked.cc/) provides more detailed documentation on the
various APIs and peripherals provided by the mod.
If you get stuck, do [ask a question on GitHub][GitHub Discussions] or pop in to the ComputerCraft's [IRC channel][IRC].
## Get Involved
CC: Tweaked lives on [GitHub]. If you've got any ideas, feedback or bugs please do [create an issue][bug].
[github]: https://github.com/cc-tweaked/CC-Tweaked/ "CC: Tweaked on GitHub"
[bug]: https://github.com/cc-tweaked/CC-Tweaked/issues/new/choose
[computercraft]: https://github.com/dan200/ComputerCraft "ComputerCraft on GitHub"
[forge]: https://files.minecraftforge.net/ "Download Minecraft Forge."
[ccrestitched]: https://modrinth.com/mod/cc-restitched "Download CC: Restitched from Modrinth"
[lua]: https://www.lua.org/ "Lua's main website"
[GitHub Discussions]: https://github.com/cc-tweaked/CC-Tweaked/discussions
[IRC]: http://webchat.esper.net/?channels=computercraft "#computercraft on EsperNet"

View File

@@ -1,34 +0,0 @@
--- @module fs
--- Returns true if a path is mounted to the parent filesystem.
--
-- The root filesystem "/" is considered a mount, along with disk folders and
-- the rom folder. Other programs (such as network shares) can exstend this to
-- make other mount types by correctly assigning their return value for getDrive.
--
-- @tparam string path The path to check.
-- @treturn boolean If the path is mounted, rather than a normal file/folder.
-- @throws If the path does not exist.
-- @see getDrive
-- @since 1.87.0
function isDriveRoot(path) end
--[[- Provides completion for a file or directory name, suitable for use with
@{_G.read}.
When a directory is a possible candidate for completion, two entries are
included - one with a trailing slash (indicating that entries within this
directory exist) and one without it (meaning this entry is an immediate
completion candidate). `include_dirs` can be set to @{false} to only include
those with a trailing slash.
@tparam string path The path to complete.
@tparam string location The location where paths are resolved from.
@tparam[opt] boolean include_files When @{false}, only directories will be
included in the returned list.
@tparam[opt] boolean include_dirs When @{false}, "raw" directories will not be
included in the returned list.
@treturn { string... } A list of possible completion candidates.
@since 1.74
]]
function complete(path, location, include_files, include_dirs) end

View File

@@ -14,7 +14,7 @@ thread, not the whole program.
:::tip
Because sleep internally uses timers, it is a function that yields. This means
that you can use it to prevent "Too long without yielding" errors, however, as
that you can use it to prevent "Too long without yielding" errors. However, as
the minimum sleep time is 0.05 seconds, it will slow your program down.
:::

View File

@@ -1,177 +0,0 @@
--- Make HTTP requests, sending and receiving data to a remote web server.
--
-- @module http
-- @since 1.1
-- @see local_ips To allow accessing servers running on your local network.
--- Asynchronously make a HTTP request to the given url.
--
-- This returns immediately, a @{http_success} or @{http_failure} will be queued
-- once the request has completed.
--
-- @tparam string url The url to request
-- @tparam[opt] string body An optional string containing the body of the
-- request. If specified, a `POST` request will be made instead.
-- @tparam[opt] { [string] = string } headers Additional headers to send as part
-- of this request.
-- @tparam[opt] boolean binary Whether to make a binary HTTP request. If true,
-- the body will not be UTF-8 encoded, and the received response will not be
-- decoded.
--
-- @tparam[2] {
-- url = string, body? = string, headers? = { [string] = string },
-- binary? = boolean, method? = string, redirect? = boolean,
-- } request Options for the request.
--
-- This table form is an expanded version of the previous syntax. All arguments
-- from above are passed in as fields instead (for instance,
-- `http.request("https://example.com")` becomes `http.request { url =
-- "https://example.com" }`).
--
-- This table also accepts several additional options:
--
-- - `method`: Which HTTP method to use, for instance `"PATCH"` or `"DELETE"`.
-- - `redirect`: Whether to follow HTTP redirects. Defaults to true.
--
-- @see http.get For a synchronous way to make GET requests.
-- @see http.post For a synchronous way to make POST requests.
--
-- @changed 1.63 Added argument for headers.
-- @changed 1.80pr1 Added argument for binary handles.
-- @changed 1.80pr1.6 Added support for table argument.
-- @changed 1.86.0 Added PATCH and TRACE methods.
function request(...) end
--- Make a HTTP GET request to the given url.
--
-- @tparam string url The url to request
-- @tparam[opt] { [string] = string } headers Additional headers to send as part
-- of this request.
-- @tparam[opt] boolean binary Whether to make a binary HTTP request. If true,
-- the body will not be UTF-8 encoded, and the received response will not be
-- decoded.
--
-- @tparam[2] {
-- url = string, headers? = { [string] = string },
-- binary? = boolean, method? = string, redirect? = boolean,
-- } request Options for the request. See @{http.request} for details on how
-- these options behave.
--
-- @treturn Response The resulting http response, which can be read from.
-- @treturn[2] nil When the http request failed, such as in the event of a 404
-- error or connection timeout.
-- @treturn string A message detailing why the request failed.
-- @treturn Response|nil The failing http response, if available.
--
-- @changed 1.63 Added argument for headers.
-- @changed 1.80pr1 Response handles are now returned on error if available.
-- @changed 1.80pr1 Added argument for binary handles.
-- @changed 1.80pr1.6 Added support for table argument.
-- @changed 1.86.0 Added PATCH and TRACE methods.
--
-- @usage Make a request to [example.tweaked.cc](https://example.tweaked.cc),
-- and print the returned page.
-- ```lua
-- local request = http.get("https://example.tweaked.cc")
-- print(request.readAll())
-- -- => HTTP is working!
-- request.close()
-- ```
function get(...) end
--- Make a HTTP POST request to the given url.
--
-- @tparam string url The url to request
-- @tparam string body The body of the POST request.
-- @tparam[opt] { [string] = string } headers Additional headers to send as part
-- of this request.
-- @tparam[opt] boolean binary Whether to make a binary HTTP request. If true,
-- the body will not be UTF-8 encoded, and the received response will not be
-- decoded.
--
-- @tparam[2] {
-- url = string, body? = string, headers? = { [string] = string },
-- binary? = boolean, method? = string, redirect? = boolean,
-- } request Options for the request. See @{http.request} for details on how
-- these options behave.
--
-- @treturn Response The resulting http response, which can be read from.
-- @treturn[2] nil When the http request failed, such as in the event of a 404
-- error or connection timeout.
-- @treturn string A message detailing why the request failed.
-- @treturn Response|nil The failing http response, if available.
--
-- @since 1.31
-- @changed 1.63 Added argument for headers.
-- @changed 1.80pr1 Response handles are now returned on error if available.
-- @changed 1.80pr1 Added argument for binary handles.
-- @changed 1.80pr1.6 Added support for table argument.
-- @changed 1.86.0 Added PATCH and TRACE methods.
function post(...) end
--- Asynchronously determine whether a URL can be requested.
--
-- If this returns `true`, one should also listen for @{http_check} which will
-- container further information about whether the URL is allowed or not.
--
-- @tparam string url The URL to check.
-- @treturn true When this url is not invalid. This does not imply that it is
-- allowed - see the comment above.
-- @treturn[2] false When this url is invalid.
-- @treturn string A reason why this URL is not valid (for instance, if it is
-- malformed, or blocked).
--
-- @see http.checkURL For a synchronous version.
function checkURLAsync(url) end
--- Determine whether a URL can be requested.
--
-- If this returns `true`, one should also listen for @{http_check} which will
-- container further information about whether the URL is allowed or not.
--
-- @tparam string url The URL to check.
-- @treturn true When this url is valid and can be requested via @{http.request}.
-- @treturn[2] false When this url is invalid.
-- @treturn string A reason why this URL is not valid (for instance, if it is
-- malformed, or blocked).
--
-- @see http.checkURLAsync For an asynchronous version.
--
-- @usage
-- ```lua
-- print(http.checkURL("https://example.tweaked.cc/"))
-- -- => true
-- print(http.checkURL("http://localhost/"))
-- -- => false Domain not permitted
-- print(http.checkURL("not a url"))
-- -- => false URL malformed
-- ```
function checkURL(url) end
--- Open a websocket.
--
-- @tparam string url The websocket url to connect to. This should have the
-- `ws://` or `wss://` protocol.
-- @tparam[opt] { [string] = string } headers Additional headers to send as part
-- of the initial websocket connection.
--
-- @treturn Websocket The websocket connection.
-- @treturn[2] false If the websocket connection failed.
-- @treturn string An error message describing why the connection failed.
-- @since 1.80pr1.1
-- @changed 1.80pr1.3 No longer asynchronous.
-- @changed 1.95.3 Added User-Agent to default headers.
function websocket(url, headers) end
--- Asynchronously open a websocket.
--
-- This returns immediately, a @{websocket_success} or @{websocket_failure}
-- will be queued once the request has completed.
--
-- @tparam string url The websocket url to connect to. This should have the
-- `ws://` or `wss://` protocol.
-- @tparam[opt] { [string] = string } headers Additional headers to send as part
-- of the initial websocket connection.
-- @since 1.80pr1.3
-- @changed 1.95.3 Added User-Agent to default headers.
function websocketAsync(url, headers) end

View File

@@ -1,10 +1,11 @@
org.gradle.jvmargs=-Xmx3G
org.gradle.parallel=true
kotlin.stdlib.default.dependency=false
kotlin.jvm.target.validation.mode=error
# Mod properties
mod_version=1.100.6
modVersion=1.101.2
# Minecraft properties (update mods.toml when changing)
mc_version=1.18.2
mapping_version=2022.03.13
forge_version=40.1.0
# NO SERIOUSLY, UPDATE mods.toml WHEN CHANGING
# Minecraft properties: We want to configure this here so we can read it in settings.gradle
mcVersion=1.18.2

71
gradle/libs.versions.toml Normal file
View File

@@ -0,0 +1,71 @@
[versions]
# Minecraft
# MC version is specified in gradle.properties, as we need that in settings.gradle.
forge = "40.1.0"
parchment = "2022.03.13"
parchmentMc = "1.18.2"
autoService = "1.0.1"
cobalt = "0.6.0"
jetbrainsAnnotations = "23.0.0"
kotlin = "1.7.10"
kotlin-coroutines = "1.6.0"
# Testing
hamcrest = "2.2"
jqwik = "1.7.0"
junit = "5.9.1"
# Build tools
cctJavadoc = "1.5.2"
checkstyle = "10.3.4"
curseForgeGradle = "1.0.11"
forgeGradle = "5.1.+"
githubRelease = "2.2.12"
illuaminate = "0.1.0-20-g8c483a4"
librarian = "1.+"
minotaur = "2.+"
mixinGradle = "0.7.+"
shadow = "7.1.2"
spotless = "6.8.0"
taskTree = "2.1.0"
[libraries]
autoService = { module = "com.google.auto.service:auto-service", version.ref = "autoService" }
cobalt = { module = "org.squiddev:Cobalt", version.ref = "cobalt" }
jetbrainsAnnotations = { module = "org.jetbrains:annotations", version.ref = "jetbrainsAnnotations" }
kotlin-coroutines = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlin-coroutines" }
kotlin-stdlib = { module = "org.jetbrains.kotlin:kotlin-stdlib-jdk8", version.ref = "kotlin" }
# Testing
hamcrest = { module = "org.hamcrest:hamcrest", version.ref = "hamcrest" }
jqwik-api = { module = "net.jqwik:jqwik-api", version.ref = "jqwik" }
jqwik-engine = { module = "net.jqwik:jqwik-engine", version.ref = "jqwik" }
junit-jupiter-api = { module = "org.junit.jupiter:junit-jupiter-api", version.ref = "junit" }
junit-jupiter-engine = { module = "org.junit.jupiter:junit-jupiter-engine", version.ref = "junit" }
junit-jupiter-params = { module = "org.junit.jupiter:junit-jupiter-params", version.ref = "junit" }
# Build tools
cctJavadoc = { module = "cc.tweaked:cct-javadoc", version.ref = "cctJavadoc" }
checkstyle = { module = "com.puppycrawl.tools:checkstyle", version.ref = "checkstyle" }
kotlin-plugin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlin" }
spotless = { module = "com.diffplug.spotless:spotless-plugin-gradle", version.ref = "spotless" }
[plugins]
kotlin = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
taskTree = { id = "com.dorongold.task-tree", version.ref = "taskTree" }
curseForgeGradle = { id = "net.darkhax.curseforgegradle", version.ref = "curseForgeGradle" }
mixinGradle = { id = "org.spongepowered.mixin", version.ref = "mixinGradle" }
minotaur = { id = "com.modrinth.minotaur", version.ref = "minotaur" }
githubRelease = { id = "com.github.breadmoirai.github-release", version.ref = "githubRelease" }
forgeGradle = { id = "net.minecraftforge.gradle", version.ref = "forgeGradle" }
librarian = { id = "org.parchmentmc.librarian.forgegradle", version.ref = "librarian" }
shadow = { id = "com.github.johnrengelman.shadow", version.ref = "shadow" }
[bundles]
kotlin = ["kotlin-stdlib", "kotlin-coroutines"]
# Testing
test = ["junit-jupiter-api", "junit-jupiter-params", "hamcrest", "jqwik-api"]
testRuntime = ["junit-jupiter-engine", "jqwik-engine"]

Binary file not shown.

View File

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

View File

@@ -10,7 +10,7 @@
(doc
(destination build/docs/lua)
(destination build/illuaminate)
(index doc/index.md)
(site
@@ -111,6 +111,6 @@
(lint
(globals
:max sleep write
cct_test describe expect howlci fail it pending stub)))
cct_test describe expect howlci fail it pending stub before_each)))
(at /src/web/mount/expr_template.lua (lint (globals :max __expr__)))

640
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -11,7 +11,7 @@
},
"devDependencies": {
"@rollup/plugin-typescript": "^8.2.5",
"@rollup/plugin-url": "^6.1.0",
"@rollup/plugin-url": "^7.0.0",
"@types/glob": "^7.2.0",
"@types/react-dom": "^18.0.5",
"glob": "^8.0.3",

View File

@@ -1 +0,0 @@
rootProject.name = "cc-tweaked-${mc_version}"

17
settings.gradle.kts Normal file
View File

@@ -0,0 +1,17 @@
pluginManagement {
repositories {
gradlePluginPortal()
maven("https://maven.minecraftforge.net")
maven("https://maven.parchmentmc.org")
}
resolutionStrategy {
eachPlugin {
if (requested.id.id == "org.spongepowered.mixin") {
useModule("org.spongepowered:mixingradle:${requested.version}")
}
}
}
}
val mcVersion: String by settings
rootProject.name = "cc-tweaked-$mcVersion"

View File

@@ -0,0 +1,125 @@
{
"multipart": [
{
"when": {
"OR": [
{"up": "true", "north": "false", "west": "false", "south": "false", "east": "false", "cable": "true"},
{"north": "false", "west": "false", "south": "false", "east": "false", "down": "true", "cable": "true"}
]
},
"apply": {"model": "computercraft:block/cable_core_facing", "x": 90}
},
{
"when": {
"OR": [
{
"up": "false",
"north": "false",
"west": "false",
"south": "false",
"east": "false",
"down": "false",
"cable": "true"
},
{"up": "false", "west": "false", "north": "true", "east": "false", "down": "false", "cable": "true"},
{"up": "false", "west": "false", "south": "true", "east": "false", "down": "false", "cable": "true"}
]
},
"apply": {"model": "computercraft:block/cable_core_facing", "y": 0}
},
{
"when": {
"OR": [
{"up": "false", "north": "false", "south": "false", "east": "true", "down": "false", "cable": "true"},
{"up": "false", "north": "false", "west": "true", "south": "false", "down": "false", "cable": "true"}
]
},
"apply": {"model": "computercraft:block/cable_core_facing", "y": 90}
},
{
"when": {
"OR": [
{"north": "true", "down": "true", "cable": "true"},
{"south": "true", "down": "true", "cable": "true"},
{"west": "true", "down": "true", "cable": "true"},
{"east": "true", "down": "true", "cable": "true"},
{"up": "true", "north": "true", "cable": "true"},
{"up": "true", "south": "true", "cable": "true"},
{"up": "true", "west": "true", "cable": "true"},
{"up": "true", "east": "true", "cable": "true"},
{"north": "true", "west": "true", "cable": "true"},
{"north": "true", "east": "true", "cable": "true"},
{"west": "true", "south": "true", "cable": "true"},
{"south": "true", "east": "true", "cable": "true"}
]
},
"apply": {"model": "computercraft:block/cable_core_any"}
},
{"when": {"down": "true"}, "apply": {"model": "computercraft:block/cable_arm", "x": 270, "y": 0}},
{"when": {"up": "true"}, "apply": {"model": "computercraft:block/cable_arm", "x": 90, "y": 0}},
{"when": {"north": "true"}, "apply": {"model": "computercraft:block/cable_arm", "x": 0, "y": 180}},
{"when": {"south": "true"}, "apply": {"model": "computercraft:block/cable_arm", "x": 0, "y": 0}},
{"when": {"west": "true"}, "apply": {"model": "computercraft:block/cable_arm", "x": 0, "y": 90}},
{"when": {"east": "true"}, "apply": {"model": "computercraft:block/cable_arm", "x": 0, "y": 270}},
{"when": {"modem": "down_off"}, "apply": {"model": "computercraft:block/wired_modem_off", "x": 90, "y": 0}},
{
"when": {"modem": "down_off_peripheral"},
"apply": {"model": "computercraft:block/wired_modem_off_peripheral", "x": 90, "y": 0}
},
{"when": {"modem": "down_on"}, "apply": {"model": "computercraft:block/wired_modem_on", "x": 90, "y": 0}},
{
"when": {"modem": "down_on_peripheral"},
"apply": {"model": "computercraft:block/wired_modem_on_peripheral", "x": 90, "y": 0}
},
{"when": {"modem": "up_off"}, "apply": {"model": "computercraft:block/wired_modem_off", "x": 270, "y": 0}},
{
"when": {"modem": "up_off_peripheral"},
"apply": {"model": "computercraft:block/wired_modem_off_peripheral", "x": 270, "y": 0}
},
{"when": {"modem": "up_on"}, "apply": {"model": "computercraft:block/wired_modem_on", "x": 270, "y": 0}},
{
"when": {"modem": "up_on_peripheral"},
"apply": {"model": "computercraft:block/wired_modem_on_peripheral", "x": 270, "y": 0}
},
{"when": {"modem": "north_off"}, "apply": {"model": "computercraft:block/wired_modem_off", "x": 0, "y": 0}},
{
"when": {"modem": "north_off_peripheral"},
"apply": {"model": "computercraft:block/wired_modem_off_peripheral", "x": 0, "y": 0}
},
{"when": {"modem": "north_on"}, "apply": {"model": "computercraft:block/wired_modem_on", "x": 0, "y": 0}},
{
"when": {"modem": "north_on_peripheral"},
"apply": {"model": "computercraft:block/wired_modem_on_peripheral", "x": 0, "y": 0}
},
{"when": {"modem": "south_off"}, "apply": {"model": "computercraft:block/wired_modem_off", "x": 0, "y": 180}},
{
"when": {"modem": "south_off_peripheral"},
"apply": {"model": "computercraft:block/wired_modem_off_peripheral", "x": 0, "y": 180}
},
{"when": {"modem": "south_on"}, "apply": {"model": "computercraft:block/wired_modem_on", "x": 0, "y": 180}},
{
"when": {"modem": "south_on_peripheral"},
"apply": {"model": "computercraft:block/wired_modem_on_peripheral", "x": 0, "y": 180}
},
{"when": {"modem": "west_off"}, "apply": {"model": "computercraft:block/wired_modem_off", "x": 0, "y": 270}},
{
"when": {"modem": "west_off_peripheral"},
"apply": {"model": "computercraft:block/wired_modem_off_peripheral", "x": 0, "y": 270}
},
{"when": {"modem": "west_on"}, "apply": {"model": "computercraft:block/wired_modem_on", "x": 0, "y": 270}},
{
"when": {"modem": "west_on_peripheral"},
"apply": {"model": "computercraft:block/wired_modem_on_peripheral", "x": 0, "y": 270}
},
{"when": {"modem": "east_off"}, "apply": {"model": "computercraft:block/wired_modem_off", "x": 0, "y": 90}},
{
"when": {"modem": "east_off_peripheral"},
"apply": {"model": "computercraft:block/wired_modem_off_peripheral", "x": 0, "y": 90}
},
{"when": {"modem": "east_on"}, "apply": {"model": "computercraft:block/wired_modem_on", "x": 0, "y": 90}},
{
"when": {"modem": "east_on_peripheral"},
"apply": {"model": "computercraft:block/wired_modem_on_peripheral", "x": 0, "y": 90}
}
]
}

View File

@@ -1,49 +1,16 @@
{
"variants": {
"facing=north,state=off": {
"model": "computercraft:block/computer_advanced_off"
},
"facing=south,state=off": {
"model": "computercraft:block/computer_advanced_off",
"y": 180
},
"facing=west,state=off": {
"model": "computercraft:block/computer_advanced_off",
"y": 270
},
"facing=east,state=off": {
"model": "computercraft:block/computer_advanced_off",
"y": 90
},
"facing=north,state=on": {
"model": "computercraft:block/computer_advanced_on"
},
"facing=south,state=on": {
"model": "computercraft:block/computer_advanced_on",
"y": 180
},
"facing=west,state=on": {
"model": "computercraft:block/computer_advanced_on",
"y": 270
},
"facing=east,state=on": {
"model": "computercraft:block/computer_advanced_on",
"y": 90
},
"facing=north,state=blinking": {
"model": "computercraft:block/computer_advanced_blinking"
},
"facing=south,state=blinking": {
"model": "computercraft:block/computer_advanced_blinking",
"y": 180
},
"facing=west,state=blinking": {
"model": "computercraft:block/computer_advanced_blinking",
"y": 270
},
"facing=east,state=blinking": {
"model": "computercraft:block/computer_advanced_blinking",
"y": 90
}
"facing=east,state=blinking": {"y": 90, "model": "computercraft:block/computer_advanced_blinking"},
"facing=east,state=off": {"y": 90, "model": "computercraft:block/computer_advanced_off"},
"facing=east,state=on": {"y": 90, "model": "computercraft:block/computer_advanced_on"},
"facing=north,state=blinking": {"y": 0, "model": "computercraft:block/computer_advanced_blinking"},
"facing=north,state=off": {"y": 0, "model": "computercraft:block/computer_advanced_off"},
"facing=north,state=on": {"y": 0, "model": "computercraft:block/computer_advanced_on"},
"facing=south,state=blinking": {"y": 180, "model": "computercraft:block/computer_advanced_blinking"},
"facing=south,state=off": {"y": 180, "model": "computercraft:block/computer_advanced_off"},
"facing=south,state=on": {"y": 180, "model": "computercraft:block/computer_advanced_on"},
"facing=west,state=blinking": {"y": 270, "model": "computercraft:block/computer_advanced_blinking"},
"facing=west,state=off": {"y": 270, "model": "computercraft:block/computer_advanced_off"},
"facing=west,state=on": {"y": 270, "model": "computercraft:block/computer_advanced_on"}
}
}

View File

@@ -1,49 +1,16 @@
{
"variants": {
"facing=north,state=off": {
"model": "computercraft:block/computer_command_off"
},
"facing=south,state=off": {
"model": "computercraft:block/computer_command_off",
"y": 180
},
"facing=west,state=off": {
"model": "computercraft:block/computer_command_off",
"y": 270
},
"facing=east,state=off": {
"model": "computercraft:block/computer_command_off",
"y": 90
},
"facing=north,state=on": {
"model": "computercraft:block/computer_command_on"
},
"facing=south,state=on": {
"model": "computercraft:block/computer_command_on",
"y": 180
},
"facing=west,state=on": {
"model": "computercraft:block/computer_command_on",
"y": 270
},
"facing=east,state=on": {
"model": "computercraft:block/computer_command_on",
"y": 90
},
"facing=north,state=blinking": {
"model": "computercraft:block/computer_command_blinking"
},
"facing=south,state=blinking": {
"model": "computercraft:block/computer_command_blinking",
"y": 180
},
"facing=west,state=blinking": {
"model": "computercraft:block/computer_command_blinking",
"y": 270
},
"facing=east,state=blinking": {
"model": "computercraft:block/computer_command_blinking",
"y": 90
}
"facing=east,state=blinking": {"y": 90, "model": "computercraft:block/computer_command_blinking"},
"facing=east,state=off": {"y": 90, "model": "computercraft:block/computer_command_off"},
"facing=east,state=on": {"y": 90, "model": "computercraft:block/computer_command_on"},
"facing=north,state=blinking": {"y": 0, "model": "computercraft:block/computer_command_blinking"},
"facing=north,state=off": {"y": 0, "model": "computercraft:block/computer_command_off"},
"facing=north,state=on": {"y": 0, "model": "computercraft:block/computer_command_on"},
"facing=south,state=blinking": {"y": 180, "model": "computercraft:block/computer_command_blinking"},
"facing=south,state=off": {"y": 180, "model": "computercraft:block/computer_command_off"},
"facing=south,state=on": {"y": 180, "model": "computercraft:block/computer_command_on"},
"facing=west,state=blinking": {"y": 270, "model": "computercraft:block/computer_command_blinking"},
"facing=west,state=off": {"y": 270, "model": "computercraft:block/computer_command_off"},
"facing=west,state=on": {"y": 270, "model": "computercraft:block/computer_command_on"}
}
}

View File

@@ -1,49 +1,16 @@
{
"variants": {
"facing=north,state=off": {
"model": "computercraft:block/computer_normal_off"
},
"facing=south,state=off": {
"model": "computercraft:block/computer_normal_off",
"y": 180
},
"facing=west,state=off": {
"model": "computercraft:block/computer_normal_off",
"y": 270
},
"facing=east,state=off": {
"model": "computercraft:block/computer_normal_off",
"y": 90
},
"facing=north,state=on": {
"model": "computercraft:block/computer_normal_on"
},
"facing=south,state=on": {
"model": "computercraft:block/computer_normal_on",
"y": 180
},
"facing=west,state=on": {
"model": "computercraft:block/computer_normal_on",
"y": 270
},
"facing=east,state=on": {
"model": "computercraft:block/computer_normal_on",
"y": 90
},
"facing=north,state=blinking": {
"model": "computercraft:block/computer_normal_blinking"
},
"facing=south,state=blinking": {
"model": "computercraft:block/computer_normal_blinking",
"y": 180
},
"facing=west,state=blinking": {
"model": "computercraft:block/computer_normal_blinking",
"y": 270
},
"facing=east,state=blinking": {
"model": "computercraft:block/computer_normal_blinking",
"y": 90
}
"facing=east,state=blinking": {"y": 90, "model": "computercraft:block/computer_normal_blinking"},
"facing=east,state=off": {"y": 90, "model": "computercraft:block/computer_normal_off"},
"facing=east,state=on": {"y": 90, "model": "computercraft:block/computer_normal_on"},
"facing=north,state=blinking": {"y": 0, "model": "computercraft:block/computer_normal_blinking"},
"facing=north,state=off": {"y": 0, "model": "computercraft:block/computer_normal_off"},
"facing=north,state=on": {"y": 0, "model": "computercraft:block/computer_normal_on"},
"facing=south,state=blinking": {"y": 180, "model": "computercraft:block/computer_normal_blinking"},
"facing=south,state=off": {"y": 180, "model": "computercraft:block/computer_normal_off"},
"facing=south,state=on": {"y": 180, "model": "computercraft:block/computer_normal_on"},
"facing=west,state=blinking": {"y": 270, "model": "computercraft:block/computer_normal_blinking"},
"facing=west,state=off": {"y": 270, "model": "computercraft:block/computer_normal_off"},
"facing=west,state=on": {"y": 270, "model": "computercraft:block/computer_normal_on"}
}
}

View File

@@ -0,0 +1,16 @@
{
"variants": {
"facing=east,state=empty": {"y": 90, "model": "computercraft:block/disk_drive_empty"},
"facing=east,state=full": {"y": 90, "model": "computercraft:block/disk_drive_full"},
"facing=east,state=invalid": {"y": 90, "model": "computercraft:block/disk_drive_invalid"},
"facing=north,state=empty": {"y": 0, "model": "computercraft:block/disk_drive_empty"},
"facing=north,state=full": {"y": 0, "model": "computercraft:block/disk_drive_full"},
"facing=north,state=invalid": {"y": 0, "model": "computercraft:block/disk_drive_invalid"},
"facing=south,state=empty": {"y": 180, "model": "computercraft:block/disk_drive_empty"},
"facing=south,state=full": {"y": 180, "model": "computercraft:block/disk_drive_full"},
"facing=south,state=invalid": {"y": 180, "model": "computercraft:block/disk_drive_invalid"},
"facing=west,state=empty": {"y": 270, "model": "computercraft:block/disk_drive_empty"},
"facing=west,state=full": {"y": 270, "model": "computercraft:block/disk_drive_full"},
"facing=west,state=invalid": {"y": 270, "model": "computercraft:block/disk_drive_invalid"}
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,20 @@
{
"variants": {
"bottom=false,facing=east,top=false": {"y": 90, "model": "computercraft:block/printer_empty"},
"bottom=false,facing=east,top=true": {"y": 90, "model": "computercraft:block/printer_top_full"},
"bottom=false,facing=north,top=false": {"y": 0, "model": "computercraft:block/printer_empty"},
"bottom=false,facing=north,top=true": {"y": 0, "model": "computercraft:block/printer_top_full"},
"bottom=false,facing=south,top=false": {"y": 180, "model": "computercraft:block/printer_empty"},
"bottom=false,facing=south,top=true": {"y": 180, "model": "computercraft:block/printer_top_full"},
"bottom=false,facing=west,top=false": {"y": 270, "model": "computercraft:block/printer_empty"},
"bottom=false,facing=west,top=true": {"y": 270, "model": "computercraft:block/printer_top_full"},
"bottom=true,facing=east,top=false": {"y": 90, "model": "computercraft:block/printer_bottom_full"},
"bottom=true,facing=east,top=true": {"y": 90, "model": "computercraft:block/printer_both_full"},
"bottom=true,facing=north,top=false": {"y": 0, "model": "computercraft:block/printer_bottom_full"},
"bottom=true,facing=north,top=true": {"y": 0, "model": "computercraft:block/printer_both_full"},
"bottom=true,facing=south,top=false": {"y": 180, "model": "computercraft:block/printer_bottom_full"},
"bottom=true,facing=south,top=true": {"y": 180, "model": "computercraft:block/printer_both_full"},
"bottom=true,facing=west,top=false": {"y": 270, "model": "computercraft:block/printer_bottom_full"},
"bottom=true,facing=west,top=true": {"y": 270, "model": "computercraft:block/printer_both_full"}
}
}

View File

@@ -1,19 +1,8 @@
{
"variants": {
"facing=north": {
"model": "computercraft:block/speaker"
},
"facing=south": {
"model": "computercraft:block/speaker",
"y": 180
},
"facing=west": {
"model": "computercraft:block/speaker",
"y": 270
},
"facing=east": {
"model": "computercraft:block/speaker",
"y": 90
}
"facing=east": {"model": "computercraft:block/speaker", "y": 90},
"facing=north": {"model": "computercraft:block/speaker"},
"facing=south": {"model": "computercraft:block/speaker", "y": 180},
"facing=west": {"model": "computercraft:block/speaker", "y": 270}
}
}

View File

@@ -1,19 +1,8 @@
{
"variants": {
"facing=north": {
"model": "computercraft:block/turtle_advanced"
},
"facing=south": {
"model": "computercraft:block/turtle_advanced",
"y": 180
},
"facing=west": {
"model": "computercraft:block/turtle_advanced",
"y": 270
},
"facing=east": {
"model": "computercraft:block/turtle_advanced",
"y": 90
}
"facing=east": {"model": "computercraft:block/turtle_advanced", "y": 90},
"facing=north": {"model": "computercraft:block/turtle_advanced", "y": 0},
"facing=south": {"model": "computercraft:block/turtle_advanced", "y": 180},
"facing=west": {"model": "computercraft:block/turtle_advanced", "y": 270}
}
}

View File

@@ -1,19 +1,8 @@
{
"variants": {
"facing=north": {
"model": "computercraft:block/turtle_normal"
},
"facing=south": {
"model": "computercraft:block/turtle_normal",
"y": 180
},
"facing=west": {
"model": "computercraft:block/turtle_normal",
"y": 270
},
"facing=east": {
"model": "computercraft:block/turtle_normal",
"y": 90
}
"facing=east": {"model": "computercraft:block/turtle_normal", "y": 90},
"facing=north": {"model": "computercraft:block/turtle_normal", "y": 0},
"facing=south": {"model": "computercraft:block/turtle_normal", "y": 180},
"facing=west": {"model": "computercraft:block/turtle_normal", "y": 270}
}
}

View File

@@ -1,16 +1,8 @@
{
"variants": {
"modem=false,peripheral=false": {
"model": "computercraft:block/wired_modem_full_off"
},
"modem=true,peripheral=false": {
"model": "computercraft:block/wired_modem_full_on"
},
"modem=false,peripheral=true": {
"model": "computercraft:block/wired_modem_full_off_peripheral"
},
"modem=true,peripheral=true": {
"model": "computercraft:block/wired_modem_full_on_peripheral"
}
"modem=false,peripheral=false": {"model": "computercraft:block/wired_modem_full_off"},
"modem=false,peripheral=true": {"model": "computercraft:block/wired_modem_full_off_peripheral"},
"modem=true,peripheral=false": {"model": "computercraft:block/wired_modem_full_on"},
"modem=true,peripheral=true": {"model": "computercraft:block/wired_modem_full_on_peripheral"}
}
}

View File

@@ -1,54 +1,16 @@
{
"variants": {
"facing=down,on=false": {
"model": "computercraft:block/wireless_modem_advanced_off",
"x": 90,
"y": 90
},
"facing=up,on=false": {
"model": "computercraft:block/wireless_modem_advanced_off",
"x": 270,
"y": 90
},
"facing=north,on=false": {
"model": "computercraft:block/wireless_modem_advanced_off"
},
"facing=south,on=false": {
"model": "computercraft:block/wireless_modem_advanced_off",
"y": 180
},
"facing=west,on=false": {
"model": "computercraft:block/wireless_modem_advanced_off",
"y": 270
},
"facing=east,on=false": {
"model": "computercraft:block/wireless_modem_advanced_off",
"y": 90
},
"facing=down,on=true": {
"model": "computercraft:block/wireless_modem_advanced_on",
"x": 90,
"y": 90
},
"facing=up,on=true": {
"model": "computercraft:block/wireless_modem_advanced_on",
"x": 270,
"y": 90
},
"facing=north,on=true": {
"model": "computercraft:block/wireless_modem_advanced_on"
},
"facing=south,on=true": {
"model": "computercraft:block/wireless_modem_advanced_on",
"y": 180
},
"facing=west,on=true": {
"model": "computercraft:block/wireless_modem_advanced_on",
"y": 270
},
"facing=east,on=true": {
"model": "computercraft:block/wireless_modem_advanced_on",
"y": 90
}
"facing=down,on=false": {"y": 0, "x": 90, "model": "computercraft:block/wireless_modem_advanced_off"},
"facing=down,on=true": {"y": 0, "x": 90, "model": "computercraft:block/wireless_modem_advanced_on"},
"facing=east,on=false": {"y": 90, "x": 0, "model": "computercraft:block/wireless_modem_advanced_off"},
"facing=east,on=true": {"y": 90, "x": 0, "model": "computercraft:block/wireless_modem_advanced_on"},
"facing=north,on=false": {"y": 0, "x": 0, "model": "computercraft:block/wireless_modem_advanced_off"},
"facing=north,on=true": {"y": 0, "x": 0, "model": "computercraft:block/wireless_modem_advanced_on"},
"facing=south,on=false": {"y": 180, "x": 0, "model": "computercraft:block/wireless_modem_advanced_off"},
"facing=south,on=true": {"y": 180, "x": 0, "model": "computercraft:block/wireless_modem_advanced_on"},
"facing=up,on=false": {"y": 0, "x": 270, "model": "computercraft:block/wireless_modem_advanced_off"},
"facing=up,on=true": {"y": 0, "x": 270, "model": "computercraft:block/wireless_modem_advanced_on"},
"facing=west,on=false": {"y": 270, "x": 0, "model": "computercraft:block/wireless_modem_advanced_off"},
"facing=west,on=true": {"y": 270, "x": 0, "model": "computercraft:block/wireless_modem_advanced_on"}
}
}

View File

@@ -1,54 +1,16 @@
{
"variants": {
"facing=down,on=false": {
"model": "computercraft:block/wireless_modem_normal_off",
"x": 90,
"y": 90
},
"facing=up,on=false": {
"model": "computercraft:block/wireless_modem_normal_off",
"x": 270,
"y": 90
},
"facing=north,on=false": {
"model": "computercraft:block/wireless_modem_normal_off"
},
"facing=south,on=false": {
"model": "computercraft:block/wireless_modem_normal_off",
"y": 180
},
"facing=west,on=false": {
"model": "computercraft:block/wireless_modem_normal_off",
"y": 270
},
"facing=east,on=false": {
"model": "computercraft:block/wireless_modem_normal_off",
"y": 90
},
"facing=down,on=true": {
"model": "computercraft:block/wireless_modem_normal_on",
"x": 90,
"y": 90
},
"facing=up,on=true": {
"model": "computercraft:block/wireless_modem_normal_on",
"x": 270,
"y": 90
},
"facing=north,on=true": {
"model": "computercraft:block/wireless_modem_normal_on"
},
"facing=south,on=true": {
"model": "computercraft:block/wireless_modem_normal_on",
"y": 180
},
"facing=west,on=true": {
"model": "computercraft:block/wireless_modem_normal_on",
"y": 270
},
"facing=east,on=true": {
"model": "computercraft:block/wireless_modem_normal_on",
"y": 90
}
"facing=down,on=false": {"y": 0, "x": 90, "model": "computercraft:block/wireless_modem_normal_off"},
"facing=down,on=true": {"y": 0, "x": 90, "model": "computercraft:block/wireless_modem_normal_on"},
"facing=east,on=false": {"y": 90, "x": 0, "model": "computercraft:block/wireless_modem_normal_off"},
"facing=east,on=true": {"y": 90, "x": 0, "model": "computercraft:block/wireless_modem_normal_on"},
"facing=north,on=false": {"y": 0, "x": 0, "model": "computercraft:block/wireless_modem_normal_off"},
"facing=north,on=true": {"y": 0, "x": 0, "model": "computercraft:block/wireless_modem_normal_on"},
"facing=south,on=false": {"y": 180, "x": 0, "model": "computercraft:block/wireless_modem_normal_off"},
"facing=south,on=true": {"y": 180, "x": 0, "model": "computercraft:block/wireless_modem_normal_on"},
"facing=up,on=false": {"y": 0, "x": 270, "model": "computercraft:block/wireless_modem_normal_off"},
"facing=up,on=true": {"y": 0, "x": 270, "model": "computercraft:block/wireless_modem_normal_on"},
"facing=west,on=false": {"y": 270, "x": 0, "model": "computercraft:block/wireless_modem_normal_off"},
"facing=west,on=true": {"y": 270, "x": 0, "model": "computercraft:block/wireless_modem_normal_on"}
}
}

View File

@@ -1,8 +1,8 @@
{
"parent": "minecraft:block/orientable",
"textures": {
"side": "computercraft:block/computer_advanced_side",
"top": "computercraft:block/computer_advanced_top",
"front": "computercraft:block/computer_advanced_front_blink",
"top": "computercraft:block/computer_advanced_top"
"side": "computercraft:block/computer_advanced_side"
}
}

View File

@@ -1,8 +1,8 @@
{
"parent": "minecraft:block/orientable",
"textures": {
"side": "computercraft:block/computer_advanced_side",
"top": "computercraft:block/computer_advanced_top",
"front": "computercraft:block/computer_advanced_front",
"top": "computercraft:block/computer_advanced_top"
"side": "computercraft:block/computer_advanced_side"
}
}

View File

@@ -1,8 +1,8 @@
{
"parent": "minecraft:block/orientable",
"textures": {
"side": "computercraft:block/computer_advanced_side",
"top": "computercraft:block/computer_advanced_top",
"front": "computercraft:block/computer_advanced_front_on",
"top": "computercraft:block/computer_advanced_top"
"side": "computercraft:block/computer_advanced_side"
}
}

View File

@@ -1,8 +1,8 @@
{
"parent": "minecraft:block/orientable",
"textures": {
"side": "computercraft:block/computer_command_side",
"top": "computercraft:block/computer_command_top",
"front": "computercraft:block/computer_command_front_blink",
"top": "computercraft:block/computer_command_top"
"side": "computercraft:block/computer_command_side"
}
}

View File

@@ -1,8 +1,8 @@
{
"parent": "minecraft:block/orientable",
"textures": {
"side": "computercraft:block/computer_command_side",
"top": "computercraft:block/computer_command_top",
"front": "computercraft:block/computer_command_front",
"top": "computercraft:block/computer_command_top"
"side": "computercraft:block/computer_command_side"
}
}

View File

@@ -1,8 +1,8 @@
{
"parent": "minecraft:block/orientable",
"textures": {
"side": "computercraft:block/computer_command_side",
"top": "computercraft:block/computer_command_top",
"front": "computercraft:block/computer_command_front_on",
"top": "computercraft:block/computer_command_top"
"side": "computercraft:block/computer_command_side"
}
}

View File

@@ -1,8 +1,8 @@
{
"parent": "minecraft:block/orientable",
"textures": {
"side": "computercraft:block/computer_normal_side",
"top": "computercraft:block/computer_normal_top",
"front": "computercraft:block/computer_normal_front_blink",
"top": "computercraft:block/computer_normal_top"
"side": "computercraft:block/computer_normal_side"
}
}

View File

@@ -1,8 +1,8 @@
{
"parent": "minecraft:block/orientable",
"textures": {
"side": "computercraft:block/computer_normal_side",
"top": "computercraft:block/computer_normal_top",
"front": "computercraft:block/computer_normal_front",
"top": "computercraft:block/computer_normal_top"
"side": "computercraft:block/computer_normal_side"
}
}

View File

@@ -1,8 +1,8 @@
{
"parent": "minecraft:block/orientable",
"textures": {
"side": "computercraft:block/computer_normal_side",
"top": "computercraft:block/computer_normal_top",
"front": "computercraft:block/computer_normal_front_on",
"top": "computercraft:block/computer_normal_top"
"side": "computercraft:block/computer_normal_side"
}
}

View File

@@ -0,0 +1,8 @@
{
"parent": "minecraft:block/orientable",
"textures": {
"top": "computercraft:block/disk_drive_top",
"front": "computercraft:block/disk_drive_front",
"side": "computercraft:block/disk_drive_side"
}
}

View File

@@ -0,0 +1,8 @@
{
"parent": "minecraft:block/orientable",
"textures": {
"top": "computercraft:block/disk_drive_top",
"front": "computercraft:block/disk_drive_front_accepted",
"side": "computercraft:block/disk_drive_side"
}
}

View File

@@ -0,0 +1,8 @@
{
"parent": "minecraft:block/orientable",
"textures": {
"top": "computercraft:block/disk_drive_top",
"front": "computercraft:block/disk_drive_front_rejected",
"side": "computercraft:block/disk_drive_side"
}
}

View File

@@ -1,8 +1,9 @@
{
"parent": "minecraft:block/orientable",
"parent": "computercraft:block/monitor_base",
"textures": {
"side": "computercraft:block/monitor_advanced_4",
"front": "computercraft:block/monitor_advanced_15",
"top": "computercraft:block/monitor_advanced_0"
"side": "computercraft:block/monitor_advanced_4",
"top": "computercraft:block/monitor_advanced_0",
"back": "computercraft:block/monitor_advanced_32"
}
}

View File

@@ -1,8 +1,9 @@
{
"parent": "minecraft:block/orientable",
"parent": "computercraft:block/monitor_base",
"textures": {
"side": "computercraft:block/monitor_normal_4",
"front": "computercraft:block/monitor_normal_15",
"top": "computercraft:block/monitor_normal_0"
"side": "computercraft:block/monitor_normal_4",
"top": "computercraft:block/monitor_normal_0",
"back": "computercraft:block/monitor_normal_32"
}
}

View File

@@ -0,0 +1,8 @@
{
"parent": "minecraft:block/orientable",
"textures": {
"top": "computercraft:block/printer_top",
"front": "computercraft:block/printer_front_both_trays",
"side": "computercraft:block/printer_side"
}
}

View File

@@ -0,0 +1,8 @@
{
"parent": "minecraft:block/orientable",
"textures": {
"top": "computercraft:block/printer_top",
"front": "computercraft:block/printer_front_bottom_tray",
"side": "computercraft:block/printer_side"
}
}

View File

@@ -0,0 +1,8 @@
{
"parent": "minecraft:block/orientable",
"textures": {
"top": "computercraft:block/printer_top",
"front": "computercraft:block/printer_front_empty",
"side": "computercraft:block/printer_side"
}
}

View File

@@ -0,0 +1,8 @@
{
"parent": "minecraft:block/orientable",
"textures": {
"top": "computercraft:block/printer_top",
"front": "computercraft:block/printer_front_top_tray",
"side": "computercraft:block/printer_side"
}
}

View File

@@ -1,8 +1,8 @@
{
"parent": "minecraft:block/orientable",
"textures": {
"side": "computercraft:block/speaker_side",
"top": "computercraft:block/speaker_top",
"front": "computercraft:block/speaker_front",
"top": "computercraft:block/speaker_top"
"side": "computercraft:block/speaker_side"
}
}

View File

@@ -1,4 +1 @@
{
"loader": "computercraft:turtle",
"model": "computercraft:block/turtle_advanced_base"
}
{"parent": "computercraft:block/turtle_base", "textures": {"texture": "computercraft:block/turtle_advanced"}}

View File

@@ -1,6 +0,0 @@
{
"parent": "computercraft:block/turtle_base",
"textures": {
"texture": "computercraft:block/turtle_advanced"
}
}

View File

@@ -0,0 +1,4 @@
{
"parent": "computercraft:block/turtle_upgrade_base_left",
"textures": {"texture": "computercraft:block/turtle_crafty_face"}
}

View File

@@ -0,0 +1,4 @@
{
"parent": "computercraft:block/turtle_upgrade_base_right",
"textures": {"texture": "computercraft:block/turtle_crafty_face"}
}

View File

@@ -0,0 +1,4 @@
{
"parent": "computercraft:block/turtle_upgrade_base_left",
"textures": {"texture": "computercraft:block/wireless_modem_advanced_face"}
}

View File

@@ -0,0 +1,4 @@
{
"parent": "computercraft:block/turtle_upgrade_base_right",
"textures": {"texture": "computercraft:block/wireless_modem_advanced_face"}
}

View File

@@ -0,0 +1,4 @@
{
"parent": "computercraft:block/turtle_upgrade_base_left",
"textures": {"texture": "computercraft:block/wireless_modem_advanced_face_on"}
}

View File

@@ -0,0 +1,4 @@
{
"parent": "computercraft:block/turtle_upgrade_base_right",
"textures": {"texture": "computercraft:block/wireless_modem_advanced_face_on"}
}

View File

@@ -0,0 +1,4 @@
{
"parent": "computercraft:block/turtle_upgrade_base_left",
"textures": {"texture": "computercraft:block/wireless_modem_normal_face"}
}

View File

@@ -0,0 +1,4 @@
{
"parent": "computercraft:block/turtle_upgrade_base_right",
"textures": {"texture": "computercraft:block/wireless_modem_normal_face"}
}

View File

@@ -0,0 +1,4 @@
{
"parent": "computercraft:block/turtle_upgrade_base_left",
"textures": {"texture": "computercraft:block/wireless_modem_normal_face_on"}
}

View File

@@ -0,0 +1,4 @@
{
"parent": "computercraft:block/turtle_upgrade_base_right",
"textures": {"texture": "computercraft:block/wireless_modem_normal_face_on"}
}

View File

@@ -1,4 +1 @@
{
"loader": "computercraft:turtle",
"model": "computercraft:block/turtle_normal_base"
}
{"parent": "computercraft:block/turtle_base", "textures": {"texture": "computercraft:block/turtle_normal"}}

View File

@@ -1,6 +0,0 @@
{
"parent": "computercraft:block/turtle_base",
"textures": {
"texture": "computercraft:block/turtle_normal"
}
}

View File

@@ -0,0 +1,4 @@
{
"parent": "computercraft:block/turtle_upgrade_base_left",
"textures": {"texture": "computercraft:block/turtle_speaker_face"}
}

View File

@@ -0,0 +1,4 @@
{
"parent": "computercraft:block/turtle_upgrade_base_right",
"textures": {"texture": "computercraft:block/turtle_speaker_face"}
}

View File

@@ -1,6 +1 @@
{
"parent": "minecraft:block/cube_all",
"textures": {
"all": "computercraft:block/wired_modem_face"
}
}
{"parent": "minecraft:block/cube_all", "textures": {"all": "computercraft:block/wired_modem_face"}}

View File

@@ -1,6 +1 @@
{
"parent": "minecraft:block/cube_all",
"textures": {
"all": "computercraft:block/wired_modem_face_peripheral"
}
}
{"parent": "minecraft:block/cube_all", "textures": {"all": "computercraft:block/wired_modem_face_peripheral"}}

View File

@@ -1,6 +1 @@
{
"parent": "minecraft:block/cube_all",
"textures": {
"all": "computercraft:block/wired_modem_face_on"
}
}
{"parent": "minecraft:block/cube_all", "textures": {"all": "computercraft:block/wired_modem_face_on"}}

View File

@@ -1,6 +1 @@
{
"parent": "minecraft:block/cube_all",
"textures": {
"all": "computercraft:block/wired_modem_face_peripheral_on"
}
}
{"parent": "minecraft:block/cube_all", "textures": {"all": "computercraft:block/wired_modem_face_peripheral_on"}}

View File

@@ -1,7 +1,4 @@
{
"parent": "computercraft:block/modem",
"textures": {
"front": "computercraft:block/wired_modem_face",
"back": "computercraft:block/modem_back"
}
"textures": {"front": "computercraft:block/wired_modem_face", "back": "computercraft:block/modem_back"}
}

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