The HTTP filtering system becomes even more complex! Though in this
case, it's pretty minimal, and definitely worth doing.
For instance, the following rule will allow connecting to localhost on
port :8080.
[[http.rules]]
host = "127.0.0.1"
port = 8080
action = "allow"
# Other rules as before.
Closes#540
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.
This allows for configuring the size of computers and pocket computers,
as well as the max size of monitors.
There's several limitations with the current implementation, but it's
still "good enough" for an initial release:
- Turtles cannot be resized.
- GUIs do not scale themselves, so "large" sizes will not render within
the default resolution.
We never added back replacing of ${version} strings, which means that CC
was reporting incorrect version numbers in _HOST, the user agent and
network versions. This meant we would allow connections even on
mismatched versions (#464).
We shift all version handling into ComputerCraftAPI(Impl) - this now
relies on Forge code, so we don't want to run it in emulators.
This moves monitor networking into its own packet, rather than serialising
using NBT. This allows us to be more flexible with how monitors are
serialised.
We now compress terminal data using gzip. This reduces the packet size
of a max-sized-monitor from ~25kb to as little as 100b.
On my test set of images (what I would consider to be the extreme end of
the "reasonable" case), we have packets from 1.4kb bytes up to 12kb,
with a mean of 6kb. Even in the worst case, this is a 2x reduction in
packet size.
While this is a fantastic win for the common case, it is not abuse-proof.
One can create a terminal with high entropy (and so uncompressible). This
will still be close to the original packet size.
In order to prevent any other abuse, we also limit the amount of monitor
data a client can possibly receive to 1MB (configurable).
timetout, max_upload, max_download and max_websocket_message may now be
configured on a domain-by-domain basis. This uses the same system that
we use for the block/allow-list from before:
Example:
[[http.rules]]
host = "*"
action = "allow"
max_upload = 4194304
max_download = 16777216
timeout = 30000
When creating a peripheral or custom Lua object, one must implement two
methods:
- getMethodNames(): String[] - Returns the name of the methods
- callMethod(int, ...): Object[] - Invokes the method using an index in
the above array.
This has a couple of problems:
- It's somewhat unwieldy to use - you need to keep track of array
indices, which leads to ugly code.
- Functions which yield (for instance, those which run on the main
thread) are blocking. This means we need to spawn new threads for
each CC-side yield.
We replace this system with a few changes:
- @LuaFunction annotation: One may annotate a public instance method
with this annotation. This then exposes a peripheral/lua object
method.
Furthermore, this method can accept and return a variety of types,
which often makes functions cleaner (e.g. can return an int rather
than an Object[], and specify and int argument rather than
Object[]).
- MethodResult: Instead of returning an Object[] and having blocking
yields, functions return a MethodResult. This either contains an
immediate return, or an instruction to yield with some continuation
to resume with.
MethodResult is then interpreted by the Lua runtime (i.e. Cobalt),
rather than our weird bodgey hacks before. This means we no longer
spawn new threads when yielding within CC.
- Methods accept IArguments instead of a raw Object array. This has a
few benefits:
- Consistent argument handling - people no longer need to use
ArgumentHelper (as it doesn't exist!), or even be aware of its
existence - you're rather forced into using it.
- More efficient code in some cases. We provide a Cobalt-specific
implementation of IArguments, which avoids the boxing/unboxing when
handling numbers and binary strings.
- Use jacoco for Java-side coverage. Our Java coverage is /terrible
(~10%), as we only really test the core libraries. Still a good thing
to track for regressions though.
- mcfly now tracks Lua side coverage. This works in several stages:
- Replace loadfile to include the whole path
- Add a debug hook which just tracks filename->(lines->count). This
is then submitted to the Java test runner.
- On test completion, we emit a luacov.report.out file.
As the debug hook is inserted by mcfly, this does not include any
computer startup (such as loading apis, or the root of bios.lua),
despite they're executed.
This would be possible to do (for instance, inject a custom header
into bios.lua). However, we're not actually testing any of the
behaviour of startup (aside from "does it not crash"), so I'm not
sure whether to include it or not. Something I'll most likely
re-evaluate.
This is relatively unoptimised right now, but should be efficient enough
for most practical applications.
- Add textutils.json_null. This will be serialized into a literal
`null`. When deserializing, and parse_null is true, this will be
returned instead of a nil.
- Add textutils.unserializeJSON (and textutils.unserializeJSON). This
is a standard compliant JSON parser (hopefully).
- Passing in nbt_style to textutils.unserializeJSON will handle
stringified NBT (no quotes around object keys, numeric suffices). We
don't currently support byte/long/int arrays - something to add in
a future commit.
- Remove stub for table.pack/table.unpack.
- Remove Lua 5.3 bitlib stub. We're not on 5.3, there's no
point emulating it.
- Change peripheral.call to correctly adjust the error level. This is a
terrible hack, but I believe the only good option.
It'd be good to remove load as well, but it's a little more complex due
to our injecting of _ENV.
Closes#363
- Return EPOCH if a zip entry's creation/modification/access time is
missing.
- If a BasicFileAttributes.*Time method returns null, use 0 as our
time. This shouldn't happen, but is a good sanity check.
Fixes#371
- fs.getCapacity just returns the capacity of the current drive, if
available. This will be nil on rom mounts.
- fs.attributes returns an lfs like table of various file attributes.
Currently, this contains:
- access, modification, created: When this file was last accessed,
modified and created. Time is measured in milliseconds since the
epoch, same as os.epoch("utc") and what is accepted by os.date.
- size: Same as fs.getSize
- isDir: same as fs.isDir
Closes#262
- contains now performs a case-insensitive comparison. While this is a
little dubious, it's required for systems like Windows, where foo and
Foo are the same folder.
- Impose a depth limit on copyRecursive. If there are any other cases
where we may try to copy a folder into itself, this should prevent
the computer entirely crashing.
- Remove *Stream methods on IMount/IWritableMount, and make the channel
ones the primary.
- Fix location of AbstractTurtleUpgrade
- Make IComputerAccess.getAvailablePeripheral and .getMainThreadMonitor
mandatory.
- IComputerAccess throws a specialised NotAttachedException
Before it would remain the same across world reloads, and thus would be
out-of-date after leaving the first world. This architecture technically
allows for running multiple servers at once, though that's not going to
matter that soon.
This is sufficiently useful a class, that it's worthwhile exposing it.
Hopefully we can slowly encourage other mods to migrate to it (well, at
least in 1.14), and so make error messages more consistent.
Also:
- Add Javadoc for all public methods
- Clarify the method names a little (getNumber -> getDouble,
getReal -> getFiniteDouble).
- Make the *Table methods return a Map<?,?> instead of
Map<Object, Object>.
Lua 5.2+ uses loadfile(filename, mode, env), not loadfile(filename,
env). While this is a minor incompatibility, it'd be nice to be
consistent as much as possible.
We try to handle the incorrect case too, as obviously we don't want to
break existing programs.
So very little works, but it compiles and runs.
Things to resolve over the next few days:
- Horrible mappings (should largely be resolved by tomorrow).
- Cannot send extra data over containers - we'll have to see what Forge
does here.
- Turtle models are broken
- No block drops yet - this will largely be cherry-picking whatever I
did on Fabric.
- Weird inventory desyncs (items don't show up initially when
interacting with a CC inventory).
- Probably lots of other things.
- Adds a CheckStyle configuration which is pretty similar to CC's
existing one.
- Add the Gradle license plugin.
- Ensure the existing source code is compatible with these additional
checks.
See #239
- Define an expect(index, actual_value, types...) helper function which
takes an argument index, value and list of permissable types and
ensures the value is of one of those types.
If not, it will produce an error message with the expected and actual
type, as well as the argument number and (if available) the function
name.
- Expose expect in the global scope as _G["~expect"], hopefully making
it clear it is internal.
- Replace most manual type checks with this helper method.
- Write tests to ensure this argument validation works as expected
Also fix a couple of bugs exposed by this refactor and the subsequent
tests:
- Make rednet checks a little more strict - rednet.close(false) is no
longer valid.
- Error when attempting to redirect the terminal to itself
(term.redirect(term)).
Actually, many *globs*. It additionally prints the glob if no files
matched it, since that's clearer.
Also move the ComputerTestDelegate's filesystem to be disk-based. This
is what actual computers use, and the MemoryMount is a little broken.
Look, I originally had this split into several commits, but lots of
other cleanups got mixed in. I then backported some of the cleanups to
1.12, did other tidy ups there, and eventually the web of merges was
unreadable.
Yes, this is a horrible mess, but it's still nicer than it was. Anyway,
changes:
- Flatten everything. For instance, there are now three instances of
BlockComputer, two BlockTurtle, ItemPocketComputer. There's also no
more BlockPeripheral (thank heavens) - there's separate block classes
for each peripheral type.
- Remove pretty much all legacy code. As we're breaking world
compatibility anyway, we can remove all the code to load worlds from
1.4 days.
- The command system is largely rewriten to take advantage of 1.13's
new system. It's very fancy!
- WidgetTerminal now uses Minecraft's "GUI listener" system.
- BREAKING CHANGE: All the codes in keys.lua are different, due to the
move to LWJGL 3. Hopefully this won't have too much of an impact.
I don't want to map to the old key codes on the Java side, as there
always ends up being small but slight inconsistencies. IMO it's
better to make a clean break - people should be using keys rather
than hard coding the constants anyway.
- commands.list now allows fetching sub-commands. The ROM has already
been updated to allow fancy usage such as commands.time.set("noon").
- Turtles, modems and cables can be waterlogged.
OK, so let's get this out of the way, there's some actual changes mixed
in here too. I'm really sorry:
- Turtles can now not be renamed with unnamed item tags (previously it
would clear the name, this seemed a little unideal).
- commands.getBlock(s)Data will also include NBT.
Now, onto the horror story which is these inspection changes:
- Make a lot of methods static
- Typo fixes
- Make utility classes final + private constructor
- Lots of reformatting (ifs -> ternary, invert control flow, etc...)
- ???
- Profit!
I'm so going to regret this - can pretty much guarantee this is going to
break something.
This runs tests on CraftOS using a tiny test runner that I originally
knocked up for LuaDash. It can be run both from JUnit (so IDEA and
Gradle) and in-game in the shell, so is pretty accessible to work with.
I also add a very basic POC test for the io library. I'd like to flesh
this out soon enough to contain most of the things from the original io
test.
TimeoutState now introduces a TIMESLICE, which is the maximum period of
time a computer can run before we will look into pausing it.
When we have executed a task for more than this period, and if there are
other computers waiting to execute work, then we will suspend the
machine.
Suspending the machine sets a flag on the ComputerExecutor, and pauses
the "cumulative" time - the time spent handling this particular event.
When resuming the machine, we restart our timer and resume the machine.