Fixes#2141. Hah, I wrote some tests for this in
b03546a158b81a2e69ec636d0ba437f1dd73ad12, but they pass because hoppers
still support vanilla inventories, but turtles don't.
Wish NeoForge registered a fallback for any inventory, like Fabric does,
but there we go.
- Fix isValidClipboard always returning true.
- Fix characters >=128 being rejected. We changed the signature from a
byte to an int in 0f123b5efdca5f277f2c15208b9241d3fb9ca8fa, 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.
Sort of closes#2125. I've really struggled to find a way to make it
clear that the information returned here is a snapshot of the current
item, and not a live view and/or proxy. Most wordings I've tried end up
feeling really clunky — given that this is a relatively rare
misunderstanding, let's not stress about this too much.
Oh dear. I'd originally set out to *remove* logic from DiskItem — we're
so close to being able to remove this item in 1.21! However, while
looking at this code, I realised I could remove the whole Forge-specific
doesSneakBypassUse.
We now remove the use hook on the block, and override useOn on the item.
Obvious in retrospect!
Oh. This is from ye olde days (it's one of the first PRs to CC[^1]!). In
pre-1.13 days, furnaces changing their lit state would replace the block
(creating a new BE) and then set back the old BE. CC wouldn't pick up
the second event, and so would continue to use the peripheral from the
first.
We don't really need this any more, for a couple of reasons:
a) Furnaces don't do this any more.
b) Peripherals are now refreshed on the next tick rather than
immediately.
c) Forge's capabilities have an explicit invalidate() hook already. This
technically only detects *removing* block entities, but I'm not sure
there's any cases where you add a block entity without also
triggering a block state change.
Ironically, the place we probably need this more is Fabric, where the
lookup API doesn't have a public invalidate hook (it's hidden away in
the BlockApiCache). I'm mostly relying on c) here, in that we just won't
see this happen in practice.
[^1]: https://github.com/dan200/ComputerCraft/pull/180
We have several items (e.g. ComputerItem), which only exist for their
custom tooltip implementation. We remove these, and replace them
vanilla-style component-based tooltips (TooltipProvider).
The implementation here is a little janky — as the vanilla list of
components is hard-coded, and neither mod loader offers a way to extend
it. For now we just use the generic mod-loader tooltip hook — this
probably would be easier with a mixin, but let's do things Properly.
It would be nice to fully remove DiskItem (we only keep this around for
doesSneakBypassUse), but that can be a future task.
Introduced by the previous commit — I'd made one of the checks too lax.
Add some tests for this, so it doesn't happen again, though this code
does get a complete rewrite in 1.21 anyway >_>.
Another go at fixing #2127.
In a892739f8eb87fb078dedae07d8c8614b9d6da4b we set the precision on the
Tbo uniform. However, this is stripped in the shader pre-processing
Pojav/gl4es does, and so has no effect. As a (terrible) workaround, we
now just ignore shader loading errors. This probably does leak memory
(we'll never clean up the program), but there's not much we can do about
that.
We send the item-form of the current computer in the computer menu data.
However, this leaks the current LockCode, as we include all components.
We now only gather a safe subset of components when constructing the
item.
These just return details about the currently equipped *item*. This
allows us to expose information about the currently equipped upgrade,
without having to invent a whole new format.
Docs are a bit consise, but didn't really know how to flesh them out any
further.
Fixes#964, fixes#1613, closes#1692.
Some people run Minecraft on OpenGL ES GPUs via the gl4es translation
bridge. This sets the default precision for floats and ints, but not
usamplerBuffer.
Using lowp should be fine here (we don't need to encode much info!), but
we use mediump just in case. Have run this through the Mali Offline
compiler, and it seems fine with it.
Fixes#2127.
This bumps them to be 48x48, which allows them to be downscaled to a
mipmap level of 4. We possibly should bump these to be 64x64 (actual
power of two), but I kinda want to avoid that, as it's so much wasted
space. If this does become a problem, we should probably put these on a
separate atlas instead.
Honestly, the whole design around volume and playSound/playAudio is a
little janky — it probably should be a separate setVolume method which
updates directly. But too late to change that now, so let's do what we
can.
See #2108
ComputerItem was just an empty subclass, so no sense keeping around. We
probably could get rid of CommandComputerItem too (just do an `instanceof
GameMasterBlock` in `getPlacementState`), but there's no rush.
We now register these separately, rather than relying on the implicit
IMedia. This allows us to share a bit more logic between
PocketComputerItem and AbstractComputerItem. This doesn't make much
difference on 1.20.1, but does help a bit more on 1.21.1.
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.
This allows shift+clicking a pocket computer on to a lectern. These
computers can be right clicked, opening the no-term computer GUI.
Terminal contents is rendered in-world, and broadcast to everyone in
range.
- Add a new lectern PocketHolder.
- Refactor some of the `PocketItemComputer` code to allow ticking pocket
computers from a non-player/entity source.
- Add a new model for pocket computers. This requires several new
textures (somewhat mirroring the item ones), which is a little
unfortunate, but looks much better than reusing the map renderer or
item form.
In 94ad6dab0e5b8d9eb65467dd1b635d708ce58b53, 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.
I removed this in fc834cd97fe941a192e40962ac3bb27be102ce09, way back in
late 2024. 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 NeoForge's new
capability system, but otherwise it's almost exactly the same :D.
- 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!
It's not actually safe to reuse this, as we need to recompute the
internal StackedContents each time the inventory changes, otherwise
ShapelessRecipe.matches will continue to return true, even if the actual
inventory doesn't include the required items.
Fixes#2094
Oh, this is so broken, and really has been since the 1.13 update, if not
earlier.
- Fix call to isUnobstructed using the bounding box of the
*destination* block rather than the turtle. This is almost always
air, so the box is empty.
- Because the above check has been wrong for so many years, we now
significantly relax the "can push" checks for entities. We now allow
pushing entities in any direction.
We also remove the "isUnobstructed" check for the destination entity
pos. This causes problems (if two entities are standing on a turtle,
they'll obstruct each other), and given pistons don't perform such a
check, I don't think we need it.
- Also do a bit of cleanup around air/liquid checks. We often ended up
reading the block state multiple times, which is a little ugly.