- Use the correct index count for the cursor quad. Monitors are now
rendered as quads, rather than triangles.
- *Skip* rendering the cursor vertex, rather than additionally
rendering it.
I confess, I'm baffled how this code was ever written. From what I can
tell, this has been broken since it was first introduced in
4228011b84, and I'm sure I tested it then.
Fixes#2013. Probably.
- Move redstone methods out of the IAPIEnvironment, and into a new
RedstoneAccess. We similarly move the implementation from Environment
into a new RedstoneState class.
The interface is possibly a little redundant (interfaces with a
single implementation are always a little suspect), but it's nice to
keep the consumer/producer interfaces separate.
- Abstract most redstone API methods into a separate shared class, that
can be used by both the rs API and the new redstone relay.
- Add the new redstone relay block.
The docs are probably a little lacking here, but I really struggled to
write anything which wasn't just "look, it's the same as the redstone
API".
Several functions accept a "timeout" argument, which is implemented by
starting a timer, and then racing the desired output against the timer
event.
However, if the timer never wins, we weren't cancelling the timer, and
so it was still queued. This is especially problematic if dozens or
hundreds of rednet (or websocket) messages are received in quick
succession, as we could fill the entire event queue, and stall the
computer.
See #1995
As part of the multi-loader work, we unified some of our event listening
code (0908acbe9b). This incorrectly caused
client pocket computer state to be reset when the player changes
dimension, rather than when the player (dis)connects.
The server code isn't aware of this behaviour, and so does not resend
pocket computer state when the player moves level. We could change this,
but just fixing when we clear the pocket computer state is a much nicer
fix!
Fixes#2004
The most annoying thing about pocket computers is handling computer
state (label, upgrades, etc...). Unlike other computers, which are tied
to a specific block entity, pocket computers float untethered. We can't
hold a reference to a specific item stack (as the computer might be
moved between inventories, crafted, etc...), so instead we explicitly
sync data between the computer and *current* stack, whenever the holding
player/entity is ticked.
In ed0b156e05 I rewrote this syncing code
to always treat the computer as the source of truth. Upgrades would be
copied to the computer, but never the other way round. However, this
meant that upgrades obtained by crafting would never be detected,
requiring the computer to be destroyed and recreated.
A more long-term fix here is probably to rewrite IPocketAccess to only
allow updating upgrade data on the main thread, and when we have a valid
PocketHolder. This is a breaking API change though, and so will have to
wait for 1.21.3.
For now, we just add a hook that refreshes the upgrade after crafting.
Fixes#1957
One of the easiest things to mess up with writing a custom peripheral is
handling attached peripherals. IPeripheral.{attach,detach} are called
from multiple threads, so naive implementations that just store
computers in a set/list will at some point throw a CME.
Historically I've suggested using a concurrent collection (i.e.
ConcurrentHashMap). While this solves the problems of CMEs, it still has
some flaws. If a computer is detached while iterating over the
collection, the iterator will still yield the now-detached peripheral,
causing usages of that computer (e.g. queueEvent) to throw an exception.
The only fix here is to use a lock when updating and iterating over the
collection. This does come with some risks, but I think they are not too
serious:
- Lock contention: Contention is relatively rare in general (as
peripheral attach/detach is not especially frequent). If we do see
contention, both iteration and update actions are cheap, so I would
not expect the other thread to be blocked for a significant time.
- Deadlocks: One could imagine an implementation if IComputerAccess
that holds a lock both when detaching a peripheral and inside
queueEvent.
If we queue an event on one thread, and try to detach on the other,
we could see a deadlock:
Thread 1 | Thread 2
----------------------------------------------------------
AttachedComputerSet.queueEvent | MyModem.detach
(take lock #1) | (take lock #2)
-> MyModem.queueEvent | AttachedComputerSet.remove
(wait on lock #2) | (wait on lock #1)
Such code would have been broken already (some peripherals already
use locks), so I'm fairly sure we've fixed this in CC. But definitely
something to watch out for.
Anyway, the long and short of it:
- Add a new AttachedComputerSet that can be used to track the computers
attached to a peripheral. We also mention this in the attach/detach
docs, to hopefully make it a little more obvoius.
- Update speakers and monitors to use this new class.
Under Forge, netty-codec lives on the BOOT layer. However, this means it
does not have access to our jzlib (which lives on the GAME layer). To
fix this, we now shadow netty-codec (and its dependents, like netty-http
and netty-proxy) rather than jar-in-jaring them.
This involves some horrible build logic, but means websocket compression
works on Forge.
Fixes#1958.
- Place the player above the test region before running tests. This
guarantees the client has the chunks loaded (and rendered) before we
start running tests.
- Reset the time after running the monitor/printout tests.
- Fix rotation of turtle item models.
This still isn't perfect - the first test still fails with Iris and
Sodium - but is an improvement. Probably will still fail in CI though
:D:.
Previously we used an RGBA byte array. However, this comes with some
overhead (extra memory reads, bounds checks).
Minecraft 1.21+ uses ARGB32 colours for rendering (well, in the public
code — internaly it converts to ABGR), so it makes sense to match that
here.
We also add some helper functions for dealing with ARGB32 colours. These
can be removed in 1.21, as Minecraft will have these builtin.
This probably isn't useful in practice — nobody is escaping 1MB of data.
Right. Right???? But no harm in doing it.
- Cache globals as locals.
- Remove redundant pattern capture.
- Merge string.format calls into one.
Also remove the "if str then" check. I assume we accepted nil values a
long time ago, but that was broken when we added arg checks. Woops!
While mods shouldn't be depending on common, sometimes it's unavoidable
(e.g. for cc-prometheus). In those cases, you want all the CC classes
available, not just the common ones.
In cdcd82679c, we rewrote the Lua
conversion function to update the "Java -> Lua" mapping after
conversion, rather than part way through.
This made the code a little cleaner (as we only updated the mapping in
one place), but is entirely incorrect — we need to store the object
first, in order to correctly handle recursive objects — otherwise we'll
just recurse infinitely (or until we overflow).
This partially reverts the above commit, while preserving the new
behaviour for singleton collections.
Fixes#1955.
Even more of these! I really need to stop getting bored half way through
writing sentences and then continue writing at the wrong place. Or,
y'know, get better at proof reading.
While Item.inventoryTick is passed a slot number, apparently that slot
corresponds to the offset within a particular inventory compartment
(such as the main inventory or armour)[^1], rather than the inventory as
a whole.
In the case of the off-hand, this means the pocket computer is set to be
in slot 0. When we next tick the computer (to send terminal updates), we
then assume the item has gone missing, and so skip sending updates.
Fixes#1945.
[^1]: A fun side effect of this is that the "selected" flag is true for
the off-hand iff the player has slot 0 active. This whole thing feels
like a vanilla bug, but who knows!
- Mention only diamond tools can be used as upgrades, and be clearer
that only the pickaxe and sword are actually useful. We probably
could be more explicit here, but struggled to find a way to do that.
- Expliitly list which peripherals can be equipped.
- Add turtle recipes.
It's not entirely clear what the correct behaviour of fs.getDir("..")
should be, and there's not much consensus between various languages.
I think the intended behaviour of this function is to move "up" one
directory level in the path, meaning it should return "../..".
CC tries to preserve sharing of objects when crossing the Lua/Java
boundary. For instance, if you queue (or send over a modem)
`{ tbl, tbl }`, then the returned table will have `x[1] == x[2]`.
However, this sharing causes issues with Java singletons. If some code
uses a singleton collection (such as List.of()) in multiple places, then
the same Lua table will be used in all those locations. It's incredibly
easy to accidentally, especially when using using Stream.toList.
For now, we special case these collections and don't de-duplicate them.
I'm not wild about this (it's a bit of a hack!), but I think it's
probably the easiest solution for now.
Fixes#1940
- Add a new custom lectern block, that is used to hold the printed
pages. We have to roll quite a lot of custom logic, so this is much
cleaner than trying to mixin to the existing lectern code.
- Add a new (entity) model for printed pages and books placed on a
lectern. I did originally think about just rendering the item (or the
in-hand/map version), but I think this is a bit more consistent with
vanilla.
However, we do still need to sync the item to the client (mostly to
get the current page count!). There is a risk of chunkbanning here,
but I think it's much harder than vanilla, due to the significantly
reduced page limit.
Rather than having a general "held-item" container, we now have a
specialised one for printouts. This now is a little more general,
supporting any container (not just the player inventory), and syncs the
current page via a data slot.
Currently this isn't especially useful, but should make it a little
easier to add lectern support in the future.
There's a whole load of gnarly issues that occur when a turtle is broken
mid-dig/attack (normally due to an explosion). We fixed most of these in
24af36743d, but not perfectly.
Part of the fix here was to not capture drops if the turtle BE has been
removed. However, on removal, turtles drop their items *before* removing
the BE. This meant that the drop consumer still triggered, and attempted
to insert items back into the turtle.
This bug only triggers if the turtle contains a stack larger than 10
(ish, I think) items, which is possibly why I'd never reproduced before.
We now drop items after removing the BE, which resolves the issue.
Fixes#1936.