BYTECODE WAS NOT SUPPOSED TO BE REWRITTEN
YEARS OF DEBUGGING REMAPPING FAILURES yet NO ACTUAL SOLUTION FOUND.
Wanted to use Mixins for anyway for a laugh? We had a tool for that: it
was called "FABRIC LOOM".
"Yes, please produce completely broken jars for no discernable reason"
Statements dreamed up by the utterly Deranged.
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
This removes our two mixins used on Forge:
- Breaking progress for cabled/wired modems.
- Running client commands from chat click events. We now suggest the
command on Forge instead.
Occasionally we get issues where the mixin annotation processor doesn't
write its tsrg file in time for the reobfJar/reobfJarJar task. I thought
we'd fixed that cb8e06af2a, but sometimes
we still produce missing jars - I have a feeling this might be to do
with incremental compilation.
We can maybe re-evaluate this on 1.20.4, where we don't need to worry
about remapping any more.
Here's a fun bug you can try at home:
- Create a new world
- Spawn in a pocket computer, turn it on, and place it in a chest.
- Reload the world - the pocket computer in the chest should now be
off.
- Spawn in a new pocket computer, and turn it on. The computer in chest
will also appear to be on!
This bug has been present since pocket computers were added (27th March,
2024).
When a pocket computer is added to a player's inventory, it is assigned
a unique *per-session* "instance id" , which is used to find the
associated computer. Note the "per-session" there - these ids will be
reused if you reload the world (or restart the server).
In the above bug, we see the following:
- The first pocket computer is assigned an instance id of 0.
- After reloading, the second pocket computer is assigned an instance
id of 0.
- If the first pocket computer was in our inventory, it'd be ticked and
assigned a new instance id. However, because it's in an inventory, it
keeps its old one.
- Both computers look up their client-side computer state and get the
same value, meaning the first pocket computer mirrors the second!
To fix this, we now ensure instance ids are entirely unique (not just
per-session). Rather than sequentially assigning an int, we now use a
random UUID (we probably could get away with a random long, but this
feels more idiomatic).
This has a couple of user-visible changes:
- /computercraft no longer lists instance ids outside of dumping an
individual computer.
- The @c[instance=...] selector uses UUIDs. We still use int instance
ids for the legacy selector, but that'll be removed in a later MC
version.
- Pocket computers now store a UUID rather than an int.
Related to this change (I made this change first, but then they got
kinda mixed up together), we now only create PocketComputerData when
receiving server data. This makes the code a little uglier in some
places (the data may now be null), but means we don't populate the
client-side pocket computer map with computers the server doesn't know
about.
- Add a check to ensure declared dependencies in the :core project, and
those inherited from Minecraft are the same.
- Compute the next Cobalt version, rather than specifying it manually.
- Add the gradle versions plugin (and version catalog update), and
update some versions.
- Update Cobalt to 0.8.0, switching our Lua version to 5.2(ish).
- Remove our `load` wrapper, as we no longer need to inject _ENV into
the enviroment table.
- Update the parser to handle labels and goto. This doesn't check that
gotos are well formed, but at least means the parser doesn't fall
over on them.
- Update our docs to reflect the changes to Cobalt.
Historically we've used copy-cat to provide a web-based emulator for
running example code on our documentation site. However, copy-cat is
often out-of-date with CC:T, which means example snippets fail when you
try to run them!
This commit vendors in copy-cat (or rather an updated version of it)
into CC:T itself, allowing us to ensure the emulator is always in sync
with the mod.
While the ARCHITECTURE.md documentation goes into a little bit more
detail here, the general implementation is as follows
- In project/src/main we implement the core of the emulator. This
includes a basic reimplementation of some of CC's classes to work on
the web (mostly the HTTP API and ComputerThread), and some additional
code to expose the computers to Javascript.
- This is all then compiled to Javascript using [TeaVM][1] (we actually
use a [personal fork of it][2] as there's a couple of changes I've
not upstreamed yet).
- The Javascript side then pulls in the these compiled classes (and
the CC ROM) and hooks them up to [cc-web-term][3] to display the
actual computer.
- As we're no longer pulling in copy-cat, we can simplify our bundling
system a little - we now just compile to ESM modules directly.
[1]: https://github.com/konsoletyper/teavm
[2]: https://github.com/SquidDev/teavm/tree/squid-patches
[3]: https://github.com/squiddev-cc/cc-web-term
Had an issue last week where testFixtures had a couple of issues which I
didn't pick up on, as the pre-commit hooks only check the main and test
source set.
We now add a per-project "checkstyle" task, which dependes on the
per-source-set checkstyle tasks.
I removed this in aa0d544bba, way back in
late 2021. Looks like it's been updating in the meantime and I hadn't
noticed, so add it back.
I've simplified the code a little bit, to make use of our new capability
helpers, but otherwise it's almost exactly the same :D.
- Add a generic PermissionRegistry interface. This behaves similarly to
our ShaderMod interface, searching all providers until it finds a
compatible one.
We could just make this part of the platform code instead, but this
allows us to support multiple systems on Fabric, where things are
less standardised.
This interface behaves like a registry, rather than a straight
`getPermission(node, player)` method, as Forge requires us to list
our nodes up-front.
- Add Forge (using the built-in system) and Fabric (using
fabric-permissions-api) implementations of the above interface.
- Register permission nodes for our commands, and use those
instead. This does mean that the permissions check for the root
/computercraft command now requires enumerating all child
commands (and so potential does 7 permission lookups), but hopefully
this isn't too bad in practice.
- Remove UserLevel.OWNER - we never used this anywhere, and I can't
imagine we'll want to in the future.
- Split the front face of the computer model into two layers - one for
the main texture, and one for the cursor. This is actually a
simplification of what we had before, which is nice.
- Make the cursor layer render as an emissive quad, meaning it glows in
the dark. This is very easy on Forge (just some model JSON) and very
hard on Fabric (requires a custom model loader).
- Add a new recipe type for turtle overlays, and recipe generator
support for this recipe.
- Add trans and rainbow flags.
- Exclude .license files from the generated jar. I'm not thrilled on
the whole .license file system, but it's kinda the easiest way.
- Regenerate data. Yes, this is 90% of the commit :D.
This adds SPDX license headers to all source code files, following the
REUSE[1] specification. This does not include any asset files (such as
generated JSON files, or textures). While REUSE does support doing so
with ".license" files, for now we define these licences using the
.reuse/dep5 file.
[1]: https://reuse.software/
While it is a really nice library, it ends up being a bit overkill for
our needs - we don't need config syncing or anything. By NIHing our own,
we can drop one dependency and ease the updating burden a little.
Closes#1296
Mostly in prep for 1.19.4.
- Update to Loom 1.1.
- Simplifies our handling of remapped configurations a little.
- Removes the need for a fake fabric.mod.json in the API jar.
For reasons I don't quite understand, this required us to bump the
Fabric API version. Otherwise interfaces are not injected.
- Update to Rollup 3.0.
- Do NOT update NullAway: It now correctly checks @Nullable fields in
inherited classes. This is good, but also a pain as Minecraft is a
little over-eager in where it puts @Nullable.
I was originally pretty sceptical about this, but it actually ends up
being useful for the same reason any other form of datagen is: we can
ensure that names are well formed, and that every string is actually
translated.
There's some future work here to go through all the custom translation
keys and move them into constants (maybe also do something with the
/computercraft command?), but that's a separate chunk of work.
The main motivation for this is to add translation keys to our config:
the Fabric version of Forge Config API provides a config UI, so it's
useful to provide user-friendly strings. Our generator also
automatically copies comments over, turning them into tooltips.
This also updates all of the other language files to match en_us.json
again: it's a very noisy diff as the file is now sorted alphabetically.
Hopefully this won't affect weblate though
[^1]: Amusing really that the Fabric port actually is more useful than
the original.
This fixes several issues I had with consuming multi-loader CC:T in
various upstream mods.
- Include /all/ sources in the Forge/Fabric jar. Before it was just the
common classes, and not the core or API.
- Use some Gradle magic to remove superfluous dependencies from the POM
file. Also make sure Cobalt and Netty are present as dependencies.
- Start using minimize() in our shadow jar config again.
- Add support for Fabric. This is mostly pretty simple, though does
require a lot more mixins than Forge.
Half this diff is due to data generators: we run them separately as
some aspects (recipes mostly) are different between the loaders.
- Add integration with Iris (same as our Oculus support) and REI
(mostly the same as our JEI support).
- Generic peripherals only support inventories (or rather
InventoryStorage) right now. Supporting more of the Fabric storage
API is going to be tricky due to the slotted nature of the API: maybe
something to revisit after Transfer API V3 (V4?, I've lost track).
Note, this does /not/ mean I will be publishing a Fabric version of
CC:T. My plan is to rebase CC:R on top of this, hopefully simplifying
the maintenance work on their end and making the two mods a little more
consistent.
- Publish javadoc again: for now this is just the common-api
- Remove all dependencies from the published Forge jar. This is
technically not needed (fg.deobf does this anyway), but seems
sensible.
It should be possible to consume the ComputerCraft's core (i.e.
non-Minecraft code) in other projects, such as emulators. While this
has been possible for years, it's somewhat tricky from a maintenance
perspective - it's very easy to accidentally add an MC dependency
somewhere!
By publishing a separate "core" jar, we can better distinguish the
boundaries between our Lua runtime and the Minecraft-specific code.
Ideally we could have one core project (rather than separate core and
core-api modules), and publish a separate "api" jar, like we do for the
main mod. However, this isn't really possible to express using Maven
dependencies, and so we must resort to this system.
Of course, this is kinda what the Java module system is meant to solve,
but unfortunately getting that working with Minecraft is infeasible.
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).
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.
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.