MC 1.21.4 means we have to move more data generation code into the
client source set. Given all this code movement, it probably makes sense
to put data generation in a separate source set instead.
1.21.4 also has split data generators for client and server, but neither
mod loader recommends this. This means we can/should merge DataProviders
and ClientDataProviders into a single class.
Data generators are no longer bundled with the jar, which does reduce
file size, but by a tiny amount (~70KiB).
This was only present on the 1.21 NF version, hence not being noticed
before. Fixes#2020.
I pruned my Gradle cache recently, and I'm on some truly terrible hotel
wifi, so this is entirely untested. No beta, we die like men.
I've tried so many rewrites of the config system over the last few
months, in an attempt to get started on #1727. All of them stink, so
this is an attempt to apply some of the cleanup.
- Move some of the common logic into ConfigFile. This means we now
store more information ourselves for Forge, rather than reading it
out of the ForgeConfigSpec.
- Don't include the Range/Allowed keys in the translation key. This was
mostly there because of how we read comments from Forge, but it never
made much sense.
- Remove our separate Trie structure, and just encode the tree as part
of the children of a Group.
If the cursor is not visible then we'd end up blinking the last
character on the screen. And if the screen was empty we'd spew the logs
with GL errors.
Some mods run their own datafixer chain, rather than piggybacking on top
of vanilla's. This is A BAD IDEA, but what can you do. If such a mod
tries to use ItemStackComponentizationFix in their own schema, then
CC:T's mixins will try to look up the turtle block entitie, and fail (as
they're not registered under the modded schema).
We now inject the block entity fix as a separate fixer, rather than
abusing ItemStackComponentizationFix.
See #2012
- 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
4228011b848e99de64eb79c26598d81490c32bad, and I'm sure I tested it then.
Fixes#2013. Probably.
Been dragging my feet over this for a while now, but increasingly
uncomfortable with Overwolf. I'm not going to delete the project (or any
existing versions), just not publish any new versions there.
- Don't construct a fake player when crafting: vanilla now has its own
automated crafting, so no longer requires the presence of a player.
- Fix remainder stack not being set in some situations. Closes#2007.
- 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 (0908acbe9bbb63d9c1be513d098e9a14d5bb68e3). 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
v4 of the action seems to be much more restrictive in what can upload
coveage. I'll miss this (the historic view of coverage was nice!), but
not worth trying to get working again.
We also stop running client tests. These break so often, we only really
ran them for code coverage reasons.
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 ed0b156e05ff64784f2f80346c82ab5142d954dc 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
The update to Python 3.12 has broken the pre-commit action (as it
installs via pip rather than pipx). The maintainer seems unwilling to
fix it (to put it diplomatically), so let's just stop using the action
and imlement it ourselves.
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.