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.
We were seeing some strange issues in the Fabric test code where we
tried to load the implementation from a different classloader. This
ensures that the classloaders are consistent.
Due to the asynchronous nature of main-thread tasks, it's possible for
them to be executed on peripherals which have been detached. This has
been known for a long time (#893 was opened back in 2021), but finding a
good solution here is tricky.
Most of the time the method will silently succeed, but if we try to
interact with an IComputerAccess (such as in inventory methods, as seen
in #1750), we throw a NotAttachedException exception and spam the logs!
This is an initial step towards fixing this - when calling a peripheral
method via peripheral.call/modem.callRemote, we now wrap any enqueued
main-thread tasks and silently skip them if the peripheral has been
detached since.
This means that peripheral methods may start to return nil when they
didn't before. I think this is *fine* (though not ideal for sure!) - we
return nil if the peripheral has been detached, so it's largely
equivalent to that.
Double chests peripherals were getting reattached every time there was a
block update, as the inventories were not comparing equal (despite being
so!). We now check for a couple of common cases, which should be enough
for vanilla/vanilla-like inventories.
I actively Do Not Like This Code, but do not see a good alternative.
This should never happen, but apparently it does!? We now log an error
(rather than crashing), and include the original BE (and associated
block), as the BE type isn't very useful.
See #1750. Technically this fixes it, but want to do some more poking
there first.
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.
- Remove "initial connections" flag, and just refresh connections +
peripherals on the first tick.
- Remove "peripheral attached" from NBT, and just read/write it from
the block state. This might cause issues with #1010, but that's
sufficiently old I hope it won't!
Our GatedPredicate hack was clever, but also fundamentally didn't work.
The predicate is called before extraction, so if extraction fails (for
instance, canTakeItemThroughFace returns false), then we still think an
item has been removed.
To fix that, we inline StorageUtil.move, specialising it for what we
need.
This feels a little overkill, but nice to standardise how this code
looks.
There's a bit of me which wonders if we should remove
IPeripheral.equals, and just use Object.equals, but I do also kinda like
the explicitness of the current interface? IDK.
This ensures the client decoder is in sync with the server. Well, mostly
- we don't handle the anti-jerk, but that should correct itself within a
few samples.
Fixes#1748
The original runtime error reporting PR[^1] added a "cc.exception"
module, which allowed coroutine managers (such as parallel) to throw
rich errors, detailing the original context where the error was thrown.
Unfortunately, the change to parallel broke some programs (>_>, don't do
string pattern matching on your errors!), and so had to be reverted,
along with the cc.exception module.
As a minimal replacement for this, we add support for user-thrown
exceptions within our internal code. If an error object "looks" like an
exception ("exception" __name, and a message and thread field), then we
use that as our error information instead.
This is currently undocumented (at least in user-facing documentation),
mostly because I couldn't figure out where to put it - the interface
should remain stable.
[^1]: https://github.com/cc-tweaked/CC-Tweaked/pull/1320
This adds support for computer selectors, in the style of entity
selectors. The long-term goal here is to replace our existing ad-hoc
selectors. However, to aid migration, we currently support both - the
previous one will most likely be removed in MC 1.21.
Computer selectors take the form @c[<key>=<value>,...]. Currently we
support filtering by id, instance id, label, family (as before) and
distance from the player (new!). The code also supports computers within
a bounding box, but there's no parsing support for that yet.
This commit also (finally) documents the /computercraft command. Well,
sort of - it's definitely not my best word, but I couldn't find better
words.
When rendering non-origin monitors, we would fetch the origin monitor,
read its client state, and then cache that on the current monitor to
avoid repeated lookups.
However, if the origin monitor is unloaded/removed on the client, and
then loaded agin, this cache will be not be invalidated, causing us to
render both the old and new monitor!
I think the correct thing to do here is cache the origin monitor. This
allows us to check when the origin monitor has been removed, and
invalidate the cache if needed.
However, I'm wary of any other edge cases here, so for now we do
something much simpler, and remove the cache entirely. This does mean
that monitors now need to perform extra block entity lookups, but the
performance cost doesn't appear to be too bad.
Fixes#1741
Historically, computers tracked whether any world-visible state
(on/off/blinking, label and redstone outputs) had changed with a single
"has changed" flag. While this is simple to use, this has the curious
side effect of that term.setCursorBlink() or os.setComputerLabel() would
cause a block update!
This isn't really a problem in practice - it just means slightly more
block updates. However, the redstone propagation sometimes causes the
computer to invalidate/recheck peripherals, which masks several other
(yet unfixed) bugs.
- colors.toBlit now performs bounds checks on the passed value,
preventing weird behaviour like color.toBlit(2 ^ 16) returning "10".
- The window API now uses colors.toBlit (or rather a copy of it) for
parsing colours, allowing doing silly things like
term.setTextColour(colours.blue + 5).
- Add some top-level documentation to the term API to explain some of
the basics.
Closes#1736
Minecraft sometimes keeps chunks in-memory, but not actively loaded. If
we schedule a block entity to be ticked and that chunk is is then
transitioned to this partially-loaded state, then the block entity is
never actually ticked.
This is most visible with monitors. When a monitor's contents changes,
if the monitor is not already marked as changed, we set it as changed
and schedule a tick (see ServerMonitor). However, if the tick is
dropped, we don't clear the changed flag, meaning subsequent changes
don't requeue the monitor to be ticked, and so the monitor is never
updated.
We fix this by maintaining a list of block entities whose tick was
dropped. If these block entities (or rather their owning chunk) is ever
re-loaded, then we reschedule them to be ticked.
An alternative approach here would be to add the scheduled tick directly
to the LevelChunk. However, getting hold of the LevelChunk for unloaded
blocks is quiet nasty, so I think best avoided.
Fixes#1146. Fixes#1560 - I believe the second one is a duplicate, and
I noticed too late :D.
When we remove a wired node from a network, we need to find connected
components in the rest of the graph. Typically, this requires a
traversal of the whole graph, taking O(|V| + |E|) time.
If we remove a lot of nodes at once (such as when unloading chunks),
this ends up being quadratic in the number of nodes. In some test
networks, this can take anywhere from a few seconds, to hanging the game
indefinitely.
This attempts to reduce the cases where this can happen, with a couple
of optimisations:
- Instead of constructing a new hash set of reachable nodes (requiring
multiple allocations and hash lookups), we store reachability as a
temporary field on the WiredNode.
- We abort our traversal of the graph if we can prove the graph remains
connected after removing the node.
There's definitely future work to be done here in optimising large wired
networks, but this is a good first step.
- Replace usages of WiredNetwork.connect/disconnect/remove with the
WiredNode equivalents.
- Convert "testLarge" into a proper JMH benchmark.
- Don't put a peripheral on every node in the benchmarks. This isn't
entirely representative, and means the peripheral juggling code ends
up dominating the benchmark time.
We've been out-of-date for a while now, as we needed to update
lua_menhir to work with lrgrep 3.
- Better handling of standalone names/expressions - we now correctly
handle lists of names.
- Handle missing commas in tables in a few more places.
- We checked the backing array when reading rather than the file's
length, so could read beyond the end of the file.
- We used the entry length when resizing, which effectively meant we
doubled the size of the backing array on each write.
- cc.require now uses the internal _LOADED table to get the list of
built-in globals. This fixes several globals not showing up on the
list (e.g. utf8), and allows us to inject more modules from the Java
side.
- ILuaAPI now has a getModuleName() function. This is used to inject
the API into the aforementioned _LOADED table, allowing it to be
"require"d.
One common issue we get when a program exits after handling a "key"
event is that it leaves the "char" event on the queue. This means that
the shell (or whatever program we switch in to) then receives the "char"
event, often displaying it to the screen.
Previously we've got around this by doing sleep(0) before exiting the
program. However, we also see this problem in edit's run handler script,
and I'm less comfortable doing the same hack there.
This adds a new internal discard_char function, which will either
wait one tick or return when seeing a char/key_up event.
Fixes#1705
- Mark our core test-fixtures jar as part of the "cctest", rather than
a separate library. I'm fairly sure this was actually using the
classpath version of CC rather than the legacyClasspath version!
- Add a new "testMinecraftLibrary" configuration, instead of trying to
infer it from the classpath. We have to jump through some hoops to
avoid having multiple versions of a library on the classpath at once,
but it's not too bad.
I'm working on a patch to bsl which might allow us to kill of
legacyClasspath instead. Please, anything is better than this.
Forge doesn't run client-side commands from sendUnsignedCommand, so we
still require a mixin there.
We do need to change the command name, as Fabric doesn't properly merge
the two command trees.
I didn't make a new years resolution to stop writing build tooling, but
maybe I should have.
This replaces our use of VanillaGradle with a new project,
VanillaExtract. This offers a couple of useful features for multi-loader
dev, including Parchment and Unpick support, both of which we now use in
CC:T.
- Debug hooks are now correctly called for every function.
- Fix several minor inconsistencies with debug.getinfo.
- Fix Lua tables being sized incorrectly when created from varargs.
- Update FG to 6.0.20 - no major changes, but required for the Gradle
update.
- Update Loom to 1.5.x - this adds Vineflower support by default, so we
can remove loom-vineflower.
This was copied over from the old binary handle, and so states we
always return a single number if no count is given. This is only the
case when the file is opened in binary mode.
Rather than mixing-in to CachedOutput, we just wrap our DataProviders to
use a custom CachedOutput which reformats the JSON before writing. This
allows us to drop mixins for common+non-client code.
Disk drives have had a long-standing issue with mutating their contents
on the computer thread, potentially leading to all sorts of odd bugs.
We tried to fix this by moving setDiskLabel and the mounting code to run
on the main thread. Unfortunately, this means there is a slight delay to
mounts being attached, breaking disk startup.
This commit implements an alternative solution - we now do mounting on
the computer thread again. If the disk's stack is modified, we update it
in the peripheral-facing item, but not the actual inventory. The next
time the disk drive is ticked, we then sync the two items.
This does mean that there is a fraction of a tick where the two will be
out-of-sync. This isn't ideal - it would potentially be possible to
cycle through disk ids - but I don't really think that's avoidable
without significantly complicating the IMedia API.
Fixes#1649, fixes#1686.
Originally we exposed a single registerTurtleUpgradeModellermethod which
could be called from both Fabric (during a mod's client init) and Forge
(during FMLClientSetupEvent).
This was fine until we allowed upgrades to specify model dependencies,
which would then automatically loaded, as this means model loading now
depends on upgrade modellers being loaded. Unknown to me, this is not
guaranteed to be the case on Forge - mod setup happens at the same time
as resource reloading!
Unfortunately there's not really a salvageable way of fixing this with
the current API. Forge now uses a registration event-based system,
meaning we can guarantee all modellers are loaded before models are
baked.
- Add support for version overrides/exclusions in our dependency check.
Sometimes mod loaders use different versions to vanilla, and we need
some way to handle that.
- Rescan wired network connections on the tick after invalidation,
rather than when invalidated.
- Convert some constant lambdas to static method references. Lambdas
don't allocate if they don't capture variables, so this has the same
performance and is a little less ugly.
- Small code-style/formatting changes.
Historically we used Forge's SimpleChannel methods (and
PacketDistributor) to send the packets to the client. However, we don't
need to do that - it is sufficient to convert it to a vanilla packet,
and send the packet ourselves.
Given we need to do this on Fabric, it makes sense to do this on Forge
as well. This allows us to unify (and thus simplify) a lot of how packet
sending works.
At the same time, we also remove the handling of speaker audio during
decoding. We originally did this to avoid the additional copy of audio
data. However, this doesn't work on 1.20.4 (as packets aren't
encoded/decoded on singleplayer), so it makes sense to do this
Correctly(TM).
This also allows us to get rid of ClientNetworkContext.get(). We do
still need to service load this class (as Forge's networking isn't split
up in the same way Fabric's is), but we'll be able to drop that in
1.20.4.
Finally, we move the record playing code from ClientNetworkContext to
ClientPlatformHelper. This means the network context no longer needs to
be platform-specific!
After embarrassing, let's do some proper work.
Rather than passing the level and position each time we call
ComponentAccess.get(), we now pass them at construction time (in the
form of the BE). This makes the consuming code a little cleaner, and is
required for the NeoForge changes in 1.20.4.
I was able to reproduce this by starting two computers, and then warming
up the JIT by running:
while true do os.queueEvent("x") os.pullEvent("x") end
and then running the following on one computer, while typing on the
other:
while true do end
I'm not quite sure why this happens. It's possible that once the JIT is
warm, we can resume computers without actually allocating anything,
though I'm a little unconvinced.
Fixes#1672
Everything old is new again!
CC's network message implementation has gone through several iterations:
- Originally network messages were implemented with a single class,
which held an packet id/type and and opaque blobs of data (as
string/int/byte/NBT arrays), and a big switch statement to decode and
process this data.
- In 42d3901ee3, we split the messages
into different classes all inheriting from NetworkMessage - this bit
we've stuck with ever since.
Each packet had a `getId(): int` method, which returned the
discriminator for this packet.
- However, getId() was only used when registering the packet, not when
sending, and so in ce0685c31f we
removed it, just passing in a constant integer at registration
instead.
- In 53abe5e56e, we made some relatively
minor changes to make the code more multi-loader/split-source
friendly. However, this meant when we finally came to add Fabric
support (8152f19b6e), we had to
re-implement a lot of Forge's network code.
In 1.20.4, Forge moves to a system much closer to Fabric's (and indeed,
Minecraft's own CustomPacketPayload), and so it makes sense to adapt to
that now. As such, we:
- Add a new MessageType interface. This is implemented by the
loader-specific modules, and holds whatever information is needed to
register the packet (e.g. discriminator, reader function).
- Each NetworkMessage now has a type(): MessageType<?> function. This
is used by the Fabric networking code (and for NeoForge's on 1.20.4)
instead of a class lookup.
- NetworkMessages now creates/stores these MessageType<T>s (much like
we'd do for registries), and provides getters for the
clientbound/serverbound messages. Mod initialisers then call these
getters to register packets.
- For Forge, this is relatively unchanged. For Fabric, we now
`FabricPacket`s.
- Clean up option parsing a bit, so it uses the Option, rather than its
corresponding character code.
- Add a new -L/--allow-local-domains flag to remove the $private rule
from the HTTP rules.
While ComputerFamily is still useful, there's definitely some places
where it adds an extra layer of indirection. This commit attempts to
clean up some places where we no longer need it.
- Remove ComputerFamily from AbstractComputerBlock. The only place this
was needed is in TurtleBlock, and that can be replaced with normal
Minecraft explosion resistence!
- Pass in the fuel limit to the turtle block entity, rather than
deriving it from current family.
- The turtle BERs now derive their model from the turtle's item, rather
than the turtle's family.
- When creating upgrade/overlay recipes, use the item's name, rather
than {pocket,turtle}_family. This means we can drop getFamily() from
IComputerItem (it is still needed on to handle the UI).
- We replace IComputerItem.withFamily with a method to change to a
different item of the same type. ComputerUpgradeRecipe no longer
takes a family, and instead just uses the result's item.
- Computer blocks now use the normal Block.asItem() to find their
corresponding item, rather than looking it up via family.
The above means we can remove all the family-based XyzItem.create(...)
methods, which have always felt a little ugly.
We still need ComputerFamily for a couple of things:
- Permission checks for command computers.
- Checks for mouse/colour support in ServerComputer.
- UI textures.
- 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.
Previously we prevented our published full jar depending on any of the
other projects by excluding the whole cc.tweaked jar. However, as Cobalt
also now lives in that group, this meant we were missing the Cobalt
dependency.
Rather than specifying a wildcard, we now exclude the dependencies when
adding them to the project.
This is a bit of an odd combination of a few bugs:
- When the terminal component is blurred, we fire a mouse_up event for
the last-held button. However, we had an off-by-1 error here, so this
only triggered for the right/middle buttons.
- This was obsucuring the second bug, which is when we clicked within
the terminal, this caused the terminal to be blurred (thus releasing
the mouse) and then focused again.
We fix this by only setting the focus if there's actually a change.
Fixes#1655
When adding/removing observers, we locked on the observer, then
acquired the global lock. When a metric is observed, then we acquire the
global lock and then the observer lock.
If these happen at the same time, we can easily end up with a deadlock.
We simply avoid holding the observer lock for the entire add/remove
process (instead only locking when actually needed).
Closes#1639
This commit adds abstract classes to describe the interface for our
mod-loader-specific generic peripherals (inventories, fluid storage,
item storage).
This offers several advantages:
- Javadoc to illuaminate conversion no longer needs the Forge project
(just core and common).
- Ensures we have a consistent interface between Forge and Fabric.
Note, this does /not/ implement fluid or energy storage for Fabric. We
probably could do fluid without issue, but not something worth doing
right now.
Rather than assuming static methods are generic, and instance methods
are direct, the Generator now has separate entrypoints for handling
instance and generic methods.
As a result of this change, we've also relaxed some of the validation
code. As a result, we now allow calling private/protected methods
which are annotated with @LuaFunction.
This adds a new "java_allocation" metric, which tracks the number of
bytes allocated while executing the computer (as measured by Java). This
is not an 100% reliable number, but hopefully gives some insight into
what computers are doing.
Historically CC has supported two modes when working with file handles
(and HTTP requests):
- Text mode, which reads/write using UTF-8.
- Binary mode, which reads/writes the raw bytes.
However, this can be confusing at times. CC/Lua doesn't actually support
unicode, so any characters beyond the 0.255 range were replaced with
'?'. This meant that most of the time you were better off just using
binary mode.
This commit unifies text and binary mode - we now /always/ read the raw
bytes of the file, rather than converting to/from UTF-8. Binary mode now
only specifies whether handle.read() returns a number (and .write(123)
writes a byte rather than coercing to a string).
- Refactor the entire handle hierarchy. We now have an AbstractMount
base class, which has the concrete implementation of all methods. The
public-facing classes then re-export these methods by annotating
them with @LuaFunction.
These implementations are based on the
Binary{Readable,Writable}Handle classes. The Encoded{..}Handle
versions are now entirely removed.
- As we no longer need to use BufferedReader/BufferedWriter, we can
remove quite a lot of logic in Filesystem to handle wrapping
closeable objects.
- Add a new WritableMount.openFile method, which generalises
openForWrite/openForAppend to accept OpenOptions. This allows us to
support update mode (r+, w+) in fs.open.
- fs.open now uses the new handle types, and supports update (r+, w+)
mode.
- http.request now uses the new readable handle type. We no longer
encode the request body to UTF-8, nor decode the response from UTF-8.
- Websockets now return text frame's contents directly, rather than
converting it from UTF-8. Sending text frames now attempts to treat
the passed string as UTF-8, rather than treating it as latin1.
- 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.
This tries to cover some holes in our existing coverage.
- Port some of our Java readable handle tests to Lua (and also clean up
the Java versions to stop using ObjectWrapper - that dates to
pre-@LuaFunction!)
- Test a couple of discrepancies between binary and text handles. This
is mostly to do with the original number-based .read() and .write()
interface for binary handles.
- Fix a couple of edge cases in file-size accounting.
This is largely based on our existing wiki page. I've pruned out a
couple of entries which I think are largely irrelevant (config file
splitting, Java API changes).
10/10 job by me of changing nothing since 1.13. Shame to break that
streak really.
Does it count as an emulator when it's official? I hope not, as this'd
make it my fourth or fifth emulator at this point.
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
Developing/debugging CraftOS is a massive pain to do inside Minecraft,
as any change to resources requires a compile+hot swap cycle (and
sometimes a `/reload` in-game). As such, it's often more convenient to
spin up an emulator, pointing it to load the ROM from CC:T's sources.
However, this isn't practical when also making changes to the Java
classes. In this case, we either need to go in-game, or build a custom
version of CCEmuX.
This commit offers an alternative option: we now have our own emulator,
which allows us to hot swap both Lua and Java to our heart's content.
Most of the code here is based on our monitor TBO renderer. We probably
could share some more of this, but there's not really a good place for
it - feels a bit weird just to chuck it in :core.
This is *not* a general-purpose emulator. It's limited in a lot of
ways (won't launch on Mac[^1], no support for multiple computers) - just
stick to what's there already.
[^1]: We require OpenGL 4.5 due to our use of DSA.
In practice, we're never going to change this to true by default. The
old Tekkit Legends pack enabled this[^1], and that caused a lot of
problems, though admittedly back in 2016 so things might be better now.
If people do want this functionality, it should be fairly easy to
replicate with a datapack, adding a file to rom/autorun.
[^1]: See https://www.computercraft.info/forums2/index.php?/topic/27663-
Hate that I remember this, why is this still in my brain?
- Move most error message constants to a new MountHelpers class.
- Be a little more consistent in when we throw "No such file" vs "Not a
file/directory" messages.
The two implementations aren't entirely compatible - the implementation
returned by .of will throw an NPE on .contains(null), whereas the
Collections implementations just return false. However, we try to avoid
passing null to collections methods, so this should be safe.
There's no strong reason to do this, but it helps make the code a little
more consistent
As of 1.20, sign messages are immutable - we need to do
text = text.setMesssage(...) instead. Also do a tiny bit of cleanup to
this function while we're here.
Probably not the best use of my lunch break :D:.
Fixes#1611.
This is an attempt to enforce better separation between ComputerThread
and ComputerExecutor. Both of these classes are pretty complex in their
own right, and the way the two bleed into each other makes it all the
more confusing!
This effectively splits the ComputerExecutor into two separate classes:
- ComputerScheduler.Executor (with the actual implementation inside
ComputerThread): This holds all the ComputerThread-related logic
which used to be in ComputerExecutor, including:
- before/after work hooks
- is-on-thread tracking
- virtual runtime computation
- ComputerScheduler.Worker: This encapsulates all the computer-related
behaviour. The actual implementation remains in ComputerExecutor.
The boundaries are still a little fuzzy here, and it's all definitely
more coupled then I'd like, but still an improvement!
There are several additional changes at the same time:
- TimeoutState has also been split up, to better define the boundary
between consumers (such as ComputerExecutor and ILuaMachine) and
controllers (ComputerThread).
The getters still live in TimeoutState, but the core logic lives in
ManagedTimeoutState.
- We no longer track cumulative time in the TimeoutState. Instead, we
allow varying the timeout of a computer. When a computer is paused,
we store the remaining time, and restore it when resuming again.
This also allows us give a longer timeout for computer
startup/shutdown, hopefully avoiding some of those class-not-found
issues we've seen.
- We try to make the state machine of how ComputerExecutors live on the
queue a little more explicit. This is very messy/confusing -
something I want to property test in the future.
I'm sure there's more to be done here, especially in ComputerExecutor,
but hopefully this makes future changes a little less intimidating.
Allows registering arbitrary block lookup functions instead of a
platform-specific capability. This is roughly what Fabric did before,
but generalised to also take an invalidation callback.
This callback is a little nasty - it needs to be a NonNullableConsumer
on Forge, but that class isn't available on Fabric. For now, we make the
lookup function (and thus the generic peripheral provider) generic on
some <T extends Runnable> type, then specialise that on the Forge side.
Hopefully we can clean this up when NeoForge reworks capabilities.
This is the second time I've rewritten our class generation in a little
over a month. Oh dear!
Back in d562a051c7 we started using method
handles inside our generated ASM, effectively replacing a direct call
with .invokeExact on a constant method handle.
This goes one step further and removes our ASM entirely, building up a
MethodHandle that checks arguments and then wraps the return value.
Rather than generating a class, we just return a new LuaFunction
instance that invokeExacts the method handle.
This is definitely slower than what we had before, but in the order of
8ns vs 12ns (in the worst case, sometimes they're much more comparable),
so I'm not too worried in practice.
However, generation of the actual method is now a bit faster. I've not
done any proper benchmarking, but it's about 20-30% faster.
This also gives us a bit more flexibility in the future, for instance
uisng bound MethodHandles in generation (e.g. for instance methods on
GenericSources). Not something I'm planning on doing right now, but is
an option.
Or rather, being published to the wrong place. The java-convention
plugin sets the group, but that was applied after the publishing one - I
was hoping it'd read that property lazy, but clearly not!
Wow, some of this is /old/. All the Maps.newHashMap stuff dates back to
Java 6, so must originally be CCTweaks code?!
We're unlikely to drop our Guava dependency (we use too much other
stuff), but we should make the most of the stdlib where possible.
This should be significantly faster than LoadingCache (2.5x in my
benchmarks, but not sure they're representative). This isn't super
important - a lookup only takes 6us - but still worth using!
Previously we had the invariant that if we had a server monitor, we also
had a terminal. When a monitor shrank into a place, we deleted the
monitor, and then recreated it when a peripheral was requested.
As of ab785a0906 this has changed
slightly, and we now just delete the terminal (keeping the ServerMonitor
around). However, we didn't adjust the peripheral code accordingly,
meaning we didn't recreate the /terminal/ when a peripheral was
requested.
The fix for this is very simple - most of the rest of this commit is
some additional code for ensuring monitor invariants hold, so we can
write tests with a little more confidence.
I'm not 100% sold on this approach. It's tricky having a double layer of
nullable state (ServerMonitor, and then the terminal). However, I think
this is reasonable - the ServerMonitor is a reference to the multiblock,
and the Terminal is part of the multiblock's state.
Even after all the refactors, monitor code is still nastier than I'd
like :/.
Fixes#1608
Currently redirects would be returned from the proxy, and then
immediately followed by XMLHTTPRequest. The proxy now follows requests
(when requested), so that should no longer happen.
We should probably switch over to fetch(...) here, to allow setting
follow_redirects to false, but that's a job for another day.
Haha, so many web emulator related commits of late. This'll die down
soon.
We can't use FriendlyByte.readCollection to read to a
pre-allocated/array-backed NonNullList, as that doesn't implement
List.add. Instead, we just need to do a normal loop.
We add a couple of tests to round-trip our recipe specs. Unfortunately
we can't test the recipes themselves as our own registries aren't set
up, so this'll have to do for now.
- Update to Rollup 4.x
- Replace terser and postcss with swc and lightningcss. This is
definitely more code for us to write (maybe I should turn them into
proper plugins we can depend on), but both speedier and fewer
dependencies.
- Drop dependency on glob - we can get away with fs.readdir for what we
needed it for.
Oh, this was a really nasty bug to reproduce. I'm not sure why - it's
very simple - I guess I've only just seen screenshots of it, and never
sat down to try myself. Reminder to actually report your bugs folks!
In this case:
1. Place down three down three monitors and then a computer.
2. Display something on the monitor (monitor left paint a) is my go-to.
3. Break the middle monitor.
We'd expect the left most monitor to be cleared, however it actually
preserves the monitor contents, resizing (and skewing it) to fit on its
new size!
This is because we clear the server monitor, but never sync that over to
the client, so the client monitor retains the old contents. To fix that,
instead of nulling out the server monitor, we null out the underlying
Terminal. This causes the change to be synced, fixing the bug.
Paint implements its menu slightly differently to edit, in that it takes
control of the event loop until the menu is closed. This means that the
term_resize event is ignored, and so the canvas not redrawn when the
menu is open.
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.
This moves MemoryMount to the main core module, and converts it to be a
"proper" WritableMount. It's still naively implemented - definitely
would be good to flesh out our tests in the future - but enough for what
we need it for.
We also do the following:
- Remove the FileEntry.path variable, and instead pass the path around
as a variable.
- Clean up BinaryReadableHandle to use ByteBuffers in a more idiomatic
way.
- Add a couple more tests to our FS tests. These are in a bit of an odd
place, where we want both Lua tests (for emulator compliance) and
Java tests (for testing different implementations) - something to
think about in the future.
- Move the frontend code into src/frontend
- Move our custom element SSR system into src/htmlTransform.
This is mostly in prep for merging in copy-cat's core, as that's a whole
bunch of extra code.
This attempts to reduce some duplication in recipe serialisation (and
deserialisation) by moving the structure of a recipe (group, category,
ingredients, result) into seprate types.
- Add ShapedRecipeSpec and ShapelessRecipeSpec, which store the core
properties of shaped and shapeless recipes. There's a couple of
additional classes here for handling some of the other shared or
complex logic.
- These classes are now used by two new Custom{Shaped,Shapeless}Recipe
classes, which are (mostly) equivalent to Minecraft's
shaped/shapeless recipes, just with support for nbt in results.
- All the other similar recipes now inherit from these base classes,
which allows us to reuse a lot of this serialisation code. Alas, the
total code size has still gone up - maybe there's too much
abstraction here :).
- Mostly unrelated, but fix the skull recipes using the wrong UUID
format.
This allows us to remove our mixin for nbt in recipes (as we just use
our custom recipe now) and simplify serialisation a bit - hopefully
making the switch to codecs a little easier.
- Add AbstractInMemoryMount, which contains all of ArchiveMount's file
tree logic, but not the caching functionality.
- Convert MemoryMount to inherit from AbstractInMemoryMount.
- Add a helper method to add a file to an AbstractInMemoryMount, and
use that within {Resource,Jar}Mount.
There's definitely more work to be done here - it might be nice to split
FileEntry into separate Directory and File interfaces, or at least make
them slightly more immutable, but that's definitely a future job.
- Add a new WebsocketClient interface, which WebsocketHandle uses for
sending messages and closing. This reduces coupling between Websocket
and WebsocketHandle, which is nice, though admitedly only use for
copy-cat :).
- WebsocketHandle now uses Websocket(Client).isClosed(), rather than
tracking the closed state itself - this makes the class mostly a thin
Lua wrapper over the client, which is nice.
- Convert Options into a record.
- Clarify the behaviour of ws.close() and the websocket_closed event.
Our previous test was incorrect as it called WebsocketHandle.close
(rather than WebsocketHandle.doClose), which had slightly different
semantics in whether the event is queued.
We already use preact for the copy-cat integration, so it makes sense to
use it during the static pass too. This allows us to drop a dependency
on react.
- Placing a command computer requires the player to be in creative and
opped.
- Breaking a command computer now requires the player to be opped, as
well as in creative.
As we've now got a dedicated item class for command comptuers, we move
the command-specific IMedia override to that class.
Fixes#1582.
As this is responsible for interrupting computers, we should make sure
its priority is higher than the background threads. It spends most of
its time sleeping, so should be fine.
Rather than having a mess of lambdas, we now move the bulk of the
implemetation to their own methods. The lambdas now just do argument
extraction - it's all stringly typed, so good to keep that with the
argument definition.
This also removes a couple of exception keys (and thus their translation
keys) as we no longer use them.
When the target method is in a different class loader to CC, our
generated method fails, as it cannot find the target class. To get
around that, we create a MethodHandle to the target method, and then
inject that into the generated class (with Java's new dynamic constant
system). We can then invoke the MethodHandle in our generated code,
avoiding any references to the target class/method.
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.
Wow, this is old. It looks like it's a legacy of when this method was on
TileGeneric (and so returned false by default). As all implementations
now return true (turtle tools no longer block redstone), we don't really
need this any more.
- Split buttons.png into individual textures.
- Split corners_xyz.png into the following:
- borders_xyz.png: A nine-sliced texture of the computer borders.
- pocket_bottom_xyz.png: A horizontally 3-sliced texture of the
bottom part of a pocket computer.
- sidebar_xyz.png: A vertically 3-sliced texture of the computer
sidebar.
While not splitting the sliced textures into smaller ones may seem a
little odd, it's consistent with what vanilla does in 1.20.2, and I
think will make editing them easier than juggling 9 textures.
I do want to make this more data-driven in the future, but that will
have to wait until the changes in 1.20.2.
This also adds a tools/update-resources.py program, which performs this
transformation on a given resource pack.
- 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.
- Support printing and parsing hex float literals
- Fix string.format "%q"'s handling of nan and inf (Kan18)
- Fix string is-letter/is-digit patterns treating characters as
unicode.
- tostring(...) now uses __name.
Should be max_websocket_message, not just websocket_message.
Also add some additional validation to address rules, to check no
unrecognised keys are present.
Closes#1566.
We're very inconsistent with whether we use locks or concurrent maps
here. Something to sort out in the future, but for now add some missing
@GuardedBy annotations.
- Prefer {read,write}Nullable when possible.
- Use SoundEvent.{writeTo,readFrom}Network, instead of sending the
registry entries. This allows playing discs which don't register
their SoundEvent on the server.
- Add a couple of tests for round-tripping these packets.
This requires supporting registries in our platform test
code. Thankfully this is mostly the same as what we can do in Fabric -
the duplication is unfortunate - but it's easy enough.
I want to write some tests to check that various packets round-trip
corretly. However, these packets don't (and shouldn't) implement
.equals, and so we need a more reflective(/hacky) way of comparing them.
This made more sense on 1.19.2 and before, but now that we have to do
this for tooltips, we might as well do it for messages as well.
Closes#1538, though hopefully will be resolved on the VO side too.
- Remove some unused translation keys.
- Run tools/language.py to sort the current translations and remove the
aforementioned unused keys.
- Update turtle tool impostor recipes - these now include the tool NBT!
Translations for Polish
Translations for French
Translations for Spanish
Translations for German
Co-authored-by: Patriik <apatriik0@gmail.com>
Co-authored-by: Sammy <SammyKoch@pm.me>
Co-authored-by: SquidDev <git@squiddev.cc>
- Move the tool action before the "is block present" check, fixes
#1527. This is where it was before, but we flipped it around in the
tool rewrite.
- Don't reuse as much turtle.place logic for tool actions. This fixes
some instances where tools could till/level dirt through solid
blocks.
- Overhaul model loading to work with the new API. This allows for
using the emissive texture system in a more generic way, which is
nice!
- Convert some of our custom models to use Fabric's model hooks (i.e.
emitItemQuads). We don't make use of this right now, but might be
useful for rendering tools with enchantment glints.
Note this does /not/ change any of the turtle block entity rendering
code to use Fabric/Forge's model code. This will be a change we want
to make in the future.
- Some cleanup of our config API. This fixes us printing lots of
warnings when creating a new config file on Fabric (same bug also
occurs on Forge, but that's a loader problem).
- Fix a few warnings
We've supported resource conditions in the upgrade JSON for an age, but
don't expose it in our data generators at all.
Indeed, using these hooks is a bit of a pain to do in multi-loader
setups, as the JSON is different between the two loaders. We could
generate the JSON for all loaders at once, but it feels nicer to use
the per-loader APIs to add the conditions.
For now, we just support generating a single condition - whether a mod
is loaded not, via the requireMod(...) method.
We were generating methods with the original object, rather than the
extra one.
Updated our tests to actually catch this. Unfortunately the only places
we use this interface is in HTTP responses and transferred files,
neither of which show up in the Lua-side tests.
We switched to Forge's loot modifier system in the 1.20 update, as
LootTable.addPool had been removed. Turns out this was by accident, and
so we switch back to the previous implementation, as it's much simpler
and efficient.
- Attach permission checks to the first argument (so the literal
command name) rather than the last argument. This fixes commands
showing up when they shouldn't.
- HelpingArgumentBuilder now inherits permissions of its leaf nodes.
This only really impacts the "track" subcommand.
- Don't autocomplete the computer selector for the "queue" subcommand.
As everyone has permission for this command, it's possible to find
all computer ids and labels in the world.
I'm in mixed minds about this, but don't think this is an exploit -
computer ids/labels are sent to in-range players so shouldn't be
considered secret - but worth patching none-the-less.
- Document that settings.set doesn't persist values. I think this
closes#1512 - haven't heard back from them.
- Add missing close reasons to the websocket_closed event. Closes#1493.
- Mention what values are preserved by os.queueEvent. This is just the
same as modem.transmit. Closes#1490.
- Normalise upgrade keys, to be "allowEnchantments" and
"consumeDurability". We were previously inconsistent with
allow/allows and consumes.
- Add tests for durability and enchantments of pickaxes.
- Fix a couple of issues with the original upgrade NBT being modified.
- Now store the item's tag under a separate key rather than on the
root. This makes syncing the NBT between the two much nicer.
Turtle tools now accept two additional JSON fields
- allowEnchantments: Whether items with enchantments (or any
non-standard NBT) can be equipped.
- consumesDurability: Whether durability will be consumed. This can be
"never" (the current and default behaviour), "always", and
"when_enchanted".
Closes#1501.
This is a pre-requisite for #1501, and some other refactorings I want to do.
Also fix items in the turtle upgrade slots vanishing. We now explicitly
invalidate the cache when setting the item.
I think this left over from CCTweaks or Peripheral++. It doesn't really
make sense as an API - if/when we add multiple upgrades, we'll want a
different API for this.
This removes a tiny bit of duplication (at the cost of mode code), but
makes the interface more intuitive, as there's no bouncing between
getCombination -> cache -> buildModel.
It turns out we don't document the "port" option anywhere, so probably
worth doing a bit of an overhaul here.
- Expand the top-level HTTP rules comment, clarifying how things are
matched and describing each field.
- Improve the comments on the default HTTP rule. We now also describe
the $private rule and its motivation.
- Don't drop/ignore invalid rules. This gets written back to the
original config file, so is very annoying! Instead we now log an
error and convert the rule into a "deny all" rule, which should make
it obvious something is wrong.
- Remove the "force_print" code. This is a relic of before we used
table.pack, and so didn't know how many expressions had been
returned.
- Check the input string is a valid expression separately before
wrapping it in an _echo(...). Fixes#1506.
- Update to Loom 1.2 and FG 6.0. ForgeGradle has changed how it
generates the runXyz tasks, which makes running our tests much
harder. I've raised an issue upstream, but for now we do some nasty
poking of internals.
- Fix Sodium/Iris tests. Loom 1.1 changed how remapped configurations
are generated - we create a dummy source set and associate the
remapped configuration with that. All nasty stuff.
- Publish the common library. I'm not a fan of this, but given how much
internals I'm poking elsewhere, should probably get off my high
horse.
- Add renderdoc support to the client gametests, enabled with
-Prenderdoc.
- Fix mainThread=true methods calling IArguments.escapes too late. This
should be done before scheduling on the main thread, not on the main
thread itself!
- Fix VarargsArguments.escapes not checking that the argument haven't
been closed. This is slightly prone to race conditions, but I don't
think it's worth the overhead of tracking the owning thread.
Maybe when panama and its resource scopes are released.
Thanks Sara for pointing this out!
Slightly irked that none of our tests caught this. Alas.
Also fix a typo in AddressPredicate. Yes, no commit discipline.
- Move the class cache out of Generator into MethodSupplierImpl. This
means we cache class generation globally (that's really expensive!),
but the class -> method list lookup is local.
- Move the global GenericSource/GenericMethod registry out of core,
passing in the list of generic methods to the ComputerContext.
I'm not entirely thrilled by the slight overlap of MethodSupplierImpl and
Generator here, something to clean up in the future.
- Move several interfaces out of `d00.computercraft.core.asm` into a
new `aethods` package. It may make sense to expose this to the
public API in a future commit (possibly part of #1462).
- Add a new MethodSupplier<T> interface, which provides methods to
iterate over all methods exported by an object (either directly, or
including those from ObjectSources).
This interface's concrete implementation (asm.MethodSupplierImpl),
uses Generators and IntCaches as before - we can now make that all
package-private though, which is nice!
- Make the LuaMethod and PeripheralMethod MethodSupplier local to the
ComputerContext. This currently has no effect (the underlying
Generator is still global), but eventually we'll make GenericMethods
non-global, which unlocks the door for #1382.
- Update everything to use this new interface. This is mostly pretty
sensible, but is a little uglier on the MC side (especially in
generic peripherals), as we need to access the global ServerContext.
- Remove SidedGenericPeripheral (we never used this!), adding the
functionality to GenericPeripheral directly. This is just used on the
Fabric side for now, but might make sense with Forge too.
- Move GenericPeripheralBuilder into the common project - this is
identical between the two projects!
- GenericPeripheralBuilder now generates a list of methods internally,
rather than being passed the methods.
- Add a tiny bit of documentation.
- Use integer indexes instead of strings (i.e. text, textColour). This
is a tiny bit faster.
- Avoid re-creating tables when clearing.
We're still mostly limited by the VM (slow) and string concatenation
(slow!). Short of having some low-level mutable buffer type, I don't
think we can improve this much :(.
Instead of reporting an error with `.report(f(...))`, we now do
`.report(f, ...)`. This allows consumers to ignore error messages when
not needed, such as when just doing syntax highlighting.
When a turtle attempts to place a block, it does so by searching for
nearby blocks and attempting to place the item against that block.
This has slightly strange behaviour when working with "placable"
non-block items though (such as buckets or boats). In this case, we call
Item.use, which doesn't take in the position of the block we're placing
against. Instead these items do their own ray trace, using the default
reach distance.
If the block we're trying to place against is non-solid, the ray trace
will go straight through it and continue (up to the maximum of 5
blocks), allowing placing the item much further away.
Our fix here is to override the default reach distance of our fake
players, limiting it to 2. This is easy on Forge (it has built-in
support), and requires a mixin on Fabric.
Closes#1497.
- Reverse quads in our model transformer and when rendering as a block
entity.
- Correctly recompute normals when the quads have been inverted.
Closes#1283
- 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).
This was broken/commented out already as part of the 1.20 update. I
don't think this is really going to be easy to add back without a lot of
reflection, so going to remove this feature instead.
Closes#1471.
This adds two slots to the right of the turtle interface which contain
the left and right upgrades of a turtle.
- Add turtle_upgrade_{left,right} indicators, which used as the
background texture for the two upgrade slots. In order to use
Slot.getNoItemIcon, we need to bake these into the block texture
atlas.
This is done with the new atlas JSON and a data generator - it's
mostly pretty simple, but we do now need a client-side data
generator, which is a little ugly to do.
- Add a new UpgradeContainer/UpgradeSlot, which exposes a turtle's
upgrades in an inventory-like way.
- Update the turtle menu and screen to handle these new slots.
Since 1.19.3, this was only populated when the player opened the
creative menu, and so was useless in survival or multi-player
worlds.
Rather than removing the field entirely (🦑 backwards compatibility), we
replace it with the empty list. We also remove it from the docs, and add
a note explaining what the field used to do.
Closes#1285, albeit in the least satisfactory way possible.
Fixes#1473.
There's an argument we should use Screen.hasControlDown() (which handles
Cmd vs Ctrl) instead of checking the modifiers, but we then need to
update all the translation strings, and I'm not convinced it's worth it
right now.
- Use GuiGraphics for rendering UI elements. Almost definitely some
z-fighting issues slipped in here.
- Use Forge's loot modifier system for handling treasure disks. I have
mixed feelings about this - it's a nice system, but also is far less
efficient than the previous approach.
- Regenerate data. This is the brunt of the commit, but nothing
especially interesting here.
- Remove ITurtleItem (and ITurtleBlockEntity): this was, AFAIK, mostly
a relic of the pre-1.13 code where we had multiple turtle items.
I do like the theory of abstracting everything out behind an
interface, but given there's only one concrete implementation, I'm
not convinced it's worth it right now.
- Remove TurtleItemFactory/PocketComputerItemFactory: we now prefer
calling the instance .create(...) method where we have the item
available (for instance upgrade recipes).
In the cases we don't (creating an item the first time round), we now
move the static .create(...) method to the actual item class.
- Provide a helper method for creating threads with a lower priority.
- Use that in our network code (which already used this priority) and
for the computer worker threads (which used the default priority
before). I genuinely thought I did this years ago.
Instead of creating the upgrade serialiser registries in mod
initialisation, we now do it when the API is created. This ensures the
registries are available for other mods, irrespective of mod load order.
This feels a little sad (we're doing side effects in the static
initialiser), but is /fine/ - it's pretty much what other mods do.
This is mostly aiming to give an overview rather than be anything
comprehensive (there's another 230+ undocumented classes to go :p), but
it's a start.
Mostly just an excuse for me to procrastinate working on the nasty bugs
though!
This means the config is no longer stored as static fields, which is a
little cleaner. Would like to move everything else in the future, but
this is a good first step.
We could do this in a more concise manner by wrapping Throwable rather
than reimplementing printStackTrace. However, doing this way allows us
to handle nested exceptions too.
Modrinth proxies images hosted on non-trusted domains through wsrv.nl,
for understandable reasons. However, wsrv.nl blocks tweaked.cc - I'm not
sure why. Instead we reference the image on GH directly, which works!
Also:
- Fix the modrinthSyncBody task pointing to a missing file.
- Update the licenses of a few files, post getting permission from
people. <3 all.
- Add a `timeout` parameter to http request and websocket methods.
- For requests, this sets the connection and read timeout.
- For websockets, this sets the connection and handshake timeout.
- Remove the timeout config option, as this is now specified by user
code.
- Use netty for handling websocket handshakes, meaning we no longer
need to deal with pongs.
In this case, we use Lua's tostring(x) semantics (well, modulo
metamethods), instead of Java's Object.toString(x) call. This ensures
that values are formatted (mostly) consistently between Lua and Java
methods.
- Add IArguments.getStringCoerced, which uses Lua's tostring semantics.
- Add a Coerced<T> wrapper type, which says to use the .getXCoerced
methods. I'm not thrilled about this interface - there's definitely
an argument for using annotations - but this is probably more
consistent for now.
- Convert existing methods to use this call.
Closes#1445
- Fix monitor renderer debug text showing up even when debug overlay
was not visible. This was a Forge-specific bug, which is why I'd not
noticed it I guess??
- Don't crash on alternative implementations of LoggerContext. Fixes
#1431. I'm not 100% sure what is causing this - it doesn't happen
with just CC:T at least - but at least we can bodge around it.
This is a little more general than InventoryStorage and means we can get
rid of our nasty double chest hack.
The generic peripheral system doesn't currently support generics (hah),
and so we need to use a wrapper class for now.
- Standardise our badges a little, adding a modrinth badge.
- Mention Fabric and Forge support.
- Don't include MC version in the Modrinth version number. I feel this
was required at some point, but apparently not any more! This also
allows us to use Modrinth for the Forge update JSON.
This is a horrible commit: It's a breaking change in a pretty subtle
way, which means it won't be visible while updating. Fortunately I think
the only mod on 1.19.4 is Plethora, but other mods (Mek, Advanced
Peripherals) may be impacted when they update. Sorry!
For some motivation behind the original issue:
The default IArguments implementation (VarargArguments) lazily converts
Lua arguments to Java ones. This is mostly important when passing tables
to Java functions, as we can avoid the conversion entirely if the
function uses IArguments.getTableUnsafe.
However, this lazy conversion breaks down if IArguments is accessed on a
separate thread, as Lua values are not thread-safe. Thus we need to
perform this conversion before the cross-thread sharing occurs.
Now, ideally this would be an implementation detail and entirely
invisible to the user. One approach here would be to only perform this
lazy conversion for methods annotated with @LuaFunction(unsafe=true),
and have it be eager otherwise.
However, the peripheral API gets in the way here, as it means we can no
longer inspect the "actual" method being invoked. And so, alas, this
must leak into the public API.
TLDR: If you're getting weird errors about scope, add an
IArguments.escapes() call before sharing the arguments between threads.
Closes#1384
- 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.
- Fix several inaccuracies with several files not marking Dan's
authorship. Most of these are new files, where the code was moved from
somewhere else:
- In the public API: IDynamicLuaObject, ILuaAPI, TaskCallbakc,
IDynamicPeripheral, UpgradeBase
- In the ROM: fs, http, require
- Do not mark Dan as an author for entirely new code. This affects
DetailHelpers, DropConsumer, FluidData, InventoryMethods, ItemDetails,
MonitorRenderState, NoTermComputerScreen, Palette, PlatformHelperImpl,
UploadFileMessage, the Terminal tests, and any speaker-related files.
- Relicence many files under the MPL where we have permission to do
so. See #1339 for further details.
Thank you to everyone who has contributed so far! Cannot overstate how
appreciated it is <3.
Trying to play a non-DFPWM (or WAV) file will generate terrible noise,
which in turns generates confused users. Instead, fail to play the audio
file and redirect them to the docs.
When a client sided pocket computer was first seen via an item stack
(rather than the computer state being synced over the networK), it would
always be created in greyscale due to this incorrect instanceof check.
Closes#1347
- Consult __name in native code too. Closes#1355. This has the added
advantage that unconvertable values (i.e. functions) will now
correctly be reported as their original type, not just nil.
- Fix the error message in cc.expect, so it matches the rest of Lua.
This has been bugging me for years, and I keep forgetting to change
it.
- Several files where @MCJack123 is the exclusive contributor. He has
signed over all contributions to "any OSI-approved license". Thank
you!
- Various the file handle classes: Looking at these again, I don't
think they contain any of the original code.
- Timeouts are now driven by an interrupt system, rather than polling.
While we do not impose memory limits, this should close#1333.
- Update the table library to largely match Lua 5.4:
- Add table.move
- Table methods (with the exception of foreach/foreachi) now use
metamethods (closes#1088).
There's still some remaining quirks (for instance, table.insert
accepts values out-of-bounds), but I think that's fine.
- Cobalt's threaded-coroutine system is gone (load now supports
yielding), so we no longer track coroutine metrics.
- Type errors now use __name. See #1355, though this does not apply to
CC methods (either on the Java or CraftOS side), so is not enough to
resolve it.
See https://github.com/SquidDev/Cobalt/compare/v0.6.0...v0.7.0 for the
full delta.
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/
Many thanks to Lem for managing to reproduce it. It was actually an easy
bug bug to spot on second look, but having a reliable way to verify was
super helpful.
Fixes#1338
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.
We define a tag which allows specifying which blocks can be used. Right
now this is is just cauldrons and hives, as they have "placing into"
semantics.
Closes#1305. Many thanks to Lindsay-Needs-Sleep for their initial work
on this!
Fixes#1008. I believe also fixes#854.
- We now write to a "ids.json.new" file, then move that on top of the
original ids.json file instead.
- Use FileChannel.force to ensure the new file is properly flushed to
disk. I can't really guarantee this'll work with the later
Files.move, but it's better than not doing it!
Closes#1346.
See the discussion in #1352 - Netty uses the system one by default,
so no sense creating our own.
Also make sure we through the HTTP error every time, not just on the
first failure. Otherwise we get cryptic connection dropped errors.
Given an input like f(x), which is both a valid statement and
expression, both parsers would accept the whole input. However, this was
treated the same as both parsers rejecting the input, resulting in a
crash when trying to print the error.
We now return immediately when any parser accepts the input.
Fixes#1354
Translations for Italian
Translations for French
Co-authored-by: Alessandro <ale.proto00@gmail.com>
Co-authored-by: RomanPlayer22 <romansulc13122006@gmail.com>
Co-authored-by: chesiren <chesiren63@gmail.com>
If someone had a recursive table (created with an IIFE), then we'd throw
an error inside reserialize. We now catch this error and silently drop
the value.
I'm not thrilled by this behaviour - there's an argument we should
return false instead - but it's consistent with what we currently do.
Closes#1337.
Historically, the VBO was an order of magnitude slower than the TBO
renderer. However, as of fccca22d3f, the
difference is much smaller now. While TBOs /are/ still faster, this only
has a measurable impact in extreme stress tests, and so isn't worth the
occasional issues which occur.
I'm still keeping the code around for now: I'm incredibly fond of it,
even three years later. I may end up re-evaluating this the next time
Minecraft's rendering code changes :D.
This also adds a line to the debug screen showing the current monitor
renderer, though maybe less useful now that almost everyone will be
using VBOs!
- Fix search failing when something is missing a summary (i.e. the
window API)
- Correctly use ":" or "." for type members - previously it was
incredibly inconsistent.
Previously it was possible to access all methods of the multishell
redirect by calling term.current(). This is definitely not intended, as
it leaks all sorts of internals to the user.
Also bump illuaminate - the new version is about twice as fast on my
machine.
Woops!
- Fix the REPL not printing values, as exception.try didn't return
values. It did originally, and then I tried to simplify it >_>
- Change repl_exprs to run an expression and program parser in
parallel, rather than handling the parallelism on the grammar side -
that has a few shift/reduce conflicts which result in bad parse
errors.
- Bump Cobalt to 0.6.0. We now track both line and column numbers of
each bytecode instruction, allowing us to map an error to a concrete
position.
- `loadfile` (and similar functions) now use the full path, rather than
the file name. Cobalt truncates this to 30 characters (rather than
the previous 60) so this should be less noisy.
- The shell, edit and Lua REPL now display the corresponding source
code alongside an error.
Note this is incredibly limited right now - it won't cope with errors
which cross coroutine boundaries. Supporting this is on the roadmap,
but requires some careful API design.
While it's a nice immersive interaction, it's far too easy to trigger by
accident. Dying/undying can now only be done via crafting and the
cauldron.
Closes#1321
It's much less aggressive than dunking it in a cauldron, so won't damage
any of your precious electronics.
I had this idea back in 2017 (dan200/ComputerCraft#230). Can't believe
it took me almost 6 years to implement.
In older versions we just used a hard-coded list of items and
superclasses. This was somewhat ugly, and so in 1.19.3 I tried to make
this code more generic.
However, this has a lot of unintended consequences - for instance
turtles can now throw ender pearls, which is definitely not intended!
By using a tag, we can emulate the old behaviour, while still allowing
modders and pack devs to add additional items if needed.
- Encode the DFA as a virtual machine (identical to lrgrep) rather than
compiling it to a series of Lua functions. While this is a little
slower and uglier, it's much more space efficient, shaving off 16Kb.
- Minimise the DFA properly. This only shaves off a few states, but
every little helps.
- Run the error handling code from a non-reduced parser stack. This was
incredibly nasty to get right (and positions are still not correctly
handled), but it fixes several broken error messages.
- Move modem recipes out of the usage section.
- Add missing argument names to BinaryWriableHandle.write. Illuaminate
really should catch this, but for now I did a grep and couldn't find
any more instances of this.
- Add several (internal) modules for lexing and parsing Lua code. These
allow us to provide (hopefully) higher quality error messages than
Lua's built-in messages.
- `shell.run`, `edit` and `lua` now use this parser when fed invalid
code. This allows us to provide better syntax errors, while not
having any impact on the happy path.
Note this does not affect any other mechanism for loading code
(`load`, `require`, `dofile`).
There's still a lot of work to do here in improving error message
quality, but hopefully this provides a good starting point.
- Document the thread safety of DetailRegistry a little better.
- Turtles now duplicate their inventory to the "previous
inventory" (now called inventorySnapshot) immediately, rather than
when the block is ticked.
This is slightly more resource intensive, but I don't think it's so
bad we need to worry.
- As this snapshot is now always up-to-date, we can read it from the
computer thread. Given the item is immutable, it's safe to read NBT
from it.
_Technically_ this is not safe under the Java memory model, but in
practice I don't think we'll observe the wrong value.
Closes#1306
Just ran[^1] over the codebase. Turns out we'd duplicated one of the
changelog entries entirely - I suspect due to a version merge gone
wrong!
[^1]: https://github.com/crate-ci/typos/
When the peripheral is attached, we add the computer to the map and
queue the actual disk to be mounted next tick. This avoids the
thread-safety issues with mutating the item (and creating disk ids) that
might be caused by doing it on the computer thread.
The mount is now also managed separately to the MediaStack, as that was
meant to be an immutable snapshot of the item!
Fixes#1282
This gives us slightly better guarantees that the config has actually
been loaded. This, along with a FCAP bump, fixes this config option
not doing anything on Fabric.
I originally put cc.import in a separate directory from the main
modules. This means that programs must extend the package path in order
to import these modules.
However, this ends up being a mixed blessing: while it makes it much
harder for users to accidentally require user code, it also means we
can't expose a public interface which wraps a private module.
Instead, cc.import now lives on the main package path, but lives under
the cc.internal namespace and is not documented anywhere. Hopefully this
should be enough of a clue that one shouldn't use it :p.
I was having issues where dropped items would clip into blocks when
dropped, and then phase upwards through the turtle instead. This makes
things a little more consistent with dispenser behaviour.
Instead of taking control of the breaking logic in all cases, we now
only do so when we have both a cable and modem. This allows us to fall
back to default vanilla behaviour and so correctly drop the modem/cable
item.
We now call getLevel() when attaching the peripheral, so need the
position to be available immediately. Fixes#1274.
I /think/ the entity should always be present, as peripherals are
only created on startup or when calling pocket.equipBack, both of which
require a player.[^1]
I suspect this was a little broken before (the level wouldn't be
available if a modem received a message before the position had
been set), but that would be much rarer.
I'm not 100% convinced about the thread-safety of this code (the writes
to level may not be immediately visible on other threads), so may need
to think about that.
[^1]: Note that when peripherals come to be /attached/ they may no
longer have a player (as there's a gap between turning a computer on and
it actually starting). However, the level/position will have been
initialised by then, so this isn't a problem.
Use `InteractionResult.sidedSuccess` / `.CONSUME` where applicable instead of `.SUCCESS`. This prevents the server from sending an additional swing animation packet to the client. Normally this isn't a problem, since the client will de-duplicate swing packets if they are within the animation duration of the currently playing swing; however, when connected to a server with a high ping the packet is sent after the animation is already finished on the client, resulting in a duplicate animation.
We now perform movement translations before rendering the label, rather
than afterwards. This means the label moves smoothly(ish), rather than
jumping from block to block.
I've been meaning to fix this for over 6 years, and just kept
forgetting.
Previously ILuaContext.executeMainThreadTask worked by running
ILuaContext.issueMainThreadTask, pulling task_complete events, and then
returning the results.
While this makes the implementation simple, it means that the task's
results were converted into Lua values (in order to queue the event) and
then back into Java ones (when the event was pulled), before eventually
being converted into Lua once more.
Not only is this inefficient, as roundtripping isn't lossless, you
couldn't return functions or rich objects from main thread functions
(see https://github.com/dan200/ComputerCraft/issues/125).
We now store the return value on the Java side and then return that when
the receiving the task_complete event - the event no longer carries the
result. Note this does not affect methods using issueMainThreadTask!
- Fix client classes not being included in Forge.
- Only remap Nettty's HTTP classes, not all of them. This feels a
little more error prone - maybe we should jar-in-jar this in the
future.
- Use the correct refmaps on Forge.
- Prevent the Fabric jar pulling in some other mods.
Closes#1247
- Correctly handle FileOperationExceptions for the root mount.
- Remove some checks from MountWrapper: Mount/WritableMount should do
these already!
- Normalise file paths, always using a '/'.
- Separate FileMount into separate FileMount and WritableFileMount
classes. This separates the (relatively simple) read-only code from
the (soon to be even more complex) read/write code.
It also allows you to create read-only mounts which don't bother with
filesystem accounting, which is nice.
- Make openForWrite/openForAppend always return a SeekableFileHandle.
Appendable files still cannot be seeked within, but that check is now
done on the FS side.
- Refactor the various mount tests to live in test contract interfaces,
allowing us to reuse them between mounts.
- Clean up our error handling a little better. (Most) file-specific code
has been moved to FileMount, and ArchiveMount-derived classes now
throw correct path-localised exceptions.
Currently published under 1.102.0-SNAPSHOT if anybody wants/needs to
poke. I'm going to break Mount/WritableMount, but everything else should
be stable!
Lots of minor changes, but nothing too nasty - just tedious.
Known bugs/issues:
- REI and JEI haven't been updated at the time of writing, so our usage
of their APIs may be incompatible.
- Crash when opening the config UI in Fabric, as forgeconfigapi-port
hasn't been updated yet.
Will hold off on doing a release until those mods have updated.
- Flip http.websocket and http.websocketAsync docs (fixes#1244)
- Fix http.request queuing a http_failure event with no URL when
passing a malformed URL
- Fix http.websocketAsync not queuing websocket_failure events on
immediate failure.
In classic squid tradition: 20% code, and 80% test logic.
Closes#962. Alas, whoever reported this has deleted their account, so
they can't even be happy about it :(.
- Update ForgeConfigAPI to the latest version, to fix the race
condition.
- Move WirelessNetwork lifecycle management to ServerContext.
- Some doc fixes.
- Remove deprecated API members in prep for 1.19.3. This allows us to
remove the mc-stubs and forge-stubs projects.
- Make several methods take a MinecraftServer instead of a Level (or
nothing at all).
- Remove I prefixes from a whole bunch of interfaces, making things a
little more consistent with Java conventions.
This avoids touching the "main" interfaces people consume for now. I
want to do that another Minecraft version, to avoid making the update
too painful.
- Remove IFileSystem and associated getters. This has never worked very
well and I don't think has got much (any?) usage.
I kinda hate this, but not sure what else to do. It might be worth
rewriting sanitizePath in the future to loop through the string once,
but I think this is good enough for now.
This removes the patching of fs and http, and replaces them with their
own standard Lua APIs. This makes the bios a little simpler, and means
we can move the documentation in line.
- Ensure they're correctly synced to the client. This definitely isn't
comprehensive, but doing anything further probably involves multiple
players, which is tricky.
- Quick rendering test for in-hand computers.
Forge requires the file to be in the root of the jar, hence doing it
this way round. The icon is read using ModContainer.findPath, so this
shouldn't conflict with other mods.
Love being on the bleedin' edge. More importantly, this fixes a couple
of issues:
- Translations are loaded on the server, meaning .getItemDetail
correctly translates modded items.
- Shulker boxes cannot be moved inside other shulker boxes using the
transfer API.
- Start using Fab API's ItemStack.getRecipeRemainder().
Translations for Swedish
Translations for French
Co-authored-by: Naheulf <newheulf@gmail.com>
Co-authored-by: SquidDev <git@squiddev.cc>
Co-authored-by: Алексей <handbrake.mine@gmail.com>
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.
- Add a new ClientJavaExec Gradle task, which is used for client-side
tests. This:
- Copies the exec spec from another JavaExec task.
- Sets some additional system properties to configure on gametest framework.
- Runs Java inside an X framebuffer (when available), meaning we
don't need to spin up a new window.
We also configure this task so that only one instance can run at
once, meaning we don't spawn multiple MC windows at once!
- Port our 1.16 client test framework to 1.19. This is mostly the same
as before, but screenshots no longer do a golden test: they /just/
write to a folder. Screenshots are compared manually afterwards.
This is still pretty brittle, and there's a lot of sleeps scattered
around in the code. It's not clear how well this will play on CI.
- Roll our own game test loader, rather than relying on the mod loader
to do it for us. This ensures that loading is consistent between
platforms (we already had to do some hacks for Forge) and makes it
easier to provide custom logic for loading client-only tests.
- Run several client tests (namely those involving monitor rendering)
against Sodium and Iris too. There's some nastiness here to set up
new Loom run configurations and automatically configure Iris to use
Complementary Shaders, but it's not too bad. These tests /don't/ run
on CI, so it doesn't need to be as reliable.
- Bundle the core API inside the Fabric API jar for now, to ensure
that ResourceLocation is remapped.
- Add a dummy fabric.mod.json file to the API. We'll remove this once
https://github.com/FabricMC/fabric-loom/pull/749 is released.
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.
My working tree is a mess, so this is not a good commit. I'm making a
bit of a habit of this.
- Fix UserLevel.OWNER check failing on single player servers.
- Correctly handle the "open folder" fake command.
- Some reshuffling of Forge-specific methods to make Fabric slightly
easier.
This commit got away from me, okay? No, I'm not proud of it either.
- Remove our overrides of handleUpdate tag: we now try to detect
whether we're on the client or server inside BlockEntity.load. Alas,
this is needed for Fabric.
- Remove BlockGeneric/TileGeneric entirely: we've slowly whittled this
down over the years, and nowadays we can get away with putting most
of its functionality into subclasses.
This allows us to do some nice things with overriding HorizontalBlock
(or our new HorizontalContainerBlock class), rather than
reimplementing functionality in each class. Though it would be nice
if Java had some sort of trait system :D:
- Simplify a lot of our container class so it's just defined in terms
of a NonNullList<ItemStack>. This also includes a total rewrite of
the disk drive which I'm not ... thrilled about. It ended up being
easier to copy the code from the mc-next branch :D:.
- Try to test some of the gnarly bits of this. Still a /lot/ more to be
done with testing this.
Closes#658
After several weeks of carefully arranging ribbons, we pull the string
and end up with, ... a bit of a messy bow. There were still some things
I'd missed.
- Split the mod into a common (vanilla-only) project and Forge-specific
project. This gives us room to add Fabric support later on.
- Split the project into main/client source sets. This is not currently
statically checked: we'll do that soon.
- Rename block/item/tile entities to use suffixes rather than prefixes.
- TurtlePlayer now returns a fake player, rather than extending from
Forge's implementation.
- Remove "turtle obeys block protection" config option.
- Put some of the more complex turtle actions behind the
PlatformHelper.
Another ugly commit, not thrilled about it:
- Move all config values to a separate Config class.
- Replace ComputerCraft.log with class-specific loggers.
- Replace ComputerCraft.MOD_ID with ComputerCraftAPI.MOD_ID
It's kinda funny looking at all the pre-CC:T proxy code, how much this
has come full circle. I think this design is nicer than what 1.12 did,
but it's still slighly embarassing.
- Add a new ContainerTransfer class to handle moving items between
containers. This is now used for turtle.drop/turtle.suck as well as
inventory methods.
- Any other usages of IItemHandler (which are mostly on turtle
inventories) now use Container and a couple of helper methods.
- 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.
While this does now involve a little more indirection, by having a
single location for all hooks it's much easier to keep event listeners
consistent between loaders.
The diff is pretty noisy (I've inlined some classes, and ClientRegistry
got a big restructure), but functionality should be the same.
Previously we overrode getCapability on our BlockEntity implementations.
While this is the Proper way to do things, it's obviously impossible to
do in a multi-loader environment.
We now subscribe to the AttachCapabilitiesEvent and add our caps that
way. This does require[^1] some nasty invalidation of caps in a couple
of places, which I'm not wild about.
[^1]: I'm not actually sure it does: we invalidate peripherals and wired
elements when neighbours change, so the explicit invalidation probably
isn't useful.
NetworkMessage follows vanilla's Packet much more closely now: the
handler takes a context argument, which varies between the client and
server.
- The server handler just returns the ServerPlayer who sent the
message.
- The client context provides handleXyz(...) methods for each
clientbound packet. Our packet subclasses call the appropriate
method - the implementation of which contains the actual
implementation.
Doing this allows us to move a whole bunch of client-specific code into
the main client package, dropping several @OnlyIn annotations and
generally reducing the risk of accidentally loading client classes on
the server.
We also abstract out some packet sending and general networking code to
make it easier to use in a multi-loader context.
- Replace our usages of DeferredRegistry with a custom
RegistrationHelper. This effectively behaves the same, just without
any references to Forge code!
- Replace any references to ForgeRegistries with a home-grown
Registries class. This just fetches the underlying registry and
proxies the method calls.
- Change recipe serialisers and loot item conditions to be registered
the same way as other entries.
- Move any Forge specific registration code off to the main
ComputerCraft class.
This adds two new modules: common-api and forge-api, which contain the
common and Forge-specific interfaces for CC's Minecraft-specific API.
We add a new PlatformHelper interface, which abstracts over some of the
loader-specific functionality, such as reading registries[^1] or calling
Forge-specific methods. This interface is then implemented in the main
mod, and loaded via ServiceLoaders.
Some other notes on this:
- We now split shared and client-specific source code into separate
modules. This is to make it harder to reference client code on the
server, thus crashing the game.
Eventually we'll split the main mod up too into separate source sets
- this is, of course, a much bigger problem!
- There's currently some nastiness here due to wanting to preserve
binary compatibility of the API. We'll hopefully be able to remove
this when 1.19.3 releases.
- In order to build a separate Forge-specific API jar, we compile the
common sources twice: once for the common jar and once for the Forge
jar.
Getting this to play nicely with IDEs is a little tricky and so we
provide a cct.inlineProject(...) helper to handle everything.
[^1]: We /can/ do this with vanilla's APIs, but it gives a lot of
deprecation warnings. It just ends up being nicer to abstract over it.
We'll do this everywhere eventually, but much easier to do it
incrementally:
- Use checker framework to default all field/methods/parameters to
@Nonnull.
- Start using ErrorProne[1] and NullAway[2] to check for possible null
pointer issues. I did look into using CheckerFramework, but it's much
stricter (i.e. it's actually Correct). This is technically good, but
is a much steeper migration path, which I'm not sure we're prepared
for yet!
[1]: https://github.com/google/error-prone
[2]: https://github.com/uber/NullAway
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.
- Move core-specific config options to a separate CoreConfig class.
- Use class-specific loggers, instead of a global one.
- Use log markers instead of a logComputerErrors option.
- Switch to a fairly standard code format. This is largely based on
IntelliJ defaults, with some minor tweaks applied via editor config.
Should mean people don't need to import a config!
- Use "var" everywhere instead of explicit types. Type inference is a
joy, and I intend to use it to its fullest.
- Start using switch expressions: we couldn't use them before because
IntelliJ does silly things with our previous brace style, but now we
have the luxury of them!
- Switch to using OptionalInt/OptionalLong instead of @Nullable
Long/Integers. I know IntelliJ complains, but it avoids the risk of
implicit unboxing.
- Instead of mutating PartialOptions, we now define a merge() function
which returns the new options. This simplifies the logic in
AddressRule a whole bunch.
This is a noisier diff than I'd like as this is just a direct copy from
the multi-loader branch.
- Rename "ingame" package to "gametest"
- Don't chain GameTestSequence methods - it's actually much cleaner if
we just use Kotlin's implicit this syntax.
- Use our work in 71f81e1201 to write
computer tests using Kotlin instead of Lua. This means all the logic
is in one place, which is nice!
- Add a couple more tests for some of the more error-prone bits of
functionality.
This is an initial step before refactoring this into a separate module.
It's definitely not complete - there's a lot of work needed to remove
referneces to the main ComputerCraft class for instance - but is a
useful first step.
I still don't really understand why the ROOT locale is wrong here, but
there we go. We'll need to remember to uncomment the tests on the 1.18
branch!
Also add some code to map tests back to their definition side. Alas,
this only links to the file right now, not the correct line :/.
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).
This allows other mods to create wired-modem alike blocks, which expose
peripherals on the wired network, without having to reimplement the main
modem interface.
This is not currently documented, but a peripheral_hub should provide
the following methods:
- isPresentRemote
- getTypeRemote
- hasTypeRemote
- getMethodsRemote
- callRemote
- Add a new file_transfer event. This has the signature
"file_transfer", TransferredFiles.
TransferredFiles has a single method getFiles(), which returns a list
of all transferred files.
- Add a new "import" program which waits for a file_transfer event and
writes files to the current directory.
- If a file_transfer event is not handled (i.e. its getFiles() method
is not called) within 5 seconds on the client, we display a toast
informing the user on how to upload a file.
- Use <p> everywhere. This is uglier, but also technically more
correct. This requires a version bump to cct-javadoc, and will give
me a massive headache when merging.
- Link against the existing OpenJDK docs.
We now wait for workers to terminate when closing the computer thread.
I'll be honest, I'm not happy with this code. Multi-threading is really
hard to get right, and I can't say I'm convinced this is especially well
behaved. I did look at trying to model this in TLA+, but in the end
decided it wasn't worth it.
In the future we probably want to split ComputerExecutor into two
objects, where one is our entry in the ComputerThread queue (and so
holds timing information) while the other is responsible for actual
execution.
- Correctly handle Git commands failing. We need an actual default
value, not just null!
- Use run/ and build/tmp/ for temporary test locations, not
/test-files.
- Switch over to the Gradle GH action. Not expecting massive changes,
but might provide some better caching.
- Bump some GH action versions.
- Fix a Java 8 compatability issue in our build scripts.
- Add a new Node plugin. This automatically installs npm dependencies
and provides a "NpxExecToDir" to dir task. This allows us to make the
doc website task dependencies a little nicer, by simply chaining
tasks together, rather than doing dependsOn + `input.files(the other
task output)`.
- Switch over to CurseForgeGradle from CurseGradle. The latter is
super clunky to use in non-Groovy languages.
- Copy our Modrinth description body to our repo, and add support for
syncing it. We'll still have to do CF manually I think.
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.
This converts ComputerThread from a singleton into a proper object,
which is setup when starting a computer, and tore down when the
ComputerContext is closed.
While this is mostly for conceptual elegance, it does offer some
concrete benefits:
- You can now adjust the thread count without restarting the whole
game (just leaving and rentering the world). Though, alas, no effect
on servers.
- We can run multiple ComputerThreads in parallel, which makes it much
easier to run tests in parallel. This allows us to remove our rather
silly IsolatedRunner test helper.
Computers now use a MainThreadScheduler to construct a
MainThreadScheduler.Executor, which is used to submit tasks. Our
previous (singleton) MainThread and MainThreadExecutor now implement
these interfaces.
The main purpose of this is to better manage the lifetime of the server
thread tasks. We've had at least one bug caused by us failing to reset
its state, so good to avoid those! This also allows us to use a fake
implementation in tests where we don't expect main thread tasks to run.
As we're now passing a bunch of arguments into our Computer, we bundle
the "global" ones into ComputerContext (which now also includes the Lua
machine factory!). This definitely isn't the nicest API, so we might
want to rethink this one day.
In some ways this isn't as nice as the Forge version (requires ATs,
doesn't check texture/model existence). However, it's more multi-loader
friendly and in some cases has much less boilerplate.
Blockstate JSON files are incredibly verbose, so we add a custom JSON
pretty printer which writes things in a slightly more compact manner.
This also changes how turtle upgrades are loaded - we now support
standard ResourceLocations (so computercraft:blocks/some_turtle_upgrade)
as well as ModelResourceLocations (computercraft:items/some_turtle_upgrade#inventory).
I don't think any resource packs need to touch our upgrades, but
apologies if this breaks anything.
- Convert remaining recipes over to datagen.
- Switch loot tables to use vanilla's loot table generator. It's
honestly not too different, just the earlier system confused me too
much :).
Alas, a positive diff because the JSON is so verbose. I've got a really
nice patch which makes the JSON more compact, but alas the Mixin doesn't
apply on 1.16 :(.
- Remove TrackingField and replace it with a Metric abstract class.
This has two concrete subclasses - Counter and Event. Events carry an
additional piece of data each time it is observed, such as HTTP
response size.
- Computers now accept a MetricsObserver, which tracks metrics for this
particular computer. This allows us to decouple Computer classes and
metrics information. The concrete MetricsObserver class we use within
Minecraft exposes the ServerComputer directly, so we no longer need to
do the awkward mapping and lookups!
- The /computercraft command can now do aggregates (count, avg, max)
over all Event metrics. This removes the need for special handling of
computer and server time.
There's also a small number of changes in removing the coupling between
Computer and some of its dependencies (ILuaMachine, MainThreadExecutor).
This makes some future refactorings easier, I promise!
This is a little odd (it's more complex for one!), but means we can
reuse the internal API interface in other classes, which is useful for
the data provider refactor I'm about to do.
This is much nicer in Java 17 :D (records, ServiceLoader.stream()),
but such is the perils of still targetting 1.16.
We now fuzz UploadFileMessage, generating random files and checking they
round-trip correctly.
The joy of having a long-lasting refactor branch with an absolutely
massive diff, is that you end up spotting bugs, and then it's a massive
pain to merge the fix back into trunk!
The last 4 or 5 commits have simplified things. I can now have some
unnecessary complexity as a treat!
This is some initial work on better tying the lifecycle of
computers (and ComputerCraft) related state to the lifecycle of the
current Minecraft server.
- Move server-wide methods in IComputerEnvironment (such as creating
resource mounts) into a separate interface.
- Add a new ServerContext class, which now holds the ID Assigner,
server computer registry, and some other tiny bits and bobs. This can
only be accessed by ServerContect.get(MinecraftServer), forcing
slightly better discipline for how we use these globals.
This does allow us to nuke some of the ugliest bits in IDAssigner. Even
if it makes things much longer!
Moves ID assigning out of the Computer class and into wherever we
construct the ServerComputer (so in computer blocks and pocket computer
items).
This is definitely not perfect - it'd be nice to make ServerComputers
more responsible for managing the lifecycle of computers (so assigning
ids, handling auto-starting, etc...), but I've not found a good way to
handle this yet!
They bring very little to the table now that computers do their own
thing! This also helps simplify the code in ServerMonitor a bit - turns
out we had two "dirty" flags in the implementation!
Previously we stored it alongside the terminal. While this makes sense -
it's not a property of the terminal itself, it ends up duplicating code
in a bunch of places.
We now track the colour flag on the terminal itself. This allows us to
simplify a couple of things:
- The palette now also knows whether it supports colours or not, and so
performs greyscale conversion. This means we no longer need to thread
a "greyscale" flag throughout terminal rendering.
- Remove isColour() getters from a whole load of
places (TerminalMethods, ServerTerminal, IComputerEnvironment).
Historically CC has maintained two computer registries; one on the
server (which runs the actual computer) and one on the client (which
stores the terminal and some small bits of additional data).
This means when a user opens the computer UI, we send the terminal
contents and store it in the client computer registry. We then send the
instance id alongside the "open container" packet, which is used to look
up the client computer (and thus terminal) in our client-side registry.
This patch makes the computer menu syncing behaviour more consistent
with vanilla. The initial terminal contents is sent alongside the "open
container" packet, and subsequent terminal changes apply /just/ to the
open container. Computer on/off state is synced via a vanilla
ContainerData/IIntArray.
Likewise, sending user input to the server now targets the open
container, rather than an arbitrary instance id.
The one remaining usage of ClientComputer is for pocket computers. For
these, we still need to sync the current on/off/blinking state and the
pocket computer light.
We don't need the full ClientComputer interface for this case (after
all, you can't send input to a pocket computer someone else is
holding!). This means we can tear out ClientComputer and
ClientComputerRegistry, replacing it with a much simpler
ClientPocketComputers store.
This in turn allows the following changes:
- Remove IComputer, as we no longer need to abstract over client and
server computers.
- Likewise, we can merge ComputerRegistry into the server
registry. This commit also cleans up the handling of instance IDs a
little bit: ServerComputers are now responsible for generating their
ID and adding/removing themselves from the registry.
- As the client-side terminal will never be null, we can remove a whole
bunch of null checks throughout the codebase.
- As the terminal is available immediately, we don't need to explicitly
pass in terminal sizes to the computer GUIs. This means we're no
longer reliant on those config values on the client side!
- Remove the "request computer state" packet. Pocket computers now
store which players need to know the computer state, automatically
sending data when a new player starts tracking the computer.
Caused by 4228011b84. While correct on
1.18, this isn't correct on 1.19 - I clearly messed up the merge here.
Fixes#1183, possibly #1184 - haven't been able to reproduce.
I was going to do something productive tonight, but then this happened.
Whatever, I'm retired, I'm allowed to make my entire existence just
adding 50px to things. Heck, maybe I'll do the same tomorrow too.
Closes#1133. I'm not super happy about any of the versions proposed
there, but I think this is better than nothing.
Co-authored-by: JackMacWindows <jackmacwindowslinux@gmail.com>
We clamped various values to the height of the screen, rather than the
height of the content box (height-1). We didn't notice this most of the
time as the last line of a file is empty - it only really mattered when
a file was the same height as the computer's screen.
We now do the following:
- Strip the trailing new line from a file when reading.
- Replace most usages of height with height-1.
Previously illumainate required manual users to manually download it and
place it in ./bin/. This is both inconvenient for the user, and makes it
hard to ensure people are running the "right" version.
We now provide a small Gradle plugin which registers illuaminate as a
ependency, downloading the appropriate (now versioned!) file. This also
theoretically supports Macs, though I don't have access to one to test
this.
This enables the following changes:
- The Lua lint script has been converted to a Gradle task (./gradle
lintLua).
- illuaminateDocs now uses a task definition with an explicit output
directory. We can now consume this output as an input to another
task, and get a task dependency implicitly.
- Move the pre-commit config into the root of the tree. We can now use
the default GitHub action to run our hooks.
- Simplify CONTRIBUTING.md a little bit. Hopefully it's less
intimidating now.
This is mostly copied from the work Toad and I did for CC:R.
Instead of not writing to the depth buffer when rendering terminals, we
now render terminal forgrounds with a small glPolygonOffset (or an
emulation of it where not possible). This removes the need for custom
render types, while still avoiding z-fighting between the terminal
foreground and background.
The VBO monitors backend now uses Iris's TextVertexSink API when
available: Iris overwrites the vertex format for RenderType.text, and so
we need to use this API to avoid rendering garbage.
Performance is maybe a little worse than before (<3ms) and definitely
worse than CC:R. Unfortunately we can't do our upload batching as that
conflicts with Optifine's patches - instead we need to maintain two
separate VBOs. This is a bit slower, but not so bad it's unworkable.
ITurtleUpgrade.getModel has always been rather error-prone to use, due
to its client-only nature. As ModelResourceLocation is now client-only
again in Forge 1.19.1, no seems a good time to fix this.
The getter for models is now a separate interface inside a new
dan200.computercraft.api.client package. These are registered
per-TurtleUpgradeSerialiser (as those should correspond to class
anyway). It's a little ugly, and we may rename the XxxSerialiser classes
to something more general in a future update.
I'm not wild about the interface here either - happy to change it in
future versions too.
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
Also clean up the generic arguments to IUpgradeBase/UpgradeSerialiser a
little bit. It's not great (wish Java had HKTs), but it's better.
We're doing lots of weird OpenGL shenangins anyway, so it doesn't make
sense to use it. Instead just draw directly using the Tesselator
BufferBuilder.
This might improve compatiability with Sodium/Rubidium. Please don't let
me know if it doesn't though - I really don't want to have to deal with
it any more.
- Lots of refactoring/cleanup to Forge's events and client APIs.
- Render types/layers for blocks are now set on the model rather than
in code.
- Models now can work with multiple render types. As this would
massively complicate the implementation of the turtle item model, we
now implement a much simpler version, which makes use of Forge's
BakedModel.getRenderPasses to return a separate model for the core
turtle and each upgrade.
- Send monitor contents to players immediately when they start watching
the chunk. ChunkWatchEvent.Watch is now fired from a more sensible
location, so this is much easier to implement!
Rather than blanket disabling http with http.enabled. I think it's still
useful to keep the option around, but hopefully make it clearer what the
ramifications are.
- Changed page background to render as one quad, instead of two halves.
- Set page background to a z-offset that is between zeroth (potentially
bold border) and subsequent background pages. Bold borders were at the
same z-offset before.
We removed the config which ran all JavaExec tasks with the given
launcher, so need to override this again.
A little abusrd that this isn't done by Gradle, but there we go.
No bearing on MC, but allows us to drop the depenedency in other
projects (CCEmuX, eval.tweaked.cc, etc...)
I'd quite like to spin the core into a separate project which doesn't
depend on MC at all, but not worth doing right now.
Just saves us from having to worry about conflicts with other mods which
bundle Cobalt. This might make the transition to Jar-in-Jar easier too -
not sure yet!
Also produce an API jar - fixes#1060.
- Switch to plugins { ... } imports for Forge (FG finally supports it!)
- Use FG's new fg.component to clean up our Maven metadata instead. We
also mark JEI as optional (using Gradle's registerFeature), which
means we've no stray deps inside our POM any more.
No bearing on MC, but allows us to drop the depenedency in other
projects (CCEmuX, eval.tweaked.cc, etc...)
I'd quite like to spin the core into a separate project which doesn't
depend on MC at all, but not worth doing right now.
Oh my, a same day release! Well, if we use the AoE timezone.
Entirely untested (well, aside from automated tests), I haven't even
launched a client. In my defence, its just past midnight and I've been
up since 4am.
- Add a basic data exporter to the test mod, run via a /ccexport
command. This dumps all of CC's recipes, and the item icons needed to
display those recipes.
- Post-process our illuaminate HTML, applying several transforms:
- Apply syntax highlighting to code blocks. We previously did this
at runtime, so this shaves some bytes off the bundle.
- Convert a mc-recipe custom element into a recipe grid using
react/react-dom.
- Add a recipe to the speaker page. I'll probably clean this up in the
future (though someone else is free to too!), but it's a nice
start and proof-of-concept.
I tried so hard here to use next.js and MDX instead of rolling our own
solution again, but it's so hard to make it play well with "normal"
Markdown, which isn't explicitly written for MDX.
We now track whether a tile is enqueued or not via an atomic boolean on
the block entity itself, rather than using a hash set. This is
significantly faster (>10x).
This is mostly intended for monitors, as they're the only peripheral
likely to call TickScheduler.schedule lots of times (rather than modems,
which just invoke it when opening/closing a channel[^1])[^2]. This
change is enough to allow me to update 120 monitors each tick without
any major tearing.
[^1]: GPS does do this on each gps.locate call, so it will help there,
but modems are typically limited by other computers sending messages,
not peripheral calls themselves.
[^2]: Note that montitors implement their own change tracking, so still
only call this once per tick. But it's enough to introduce some latency!
This gives us slightly better compression, as backgrounds will often be
a single run of colours while the foreground won't be.
In practice, this is rarely an issue, as most terminals are small, but
worth doing anyway.
Just like vanilla locking, this isn't accessible in survival.
> "im retired! im retired!!", i continue to insist as i slowly shrink
> and transform into a corn cob.
- Make assertions a little more relaxed
- Increase timeouts of computer tests (again :D:).
- Log where we're up to in computer tests, to make tracking stalls a
little easier
- Rewrap everything at 80 columns. To make this tolerable I'm using
IDEA's language fragment support - hence the absurd line lengths.
- Add full stops to all comments.
- Clarify that HTTP rules are applied in-order.
- Parse Co-authored-by lines too. There's several contributors (mostly
via weblate, but a few GH ones too) who weren't credited otherwise.
- Add support for git mailmap, remapping some emails to a canonnical
username. This allows us to remove some duplicates - nobody needs
both SquidDev and "Jonathan Coates."
I'm not making this file public, as it contains email addresses. This
does mean that CI builds will still contain the full list with
duplicates.
- Add a TOC to the Local IPs page.
- Increase the echo delay in our speaker audio page to 1.5s. This
sounds much better and is less clashy than 1s. Also add a
sleep(0) (eww, I know) to fix timeouts on some browsers/computers.
- Move Lua feature compat to a new "reference" section. Still haven't
figured out how to structure these docs - open to any ideas really.
- Mention FFmpeg as an option for converting to DFPWM (closes#1075).
- Allow data-mount to override built-in files. See my comment in #1069.
Previously we would compute the current timeout flags every 128
instructions of the Lua machine. While computing these flags is
_relatively_ cheap (just get the current time), it still all adds up.
Instead we now set the timeout flags from the computer monitor/watchdog
thread. This does mean that the monitor thread needs to wake up more
often[^1] _if the queue is full_, otherwise we can sleep for 100ms as
before.
This does mean that pausing is a little less accurate (can technically
take up 2*period instead). This isn't great, but in practice it seems
fine - I've not noticed any playability issues.
This offers a small (but measurable!) boost to computer performance.
[^1]: We currently sleep for scaledPeriod, but we could choose to do less.
- Reset state while the server is starting rather than once it has
started. Hopefully fixes a weird issue where wireless modems wouldn't
be "connected" on server startup.
- Correctly reset the MainThread metrics on server start/stop.
Geesh, this is nasty. Because ComputerThread is incredibly stateful, and
we want to run tests in isolation, we run each test inside its own
isolated ClassLoader (and thus ComputerThread instance).
Everything else is less nasty, though still a bit ... yuck. We also
define a custom ILuaMachine which just runs lambdas[^1], and some
utilities for starting those.
This is then tied together for four very basic tests. This is sufficient
for the changes I want to make, but might be nice to test some more
comprehensive stuff later on (e.g. timeouts after pausing).
[^1]: Which also means the ILuaMachine implementation can be changed by
other mods[^2], if someone wants to have another stab at LuaJIT :p.
[^2]: In theory. I doubt its possible in practice because so much is
package private.
This is about 5-6x faster than using a String as we don't need to
allocate and copy multiple times. In the grand scheme of things, still
vastly overshadowed by the Lua interpreter, but worth doing.
- Start making the summary lines for modules a little better. Just say
what the module does, rather than "The X API does Y" or "Provides Y".
There's still a lot of work to be done here.
- Bundle prism.js on the page, so we can highlight non-Lua code.
- Copy our local_ips wiki page to the main docs.
This allows us to sync the position to the entity immediately, rather
than the sound jumping about.
Someone has set up rick-rolling pocket computers (<3 to whoever did
this), and the lag on them irritates me enough to fix this.
Fixes#1074
- Bump Forge version to latest RB.
- Generate an 8-bit audio stream again, as we no longer need to be
compatible with MC's existing streams.
No functionality changes, just mildly less hacky.
GlStateManager.glDeleteBuffers clears a buffer before deleting it on
Linux - I assume otherwise there's memory leaks on some drivers? - which
clobbers BufferUploader's cache. Roll our own version which resets the
cache when needed.
Also always reset the cache when deleting/creating a DirectVertexBuffer.
This /significantly/ improves performance of the VBO renderer (3fps to
80fps with 120 constantly changing monitors) and offers some minor FPS
improvements to the TBO renderer.
This also makes the 1.16 rendering code a little more consistent with
the 1.18 code, cleaning it up a little in the process.
Closes#1065 - this is a backport of those changes for 1.16. I will
merge these changes into 1.18, as with everything else (oh boy, that'll
be fun).
Please note this is only tested on my machine right now - any help
testing on other CPU/GPU configurations is much appreciated.
Historically I've been reluctant to do this as people might be running
Optifine for performance rather than shaders, and the VBO renderer was
significantly slower when monitors were changing.
With the recent performance optimisations, the difference isn't as bad.
Given how many people ask/complain about the TBO renderer and shaders, I
think it's worth doing this, even if it's not as granular as I'd like.
Also changes how we do the monitor backend check. We now only check for
compatibility if BEST is selected - if there's an override, we assume
the user knows what they're doing (a bold assumption, if I may say so
myself).
- For TBOs, we now pass cursor position, colour and blink state as
variables to the shader, and use them to overlay the cursor texture
in the right place.
As we no longer need to render the cursor, we can skip the depth
buffer, meaning we have to do one fewer upload+draw cycle.
- For VBOs, we bake the cursor into the main VBO, and switch between
rendering n and n+1 quads. We still need the depth blocker, but can
save one upload+draw cycle when the cursor is visible.
This saves significant time on the TBO renderer - somewhere between 4
and 7ms/frame, which bumps us up from 35 to 47fps on my test world (480
full-sized monitors, changing every tick). [Taken on 1.18, but should be
similar on 1.16]
Like #455, this sets our uniforms via a UBO rather than having separate
ones for each value. There are a couple of small differences:
- Have a UBO for each monitor, rather than sharing one and rewriting it
every monitor. This means we only need to update the buffer when the
monitor changes.
- Use std140 rather than the default layout. This means we don't have
to care about location/stride in the buffer.
Also like #455, this doesn't actually seem to result in any performance
improvements for me. However, it does make it a bit easier to handle a
large number of uniforms.
Also cleans up the generation of the main monitor texture buffer:
- Move buffer generation into a separate method - just ensures that it
shows up separately in profilers.
- Explicitly pass the position when setting bytes, rather than
incrementing the internal one. This saves some memory reads/writes (I
thought Java optimised them out, evidently not!). Saves a few fps
when updating.
- Use DSA when possible. Unclear if it helps at all, but nice to do :).
This takes a non-trivial amount of time on the render thread[^1], so
worth doing.
I don't actually think the allocation is the heavy thing here -
VisualVM says it's toWorldPos being slow. I'm not sure why - possibly
just all the block property lookups? [^2]
[^1]: To be clear, this is with 120 monitors and no other block entities
with custom renderers. so not really representative.
[^2]: I wish I could provide a narrower range, but it varies so much
between me restarting the game. Makes it impossible to benchmark
anything!
The VBO renderer needs to generate a buffer with two quads for each
cell, and then transfer it to the GPU. For large monitors, generating
this buffer can get quite slow. Most of the issues come from
IVertexBuilder (VertexConsumer under MojMap) having a lot of overhead.
By emitting a ByteBuffer directly (and doing so with Unsafe to avoid
bounds checks), we can improve performance 10 fold, going from
3fps/300ms for 120 monitors to 111fps/9ms.
See 41fa95bce4 and #1065 for some more
context and other exploratory work. The key thing to note is we _need_ a
separate version of FWFR for emitting to a ByteBuffer, as introducing
polymorphism to it comes with a significant performance hit.
- Move all RenderType instances into a common class.
Cherry-picked from 41fa95bce4:
- Render GL_QUADS instead of GL_TRIANGLES.
- Remove any "immediate mode" methods from FWFR. Most use-cases can be
replaced with the global MultiBufferSource and a proper RenderType
(which we weren't using correctly before!).
Only the GUI code (WidgetTerminal) needs to use the immediate mode.
- Pre-convert palette colours to bytes, storing both the coloured and
greyscale versions as a byte array.
Cherry-picked from 3eb601e554:
- Pass lightmap variables around the various renderers. Fixes#919 for
1.16!
"Instead, it is a standard program, which its API into the programs that it launches."
becomes
"Instead, it is a standard program, which injects its API into the programs that it launches."
A little shorter and more explicit than constructing the Vector3d
manually. Fixes an issue where sounds were centered on the bottom left
of speakers, not the middle (see cc-tweaked/cc-restitched#85).
See #1061, closes#1064.
Nobody ever seems to implement this correctly (though it's better than
1.12, at least we've not seen any crashes), and this isn't a fight I
care enough about fighting any more.
- Remove the POSITION_COLOR render type. Instead we just render a
background terminal quad as the pocket computer light - it's a little
(lot?) more cheaty, but saves having to create a render type.
- Use the existing position_color_tex shader instead of our copy. I
looked at using RenderType.text, but had a bunch of problems with GUI
terminals. Its possible we can fix it, but didn't want to spend too
much time on it.
- Remove some methods from FixedWidthFontRenderer, inlining them into
the call site.
- Switch back to using GL_QUADS rather than GL_TRIANGLES. I know Lig
will shout at me for this, but the rest of MC uses QUADS, so I don't
think best practice really matters here.
- Fix the TBO backend monitor not rendering monitors with fog.
Unfortunately we can't easily do this to the VBO one without writing
a custom shader (which defeats the whole point of the VBO backend!),
as the distance calculation of most render types expect an
already-transformed position (camera-relative I think!) while we pass
a world-relative one.
- When rendering to a VBO we push vertices to a ByteBuffer directly,
rather than going through MC's VertexConsumer system. This removes
the overhead which comes with VertexConsumer, significantly improving
performance.
- Pre-convert palette colours to bytes, storing both the coloured and
greyscale versions as a byte array. This allows us to remove the
multiple casts and conversions (double -> float -> (greyscale) ->
byte), offering noticeable performance improvements (multiple ms per
frame).
We're using a byte[] here rather than a record of three bytes as
notionally it provides better performance when writing to a
ByteBuffer directly compared to calling .put() four times. [^1]
- Memorize getRenderBoundingBox. This was taking about 5% of the total
time on the render thread[^2], so worth doing.
I don't actually think the allocation is the heavy thing here -
VisualVM says it's toWorldPos being slow. I'm not sure why - possibly
just all the block property lookups? [^2]
Note that none of these changes improve compatibility with Optifine.
Right now there's some serious issues where monitors are writing _over_
blocks in front of them. To fix this, we probably need to remove the
depth blocker and just render characters with a z offset. Will do that
in a separate commit, as I need to evaluate how well that change will
work first.
The main advantage of this commit is the improved performance. In my
stress test with 120 monitors updating every tick, I'm getting 10-20fps
[^3] (still much worse than TBOs, which manages a solid 60-100).
In practice, we'll actually be much better than this. Our network
bandwidth limits means only 40 change in a single tick - and so FPS is
much more reasonable (+60fps).
[^1]: In general, put(byte[]) is faster than put(byte) multiple times.
Just not clear if this is true when dealing with a small (and loop
unrolled) number of bytes.
[^2]: To be clear, this is with 120 monitors and no other block entities
with custom renderers. so not really representative.
[^3]: I wish I could provide a narrower range, but it varies so much
between me restarting the game. Makes it impossible to benchmark
anything!
Forge 4.0.18 deprecated a lot of methods and moved where
RegistryEvent.NewRegistry lives, so we needed to update. This does break
the CC API a little bit (sorry!) though given Forge 1.18.2 is still in
flux, that's probably inevitable.
There's a couple of alternative ways to solve this. Ideally we'd send
our network messages at the same time as MC does
(ChunkManager.playerLoadedChunk), but this'd require a mixin.
Instead we just rely on the fact that if the chunk isn't loaded,
monitors won't have done anything and so we don't need to send their
contents!
Fixes#1047, probably doesn't cause any regressions. I've not seen any
issues on 1.16, but I also hadn't before so ¯\_(ツ)_/¯.
It's now impossible to run the client tests (tests are still there, but
none of the other infrastructure is). We've not run these for months now
due to their severe flakiness :(.
This was added in the 1.13 update and I'm still not sure why. Other mods
seem to get away without it, so I think it's fine to remove.
Also remove the fake net manager, as that's part of Forge nowadays.
Fixes#1044.
- Fixes#1026
- The remaining bytes counter wasn't being decremented, so the code that
splits off smaller packets was unreachable. Thus all file slices were
being put into a single UploadFileMessage packet.
- Fix UpgradeSpeakerPeripheral not calling super.detach (so old
computers were never cleaned up)
- Correctly lock computer accesses inside SpeakerPeripheral
Fixes#1003.
Fingers crossed this is the last bug. Then I can bump the year and push
a new release tomorrow.
We're still a few days away from release, but don't think anything else
is going to change. And I /really/ don't want to have to write this
changelog (and then merge into later versions) on the 25th.
While Minecraft will automatically push a new buffer when one is
exhausted, this doesn't help if there's only a single buffer in the
queue, and you end up with stutter.
By enquing a buffer when receiving sound we ensure there's always
something queued. I'm not 100% happy with this solution, but it does
alleviate some of the concerns in #993.
Also reduce the size of the client buffer to 0.5s from 1.5s. This is
still enough to ensure seamless audio when the server is running slow (I
tested at 13 tps, but should be able to go much worse).
When the game is paused in SSP world, speakers are not ticked. However,
System.nanoTime() continues to increase, which means the next tick
speakers believe there has been a big jump and so schedule a bunch of
extra audio.
To avoid this, we keep track of how long the game has been paused offset
nanoTime by that amount.
Fixes#994
It's just more confusing having to keep track of where the ByteBuffer is
at. In this case, I think we were forgetting to rewind after computing
the digest.
Hopefully we'll be able to drop some of these in 1.17 as Java 16 has
a few more ByteBuffer methods
Fixes#992
Speakers can now play arbitrary PCM audio, sampled at 48kHz and with a
resolution of 8 bits. Programs can build up buffers of audio locally,
play it using `speaker.playAudio`, where it is encoded to DFPWM, sent
across the network, decoded, and played on the client.
`speaker.playAudio` may return false when a chunk of audio has been
submitted but not yet sent to the client. In this case, the program
should wait for a speaker_audio_empty event and try again, repeating
until it works.
While the API is a little odd, this gives us fantastic flexibility (we
can play arbitrary streams of audio) while still being resilient in the
presence of server lag (either TPS or on the computer thread).
Some other notes:
- There is a significant buffer on both the client and server, which
means that sound take several seconds to finish after playing has
started. One can force it to be stopped playing with the new
`speaker.stop` call.
- This also adds a `cc.audio.dfpwm` module, which allows encoding and
decoding DFPWM1a audio files.
- I spent so long writing the documentation for this. Who knows if it'll
be helpful!
- Remove all the hungrarian notation in variables. Currently leaving
the format of rednet messages for now, while I work out whether this
counts as part of the public API or not.
- Fix the "repeat" program failing with broadcast packets. This was
introduced in #900, but I don't think anybody noticed. Will be more
relevant when #955 is implemented though.
This means that if the current player is breaking a cable/wired modem,
only the part they're looking at has breaking progress. Closes#355.
A mixin is definitely not the cleanest way to do this. There's a couple
of alternatives:
- CodeChickenLib's approach of overriding the BlockRendererDispatcher
instance with a delegating subclasss. One mod doing this is fine,
several is Not Great.o
- Adding a PR to Forge: I started this, and it's definitely the ideal
solution, but any event for this would have a ton of fields and just
ended up looking super ugly.
I assume people have broken coroutine dispatchers - I didn't think it
was possible to queue an actual event with no type.
See cc-tweaked/cc-restitched#31. Will fix it too once merged downstream!
testModExtra must /strictly/ be the set of dependencies which are not
present in implementation - there can't be any duplicates.
Yes, it's stupid, but the whole lazyToken("minecraft_classpath") thing
wasn't really built with this in mind, so not much we can do :)
Opening a screen KeyBinding.releaseAll(), which forces all inputs to be
considered released. However, our init() function then calls
grabMouse(), which calls Keybinding.setAll(), undoing this work.
The fix we're going for here is to call releaseAll() one more time[^1]
after grabbing the mouse. I think if this becomes any more of a problem,
we should roll our own grabMouse which _doesn't_ implement any specific
behaviour.
Fixes#975
[^1]: Obvious problem here is that we do minecraft.screen=xyz rather
than setScreen. We need to - otherwise we'd just hit a stack
overflow - but it's not great.
- Build fails right now due to module issues, so this won't be pushed
to GitHub.
- Monitors render transparently when loaded into the world. I don't
think this is a 1.17 bug, so not sure what's going on here!
Peripherals can now have multiple types:
- A single primary type. This is the same as the current idea of a
type - some identifier which (mostly) uniquely identifies this kind
of peripheral. For instance, "speaker" or "minecraft:chest".
- 0 or more "additional" types. These are more like traits, and
describe what other behaviour the peripheral has - is it an
inventory? Does it supply additional peripherals (like a wired
modem)?.
This is mostly intended for the generic peripheral system, but it might
prove useful elsewhere too - we'll have to see!
- peripheral.getType (and modem.getTypeRemote) now returns 1 or more
values, rather than exactly one.
- Add a new peripheral.hasType (and modem.hasTypeRemote) function which
determines if a peripheral has the given type (primary or
additional).
- Change peripheral.find and all internal peripheral methods to use
peripheral.hasType instead.
- Update the peripherals program to show all types
This effectively allows you to do things like
`peripheral.find("inventory")` to find all inventories.
This also rewrites the introduction to the peripheral API, hopefully
making it a little more useful.
- Capability invalidation and tile/block entity changes set a dirty bit
instead of refetching the peripheral immediately.
- Then on the block's tick we recompute the peripheral if the dirty bit
is set.
Fixes#696 and probably fixes#882. Some way towards #893, but not
everything yet.
This is probably going to break things horribly. Let's find out!
- Bump copy-cat version to have support for initial files in
directories and the blit fixes.
- Add an example nft image and move example nfp into a data/ directory.
- Fix nft parser not resetting colours on the start of each line.
The feature nobody asked for, but we're getting anyway.
Old way to register a turtle/pocket computer upgrade:
ComputerCraftAPI.registerTurtleUpgrade(new MyUpgrade(new ResourceLocation("my_mod", "my_upgrade")));
New way to register a turtle/pocket computer upgrade:
First, define a serialiser for your turtle upgrade type:
static final DeferredRegister<TurtleUpgradeSerialiser<?>> SERIALISERS = DeferredRegister.create( TurtleUpgradeSerialiser.TYPE, "my_mod" );
public static final RegistryObject<TurtleUpgradeSerialiser<MyUpgrade>> MY_UPGRADE =
SERIALISERS.register( "my_upgrade", () -> TurtleUpgradeSerialiser.simple( MyUpgrade::new ) );
SERIALISERS.register(bus); // Call in your mod constructor.
Now either create a JSON string or use a data generator to register your upgrades:
class TurtleDataGenerator extends TurtleUpgradeDataProvider {
@Override
protected void addUpgrades( @Nonnull Consumer<Upgrade<TurtleUpgradeSerialiser<?>>> addUpgrade )
simple(new ResourceLocation("my_mod", my_upgrade"), MY_UPGRADE.get()).add(addUpgrade);
}
}
See much better! In all seriousness, this does offer some benefits,
namely that it's now possible to overwrite or create upgrades via
datapacks.
Actual changes:
- Remove ComputerCraftAPI.register{Turtle,Pocket}Upgrade functions.
- Instead add {Turtle,Pocket}UpgradeSerialiser classes, which are used
to load upgrades from JSON files in datapacks, and then read/write
them to network packets (much like recipe serialisers).
- The upgrade registries now subscribe to datapack reload events. They
find all JSON files in the
data/$mod_id/computercraft/{turtle,pocket}_upgrades directories,
parse them, and then register them as upgrades.
Once datapacks have fully reloaded, these upgrades are then sent over
the network to the client.
- Add data generators for turtle and pocket computer upgrades, to make
the creation of JSON files a bit easier.
- Port all of CC:T's upgrades over to use the new system.
- Subscribe to the "on add reload listener" event, otherwise we don't
get reloads beyond the first one! This means we no longer need to
cast the resource manager to a reloadable one.
- Change the mount cache so it's keyed on path, rather than "path ✕
manager".
- Update the reload listener just to use the mount cache, rather than
having its own separate list. I really don't understand what I was
thinking before.
- Some improvements to validation of monitors. This rejects monitors
with invalid dimensions, specifically those with a width or height
of 0. Should fix#922.
- Simplify monitor collapsing a little. This now just attempts to
resize the four "corner" monitors (where present) and then expands
them if needed. Fixes#913.
- Rewrite monitor expansion so that it's no longer recursive. Instead
we track the "origin" monitor and replace it whenever we resize to
the left or upwards.
Also add a upper bound on the loop count, which should prevent things
like #922 happening again. Though as mentioned above, validation
should prevent this anyway.
- Some small bits of cleanup to general monitor code.
I have absolutely no confidence that this code is any better behaved
than the previous version. Let's find out I guess!
- Add a new GenericPeripheral interface. We don't strictly speaking
need this - could put this on GenericSource - but the separation
seems cleaner.
- GenericPeripheral.getType() returns a new PeripheralType class, which
can either be untyped() or specify a type name. This is a little
over-engineered (could just be a nullable string), but I'm planning
to allow multiple types in the future, so want some level of
future-proofing.
- Thread this PeripheralType through the method gathering code and
expose it to the GenericPeripheralProvider, which then chooses an
appropriate name.
This is a little ugly (we're leaking information about peripherals
everywhere), but I think is fine for now. It's all private internals
after all!
Closes#830
- Move TaskCallback into the API and make it package private. This
effectively means it's not an API class, just exists there for
convenience reasons.
- Replace any usage of TaskCallback.make with
ILuaContext.executeMainThreadTask.
- Some minor formatting/checkstyle changes to bring us inline with
IntelliJ config.
- Allow any tool to break an "instabreak" block (saplings, plants,
TNT). Oddly this doesn't include bamboo or bamboo sapings (they're
marked as instabreak, only to have their strength overridden again!),
so we also provide a tag for additional blocks to allow.
- Hoes and shovels now allow breaking any block for which this tool is
effective.
- Use block tags to drive any other block breaking capabilities. For
instance, hoes can break pumpkins and cactuses despite not being
effective.
This should get a little nicer in 1.17, as we can just use block tags
for everything.
Let's see how this goes.
- Update references to the new repo
- Use rrsync on the server, meaning make-doc.sh uploads relative to the
website root.
- Bump Gradle wrapper to 7.2. Not related to this change, but possibly
fixes running under Java 16. Possibly.
Yes, I know this is a terrible feature. But it's been a long week and
I'm so tired.
Also fix the ordering in motd_spec. Who thought putting the month first
was reasonable?
This means wired peripherals now correctly track their current mounts
and attached state, rather than inheriting from the origin wired modem.
Closes#890
Allows us to run multiple "computers" in parallel and send messages
betwene them. I don't think this counts as another test framework, but
it's sure silly.
- Fix broken /cctest marker
- Correctly wait for the screenshot to be taken before continuing.
- Filter out client tests in a different place, meaning we can remove
the /cctest runall command
- Bump kotlin version
- Add lightmap parameters to the text, computer and printout renderers.
- Printouts are always rendered using the current lightmap. When
interacting with the GUI, we use the fullbright lightmap coordinate.
- Pocket computers render their border using the lightmap. Terminal and
light do not use the lightmap at all.
There's some funkiness going on here with render types - it appears the
"correct" position_color_tex_lightmap render type is actually one used
for text.
Fixes#919. This bug does occur on 1.16 too, but given how complex the
rendering changes are between 1.16 and 1.17 I do /not/ want to have to
implement this twice. Sorry.
This ensures inventory slots are synced while the container is open,
meaning the hotbar (which is visible underneath the GUI) correctly
updates.
Fixes#915
When placed in the off hand, pocket computers now render a different
screen when opened in the off-hand, just rendering text at the top of
the screen rather than "opening" the whole computer.
This means you can view the world and computer in your hand at the
same time, effectively allowing you to emulate the
Plethora/MoarPeripherals keyboard (and much more).
This currently requires you to move the pocket computer to the other
hand to open it normally. I did look into allowing for shift+right click
to open normally, but this is awkward when you're looking at a something
like a monitor - you need to shift as otherwise you'd click the block!
Plethora hooks into onItemUseFirst instead, and this might be an option
in the future - meaning that right click would always open some computer
GUI and never the blocks. This may be something we change in the future
- let's get some feedback first!
Closes#861. Apologies for this essay, but if you got this far you were
probably interested!
As always, a massive diff which is largely just moving files between
projects. This does fix a couple of issues with advancements, but
otherwise should behave the same.
Speaking of which, should probably go and test some of these recipes...
Instead of using ids for each computer each computer is spawned with id
0 but has a label which matches up to its test name. This has several
advantages:
- No more confusing IDs: the test code now just does thenComputerOk()
and that's it - the computer to track is inferred from the test name.
- All files are stored on one computer, which means we can write code
which is shared between tests.
This spins up a Minecraft instance (much like we do for the server) and
instructs the client to take screenshots at particular times. We then
compare those screenshots and assert they match (modulo some small
delta).
Basically mimic the actual API that Minecraft would expose if the
methods hadn't been stripped. Lots of ATs and unsafe hacks to get this
working, but thankfully the API we can expose to the user is pretty
nice. Yay for Kotlin?
Anyway, will cause some immediate pain (yay merge conflicts) but should
make keeping the two in sync much easier.
These are still equivalent to the official mappings but also include
method names and javadoc. Yay!
A bit weird to be on versioned mappings after 8 months of MojMap :).!
- Fix missing shader for printout render type
- Use current buffer provider for pocket computers rather than the
tesselator. This requires us to use a non-depth-writing terminal +
depth blocker, as otherwise one gets z-fighting.
- Thus refactor some of the shaders to be terminal wide, not just for
monitors.
Fixes#894
- Use linear attenuation.
- Fix speakers being 16 times as loud as they should be. They correctly
cut off at the right distance, but didn't fade out as one might
expect.
- Clamp volume at 0, not 1. Fixes#892
I don't think anybody actually used these, and I'm not convinced they
had much value anyway.
It might be worth switching the refueling code to work as a registry
instead, though events are kinda nice.
- Remap everything to use MojMap class names too. This is what Forge
uses, so \o/.
This does NOT currently rename any classes to use suffix notation or
BlockEntity. That will come in a later change. We do however rename
references of "World" to "Level".
- Move the test mod into a separate "cctest" source set. As Forge now
works using Jigsaw we cannot have multiple mods defining the same
package, which causes problems with our JUnit test classes.
- Remove our custom test framework and replace it with vanilla's (this
is no longer stripped from the jar). RIP kotlin coroutines.
It's still worth using Kotlin here though, just for extension
methods.
- Other 1.17-related changes:
- Use separate tile/block entity tick methods for server and client
side, often avoiding ticking at all on the client.
- Switch much of the monitor rendering code to use vanilla's
built-in shader system. It's still an incredibly ugly hack, so not
really expecting this to work with any rendering mods, but we'll
cross that bridge when we come to it.
It's probably the lowest traffic module :p.
Also (somewhat) improve the deprecated messages in os.loadAPI. We really
need a proper article on require and converting from os.loadAPI.
By default CT applies them on the client and server. In a single player
world, this means we try to create two upgrades, which obviously fails!
Fixes#721
I've written three or four integrations with bundled cables now over the
various versions, and I'm still not convinced this one is right. It
appears to work though, so we'll see.
We need depend on the main jar here (rather than the API jar), as
otherwise our javadoc tools fails - the API references some internal
classes which aren't on our classpath.
It might be nice to write tests for this (and CT) in the future -
goodness knows these features are fragile - but that'll require some
more gradle work which I don't want to do right now.
Closes#772
Building against 1.16.4 for now to ensure we don't break it. Hopefully
we can bump this too once most people have migrated.
Will push a release tomorrow - don't want to be sorting out merge
conflicts at 23:30.
As explained in the comment, "built-in" rendering types are now manually
rendered ("finish"ed) before calling finish() on the main renderer. This
means our depth blocker hasn't actually been drawn (if a monitor is the
last TE to be rendered), and so blocks pass the depth test when they
shouldn't.
Fixes#599
I hope the Fabric folks now realise this is gonna be a race of who can
update first :p. Either way, this was a very easy update - only changes
were due to unrelated Forge changes.
A lot is broken, but at least we can get in game:
- GUIs render a whole bunch of additional "inventory" text, which we
really don't want.
- Computers load from the wrong location.
- There's some issues with using Forge's tags from outside of JSON
recipes. We need to work out why.
2020-07-11 20:36:10 +01:00
3477 changed files with 133718 additions and 87620 deletions
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.
"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:
(a) You must give any other recipients of the Work or Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License.
You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE LEGAL SERVICES. DISTRIBUTION OF THIS LICENSE DOES NOT CREATE AN ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES REGARDING THE INFORMATION PROVIDED, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM ITS USE.
License
THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). THE WORK IS PROTECTED BY COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED.
BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE TO BE BOUND BY THE TERMS OF THIS LICENSE. TO THE EXTENT THIS LICENSE MAY BE CONSIDERED TO BE A CONTRACT, THE LICENSOR GRANTS YOU THE RIGHTS CONTAINED HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND CONDITIONS.
1. Definitions
a. "Adaptation" means a work based upon the Work, or upon the Work and other pre-existing works, such as a translation, adaptation, derivative work, arrangement of music or other alterations of a literary or artistic work, or phonogram or performance and includes cinematographic adaptations or any other form in which the Work may be recast, transformed, or adapted including in any form recognizably derived from the original, except that a work that constitutes a Collection will not be considered an Adaptation for the purpose of this License. For the avoidance of doubt, where the Work is a musical work, performance or phonogram, the synchronization of the Work in timed-relation with a moving image ("synching") will be considered an Adaptation for the purpose of this License.
b. "Collection" means a collection of literary or artistic works, such as encyclopedias and anthologies, or performances, phonograms or broadcasts, or other works or subject matter other than works listed in Section 1(f) below, which, by reason of the selection and arrangement of their contents, constitute intellectual creations, in which the Work is included in its entirety in unmodified form along with one or more other contributions, each constituting separate and independent works in themselves, which together are assembled into a collective whole. A work that constitutes a Collection will not be considered an Adaptation (as defined above) for the purposes of this License.
c. "Distribute" means to make available to the public the original and copies of the Work or Adaptation, as appropriate, through sale or other transfer of ownership.
d. "Licensor" means the individual, individuals, entity or entities that offer(s) the Work under the terms of this License.
e. "Original Author" means, in the case of a literary or artistic work, the individual, individuals, entity or entities who created the Work or if no individual or entity can be identified, the publisher; and in addition (i) in the case of a performance the actors, singers, musicians, dancers, and other persons who act, sing, deliver, declaim, play in, interpret or otherwise perform literary or artistic works or expressions of folklore; (ii) in the case of a phonogram the producer being the person or legal entity who first fixes the sounds of a performance or other sounds; and, (iii) in the case of broadcasts, the organization that transmits the broadcast.
f. "Work" means the literary and/or artistic work offered under the terms of this License including without limitation any production in the literary, scientific and artistic domain, whatever may be the mode or form of its expression including digital form, such as a book, pamphlet and other writing; a lecture, address, sermon or other work of the same nature; a dramatic or dramatico-musical work; a choreographic work or entertainment in dumb show; a musical composition with or without words; a cinematographic work to which are assimilated works expressed by a process analogous to cinematography; a work of drawing, painting, architecture, sculpture, engraving or lithography; a photographic work to which are assimilated works expressed by a process analogous to photography; a work of applied art; an illustration, map, plan, sketch or three-dimensional work relative to geography, topography, architecture or science; a performance; a broadcast; a phonogram; a compilation of data to the extent it is protected as a copyrightable work; or a work performed by a variety or circus performer to the extent it is not otherwise considered a literary or artistic work.
g. "You" means an individual or entity exercising rights under this License who has not previously violated the terms of this License with respect to the Work, or who has received express permission from the Licensor to exercise rights under this License despite a previous violation.
h. "Publicly Perform" means to perform public recitations of the Work and to communicate to the public those public recitations, by any means or process, including by wire or wireless means or public digital performances; to make available to the public Works in such a way that members of the public may access these Works from a place and at a place individually chosen by them; to perform the Work to the public by any means or process and the communication to the public of the performances of the Work, including by public digital performance; to broadcast and rebroadcast the Work by any means including signs, sounds or images.
i. "Reproduce" means to make copies of the Work by any means including without limitation by sound or visual recordings and the right of fixation and reproducing fixations of the Work, including storage of a protected performance or phonogram in digital form or other electronic medium.
2. Fair Dealing Rights. Nothing in this License is intended to reduce, limit, or restrict any uses free from copyright or rights arising from limitations or exceptions that are provided for in connection with the copyright protection under copyright law or other applicable laws.
3. License Grant. Subject to the terms and conditions of this License, Licensor hereby grants You a worldwide, royalty-free, non-exclusive, perpetual (for the duration of the applicable copyright) license to exercise the rights in the Work as stated below:
a. to Reproduce the Work, to incorporate the Work into one or more Collections, and to Reproduce the Work as incorporated in the Collections;
b. to create and Reproduce Adaptations provided that any such Adaptation, including any translation in any medium, takes reasonable steps to clearly label, demarcate or otherwise identify that changes were made to the original Work. For example, a translation could be marked "The original work was translated from English to Spanish," or a modification could indicate "The original work has been modified.";
c. to Distribute and Publicly Perform the Work including as incorporated in Collections; and,
d. to Distribute and Publicly Perform Adaptations.
e. For the avoidance of doubt:
i. Non-waivable Compulsory License Schemes. In those jurisdictions in which the right to collect royalties through any statutory or compulsory licensing scheme cannot be waived, the Licensor reserves the exclusive right to collect such royalties for any exercise by You of the rights granted under this License;
ii. Waivable Compulsory License Schemes. In those jurisdictions in which the right to collect royalties through any statutory or compulsory licensing scheme can be waived, the Licensor waives the exclusive right to collect such royalties for any exercise by You of the rights granted under this License; and,
iii. Voluntary License Schemes. The Licensor waives the right to collect royalties, whether individually or, in the event that the Licensor is a member of a collecting society that administers voluntary licensing schemes, via that society, from any exercise by You of the rights granted under this License.
The above rights may be exercised in all media and formats whether now known or hereafter devised. The above rights include the right to make such modifications as are technically necessary to exercise the rights in other media and formats. Subject to Section 8(f), all rights not expressly granted by Licensor are hereby reserved.
4. Restrictions. The license granted in Section 3 above is expressly made subject to and limited by the following restrictions:
a. You may Distribute or Publicly Perform the Work only under the terms of this License. You must include a copy of, or the Uniform Resource Identifier (URI) for, this License with every copy of the Work You Distribute or Publicly Perform. You may not offer or impose any terms on the Work that restrict the terms of this License or the ability of the recipient of the Work to exercise the rights granted to that recipient under the terms of the License. You may not sublicense the Work. You must keep intact all notices that refer to this License and to the disclaimer of warranties with every copy of the Work You Distribute or Publicly Perform. When You Distribute or Publicly Perform the Work, You may not impose any effective technological measures on the Work that restrict the ability of a recipient of the Work from You to exercise the rights granted to that recipient under the terms of the License. This Section 4(a) applies to the Work as incorporated in a Collection, but this does not require the Collection apart from the Work itself to be made subject to the terms of this License. If You create a Collection, upon notice from any Licensor You must, to the extent practicable, remove from the Collection any credit as required by Section 4(b), as requested. If You create an Adaptation, upon notice from any Licensor You must, to the extent practicable, remove from the Adaptation any credit as required by Section 4(b), as requested.
b. If You Distribute, or Publicly Perform the Work or any Adaptations or Collections, You must, unless a request has been made pursuant to Section 4(a), keep intact all copyright notices for the Work and provide, reasonable to the medium or means You are utilizing: (i) the name of the Original Author (or pseudonym, if applicable) if supplied, and/or if the Original Author and/or Licensor designate another party or parties (e.g., a sponsor institute, publishing entity, journal) for attribution ("Attribution Parties") in Licensor's copyright notice, terms of service or by other reasonable means, the name of such party or parties; (ii) the title of the Work if supplied; (iii) to the extent reasonably practicable, the URI, if any, that Licensor specifies to be associated with the Work, unless such URI does not refer to the copyright notice or licensing information for the Work; and (iv) , consistent with Section 3(b), in the case of an Adaptation, a credit identifying the use of the Work in the Adaptation (e.g., "French translation of the Work by Original Author," or "Screenplay based on original Work by Original Author"). The credit required by this Section 4 (b) may be implemented in any reasonable manner; provided, however, that in the case of a Adaptation or Collection, at a minimum such credit will appear, if a credit for all contributing authors of the Adaptation or Collection appears, then as part of these credits and in a manner at least as prominent as the credits for the other contributing authors. For the avoidance of doubt, You may only use the credit required by this Section for the purpose of attribution in the manner set out above and, by exercising Your rights under this License, You may not implicitly or explicitly assert or imply any connection with, sponsorship or endorsement by the Original Author, Licensor and/or Attribution Parties, as appropriate, of You or Your use of the Work, without the separate, express prior written permission of the Original Author, Licensor and/or Attribution Parties.
c. Except as otherwise agreed in writing by the Licensor or as may be otherwise permitted by applicable law, if You Reproduce, Distribute or Publicly Perform the Work either by itself or as part of any Adaptations or Collections, You must not distort, mutilate, modify or take other derogatory action in relation to the Work which would be prejudicial to the Original Author's honor or reputation. Licensor agrees that in those jurisdictions (e.g. Japan), in which any exercise of the right granted in Section 3(b) of this License (the right to make Adaptations) would be deemed to be a distortion, mutilation, modification or other derogatory action prejudicial to the Original Author's honor and reputation, the Licensor will waive or not assert, as appropriate, this Section, to the fullest extent permitted by the applicable national law, to enable You to reasonably exercise Your right under Section 3(b) of this License (right to make Adaptations) but not otherwise.
5. Representations, Warranties and Disclaimer
UNLESS OTHERWISE MUTUALLY AGREED TO BY THE PARTIES IN WRITING, LICENSOR OFFERS THE WORK AS-IS AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY KIND CONCERNING THE WORK, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, INCLUDING, WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTIBILITY, FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF LATENT OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OF ABSENCE OF ERRORS, WHETHER OR NOT DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF IMPLIED WARRANTIES, SO SUCH EXCLUSION MAY NOT APPLY TO YOU.
6. Limitation on Liability. EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE LAW, IN NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK, EVEN IF LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
7. Termination
a. This License and the rights granted hereunder will terminate automatically upon any breach by You of the terms of this License. Individuals or entities who have received Adaptations or Collections from You under this License, however, will not have their licenses terminated provided such individuals or entities remain in full compliance with those licenses. Sections 1, 2, 5, 6, 7, and 8 will survive any termination of this License.
b. Subject to the above terms and conditions, the license granted here is perpetual (for the duration of the applicable copyright in the Work). Notwithstanding the above, Licensor reserves the right to release the Work under different license terms or to stop distributing the Work at any time; provided, however that any such election will not serve to withdraw this License (or any other license that has been, or is required to be, granted under the terms of this License), and this License will continue in full force and effect unless terminated as stated above.
8. Miscellaneous
a. Each time You Distribute or Publicly Perform the Work or a Collection, the Licensor offers to the recipient a license to the Work on the same terms and conditions as the license granted to You under this License.
b. Each time You Distribute or Publicly Perform an Adaptation, Licensor offers to the recipient a license to the original Work on the same terms and conditions as the license granted to You under this License.
c. If any provision of this License is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this License, and without further action by the parties to this agreement, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable.
d. No term or provision of this License shall be deemed waived and no breach consented to unless such waiver or consent shall be in writing and signed by the party to be charged with such waiver or consent. This License constitutes the entire agreement between the parties with respect to the Work licensed here. There are no understandings, agreements or representations with respect to the Work not specified here. Licensor shall not be bound by any additional provisions that may appear in any communication from You.
e. This License may not be modified without the mutual written agreement of the Licensor and You.
f. The rights granted under, and the subject matter referenced, in this License were drafted utilizing the terminology of the Berne Convention for the Protection of Literary and Artistic Works (as amended on September 28, 1979), the Rome Convention of 1961, the WIPO Copyright Treaty of 1996, the WIPO Performances and Phonograms Treaty of 1996 and the Universal Copyright Convention (as revised on July 24, 1971). These rights and subject matter take effect in the relevant jurisdiction in which the License terms are sought to be enforced according to the corresponding provisions of the implementation of those treaty provisions in the applicable national law. If the standard suite of rights granted under applicable copyright law includes additional rights not granted under this License, such additional rights are deemed to be included in the License; this License is not intended to restrict the license of any rights under applicable law.
Creative Commons Notice
Creative Commons is not a party to this License, and makes no warranty whatsoever in connection with the Work. Creative Commons will not be liable to You or any party on any legal theory for any damages whatsoever, including without limitation any general, special, incidental or consequential damages arising in connection to this license. Notwithstanding the foregoing two (2) sentences, if Creative Commons has expressly identified itself as the Licensor hereunder, it shall have all rights and obligations of Licensor.
Except for the limited purpose of indicating to the public that the Work is licensed under the CCPL, Creative Commons does not authorize the use by either party of the trademark "Creative Commons" or any related trademark or logo of Creative Commons without the prior written consent of Creative Commons. Any permitted use will be in compliance with Creative Commons' then-current trademark usage guidelines, as may be published on its website or otherwise made available upon request from time to time. For the avoidance of doubt, this trademark restriction does not form part of this License.
Creative Commons may be contacted at http://creativecommons.org/.
Creative Commons Corporation (“Creative Commons”) is not a law firm and does not provide legal services or legal advice. Distribution of Creative Commons public licenses does not create a lawyer-client or other relationship. Creative Commons makes its licenses and related information available on an “as-is” basis. Creative Commons gives no warranties regarding its licenses, any material licensed under their terms and conditions, or any related information. Creative Commons disclaims all liability for damages resulting from their use to the fullest extent possible.
Using Creative Commons Public Licenses
Creative Commons public licenses provide a standard set of terms and conditions that creators and other rights holders may use to share original works of authorship and other material subject to copyright and certain other rights specified in the public license below. The following considerations are for informational purposes only, are not exhaustive, and do not form part of our licenses.
Considerations for licensors: Our public licenses are intended for use by those authorized to give the public permission to use material in ways otherwise restricted by copyright and certain other rights. Our licenses are irrevocable. Licensors should read and understand the terms and conditions of the license they choose before applying it. Licensors should also secure all rights necessary before applying our licenses so that the public can reuse the material as expected. Licensors should clearly mark any material not subject to the license. This includes other CC-licensed material, or material used under an exception or limitation to copyright. More considerations for licensors.
Considerations for the public: By using one of our public licenses, a licensor grants the public permission to use the licensed material under specified terms and conditions. If the licensor’s permission is not necessary for any reason–for example, because of any applicable exception or limitation to copyright–then that use is not regulated by the license. Our licenses grant only permissions under copyright and certain other rights that a licensor has authority to grant. Use of the licensed material may still be restricted for other reasons, including because others have copyright or other rights in the material. A licensor may make special requests, such as asking that all changes be marked or described. Although not required by our licenses, you are encouraged to respect those requests where reasonable. More considerations for the public.
Creative Commons Attribution 4.0 International Public License
By exercising the Licensed Rights (defined below), You accept and agree to be bound by the terms and conditions of this Creative Commons Attribution 4.0 International Public License ("Public License"). To the extent this Public License may be interpreted as a contract, You are granted the Licensed Rights in consideration of Your acceptance of these terms and conditions, and the Licensor grants You such rights in consideration of benefits the Licensor receives from making the Licensed Material available under these terms and conditions.
Section 1 – Definitions.
a. Adapted Material means material subject to Copyright and Similar Rights that is derived from or based upon the Licensed Material and in which the Licensed Material is translated, altered, arranged, transformed, or otherwise modified in a manner requiring permission under the Copyright and Similar Rights held by the Licensor. For purposes of this Public License, where the Licensed Material is a musical work, performance, or sound recording, Adapted Material is always produced where the Licensed Material is synched in timed relation with a moving image.
b. Adapter's License means the license You apply to Your Copyright and Similar Rights in Your contributions to Adapted Material in accordance with the terms and conditions of this Public License.
c. Copyright and Similar Rights means copyright and/or similar rights closely related to copyright including, without limitation, performance, broadcast, sound recording, and Sui Generis Database Rights, without regard to how the rights are labeled or categorized. For purposes of this Public License, the rights specified in Section 2(b)(1)-(2) are not Copyright and Similar Rights.
d. Effective Technological Measures means those measures that, in the absence of proper authority, may not be circumvented under laws fulfilling obligations under Article 11 of the WIPO Copyright Treaty adopted on December 20, 1996, and/or similar international agreements.
e. Exceptions and Limitations means fair use, fair dealing, and/or any other exception or limitation to Copyright and Similar Rights that applies to Your use of the Licensed Material.
f. Licensed Material means the artistic or literary work, database, or other material to which the Licensor applied this Public License.
g. Licensed Rights means the rights granted to You subject to the terms and conditions of this Public License, which are limited to all Copyright and Similar Rights that apply to Your use of the Licensed Material and that the Licensor has authority to license.
h. Licensor means the individual(s) or entity(ies) granting rights under this Public License.
i. Share means to provide material to the public by any means or process that requires permission under the Licensed Rights, such as reproduction, public display, public performance, distribution, dissemination, communication, or importation, and to make material available to the public including in ways that members of the public may access the material from a place and at a time individually chosen by them.
j. Sui Generis Database Rights means rights other than copyright resulting from Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, as amended and/or succeeded, as well as other essentially equivalent rights anywhere in the world.
k. You means the individual or entity exercising the Licensed Rights under this Public License. Your has a corresponding meaning.
Section 2 – Scope.
a. License grant.
1. Subject to the terms and conditions of this Public License, the Licensor hereby grants You a worldwide, royalty-free, non-sublicensable, non-exclusive, irrevocable license to exercise the Licensed Rights in the Licensed Material to:
A. reproduce and Share the Licensed Material, in whole or in part; and
B. produce, reproduce, and Share Adapted Material.
2. Exceptions and Limitations. For the avoidance of doubt, where Exceptions and Limitations apply to Your use, this Public License does not apply, and You do not need to comply with its terms and conditions.
3. Term. The term of this Public License is specified in Section 6(a).
4. Media and formats; technical modifications allowed. The Licensor authorizes You to exercise the Licensed Rights in all media and formats whether now known or hereafter created, and to make technical modifications necessary to do so. The Licensor waives and/or agrees not to assert any right or authority to forbid You from making technical modifications necessary to exercise the Licensed Rights, including technical modifications necessary to circumvent Effective Technological Measures. For purposes of this Public License, simply making modifications authorized by this Section 2(a)(4) never produces Adapted Material.
5. Downstream recipients.
A. Offer from the Licensor – Licensed Material. Every recipient of the Licensed Material automatically receives an offer from the Licensor to exercise the Licensed Rights under the terms and conditions of this Public License.
B. No downstream restrictions. You may not offer or impose any additional or different terms or conditions on, or apply any Effective Technological Measures to, the Licensed Material if doing so restricts exercise of the Licensed Rights by any recipient of the Licensed Material.
6. No endorsement. Nothing in this Public License constitutes or may be construed as permission to assert or imply that You are, or that Your use of the Licensed Material is, connected with, or sponsored, endorsed, or granted official status by, the Licensor or others designated to receive attribution as provided in Section 3(a)(1)(A)(i).
b. Other rights.
1. Moral rights, such as the right of integrity, are not licensed under this Public License, nor are publicity, privacy, and/or other similar personality rights; however, to the extent possible, the Licensor waives and/or agrees not to assert any such rights held by the Licensor to the limited extent necessary to allow You to exercise the Licensed Rights, but not otherwise.
2. Patent and trademark rights are not licensed under this Public License.
3. To the extent possible, the Licensor waives any right to collect royalties from You for the exercise of the Licensed Rights, whether directly or through a collecting society under any voluntary or waivable statutory or compulsory licensing scheme. In all other cases the Licensor expressly reserves any right to collect such royalties.
Section 3 – License Conditions.
Your exercise of the Licensed Rights is expressly made subject to the following conditions.
a. Attribution.
1. If You Share the Licensed Material (including in modified form), You must:
A. retain the following if it is supplied by the Licensor with the Licensed Material:
i. identification of the creator(s) of the Licensed Material and any others designated to receive attribution, in any reasonable manner requested by the Licensor (including by pseudonym if designated);
ii. a copyright notice;
iii. a notice that refers to this Public License;
iv. a notice that refers to the disclaimer of warranties;
v. a URI or hyperlink to the Licensed Material to the extent reasonably practicable;
B. indicate if You modified the Licensed Material and retain an indication of any previous modifications; and
C. indicate the Licensed Material is licensed under this Public License, and include the text of, or the URI or hyperlink to, this Public License.
2. You may satisfy the conditions in Section 3(a)(1) in any reasonable manner based on the medium, means, and context in which You Share the Licensed Material. For example, it may be reasonable to satisfy the conditions by providing a URI or hyperlink to a resource that includes the required information.
3. If requested by the Licensor, You must remove any of the information required by Section 3(a)(1)(A) to the extent reasonably practicable.
4. If You Share Adapted Material You produce, the Adapter's License You apply must not prevent recipients of the Adapted Material from complying with this Public License.
Section 4 – Sui Generis Database Rights.
Where the Licensed Rights include Sui Generis Database Rights that apply to Your use of the Licensed Material:
a. for the avoidance of doubt, Section 2(a)(1) grants You the right to extract, reuse, reproduce, and Share all or a substantial portion of the contents of the database;
b. if You include all or a substantial portion of the database contents in a database in which You have Sui Generis Database Rights, then the database in which You have Sui Generis Database Rights (but not its individual contents) is Adapted Material; and
c. You must comply with the conditions in Section 3(a) if You Share all or a substantial portion of the contents of the database.
For the avoidance of doubt, this Section 4 supplements and does not replace Your obligations under this Public License where the Licensed Rights include other Copyright and Similar Rights.
Section 5 – Disclaimer of Warranties and Limitation of Liability.
a. Unless otherwise separately undertaken by the Licensor, to the extent possible, the Licensor offers the Licensed Material as-is and as-available, and makes no representations or warranties of any kind concerning the Licensed Material, whether express, implied, statutory, or other. This includes, without limitation, warranties of title, merchantability, fitness for a particular purpose, non-infringement, absence of latent or other defects, accuracy, or the presence or absence of errors, whether or not known or discoverable. Where disclaimers of warranties are not allowed in full or in part, this disclaimer may not apply to You.
b. To the extent possible, in no event will the Licensor be liable to You on any legal theory (including, without limitation, negligence) or otherwise for any direct, special, indirect, incidental, consequential, punitive, exemplary, or other losses, costs, expenses, or damages arising out of this Public License or use of the Licensed Material, even if the Licensor has been advised of the possibility of such losses, costs, expenses, or damages. Where a limitation of liability is not allowed in full or in part, this limitation may not apply to You.
c. The disclaimer of warranties and limitation of liability provided above shall be interpreted in a manner that, to the extent possible, most closely approximates an absolute disclaimer and waiver of all liability.
Section 6 – Term and Termination.
a. This Public License applies for the term of the Copyright and Similar Rights licensed here. However, if You fail to comply with this Public License, then Your rights under this Public License terminate automatically.
b. Where Your right to use the Licensed Material has terminated under Section 6(a), it reinstates:
1. automatically as of the date the violation is cured, provided it is cured within 30 days of Your discovery of the violation; or
2. upon express reinstatement by the Licensor.
c. For the avoidance of doubt, this Section 6(b) does not affect any right the Licensor may have to seek remedies for Your violations of this Public License.
d. For the avoidance of doubt, the Licensor may also offer the Licensed Material under separate terms or conditions or stop distributing the Licensed Material at any time; however, doing so will not terminate this Public License.
e. Sections 1, 5, 6, 7, and 8 survive termination of this Public License.
Section 7 – Other Terms and Conditions.
a. The Licensor shall not be bound by any additional or different terms or conditions communicated by You unless expressly agreed.
b. Any arrangements, understandings, or agreements regarding the Licensed Material not stated herein are separate from and independent of the terms and conditions of this Public License.
Section 8 – Interpretation.
a. For the avoidance of doubt, this Public License does not, and shall not be interpreted to, reduce, limit, restrict, or impose conditions on any use of the Licensed Material that could lawfully be made without permission under this Public License.
b. To the extent possible, if any provision of this Public License is deemed unenforceable, it shall be automatically reformed to the minimum extent necessary to make it enforceable. If the provision cannot be reformed, it shall be severed from this Public License without affecting the enforceability of the remaining terms and conditions.
c. No term or condition of this Public License will be waived and no failure to comply consented to unless expressly agreed to by the Licensor.
d. Nothing in this Public License constitutes or may be interpreted as a limitation upon, or waiver of, any privileges and immunities that apply to the Licensor or You, including from the legal processes of any jurisdiction or authority.
Creative Commons is not a party to its public licenses. Notwithstanding, Creative Commons may elect to apply one of its public licenses to material it publishes and in those instances will be considered the “Licensor.” Except for the limited purpose of indicating that material is shared under a Creative Commons public license or as otherwise permitted by the Creative Commons policies published at creativecommons.org/policies, Creative Commons does not authorize the use of the trademark “Creative Commons” or any other trademark or logo of Creative Commons without its prior written consent including, without limitation, in connection with any unauthorized modifications to any of its public licenses or any other arrangements, understandings, or agreements concerning use of licensed material. For the avoidance of doubt, this paragraph does not form part of the public licenses.
Creative Commons may be contacted at creativecommons.org.
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
to CC, nor do I want to take it in a vastly different direction to the original mod. Instead, CC:T focuses on making the
[![Download CC: Tweaked on CurseForge](https://img.shields.io/static/v1?label=Download&message=CC:%20Tweaked&color=E04E14&logoColor=E04E14&logo=CurseForge)][CurseForge]
ComputerCraft experience as _solid_ as possible, ironing out any wrinkles that may have developed over time.
[![Download CC: Tweaked on Modrinth](https://img.shields.io/static/v1?label=Download&color=00AF5C&logoColor=00AF5C&logo=Modrinth&message=CC:%20Tweaked)][Modrinth]
## Features
CC: Tweaked is a mod for Minecraft which adds programmable computers, turtles and more to the game. A fork of the
CC: Tweaked contains all the features of the latest version of ComputerCraft, as well as numerous fixes, performance
much-beloved [ComputerCraft], it continues its legacy with improved performance and stability, along with a wealth of
improvements and several nifty additions. I'd recommend checking out [the releases page](https://github.com/SquidDev-CC/CC-Tweaked/releases)
new features.
to see the full set of changes, but here's a couple of the more interesting additions:
- Improvements to the `http` library, including websockets, support for other HTTP methods (`PUT`, `DELETE`, etc...)
CC: Tweaked can be installed from [CurseForge] or [Modrinth]. It runs on both [Minecraft Forge] and [Fabric].
and configurable limits on HTTP usage.
- Full-block wired modems, allowing one to wrap non-solid peripherals (such as turtles, or chests if Plethora is
installed).
- Pocket computers can be held like maps, allowing you to view the screen without entering a GUI.
- Printed pages and books can be placed in item frames and held like maps.
- Several profiling and administration tools for server owners, via the `/computercraft` command. This allows operators
to track which computers are hogging resources, turn on and shutdown multiple computers at once and interact with
computers remotely.
- Closer emulation of standard Lua, adding the `debug` and `io` libraries. This also enables seeking within binary
files, meaning you don't need to read large files into memory.
- Allow running multiple computers on multiple threads, reducing latency on worlds with many computers.
## Relation to CCTweaks?
This mod has nothing to do with CCTweaks, though there is no denying the name is a throwback to it. That being said,
several features have been included, such as full block modems, the Cobalt runtime and map-like rendering for pocket
computers.
## Contributing
## Contributing
Any contribution is welcome, be that using the mod, reporting bugs or contributing code. If you want to get started
Any contribution is welcome, be that using the mod, reporting bugs or contributing code. If you want to get started
@ -42,12 +26,10 @@ developing the mod, [check out the instructions here](CONTRIBUTING.md#developing
## Community
## Community
If you need help getting started with CC: Tweaked, want to show off your latest project, or just want to chat about
If you need help getting started with CC: Tweaked, want to show off your latest project, or just want to chat about
ComputerCraft we have a [forum](https://forums.computercraft.cc/) and [Discord guild](https://discord.computercraft.cc)!
ComputerCraft, do check out our [forum] and [GitHub discussions page][GitHub discussions]! There's also a fairly
There's also a fairly populated, albeit quiet [IRC channel](http://webchat.esper.net/?channels=computercraft), if that's
populated, albeit quiet [IRC channel][irc], if that's more your cup of tea.
more your cup of tea.
I'd generally recommend you don't contact me directly (email, DM, etc...) unless absolutely necessary (i.e. in order to
We also host fairly comprehensive documentation at [tweaked.cc](https://tweaked.cc/ "The CC: Tweaked website").
report exploits). You'll get a far quicker response if you ask the whole community!
## Using
## Using
CC: Tweaked is hosted on my maven repo, and so is relatively simple to depend on. You may wish to add a soft (or hard)
CC: Tweaked is hosted on my maven repo, and so is relatively simple to depend on. You may wish to add a soft (or hard)
changelog="Release notes can be found on the GitHub repository (https://github.com/SquidDev-CC/CC-Tweaked/releases/tag/v${mc_version}-${mod_version})."
changelog="Release notes can be found on the [GitHub repository](https://github.com/SquidDev-CC/CC-Tweaked/releases/tag/v${mc_version}-${mod_version})."
// See https://github.com/JetBrains/intellij-community/blob/9ba394021dc73a3926f13d6d6cdf434f9ee7046d/plugins/junit/src/com/intellij/execution/junit/JUnitRunConfigurationImporter.kt#L39
The @{modem_message} event is fired when a message is received on an open channel on any modem.
<!--
SPDX-FileCopyrightText: 2021 The CC: Tweaked Developers
SPDX-License-Identifier: MPL-2.0
-->
The [`modem_message`] event is fired when a message is received on an open channel on any [`modem`].
## Return Values
## Return Values
1. @{string}: The event name.
1. [`string`]: The event name.
2. @{string}: The side of the modem that received the message.
2. [`string`]: The side of the modem that received the message.
3. @{number}: The channel that the message was sent on.
3. [`number`]: The channel that the message was sent on.
4. @{number}: The reply channel set by the sender.
4. [`number`]: The reply channel set by the sender.
5. @{any}: The message as sent by the sender.
5. [`any`]: The message as sent by the sender.
6. @{number}: The distance between the sender and the receiver, in blocks (decimal).
6. <spanclass="type">[`number`]|[`nil`]</span>: The distance between the sender and the receiver in blocks, or [`nil`] if the message was sent between dimensions.
## Example
## Example
Prints a message when one is sent:
Wraps a [`modem`] peripheral, opens channel 0 for listening, and prints all received messages.
```lua
```lua
local modem = peripheral.find("modem") or error("No modem attached", 0)
modem.open(0)
while true do
while true do
local event, side, channel, replyChannel, message, distance = os.pullEvent("modem_message")
local event, side, channel, replyChannel, message, distance = os.pullEvent("modem_message")
print(("Message received on side %s on channel %d (reply to %d) from %f blocks away with message %s"):format(side, channel, replyChannel, distance, tostring(message)))
print(("Message received on side %s on channel %d (reply to %d) from %f blocks away with message %s"):format(
@ -4,17 +4,23 @@ see: modem_message For raw modem messages sent outside of Rednet.
see: rednet.receive To wait for a Rednet message with an optional timeout and protocol filter.
see: rednet.receive To wait for a Rednet message with an optional timeout and protocol filter.
---
---
The @{rednet_message} event is fired when a message is sent over Rednet.
<!--
SPDX-FileCopyrightText: 2021 The CC: Tweaked Developers
This event is usually handled by @{rednet.receive}, but it can also be pulled manually.
SPDX-License-Identifier: MPL-2.0
-->
@{rednet_message} events are sent by @{rednet.run} in the top-level coroutine in response to @{modem_message} events. A @{rednet_message} event is always preceded by a @{modem_message} event. They are generated inside CraftOS rather than being sent by the ComputerCraft machine.
The [`rednet_message`] event is fired when a message is sent over Rednet.
This event is usually handled by [`rednet.receive`], but it can also be pulled manually.
[`rednet_message`] events are sent by [`rednet.run`] in the top-level coroutine in response to [`modem_message`] events. A [`rednet_message`] event is always preceded by a [`modem_message`] event. They are generated inside CraftOS rather than being sent by the ComputerCraft machine.
## Return Values
## Return Values
1. @{string}: The event name.
1. [`string`]: The event name.
2. @{number}: The ID of the sending computer.
2. [`number`]: The ID of the sending computer.
3. @{any}: The message sent.
3. [`any`]: The message sent.
4. @{string|nil}: The protocol of the message, if provided.
4. <spanclass="type">[`string`]|[`nil`]</span>: The protocol of the message, if provided.
see: commands.execAsync To run a command which fires a task_complete event.
see: commands.execAsync To run a command which fires a task_complete event.
---
---
The @{task_complete} event is fired when an asynchronous task completes. This is usually handled inside the function call that queued the task; however, functions such as @{commands.execAsync} return immediately so the user can wait for completion.
<!--
SPDX-FileCopyrightText: 2021 The CC: Tweaked Developers
SPDX-License-Identifier: MPL-2.0
-->
The [`task_complete`] event is fired when an asynchronous task completes. This is usually handled inside the function call that queued the task; however, functions such as [`commands.execAsync`] return immediately so the user can wait for completion.
## Return Values
## Return Values
1. @{string}: The event name.
1. [`string`]: The event name.
2. @{number}: The ID of the task that completed.
2. [`number`]: The ID of the task that completed.
3. @{boolean}: Whether the command succeeded.
3. [`boolean`]: Whether the command succeeded.
4. @{string}: If the command failed, an error message explaining the failure. (This is not present if the command succeeded.)
4. [`string`]: If the command failed, an error message explaining the failure. (This is not present if the command succeeded.)
...: Any parameters returned from the command.
5. <abbrtitle="Variable number of arguments">…</abbr>: Any parameters returned from the command.
The @{terminate} event is fired when <kbd>Ctrl-T</kbd> is held down.
<!--
SPDX-FileCopyrightText: 2021 The CC: Tweaked Developers
This event is normally handled by @{os.pullEvent}, and will not be returned. However, @{os.pullEventRaw} will return this event when fired.
SPDX-License-Identifier: MPL-2.0
-->
@{terminate} will be sent even when a filter is provided to @{os.pullEventRaw}. When using @{os.pullEventRaw} with a filter, make sure to check that the event is not @{terminate}.
The [`terminate`] event is fired when <kbd>Ctrl-T</kbd> is held down.
This event is normally handled by [`os.pullEvent`], and will not be returned. However, [`os.pullEventRaw`] will return this event when fired.
[`terminate`] will be sent even when a filter is provided to [`os.pullEventRaw`]. When using [`os.pullEventRaw`] with a filter, make sure to check that the event is not [`terminate`].
SPDX-FileCopyrightText: 2022 The CC: Tweaked Developers
SPDX-License-Identifier: MPL-2.0
-->
# Allowing access to local IPs
By default, ComputerCraft blocks access to local IP addresses for security. This means you can't normally access any
HTTP server running on your computer. However, this may be useful for testing programs without having a remote
server. You can unblock these IPs in the ComputerCraft config.
- [Minecraft 1.13 and later, CC:T 1.87.0 and later](#cc-1.87.0)
- [Minecraft 1.13 and later, CC:T 1.86.2 and earlier](#cc-1.86.2)
- [Minecraft 1.12.2 and earlier](#mc-1.12)
## Minecraft 1.13 and later, CC:T 1.87.0 and later {#cc-1.87.0}
The configuration file can be located at `serverconfig/computercraft-server.toml` inside the world folder on either
single-player or multiplayer. Look for lines that look like this:
```toml
#A list of rules which control behaviour of the "http" API for specific domains or IPs.
#Each rule is an item with a 'host' to match against, and a series of properties. The host may be a domain name ("pastebin.com"),
#wildcard ("*.pastebin.com") or CIDR notation ("127.0.0.0/8"). If no rules, the domain is blocked.
[[http.rules]]
host = "$private"
action = "deny"
```
On 1.95.0 and later, this will be a single entry with `host = "$private"`. On earlier versions, this will be a number of
`[[http.rules]]` with various IP addresses. You will want to remove all of the `[[http.rules]]` entries that have
`action = "deny"`. Then save the file and relaunch Minecraft (Server).
Here's what it should look like after removing:
```toml
#A list of rules which control behaviour of the "http" API for specific domains or IPs.
#Each rule is an item with a 'host' to match against, and a series of properties. The host may be a domain name ("pastebin.com"),
#wildcard ("*.pastebin.com") or CIDR notation ("127.0.0.0/8"). If no rules, the domain is blocked.
[[http.rules]]
#The maximum size (in bytes) that a computer can send or receive in one websocket packet.
max_websocket_message = 131072
host = "*"
#The maximum size (in bytes) that a computer can upload in a single request. This includes headers and POST text.
max_upload = 4194304
action = "allow"
#The maximum size (in bytes) that a computer can download in a single request. Note that responses may receive more data than allowed, but this data will not be returned to the client.
max_download = 16777216
#The period of time (in milliseconds) to wait before a HTTP request times out. Set to 0 for unlimited.
timeout = 30000
```
## Minecraft 1.13 and later, CC:T 1.86.2 and earlier {#cc-1.86.2}
The configuration file for singleplayer is at `.minecraft/config/computercraft-common.toml`. Look for lines that look
like this:
```toml
#A list of wildcards for domains or IP ranges that cannot be accessed through the "http" API on Computers.
#If this is empty then all whitelisted domains will be accessible. Example: "*.github.com" will block access to all subdomains of github.com.
#You can use domain names ("pastebin.com"), wildcards ("*.pastebin.com") or CIDR notation ("127.0.0.0/8").
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.