- Remove unused MonitorRenderer. I'm sure this had been deleted
already, but apparently not!
- Add missing items to the changelog.
- Fix crash when clearing tests in a world.
- Bump Iris deps, to help with debugging #2229.
I don't love the implementation of this (see discussion in #2220), but
it's better than nothing. Wow, the editor really needs a bit of a
rewrite, the code is kinda messy.
Fixes#1396.
I've been putting this off for a while, as I had issues in the past with
people using old Node versions (e.g. #1806), but it no long works on my
machine, so time to make the switch.
Also do a bit of a package update. Hit a rollup bug while doing this
(https://github.com/rollup/plugins/issues/1877), so holding that update
back for now.
This is slightly more accurate for long strings and comments. Note that
we still work a line at a time (and in a non-incremental manner), so
doesn't actaully support multi-line strings (#1396).
We do now treat goto as a keyword (fixes#1653). We don't currently
support labels — those *technically* aren't a token (`:: foo --[[ a
comment ]] ::` is a valid label!), but maybe we could special-case the
short `::foo::` form.
This allows equipping pocket computers on both the back (as before) and
bottom of a pocket computer. The asymmetry is a little unfortunate here,
but makes some sense with the crafting recipe (above goes behind, below
goes on the bottom).
- Move some functionality from IPocketAccess into a PocketComputer
interface (and PocketComputerInternal) interface, used by the pocket
API.
IPocketAccess preserves the same interface as before. Unlike
ITurtleAccess, we /don't/ expose the PocketSide in the public API.
- Several pocket-computer methods (e.g. setUpgradeData, setColour) are
now required to be called on the main thread, and when the computer
is being held. This allows us to write back changes to the item
immediately, rather than the next time the item is ticked.
Sadly this doesn't actually remove the need for onCraftedPostProcess
as I'd originally hoped, but I think does make the code a little
simpler.
- Rename "computercraft:pocket_computer" component to
"computercraft:back_pocket_computer".
- And finally, support multiple upgrades on the pocket computer. This
is actually quite an easy change, just tedious — there's lots of
places to update!
Fixes#1406, and I think fixes#1148 — you can use a speaker to notify
you now.
Reverts 76968f2f28. We'd originally added
this to gather some numbers for #1580, with the hope that it would also
be useful for server admins. Sadly, it's not as accurate as I originally
hoped — the number sometimes goes down for unclear reasons (something to
do with the TLAB maybe??).
Closes#1739.
The main thing of note is Spotless, which also bumps the version of
Ktlint. I've been putting this off for a while[^1], as this changed a
bunch of formatting, and Spotless's (broken) caching was making it hard
to test. Ended up downloading ktlint and running it localy.
[^1]: 8204944b5f
- Fix isValidClipboard always returning true.
- Fix characters >=128 being rejected. We changed the signature from a
byte to an int in 0f123b5efd, but
didn't update all call sites.
Valhalla cannot come soon enough. I would love to be able to have
(cheap) wrapper classes for some of these types.
See Zeus-guy's comments in #860.
Now, hear me out, what if instead of having three @Nullable annotations,
we had *four*?
I've been wanting to switch away from javax.annoations for a while. The
library has been deprecated for ever and, unlike other @Nullable
annotations, the annotation is attached to the parameter/function
itself, rather than the type.
We use JSpecify rather than one of the alternatives (JetBrains,
CheckerFramework) mostly because it's what NullAway recommends. We keep
CheckerFramework around for @DefaultQualifier, and JB's for @Contract.
There are some ugly changes here — for instance, `@Nullable byte[]` is
replace by `byte @Nullable`, and `@Nullable ILuaMachine.Factory` is
`ILuaMachine.@Nullable Factory`. Ughr, I understand why, but it does not
spark joy :).
We now suggest alternative table keys when code errors with "attempt
to index/call 'foo' (a nil value)". For example: "redstone.getinput()",
will now suggest "Did you mean: getInput".
This is a bit tricky to get right! In the above example, our code reads
like:
1 GETTABUP 0 0 0 ; r0 := _ENV["redstone"]
2 GETFIELD 0 0 1 ; r0 := r0["getinput"]
3 CALL 0 1 1 ; r0()
Note, that when we get to the problematic line, we don't have access to
the original table that we attempted to index. In order to do this, we
borrow ideas from Lua's getobjname — we effectively write an evaluator
that walks back over the code and tries to reconstruct the expression
that resulted in nil.
For example, in the above case:
- We know an instruction happened at pc=3, so we try to find the
expression that computed r0.
- We know this was set at pc=2, so we step back one. This is a GETFIELD
instruction, so we check the key (it's a constant, so worth
reporting), and then try to evaluate the table.
- This version of r0 was set at pc=1, so we step back again. It's a
GETTABUP instruction, so we can just evaluate that directly.
We then use this information (indexing _ENV.redstone with "getinput") to
find alternative keys (e.g. getInput, getOutput, etc...) and then pick
some likely suggestions with Damerau-Levenshtein/OSD.
I'm not entirely thrilled by the implementation here. The core
interpretation logic is implemented in Java. Which is *fine*, but a)
feels a little cheaty and b) means we're limited to what Lua bytecode
can provide (for instance, we can't inspect outer functions, or list all
available names in scope). We obviously can expand the bytecode if
needed, but something we'd want to be careful with.
The alternative approach would be to handle all the parsing in
Lua. Unfortunately, this is quite hard to get right — I think we'd need
some lazy parsing strategy to avoid constructing the whole AST, while
still retaining all the scope information we need.
I don't know. We really could make this as complex as we like, and I
don't know what the right balance is. It'd be cool to detect patterns
like the following, but is it *useful*?
local monitor = peripheral.wrap("left")
monitor.write("Hello")
-- ^ monitor is nil. Is there a peripheral to the left of the
-- computer?
For now, the current approach feels the easiest, and should allow us to
prototype things and see what does/doesn't work.
In the original implementation of our prettier runtime errors (#1320), we
wrapped the errors thrown within parallel functions into an exception
object. This means the call-stack is available to the catching-code, and
so is able to report a pretty exception message.
Unfortunately, this was a breaking change, and so we had to roll that
back. Some people were pcalling the parallel function, and matching on
the result of the error.
This is a second attempt at this, using a technique I've affectionately
dubbed "magic throws". The parallel API is now aware of whether it is
being pcalled or not, and thus able to decide whether to wrap the error
into an exception or not:
- Add a new `cc.internal.tiny_require` module. This is a tiny
reimplementation of require, for use in our global APIs.
- Add a new (global, in the debug registry) `cc_try_barrier` function.
This acts as a marker function, and is used to store additional
information about the current coroutine.
Currently this stores the parent coroutine (used to walk the full call
stack) and a cache of whether any `pcall`-like function is on the
stack.
Both `parallel` and `cc.internal.exception.try` add this function to
the root of the call stack.
- When an error occurs within `parallel`, we walk up the call stack,
using `cc_try_barrier` to traverse up the parent coroutine's stack
too. If we do not find any `pcall`-like functions, then we know the
error is never intercepted by user code, and so its safe to throw a
full exception.
In 94ad6dab0e, we changed it so typing
characters outside of CC's codepage were replaced with '?' rather than
ignored. This can be quite annoying for non-European users (where latin1
isn't very helpful!), so it makes sense to revert this change.
See discussion in #860 for more context.
- Store the filter alongside the coroutine rather than in a separate
table (like we do in multishell).
- Remove the redudant (I think!) second loop that checks for dead
coroutines. We already check for dead coroutines in the main loop.
- Rename some variables to be a bit more consistent. This makes this
commit look noisier than it is. Sorry!
- Check whether the computer is a command computer before registering
the capability.
- Add tests to check what is/isn't a peripheral. See also #2020, where
we forgot to register a peripheral on NeoForge 1.21.1.
Fixes#2070.
We now convert uncode characters from "char" and "paste" events to CC's
charset[^1], rather than just leaving them unconverted. This means you
can paste in special characters like "♠" or "🮙" and they will be
converted correctly. Characters outside that range will be replaced with
"?", as before.
It would be nice to make this a bi-directional mapping, and do this for
Lua methods too (e.g. os.setComputerLabel). However, that has much wider
ramifications (and more likelyhood of breaking something), so avoiding
that for now.
- Remove the generic "queue event" client->server message, and replace
it with separate char/terminate/paste messages. This allows us to
delete a chunk of code (all the NBT<->Object conversion), and makes
server-side validation of events possible.
- Fix os.setComputerLabel accepting the section sign — this is treated
as special by Minecraft's formatting code. Sorry, no fun allowed.
- Convert paste/char codepoints to CC's charset. Sadly MC's char hook
splits the codepoint into surrogate pairs, which we *don't* attempt
to reconstruct, so you can't currently use unicode input for block
characters — you can paste them though!
[^1]: I'm referring this to the "terminal charset" within the code. I've
flip-flopped between "CraftOS", "terminal", "ComputerCraft", but feel
especially great.
This abstraction never made much sense on InputHandler, as we only leave
the default methods on ServerComputer.
We now add a new class (ComputerEvents), which has a series of *static*
methods, that can queue an event on a ComputerEvents.Receiver object.
This is a bit of an odd indirection (why not just make them instance
methods on Receiver?!), but I don't really want those methods leaking
everywhere.