See #354
- Remove Lua script to generate recipes/advancements for coloured
disks, turtle upgrades and pocket upgrades. Replacing them with Lua
ones.
- Generate most block drops via the data generator system. Aside from
cables, they all follow one of two templates.
- 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
Most of the port is pretty simple. The main problems are regarding
changes to Minecraft's rendering system.
- Remove several rendering tweaks until Forge's compatibility it
brought up-to-date
- Map rendering for pocket computers and printouts
- Item frame rendering for printouts
- Custom block outlines for monitors and cables/wired modems
- Custom breaking progress for cables/wired modems
- Turtle "Dinnerbone" rendering is currently broken, as normals are not
correctly transformed.
- Rewrite FixedWidthFontRenderer to to the buffer in a single sweep.
In order to do this, the term_font now also bundles a "background"
section, which is just a blank region of the screen.
- Render monitors using a VBO instead of a call list. I haven't
compared performance yet, but it manages to render a 6x5 array of
_static_ monitors at almost 60fps, which seems pretty reasonable.
- Add a cc.pretty module, which provides a Wadler style pretty printer [1].
- The cc.pretty.pretty function converts an arbitrary object into a
pretty-printed document. This can then be printed to the screen with
cc.pretty.{write, print} or converted to a string with cc.pretty.render.
- Convert the Lua REPL to use the pretty printer rather than
textutils.serialise.
[1]: http://homepages.inf.ed.ac.uk/wadler/papers/prettier/prettier.pdf
GPS requests are now sent and received on CHANNEL_GPS by default
instead. This means it should not be possible to distinguish
computers (and thus locate them) via their GPS requests.
"exit" now has a custom __tostring method, which prints an explanation
message. This is very similar to how Python achives the same
functionality:
lua> exit
Call exit() to exit
lua> exit()
> Actually leaves the REPL
Unfortunately we can't apply the config changes due to backwards
compatibility. This'll be something we may need to PR into Forge.
CraftTweaker support still needs to be added.
It appears that WB opens containers manually, and thus all of our stubs
network stubs are entirely ignored. Thus the only solution here is to
stub out the whole network handler code.
Thankfully this is simple enough - we do the same for Plethora and 1.14.
Fixes#328
This provides the following methods:
- dan200.computercraft.turtle.removeUpgrade(id: String)
- dan200.computercraft.turtle.removeUpgrade(stack: IItemStack)
- dan200.computercraft.turtle.addTool(id: String, craftItem: IItemStack[, toolItem: IItemStack][, kind: string])
While it's pretty minimal, it should allow for a reasonable amount of
functionality.
Closes#327 and #97.
We now use illuaminate[1]'s linting facilities to check the rom and
bios.lua for a couple of common bugs and other problems.
Right now this doesn't detect any especially important bugs, though it
has caught lots of small things (unused variables, some noisy code). In
the future, the linter will grow in scope and features, which should
allow us to be stricter and catch most issues.
As a fun aside, we started off with ~150 bugs, and illuaminate was able
to fix all but 30 of them, which is pretty neat.
[1]: https://github.com/SquidDev/illuaminate
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 fixes them not rendering particles when broken. Particle rendering
is a little janky right now, as it uses the whole texture - we should
probably split up the texture into smaller images. Fixes#315
This should fix several issues (see #304, etc...). I'll try to get round
to PRing this into Forge at some point, though on the other hand this is
/super/ ugly.
This shouldn't matter either way - we don't expose it in the creative
menu, and there's no recipes for it. This should shut up a log message
though. Fixes#305.
This fixes monitor rendering underwater (closes#314). By default,
isSolid returns true if the render layer is SOLID. As we use CUTOUT due
to our funky TE rendering, we need to override this to return true
anyway.
This will cause some side effects, as monitors now blocking light
propagation, but I don't think that's the end of the world.
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>.
Previously we were just returning the current tile. However, if someone
was holding a reference to this inventory (such as a GUI), then it'd be
outdated and invalid once the turtle had moved.
This caused a couple of issues:
- turtle_inventory events would not be fired when moving items in the
turtle GUI.
- As of 75e2845c01, turtles would no
longer share their inventory state after moving. Thus, removing items
from a GUI using an invalid inventory would move them from an old
tile, duplicating the items.
Fixes#298, fixes#300
Not quite sure when this changed, but I'm fairly sure isMouseOver wasn't
a thing when I wrote this. Or I'm a plonker. Both are possible.
Also fixes mouse dragging not being handled in turtles.
Fixes#299
Closes#293. Doesn't really solve anything there aside from exposing the
number, but sadly there's not really anything obvious I can do on my end
- the command API just doesn't expose anything else.
- Adds cc.completions module, with a couple of helper functions for
working with the more general completion functionality (i.e. that
provided by read).
- Adds cc.shell.completions module, which provides shell-specific
completion functions.
- Add a "program completion builder", which allows you to write stuff
like this:
shell.setCompletionFunction( "rom/programs/redstone.lua",
completion.build(
{ completion.choice, { "probe", "set ", "pulse " } },
completion.side) )
Closes#232
It appears several mods inject their own drops on the LOWEST priority,
meaning that we capture the existing drops, and the other mod will clear
the (now empty) drop list and add its own, resulting in dupe bugs.
While I'd argue it's somewhat dubious doing this on the LOWEST priority,
it's not a battle I'm prepared to fight. For now, we just remove the
block/entity drop handlers, and handle all drop logic when entities are
spawned.
Fixes#288
This is the behaviour on 1.14 already, so it makes sense to backport to
1.12.
Any mod may now insert files into assets/computercraft/lua/rom, and
they'll be automatically added to the default ROM mount. This allows
other mods to easily register new programs or autorun files.
See #242
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.
This moves expect from the bios into a new craftos.expect module,
removing the internal _G["~expect"] definition. Apparently people were
using this irrespective of the "don't use this" comment, so we need to
find another solution.
While this does introduce some ugliness (having to load the module in
weird ways for programs, duplicating the expect function in memory), it
does allow people to use the function in a supported way, and removes
the global ugliness.
I'm not entirely sure how useful all of these will be yet - still
trying to work out what/when to test things, but hopefully this'll
be a useful datapoint.
This is equally an ugly hack, but means we're at least not constructing
entities with null worlds any more.
Ideally we could always use the turtle entity, but this will require a
bit more of a refactor.
Fixes#265
- Add Forge's "name" field to the loot tables. This doesn't resolve all
our missing loot providers, but it's a start.
- Add back GUIs for pocket computers, printouts, view computer, etc...
Equivalent to `pastebin run`, but allows running arbitrary URLs
instead.
Is this a little questionable? Yes - people shouldn't be downloading
and running code from the internet. But hey, people do that already,
so we might as well make it convenient.
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
- Make mcfly's stubbing system a little more fault-tolerant.
- Add a small utility function which redirects print, printError and
write to capture their output, rather than printing to the terminal.
This can then be matched against in order to determine a program's
output.
It's a little flakey - you can't use it multiple times in an it
block, etc... but it's a nice feature.
- Add a small couple of tests to delete as a proof-of-concept.
- Convert existing changelog over to use Markdown. This mostly involves
wrapping code in backticks, and marking things as headers where
appropriate.
- Copy all of CC:T's release notes over to the changelog. This is
somewhat more verbose than Dan's notes, but keeping them in sync
seems reasonable (and allows for automation!).
As 'require' operates relative to the current program's directory,
rather than the current directory, it meant we were trying to load files
from /rom/programs.
This is never a good idea, so we add the current directory to the
package path, allowing you to use require as one'd expect.
- 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)).
This only renders the bounding box on non-screen edges of the monitor,
meaning you have an uninterrupted view of the screen when hovering
hover.
Closes#219
Rendering an item worked in principle, but had several caveats:
- The terminal did not fit well within the item's texture, so we had a
rather large border.
- The "correctness" of this was very tied to Minecraft's item rendering
code. This changed a little in 1.13, causing problems like #208.
Instead we effectively reuse the computer GUI rendering code, though
also handling coloured pocket computers and rendering the modem light.
This fixes#208, and hopefully fixes#212.
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.
- os.time, when given a table, will act the same as PUC Lua - returning
the seconds since the epoch. We preserve the previous string/nil
behaviour though - os.epoch("local") is equivalent to PUC's
os.time().
- os.date will now act accept a string and (optional) time, returning
an appropriate table.
Somewhat resolves the madness which was dan200/ComputerCraft#183, and
hopefully (though probably not) makes @Vexatos happy.
This changes the previous behaviour a little, but hopefully is more
sane:
- Only require the socket to be open when first calling receive. This
means if it closes while receving, you won't get an error.
This behaviour is still not perfect - the socket could have closed,
but the event not reached the user yet, but it's better.
- Listen to websocket_close events while receiving, and return null
should it match ours.
See #201
We were using += instead of =, meaning the budget always grew,
rather than growing while there was still space. As a result, computers
were never correctly rate limited.
Further more, if a computer went into a deficit, we would continue to
increase the budget by a negative amount, exponentially decreasing until
overflowing!
Yes, this is a very embarrassing mistake. I'd been aware that rate
limiting wasn't working as expected for a while, I hadn't realised
the problem would be this stupid.
This uses the same behaviour that repeaters and comparators do for
determining their input, meaning that redstone directly connected to the
computer is read (as you would expect).
It's worth noting that this is a shift from previous behaviour.
Therefore, it runs the (small) risk of breaking existing builds.
However, I believe it is more consistent with the expected behaviour.
Originally introduced in 173ea72001, but
the underlying cause has been happening for much longer.
- Fix order of method name parameters. Looks like this has been broken
since 1.11. Woops.
- Catch RuntimeExceptions too, as Forge converts checked into unchecked
ones.
Fixes#179
I promise! The joys of using -SNAPSHOT I guess...
This will now correctly cause orphaned threads to be cleaned up,
reducing the risk of thread saturation.
If mod loading fails, we'll continue to load colour handlers. As
blocks/items have not been registered, then we'll throw an NPE.
See MinecraftForge/MinecraftForge#5682. Somewhat fixes#168.
Forge's config system will read the default values as integers, meaning
it fails to validate against the config spec. Ideally this'd be fixed in
forge, but this is a suitable work around.
Previously we just relied on magic int values, which was confusing and
potentially error-prone. We could use EnumFacing, but that's a)
dependent on MC and b) incorrect, as we're referring to local
coordinates.
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.
- Languages are converted to JSON
- Rename most *(_advanced) blocks to *_{advanced,normal}. It's more
verbose, but means they're sorted together.
- A couple of changes to the ROM to work with some Java changes.
- Update recipes and advancements to not use damage values.
Are most of these changes small and petty? Yes. However, IMO they do
make the code more readable. Anyway, a summary of some of the more
interesting changes:
- Expose Abstract*Upgrade classes in the API
- Fix the spelling of Jonathan in the API docs (*shakes fist*)
- Fix bug with printout not working in the offhand.
- Rename any argments/variables accidentally named "m_*", and add an
inspection to prevent it happening again.
- Remove most of the Block*.Properties classes - just inline them in
the parent class.
- Return super.writeToNBT instead of reassigning at the top.
This makes use of the "sent" variable, which would otherwise go unused. It also makes rednet.send compliant to the behaviour specified in the Wiki: http://www.computercraft.info/wiki/Rednet.send
This is largely invisible (it's marked as a child of the main
"computercraft" mod), but allows other mods (such as Plethora) to add
hard/soft dependencies on CC:T in a user-friendly manner.
- Fire all the appropriate Forge hooks
- Crafting will now attempt to craft one item at a time in a loop,
instead of multiplying the resulting stack by the number of crafts.
This means we function as expected on recipes which consume
durability instead.
- Cache the recipe between crafting and getting the remainder (and each
craft loop). This should reduce any performance hit we would
otherwise get.
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.
- Move container opening (and gui handling) into a separate class
- Move turtle/computer placement code onto the block
- GUIs now use gui{Left,Top} instead of calculating it manually.
- IPeripheralTile is now exposed in the API.
This uses a similar approach to ComputerThread: executors store how long
they've spent executing tasks. We then use that time to prioritise
executors.
One should note that we use the current runtime at the point of adding
to the queue - external tasks will not contribute towards it until a
later execution.
This effectively acts as a public interface to canExecuteExternal() and
consumeTime(). It's hopefully sufficiently general that we can mess
around with the backend as much as we like in the future.
One thing to note here is that this is based on a polling API, as it's
largely intended for people running work every tick. It would be
possible to adapt this with callbacks for when work is available,
etc..., but that was not needed immediately.
This also removes IComputerOwned, as Plethora no longer needs it.
Unlike ComputerThread, we do not have a single source of tasks, and so
need a smarter way to handle scheduling and rate limiting. This
introduces a cooldown system, which works on both a global and
per-computer level:
Each computer is allowed to do some work for 5ms. If they go over that
budget, then they are marked as "hot", and will not execute work on the
next tick, until they have cooled down. This ensures that _on average_
computers perform at most 5ms of work per tick.
Obviously this is a rather large time span, so we also apply a global
10ms to all computers. This uses the same cooldown principle, meaning we
keep to an average of 10ms, even if we go over budget.
We were not updating the property instances, so we never actually used
the new values. This changes the syncing method to just copy values from
the new config file, meaning comments and structure are preserved from
the old one.
Note, we cannot just call Config.load(File) again, as the defaults are
no longer accurate.
- We send special packets for key and mouse events, which are then
processed by the container's InputState.
- InputState keeps track of currently held keys and mouse buttons.
- When closing the container, we queue key_up/mouse_up events for any
pending buttons.
We attempted to simplify this 0bfb7049b0,
but that change now means that minimumVirtualRuntime is not updated. As
a result, new tasks will have a runtime of 0 when the queue is empty.
- Some performance improvements to JEI recipe resolver
- Use a shared map for upgrade items, meaning we only need one map
lookup.
- Cache the basic upgrade recipes.
- Use the MC version within project rather than version name.
Before IPocketAccess.getEntity would return the entity which last held
fthis computer, even if not holding it any more. As
ba823bae13 describes, this caused
pocket.equip/pocket.unequip to dupe items.
We move the validation from the PocketAPI into the main IPocketAccess
implementation, to ensure this issue does not occur elsewhere. Note, we
require a separate method, as this is no longer thread-safe.
We also now return ok, err instead of throwing an exception, in order to
be consistent with the turtle functions. See dan200/ComputerCraft#328.
This makes Pocket API not equip/unequip upgrades when the pocket
computer is outside of the player inventory (e.g. dragging,
dropped, placed in a chest).
Oh goodness, this is going to painful to update to 1.13.
We now translate:
- Computer/Disk ID tooltips
- /computercraft descriptions, synopsises and usages. The last of these
may not always be translated when in SMP, as it is sometimes done on
the server, but the alternative would be more complex than I'm happy
with.
- Tracking field names. Might be worth adding descriptions too in the
future.
Also cleanup a couple of other translation keys, so they're more
consistent with Minecraft.
Closes#141
- Turtle and pocket computers provide a "creator mod id" based on their
upgrade(s).
We track which mod was active when the upgrade was registered, and
use that to determine the owner. Technically we could use the
RegistryLocation ID, but this is not always correct (such as
Plethora's vanilla modules).
- We show all upgraded turtles/pocket computers in JEI now, rather than
just CC ones.
- We provide a custom IRecipeRegistryPlugin for upgrades, which
provides custom usage/recipes for any upgrade or upgraded item. We
also hide our generated turtle/pocket computer recipes in order to
prevent duplicates.
Previously we would register the recipes within our code, but the
advancements were written manually. This now generates JSON files for
both the advancement and recipe.
While this does mean we're shipping even more JSON, we'll need to do
this for 1.13 anyway, and means our advancements are guaranteed to be
consistent.
On a side note, a couple of other changes:
- Turtle upgrades are now mounted on the right in the creative
menu/fake recipes. This means the upgrade is now clearly visible in
the inventory.
- We no longer generate legacy turtle items at all: we'll always
construct turtle_expanded.
- Several peripheral items are no longer registered as having sub-types
(namely advanced and full-block modems).
- We only have one disk advancement now, which unlocks all 16 recipes.
- We have removed the disk conversion recipes - these can be
exposed through JEI if needed.
This allows wireless modems (advanced and normal) to be used in
multiparts. There's a very limited set of uses for this (mostly allows
using Chisel and Bits with them), but it's very simple to do.
I'd like to look into MCMP support for wired modems/cables in the
future, but this will be somewhat harder due to their pre-existing
multiblock structure.
Similarly, might be fun to look into CBMP compatibility.
- Share the ILuaContext across all method calls, as well as shifting it
into an anonymous class.
- Move the load/loadstring prefixing into bios.lua
- Be less militant in prefixing chunk names:
- load will no longer do any auto-prefixing.
- loadstring will not prefix when there no chunk name is supplied.
Before we would do `"=" .. supplied_program`, which made no sense.
For instance, `pastebin run https://pastebin.com/LYAxmSby` will now
extract the code and download appropriately. Also add an error message
when we received something which is not a valid pastebin code.
See #134.
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.
Before it was not actually selected until the task had yielded for the
first time. If a computer did not yield (or took a while to do so),
nothing would actually show up.
- Only update all runtimes and the minimum runtime when queuing new
exectors. We only need to update the current executor's runtime.
- Fix overflows when comparing times within TimeoutState.
System.nanotime() may (though probably won't) return negative values.
- Hopefully explain how the scheduler works a little bit.
- Runners would set their active executor before starting resetting the
time, meaning it would be judged as running and terminated.
- Similarly, the cumulative time start was reset to 0, meaning the
computer had been judged to run for an impossibly long time.
- If a computer hit the terminate threshold, but not the hard abort
one, then we'd print the stack trace of the terminated thread - we
now do it before interrupting.
There's still race conditions here when terminating a computer, but
hopefully these changes will mean they never occur under normal
operations (only when a computer has run for far too long).
- Fix the timeout error message displaying utter rot.
- Don't resize the runner array. We don't handle this correctly, so
we shouldn't handle it at all.
- Increment virtualRuntime after a task has executed.
- The computer queue is a priority queue sorted by "virtual runtime".
- Virtual runtime is based on the time this task has executed, divided
by the number of pending tasks.
- We try to execute every task within a given period. Each computer is
allocated a fair share of that period, depending how many tasks are
in the queue. Once a computer has used more than that period, the
computer is paused and the next one resumed.
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.
Oh goodness, when will it end?
- Computer errors are shown in red.
- Lua machine operations provide whether they succeeded, and an
optional error message (reason bios failed to load, timeout error,
another Lua error), which is then shown to the user.
- Clear the Cobalt "thrown soft abort" flag when resuming, rather than
every n instructions.
- Computers will clear their "should start" flag once the time has
expired, irrespective of whether it turned on or not. Before
computers would immediately restart after shutting down if the flag
had been set much earlier.
Errors within the Lua machine are displayed in a more friendly
When closing a BufferedWriter, we close the underlying writer. As we're
using channels, this is an instance of sun.nio.cs.StreamEncoder. This
will attempt to flush the pending character.
However, if throwing an exception within .write errors, the flush will
fail and so the underlying stream is not closed. This was causing us to
leak file descriptors.
We fix this by introducing ChannelWrappers - this holds the wrapper
object (say, a BufferedWriter) and underlying channel. When closed, we
dispose of the wrapper, and then the channel. You could think of this as
doing a nested try-with-resources, rather than a single one.
Note, this is not related to JDK-6378948 - this occurs in the underlying
stream encoder instead.
- TimeoutState uses nanoseconds rather than milliseconds. While this is
slightly less efficient on Windows, it's a) not the bottleneck of Lua
execution and b) we need a monotonic counter, otherwise we could
fail to terminate computers if the time changes.
- Add an exception handler to all threads.
- Document several classes a little better - I'm not sure how useful
all of these are, but _hopefully_ it'll make the internals a little
more accessible.
- Move state management (turnOn, shutdown, etc...) event handling and
the command queue into a ComputerExecutor
- This means the computer thread now just handles running "work" on
computer executors, rather than managing a separate command queue +
requeuing it.
- Instead of setting soft/hard timeouts on the ILuaMachine, we instead
provide it with a TimeoutState instance. This holds the current abort
flags, which can then be polled within debug hooks.
This means the Lua machine has to do less state management, but also
allows a more flexible implementation of aborts.
- Soft aborts are now handled by the TimeoutState - we track when the
task was started, and now only need to check we're more than 7s since
then.
Note, these timers work with millisecond granularity, rather than
nano, as this invokes substantially less overhead.
- Instead of having n runners being observed with n managers, we now
have n runners and 1 manager (or Monitor).
The runners are now responsible for pulling work from the queue. When
the start to execute a task, they set the time execution commenced.
The monitor then just checks each runner every 0.1s and handles hard
aborts (or killing the thread if need be).
- Rename unload -> close to be a little more consistent
- Make pollAndResetChanged be atomic, so we don't need to aquire a lock
- Get the computer queue from the task owner, rather than a separate
argument.
Ideally we'd add a couple more tests in the future, but this'll do for
now.
The bootstrap class is largely yoinked from CCTweaks-Lua, so is a tad
ugly. It works though.
We now generate a table and concatinate the elements together. This has
several benefits:
- We no longer emit emit trailing spaces, which caused issues on 1.13's
command system.
- We no longer need the error level variable, nor have the weird
recursion system - it's just easier to understand.
Prior to this change we would schedule a new task which attached
peripherals on the ComputerThread on the empty task queue. This had a
couple of issues:
- Slow running tasks on the computer thread could result in delays in
peripherals being attached (technically, though rarely seen in
practice).
- Now that the ComputerThread runs tasks at once, there was a race
condition in computers being turned on/off and peripherals being
attached/detached.
Note, while the documentation said that peripherals would only be
(at|de)tached on the computer thread, wired modems would attach on the
server thread, so this was not the case in practice.
One should be aware that peripherals are still detached on the
computer thread, most notably when turning a computer on/off.
This is almost definitely going to break some less well-behaved mods,
and possible some of the well behaved ones. I've tested this on SC, so
it definitely works fine with Computronics and Plethora.
- Restrict what items can be inserted into printers. They're now closer
to brewing stands or furnaces: nothing can go in the output slot,
only ink in the ink slot, and only paper in the paper slot.
- Fix build.gradle using the wrong version
- Trim the width of tables to fit when displaying on the client. Closes
#45. Note, our solution isn't perfect, as it will wordwrap too, but
it's adaquate for now.
When a turtle was unloaded but not actually disposed of, the
m_peripheral map hangs around. As a result, when creating a new
ServerComputer, the peripherals aren't considered changed and so they're
never attached.
Fixes#50.
Also fix that blumin' deprecated method which has been around for a wee
while now.
The Computer class currently has several resposiblities such as storing
id/label, managing redstone/peirpherals, handling management of the
computer (on/off/events) and updating the output.
In order to simplify this a little bit, we move our IAPIEnvironment
implementation into a separate file, and store all "world state"
(redstone + peripherals) in there. While we still need to have some
level of updating them within the main Computer instance, it's
substantially simpler.
- Fire close events instead of failure when open websockets error.
- Handle ping events. I thought I was doing this already, but this
requires a WebsocketProtocolHandler. Fixes#118
- Run optipng on all our images. This has very little effect on most of
them (as they're all so small anyway), but has resulted in a 50%
reduction in some cases.
- Run Proguard on our shadowed dependencies (Cobalt).
- Minify our JSON files, stripping all whitespace. This is mostly
useful for FML's annotation cache, as that's a massive file, but
still a semi-useful optimisation to make.
This has helped reduce the jar by about 110kb, which isn't much but
still feels somewhat worth it.
The latest version of Cobalt has several major changes, which I'm
looking forward to taking advantage of in the coming months:
- The Lua interpreter has been split up from the actual LuaClosure
instance. It now runs multiple functions within one loop, handling
pushing/popping and resuming method calls correctly.
This means we have a theoretically infinite call depth, as we're no
longer bounded by Java's stack size. In reality, this is limited to
32767 (Short.MAX_VALUE), as that's a mostly equivalent to the limits
PUC Lua exposes.
- The stack is no longer unwound in the event of errors. This both
simplifies error handling (not that CC:T needs to care about that)
but also means one can call debug.traceback on a now-dead coroutine
(which is more useful for debugging than using xpcall).
- Most significantly, coroutines are no longer each run on a dedicated
thread. Instead, yielding or resuming throws an exception to unwind
the Java stack and switches to a different coroutine.
In order to preserve compatability with CC's assumption about LuaJ's
threading model (namely that yielding blocks the thread), we also
provide a yieldBlock method (which CC:T consumes). This suspends the
current thread and switches execution to a new thread (see
SquidDev/Cobalt@b5ddf164f1 for more
details). While this does mean we need to use more than 1 thread,
it's still /substantially/ less than would otherwise be needed.
We've been running these changes on SwitchCraft for a few days now and
haven't seen any issues. One nice thing to observe is that the number of
CC thread has gone down from ~1.9k to ~100 (of those, ~70 are dedicated
to running coroutines). Similarly, the server has gone from generating
~15k threads over its lifetime, to ~3k. While this is still a lot, it's
a substantial improvement.
This is far more elegant than our weird method of baking things and
manually inserting them into the model map. Also means we no longer need
the whole turtle_dynamic thing.
We moved the direction call within the if block, but never actally
updated the condition! I'm on a roll of stupid bug fixes today, which
really isn't a good sign.
- Only have computers implement custom block drop logic: everything
else only drops in creative mode.
- Fix redstone inputs not being received correctly. Introduced in
8b86a954ee, yes I'm a silly billy.
- Only update the neighbour which changed.
- Convert terminals from a polling-based system to a more event-driven
one: they now accept an onChanged callback, which marks the parent as
dirty.
- Schedule ticks when monitors are marked as dirty.
- Add several missing @Overrides. This has nothing to do with the rest
of the changes, but I'm bad at good git practice.
- Merge BlockPeripheralBase and BlockPeripheral, as no other classes
extended the former.
- Make BlockPeripheral use ITilePeripheral instead of
TilePeripheralBase. This allows us to use other, non-ticking tiles
instead.
- Convert advanced and normal modems to extend from a generic
TileWirelessModemBase class, and thus neither now tick.
- Move getPeripheralType and getLabel from IPeripheralTile to
TilePeripheralBase. These were mostly constant on all other tiles, so
were rather redundant.
- Make TileAdvancedModem extend TileGeneric, and be non-ticking (using
similar logic to all other blocks).
- Move updateTick onto BlockGeneric/TileGeneric instead of the full
wired modem, as it is used by several tiles now.
- Make *Cable extend from *Generic, and schedule ticks instead of
running every tick.
We currently generate the crafting item once when the upgrade is first
created, and cache it for the duration of the game. As the item never
changes throughout the game, and constructing a stack is a little
expensive (we need to fire an event, etc...), the caching is worth
having.
However, some mods may register capabilities after we've constructed our
ItemStack. This means the capability will be present on other items but
not ours, meaning they are not considered equivalent, and thus the item
cannot be equipped.
In order to avoid this, we use compare items using their share-tag, like
Forge's IngredientNBT. This means the items must still be "mostly" the
same (same enchantements, etc...), but allow differing capabilities.
See NillerMedDild/Enigmatica2Expert#655 for the original bug report -
in this case, Astral Sourcery was registering the capability in init,
but we construct upgrades just before then.
- Move IDirectionalTile constraint from IPeripheralTile to
TilePeripheralBase.
- Make *WiredModemFull no longer inherit from *PeripheralBase. While
there is still some shared logic (namely in the syncing of "anim"),
it's largely fine as we don't store label or direction in NBT.
- Add a TickScheduler. This is a thread-safe version of
World.scheduleUpdate. We simply build a set of all TEs, and schedule
them to be updated the next tick.
- Make ModemState receive an "onChanged" listener, which is fired
whenever the modem changes.
- Make WiredModemFull no longer tick, instead scheduling updates when
it is first loaded and whenever the modem changes.
FileSystemMount was originally added to allow using ReadableByteChannels
instead of InputStreams. However, as zip files do not allow seeking,
there is no benefit of using them over the original JarMount (which we
need to preserve for backwards compatibility).
Instead of maintaining two near-identical mounts, we remove the
FileSystemMount and rewrite the JarMount implementation with several
improvements:
- Rewrite the jar scanning algorithm to be closer to 1.13+'s data pack
mount. This means we no longer require the jar file to have
directories before the file (though this was not a problem in
practice).
- Add all JarMounts to a ReferenceQueue, closing up the ZipFile when
they have been garbage collected (fixes#100).
- Cache the contents of all files for 60 seconds (with some constraints
on size). This allows us to seek on ROM files too (assuming they are
small), by reading the whole thing into memory.
The cache is shared across all mounts, and has a 64MiB limit, and
thus should not have an adverse impact on memory.
This is done in 1.13+ for items and blocks, so we might as well do it
for upgrades now. Note we can't do it for ender pocket modems, as the
upgrade ID is spelled incorrectly there.
- For those where placement is stored in the metadata (computers),
don't also set it in onBlockPlacedBy.
- Remove .getDefaultState(int, EnumFacing) override, as this means we
have more control over what is passed to us (namely, placer's
direction too).
"/computercraf" auto-completes to "/computercraft_copy" instead of
"/computercraft", which is rather annoying, as the former is not meant
to be used normally.
It's rather embarassing that it's been restructured _again_, but I think
this is a nice middle-ground. The previous implementation was written
mostly for Fabric, which doesn't always map perfectly to Forge.
- Move the message identifier into the registration phrase. It's not
really a property of the message itself, rather a property of the
registry, so better suited there.
- Move message handling into the message itself. Honestly, it was just
ending up being rather messy mixing the logic in two places.
This also means we can drop some proxy methods, as it's easier to
have conditionally loaded methods.
- Move network registry into a dedicated class, as that's what we're
doing for everything else.
This means we can avoid several rather ugly instances of getItemBlock
and a cast. We also derive the ItemBlock's registered name from the
block's name, which makes the register a little less ugly.
- Move the "world directory" getter out of the proxy - we can just use
Forge's code here.
- Remove the server proxies, as both were empty. We don't tend to
register any dedicated-server specific code, so I think we can leave
them out.
- All "named" entries (blocks, items, recipes, TEs and pocket/turtle
upgrades) are registeredin one place.
- Most client side models/textures are registered in ClientRegistry -
we can't do item colours or TEs for now, as these aren't event based.
- A little cleanup to how we handle ItemPocketComputer models.
This offers several advantages
- Less registration code: the subscribers are reigstered automatically,
and we don't need to worry about sided-proxies.
- We no longer have so many .instance() calls.
- Move SpeakerPeripheral's TileSpeaker functionality to a sub-class.
- Use Vec3d instead of BlockPos for speaker's positions.
- Use WorldUtil.dropItemStack to spawn in items.
- Remove redundant lock on ModemPeripheral.
- We now error if there are too many websockets, instead of queuing
them up. As these have a more explicit "lifetime", it could be
confusing if http.websocket just blocks indefinitely.
- Fix a CCME when cleaning up resources.
- Move all HTTP tasks to a unified "MonitoredResource" model. This
provides a uniform way of tracking object's lifetimes and disposing
of them when complete.
- Rewrite HTTP requests to use Netty instead of standard Java. This
offers several advantages:
- We have access to more HTTP verbs (mostly PATCH).
- We can now do http -> https redirects.
- We no longer need to spawn in a new thread for each HTTP request.
While we do need to run some tasks off-thread in order to resolve
IPs, it's generally a much shorter task, and so is less likely to
inflate the thread pool.
- Introduce several limits for the http API:
- There's a limit on how many HTTP requests and websockets may exist
at the same time. If the limit is reached, additional ones will be
queued up until pending requests have finished.
- HTTP requests may upload a maximum of 4Mib and download a maximum
of 16Mib (configurable).
- .getResponseCode now returns the status text, as well as the status
code.
While Plethora has been updated to no longer require these, it's
probably worth keeping them around a little longer, as people may not
upgrade them in sync.
We've had this on SC for most of a year now (and SC 1 for most of its
lifetime) and not seen any issues. I'm fairly confident that it does not
allow breaking the sandbox.
- Move configuration loading into a separate file, just so it doesn't
clutter up ComputerCraft.java.
- Normalise property names, so they're all snake_case.
- Split properties into separate categories (http, turtle, peripheral),
so the main one is less cluttered.
- Define an explicit ordering of each category.
- Provide whether a message was binary or text in websocket_message
and handle.receive(). (Fixes#96)
- Provide an optional reason and status code within the websocket_close
event.
Off topic, but also cleanup the file handles a little.
- Remove redundant constructors and super calls
- Standardise naming of texture fields
- Always use postfix notations for loops
- Cleanup several peripheral classes
Previously we would send computer state (labels, id, on/off) through the
ClientComputer rather than as part of the TE description. While this
mostly worked fine, it did end up making things more complex than they
needed to be.
We sync most data to the tile each tick, so there's little risk of
things getting out of date.
There's several reasons for this change:
- Try to make ComputerCraft.java less monolithic by moving
functionality into separate module-specific classes.
- Hopefully make the core class less Minecraft dependent, meaning
emulators are a little less dependent on anything outside of /core.
Note we still need /some/ methods in the main ComputerCraft class in
order to maintain backwards compatibility with Plethora and
Computronics.
Many bits of IInventory (open/close, fields, etc...) are not actually
needed most implementations, so we can clean things up a little with a
common interface.
Some methods act the same on both sides, and so can be in utility
classes. Others are only needed on one side, and so do not really need
to be part of the proxy.
- Remove TurtleVisionCamera. It would be possible to add this back in
the future, but for now it is unused and so should be removed.
- Move frame info (cursor blink, current render frame) into a
FrameInfo class.
- Move record methods (name, playing a record) into a RecordUtil class.
- getPickBlock is now implemented directly on computers and turtles,
rather than on the tile.
- Bounding boxes are handled on the block rather than tile. This ends
up being a little ugly in the case of BlockPeripheral, but it's not
the end of the world.
- Explosion resistance is only implemented for turtles now.
- Replace BlockCableCableVariant with a boolean, removing any custom
logic around it.
- Replace our previous cable Forge-blockstate with a vanilla one, which
handles cable connections in the model logic.
This ends up being slightly cleaner as we can rely on Minecraft's own
model dependency system. Also reduces reliance on Forge's APIs, which
_potentially_ makes porting a little easier.
- Remove the two redstone commands. These are not used (maybe only by
CCEdu), and so are somewhat redundant.
- Inline the select command, converting it to a lambda.
- Inline the attack/dig commands, as they did little more than wrap the
tool command.
As CCEdu has not been updated, and is unlikely to be updated as Dan does
not have the rights to open source it, we're removing explicit support
for now.
If an alternative arises in the future, it would be good to support, but
in a way which requires less workarounds in CC's core.
Most upgrades provides a couple of constant getters (upgrade ID,
adjective, crafting item). We move the getters into a parent class and
pass the values in via the constructor instead.
Also do a tiny bit of cleanup to the upgrades. Mostly just reducing
nesting, renaming fields, etc...
- Only generate resource pack mounts if the desired directory exists.
- Allow mounting files, as well as directories (fixes#90).
As always, also a wee bit of cleanup to some of the surrounding code.