1
0
mirror of https://github.com/SquidDev-CC/CC-Tweaked synced 2025-10-17 23:17:38 +00:00

Compare commits

...

161 Commits

Author SHA1 Message Date
Jonathan Coates
a913232e62 Merge branch 'mc-1.18.x' into mc-1.19.x 2022-06-10 00:04:35 +01:00
Jonathan Coates
557765d8f0 Merge branch 'mc-1.16.x' into mc-1.18.x 2022-06-10 00:00:19 +01:00
Jonathan Coates
1e044aed68 Bump version to 1.100.6 2022-06-09 23:41:43 +01:00
Jonathan Coates
5382d34d29 Bump Forge version
Nothing major has changed, just at this point it's best to be on latest.
2022-06-09 23:34:46 +01:00
Jonathan Coates
cbbb34cdd4 Normalise language files again
Weblate keeps making things uppercase >_>
2022-06-09 08:43:19 +01:00
Jonathan Coates
8f7719a8dc Update to Minecraft 1.19
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.
2022-06-08 00:10:55 +01:00
Weblate
ca58e39707 Translations for Ukrainian
Co-authored-by: RobloMinerYT <svatoslatus2005@gmail.com>
2022-06-07 04:23:27 +00:00
Weblate
0aac966239 Added translation for Ukrainian
Co-authored-by: RobloMinerYT <svatoslatus2005@gmail.com>
2022-06-06 11:55:10 +00:00
Jonathan Coates
0e1e8dfa8c Add recipes to more pages
Might be better if we had pages for each block, but this'll do for now.
2022-06-05 12:20:07 +01:00
Jonathan Coates
a1cbc1d803 Fix turtles not preserving their lock when moving 2022-06-04 15:30:42 +01:00
Jonathan Coates
0b6dc25607 Fix command quoting for Windows
Thanks Lupus for finding this. I really need to redo how some of these
commands are run - maybe use npm scripts instead.
2022-06-01 14:33:23 +01:00
Jonathan Coates
b91809bfc7 Move some eldritch horrors to another directory
Also fix make-doc.sh uploading the wrong file.
2022-06-01 01:02:26 +01:00
Jonathan Coates
178126725e Add more eldritch horrors to the build system
- 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.
2022-06-01 00:48:36 +01:00
Jonathan Coates
cd76425877 Tiny bits and bobs
Oh my, what good commit discipline!

 - Remove unused method in NetworkHandler.
 - Correctly pass the transformation to ComputerBorderRenderer.
2022-05-30 17:42:33 +01:00
Jonathan Coates
4411756b06 Use a queue rather than a set in TickScheduler
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!
2022-05-30 14:25:51 +01:00
Jonathan Coates
1fd57a874f Send terminal text and colours separately
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.
2022-05-30 13:44:11 +01:00
Jonathan Coates
3f0704624e Fix location of DFPWM test 2022-05-30 13:36:36 +01:00
Jonathan Coates
3b6cd783cb Don't allow modems to be used in adventure mode
This (along with computer locking) should be Good Enough for BlanketCon.
2022-05-28 09:23:23 +01:00
Jonathan Coates
a07bba4ece Merge branch 'mc-1.16.x' into mc-1.18.x 2022-05-27 22:28:55 +01:00
Jonathan Coates
ab22726883 Preserve on-state of pocket computers
This is far less robust than block-based computers, but I don't think it
needs to be. Fixes #1097 Or closes? Unclear - I'm counting this as a
bug.
2022-05-27 22:23:04 +01:00
Jonathan Coates
2efad38f53 Allow computers and inventories to be locked
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.
2022-05-27 22:22:54 +01:00
Jonathan Coates
83a1af6526 Merge branch 'mc-1.16.x' into mc-1.18.x 2022-05-27 18:55:51 +01:00
Drew Edwards
8b89d88d04 Allow other mods to provide extra item/block details (#1101) 2022-05-24 22:21:18 +01:00
Jonathan Coates
36635662f1 Merge pull request #1100 from Lemmmy/lemmmy/extendable-computer-screen
Make ComputerScreenBase methods extendable
2022-05-23 18:04:30 +01:00
Drew Edwards
bbc0afa111 Make ComputerScreenBase methods extendable 2022-05-23 17:13:17 +01:00
Drew Edwards
34dc915d57 Add validation to printer slots (#1099) 2022-05-23 16:02:12 +00:00
Jonathan Coates
24ed0ca723 Try to remove some flakiness in tests
- 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
2022-05-23 10:26:18 +01:00
Jonathan Coates
5052718428 Merge branch 'mc-1.16.x' into mc-1.18.x 2022-05-22 15:03:01 +01:00
Jonathan Coates
431e4c9419 Some reformatting to config comments
- 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.
2022-05-22 14:34:31 +01:00
Jonathan Coates
2639b84eb2 Deprecate IArguments.releaseImmediate
This is only ever defined (and called) within the ILuaMachine-specific
code. Not sure why I ever made this public.
2022-05-22 14:05:04 +01:00
Jonathan Coates
d631111610 Improvements to contribution generation
- 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.
2022-05-19 14:09:08 +01:00
Jonathan Coates
c981c75b7c Merge pull request #1096 from FayneAldan/patch-1
Fix typo in documentation
2022-05-13 21:05:01 +01:00
Fayne Aldan
f05a539443 Fix typo in documentation 2022-05-13 13:41:52 -06:00
Jonathan Coates
d8a7ab540a Merge pull request #1095 from Wojbie/mc-1.16.x
Add important leading /
2022-05-10 21:42:40 +01:00
Wojbie
a7536ea4fa Add important leading /
Fixes #1094
2022-05-10 22:30:10 +02:00
Chick Chicky
d9e75d7c47 Added parse_empty_array to textutils.unserialiseJSON (#1092)
Fixes #1089.
2022-05-08 09:53:02 +00:00
Jonathan Coates
78334c4cb1 Fix counts in /computercraft {turn-on,shutdown}
We were using the size of the selectors (which is normally 1) rather
than the number of computers.
2022-05-07 20:17:44 +01:00
JackMacWindows
f5f0c7990a Add note about special JSON values in docs for textutils.unserializeJSON (#1058) 2022-05-07 10:10:25 +00:00
Jonathan Coates
87a1c1a525 Some minor documentation fixes
- 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.
2022-05-05 13:27:33 +01:00
Jonathan Coates
be45b718b3 Correctly mark reify as CLIENT 2022-05-05 00:23:38 +01:00
Jonathan Coates
ad2d1d6a05 Merge branch 'feature/optimise-timeouts' into mc-1.16.x 2022-05-04 18:29:08 +01:00
Jonathan Coates
65a7370db1 Rethink how computer timeouts are handled
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.
2022-05-04 12:33:14 +01:00
Jonathan Coates
03b0244084 Minor improvements to resetting code
- 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.
2022-05-04 11:31:59 +01:00
Jonathan Coates
6322e72110 Add a test harness for ComputerThread
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.
2022-05-03 22:58:28 +01:00
Jonathan Coates
7ad6132494 Move VarargArguments factory to VarargArguments itself 2022-05-03 18:51:34 +01:00
Jonathan Coates
e2189535b8 Fix several thread-unsafe client registrations
Also remove deprecated usage of DeferredWorkQueue. Oh goodness, some of
this code is so old now.

Fixes #1084
2022-05-03 18:48:08 +01:00
Jonathan Coates
79467499e6 Use ByteBuffers in term.blit
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.
2022-05-03 12:47:34 +01:00
Jonathan Coates
074793090d Fix Optifine detection
I really should have tested this. And not expected Optifine to be
normal.
2022-05-03 11:57:35 +01:00
Jonathan Coates
cbbab26bf3 Some minor documentation improvements
- 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.
2022-05-02 17:49:32 +01:00
Jonathan Coates
9cb7091ce7 Fix several deprecated warnings 2022-05-02 16:21:56 +01:00
Sr_endi
e909e11e05 [1.16] Make blocks rotatable for structures (#1083) 2022-05-01 12:09:38 +01:00
JackMacWindows
6239dbe9ca Add documentation on full list of 5.2/5.3 features (#1071) 2022-05-01 08:29:43 +01:00
Jonathan Coates
49601f0b7c Bump Cobalt version
Oh deary me.
2022-04-29 22:35:41 +01:00
Jonathan Coates
caa412b7d2 Merge branch 'mc-1.16.x' into mc-1.18.x 2022-04-28 20:27:48 +01:00
Jonathan Coates
9cb7a5bec7 Track owning entity when sending sounds
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
2022-04-28 19:59:31 +01:00
Cloud Chagnon
118b89ea41 Fix off by one error in printout renderer
Fixes printouts being drawn slightly offset to the left in all cases,
noticeable mainly when in item frames.
2022-04-28 17:42:04 +01:00
Jonathan Coates
f2474bbfa2 Remove redundant class 2022-04-28 17:41:07 +01:00
Jonathan Coates
159f90896e Merge branch 'mc-1.16.x' into mc-1.18.x 2022-04-27 13:52:11 +01:00
Jonathan Coates
f108ba93af Bump version to 1.100.5
> Modulo any game-breaking bugs [...] this will be the last CC: Tweaked
> release.

Terrible performance is game-breaking right? Or am I just petty?
2022-04-27 13:46:55 +01:00
Jonathan Coates
2a4f75ba15 Use Forge's new sound stream API
- 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.
2022-04-27 10:59:28 +01:00
Jonathan Coates
ad228e94a3 Merge remote-tracking branch 'origin/mc-1.16.x' into mc-1.16.x
I hate doing this, but I have too many merges in progress to rebase.
2022-04-26 22:43:22 +01:00
Jonathan Coates
42b98bce28 Reset the BufferUploader state on Linux
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.
2022-04-26 22:39:34 +01:00
Jonathan Coates
59e3608d2a Merge branch 'mc-1.16.x' into mc-1.18.x
I was right: I did not enjoy this.
2022-04-26 22:17:42 +01:00
Jonathan Coates
fccca22d3f Merge branch 'feature/font-rendering-optimise' into mc-1.16.x
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.
2022-04-26 21:43:53 +01:00
Jonathan Coates
4bfdb65989 Use VBO renderer when Optifine is installed
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).
2022-04-26 21:43:21 +01:00
Jonathan Coates
22e8b9b587 Don't render cursors separately
- 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]
2022-04-26 21:43:21 +01:00
Jonathan Coates
77a00b14ae Use UBOs for the TBO renderer
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 :).
2022-04-26 21:43:21 +01:00
Jonathan Coates
78aa757549 Memorize getRenderBoundingBox
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!
2022-04-26 21:43:21 +01:00
Jonathan Coates
1196568a7c Use Ű̶̹̚n̵̦̂́s̷̭̲͐a̶̞͔̔f̸̠́̀e̵͔̋̀ to upload the monitor's contents
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.
2022-04-26 21:43:21 +01:00
Jonathan Coates
48c4f397f9 Backport some text rendering code from 1.18
- 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!
2022-04-26 17:56:43 +01:00
Jonathan Coates
8871f40ced Move FWFR into a separate package
Just a precursor to doing any work on it.
2022-04-26 16:27:49 +01:00
Jonathan Coates
aa62c1f206 Remove redundant CSS in src/web/styles.css
Moved to illuaminate itself
2022-04-26 16:20:04 +01:00
Jonathan Coates
fd32b06d6f Merge pull request #1078 from Hasaabitt/patch-1
Fixed typo
2022-04-24 22:51:21 +01:00
Hasaabitt
739d6813c0 Fixed typo
"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."
2022-04-24 16:56:31 -04:00
Jonathan Coates
daf81b897a Use vector helpers to convert BlockPos to Vector3d
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).
2022-04-22 09:30:04 +01:00
Jonathan Coates
e865d96f7b Fix some typos in the colors API
Closes #1072
2022-04-16 21:14:43 +01:00
Jonathan Coates
79b1872cab Fall back to the given side if the internal one isn't provided
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.
2022-04-08 10:12:41 +01:00
Jonathan Coates
41fa95bce4 Cleanup and optimise terminal rendering (#1057)
- 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!
2022-04-02 10:54:03 +01:00
Jonathan Coates
2a92794da3 Merge pull request #1055 from bclindner/mc-1.16.x
Documentation fix for rednet.broadcast
2022-03-27 17:40:33 +01:00
Brian C. Lindner
b3e009cca5 doc fix 2022-03-27 16:12:42 +00:00
Jonathan Coates
ba7598c689 Merge branch 'mc-1.17.x' into mc-1.18.x 2022-03-23 08:40:25 +00:00
Jonathan Coates
70c5cbafec Merge branch 'mc-1.16.x' into mc-1.17.x 2022-03-23 08:39:39 +00:00
Jonathan Coates
2c64186965 Bump version to 1.100.4 2022-03-23 08:36:09 +00:00
Jonathan Coates
7731759c77 Bump Forge version one more time 2022-03-23 08:34:57 +00:00
Jonathan Coates
e6339b2847 Update to Forge's latest registry API
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.
2022-03-19 08:45:14 +00:00
Jonathan Coates
31ba17d085 Don't wait for the chunk to be loaded when checking for monitors
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 ¯\_(ツ)_/¯.
2022-03-18 19:59:02 +00:00
Jonathan Coates
6353e8d930 Merge branch 'mc-1.16.x' into mc-1.17.x 2022-03-03 10:45:25 +00:00
Jonathan Coates
78cce4981a Merge branch 'mc-1.17.x' into mc-1.18.x 2022-03-03 10:45:25 +00:00
Jonathan Coates
97c953a9be Fix not running the test server during a build 2022-03-03 10:11:17 +00:00
Jonathan Coates
52df7cb8a4 Switch to Forge's game test system
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 :(.
2022-03-03 09:57:36 +00:00
Jonathan Coates
6735cfd12e Update to 1.18.2
Did not enjoy, would not recommend.
2022-03-03 09:17:40 +00:00
Jonathan Coates
bcc7dd6991 Fix typo in Javadoc 2022-03-02 12:54:59 +00:00
Jonathan Coates
f994696161 Merge branch 'mc-1.17.x' into mc-1.18.x 2022-02-28 16:26:16 +00:00
Jonathan Coates
4a4e8bb4b6 Merge branch 'mc-1.16.x' into mc-1.17.x 2022-02-28 16:25:33 +00:00
Jonathan Coates
bd36185662 Bump version
Holding off until Forge releases for 1.18.2
2022-02-28 15:35:16 +00:00
Jonathan Coates
045c4fc88c Merge pull request #1027 from Toad-Dev/issue-1026
Fix large file uploads producing oversized packets.
2022-02-28 11:06:59 +00:00
Jonathan Coates
e0fcc425c6 Prevent id map being null when file is empty
Fixes #1030
2022-02-28 11:01:04 +00:00
Jonathan Coates
e01895d719 Remove turtle_player EntityType
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.
2022-02-28 10:34:41 +00:00
Jonathan Coates
87b38f4249 Fix incorrect recipe name in turtle advancement 2022-02-28 10:32:33 +00:00
Toad-Dev
60d1d1bb18 Fix large file uploads producing oversized packets.
- 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.
2022-01-23 22:31:27 -08:00
Jonathan Coates
cdf8b77ffd Merge pull request #1017 from Possseidon/patch-1
Fix table with mouse button codes in documentation.
2022-01-20 12:40:09 +00:00
Possseidon
e2ce52fe81 Fix table with mouse button codes.
Codes for right and middle mouse buttons were swapped.
2022-01-19 17:39:19 +01:00
Jonathan Coates
9edce36efd Merge branch 'mc-1.17.x' into mc-1.18.x 2022-01-14 23:01:12 +00:00
Jonathan Coates
e05588c662 Merge branch 'mc-1.16.x' into mc-1.17.x 2022-01-14 23:00:17 +00:00
Jonathan Coates
9cf70b10ef Bump version 2022-01-14 22:58:19 +00:00
Jonathan Coates
9ac8f3aeea Fix wired modems having incorrect blockstate
Fixes #1010
2022-01-14 15:37:49 +00:00
Jonathan Coates
e191b08eb5 Use Guava instead of commons-codec for hex encoding
The latter was removed in 1.18 on the server side.

Fixes #1011.
2022-01-14 15:35:58 +00:00
Jonathan Coates
a1221b99e1 Remove debugging log line
Fixes #1014
2022-01-14 14:45:55 +00:00
Jonathan Coates
85bced6b1d Merge pull request #1015 from Paspartout/patch-1
speaker_audio.md: Fix missing add/sum typo
2022-01-14 10:55:08 +00:00
Paspartout
fc4569e0cc speaker_audio.md: Fix missing add/sum typo 2022-01-13 17:36:26 +01:00
Weblate
e7f08313d9 Translations for Danish
Co-authored-by: Christian L.W <christianlw@hotmail.dk>
Co-authored-by: Christian L.W. <christianlw@hotmail.dk>
2022-01-02 23:29:24 +00:00
Jonathan Coates
79366bf2f5 Merge branch 'mc-1.17.x' into mc-1.18.x 2022-01-01 15:41:24 +00:00
Jonathan Coates
413fa5bcc8 Merge branch 'mc-1.16.x' into mc-1.17.x 2022-01-01 15:41:05 +00:00
Jonathan Coates
79fc8237b6 Bump version to 1.100.1
My new years resolution is to make no more CC:T commits.
2022-01-01 15:36:03 +00:00
Jonathan Coates
9d50d6414c Happy new year
Should be the last time I'll have to do this!
2022-01-01 00:09:34 +00:00
Jonathan Coates
16df86224b Fix pocket speakers incorrectly detaching computers
- 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.
2021-12-31 18:24:54 +00:00
Jonathan Coates
a9519f68a1 Clarify term_resize event
Closes #1000, fixes #999.

Co-authored-by: Wojbie <Wojbie@gmail.com>
2021-12-31 18:16:36 +00:00
Jonathan Coates
f1a08a3362 Merge pull request #1002 from Toad-Dev/issue-1001
Fix hasTypeRemote not working with additional types. (#1001)
2021-12-31 18:14:14 +00:00
Toad-Dev
802949d888 Fix hasTypeRemote not working with additional peripheral types.
Fixes #1001. Looks like the culprit was a simple typo.
2021-12-26 21:18:40 -08:00
Jonathan Coates
2b901f2d5e Merge branch 'mc-1.17.x' into mc-1.18.x 2021-12-25 08:05:25 +00:00
Jonathan Coates
62f2cd5cb2 Merge branch 'mc-1.16.x' into mc-1.17.x 2021-12-25 08:05:25 +00:00
Jonathan Coates
e558b31b2b Fix some typos in a dfpwm example 2021-12-21 22:25:16 +00:00
Jonathan Coates
afd82fbf1f Add speaker support to the documentation website
Happy to pick a different piece of audio, but this seemed like a fun one
to me.
2021-12-21 22:20:57 +00:00
Jonathan Coates
901d8d4c3b Merge branch 'mc-1.17.x' into mc-1.18.x 2021-12-21 15:15:53 +00:00
Jonathan Coates
f794ce42ab Merge branch 'mc-1.16.x' into mc-1.17.x 2021-12-21 15:10:19 +00:00
Jonathan Coates
f470478a0f Bump CC:T version to 1.100
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.
2021-12-21 14:55:01 +00:00
Jonathan Coates
aa009df740 Improve fs API introduction
Again, not perfect, but better than a single sentence.
2021-12-21 14:39:08 +00:00
Jonathan Coates
0c6c0badde Move turtle docs into the Java code instead
Yeah, should have seen that coming
2021-12-21 12:00:13 +00:00
Jonathan Coates
bed2e0b658 Write an introduction to the turtle API
It's better at least, I just don't know if it's good.
2021-12-21 11:53:46 +00:00
Jonathan Coates
0f9ddac83c Copy and paste the wiki guide on require
I wrote the original, so I don't need to feel guilty :)

Closes #565.
2021-12-21 00:55:16 +00:00
Jonathan Coates
932b77d7ee Rewrite several doc introductions
Mostly focussing on rednet and modem here. Not sure if I made them any
better, we'll see!
2021-12-21 00:27:07 +00:00
Jonathan Coates
5eedea1bbb Don't push non-pushable entities
Fixes #949
2021-12-20 17:58:39 +00:00
Jonathan Coates
114261944a Tick pocket computers in item entity form
See #995. And no, just because I'm adding this doesn't mean it's not a
terrible issue.
2021-12-20 17:37:42 +00:00
Jonathan Coates
4d10639efb Use correct Java annotations package 2021-12-20 12:19:52 +00:00
Jonathan Coates
aa36b49c50 Enqueue audio when receiving it
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).
2021-12-19 19:50:43 +00:00
Jonathan Coates
8a1067940d Account for the game being paused when tracking sound progress
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
2021-12-19 16:29:06 +00:00
Jonathan Coates
2562642664 Re-add JEI integration 2021-12-18 11:42:22 +00:00
Jonathan Coates
632db1cfa5 Merge branch 'mc-1.17.x' into mc-1.18.x 2021-12-18 11:38:48 +00:00
Jonathan Coates
aa0d544bba Remove MoreRed integration
It's not been updated to 1.17/1.18, nor touched since July. Can easily
be added back in if this changes.
2021-12-18 11:35:52 +00:00
Jonathan Coates
2f6ad00764 Use Java 16 ByteBuffer methods where possible 2021-12-18 11:34:44 +00:00
Jonathan Coates
05da4dd362 Merge branch 'mc-1.16.x' into mc-1.17.x 2021-12-18 11:25:28 +00:00
Jonathan Coates
0477b2742c Use duplicate() instead of rewind()
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
2021-12-18 11:23:12 +00:00
Jonathan Coates
fe3c42ce22 Mark 1.17 (and 1.18) as stable 2021-12-17 16:44:29 +00:00
Jonathan Coates
f6fcba7a39 Merge branch 'mc-1.17.x' into mc-1.18.x 2021-12-14 20:13:53 +00:00
Jonathan Coates
82a7edee12 Merge branch 'mc-1.16.x' into mc-1.17.x 2021-12-14 20:07:48 +00:00
Jonathan Coates
b048b6666d Add arbitrary audio support to speakers (#982)
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!
2021-12-13 22:56:59 +00:00
Jonathan Coates
e16f66e128 Some bits of rednet cleanup
- 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.
2021-12-13 14:30:13 +00:00
Jonathan Coates
1cfad31a0d Separate breaking progress for wired modems
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.
2021-12-13 13:30:43 +00:00
Jonathan Coates
7c373c6e06 Merge branch 'mc-1.17.x' into mc-1.18.x 2021-12-11 07:50:18 +00:00
Jonathan Coates
6196aae488 Merge branch 'mc-1.16.x' into mc-1.17.x 2021-12-11 07:49:33 +00:00
Jonathan Coates
92a0ef2b75 Bump CC:T version 2021-12-11 07:37:10 +00:00
Jonathan Coates
57c5d19f95 Update to Forge 1.18.1 2021-12-11 07:31:41 +00:00
Jonathan Coates
1f6e0f287d Ensure the origin monitor is valid too
Blurh, still not sure if this is Correct or anything, but have no clue
what's causing this. Fixes #985. Hopefully.
2021-12-10 13:13:31 +00:00
Jonathan Coates
0e4b7a5a75 Prevent terminal buttons stealing focus
I have shutdown my computer by accident far too many times now.
2021-12-08 23:16:53 +00:00
Jonathan Coates
47ad7a35dc Fix NPE when pulling an event with no type
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!
2021-12-08 22:47:21 +00:00
Jonathan Coates
3eab2a9b57 Add support for a zero-copy Lua table
The API is entirely designed for the needs of the speaker right now, so
doesn't do much else.
2021-12-07 18:27:29 +00:00
Jonathan Coates
c4024a4c4c Use an admonition instead 2021-12-02 22:41:58 +00:00
Jonathan Coates
f5fb82cd7d Merge pull request #977 from MCJack123/patch-9
Add package.searchpath
2021-12-02 12:34:07 +00:00
MCJack123
e18ba8a2c2 Add package.searchpath 2021-12-01 18:55:24 -05:00
Jonathan Coates
422bfdb60d Add 1.18 and remove 1.15 from the issue template
No, we're not pushing it to Curse yet, but while I remember.
2021-12-01 20:24:37 +00:00
Jonathan Coates
1851ed31cd Release keys when opening the offhand pocket computer screen
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.
2021-12-01 20:09:38 +00:00
678 changed files with 13789 additions and 3451 deletions

3
.gitattributes vendored
View File

@@ -1,5 +1,5 @@
# Ignore changes in generated files
src/generated/resources/data/** linguist-generated
src/generated/** linguist-generated
src/testMod/server-files/structures linguist-generated
* text=auto
@@ -13,3 +13,4 @@ src/testMod/server-files/structures linguist-generated
*.png binary
*.jar binary
*.dfpwm binary

View File

@@ -8,9 +8,9 @@ body:
label: Minecraft Version
description: What version of Minecraft are you using?
options:
- 1.15.x
- 1.16.x
- 1.17.x
- 1.18.x
validations:
required: true
- type: input

View File

@@ -12,7 +12,7 @@ chmod 600 "$HOME/.ssh/key"
# And upload
rsync -avc -e "ssh -i $HOME/.ssh/key -o StrictHostKeyChecking=no -p $SSH_PORT" \
"$GITHUB_WORKSPACE/build/docs/lua/" \
"$GITHUB_WORKSPACE/build/docs/site/" \
"$SSH_USER@$SSH_HOST:/$DEST"
rsync -avc -e "ssh -i $HOME/.ssh/key -o StrictHostKeyChecking=no -p $SSH_PORT" \
"$GITHUB_WORKSPACE/build/docs/javadoc/" \

View File

@@ -65,7 +65,7 @@ Gradle should be your entrypoint to building most documentation. There's two tas
- `./gradlew luaJavadoc` - Generate documentation stubs for Java methods.
- `./gradlew docWebsite` - Generate the whole website (including Javascript pages). The resulting HTML is stored at
`./build/docs/lua/`.
`./build/docs/site/`.
#### Writing documentation
illuaminate's documentation system is not currently documented (somewhat ironic), but is _largely_ the same as

View File

@@ -6,6 +6,7 @@ buildscript {
}
dependencies {
classpath 'net.minecraftforge.gradle:ForgeGradle:5.1.+'
classpath "org.spongepowered:mixingradle:0.7.+"
classpath 'org.parchmentmc:librarian:1.+'
}
}
@@ -22,6 +23,7 @@ plugins {
}
apply plugin: 'net.minecraftforge.gradle'
apply plugin: "org.spongepowered.mixin"
apply plugin: 'org.parchmentmc.librarian.forgegradle'
version = mod_version
@@ -46,10 +48,6 @@ tasks.withType(JavaExec).configureEach {
}
sourceSets {
main.java {
exclude 'dan200/computercraft/shared/integration/jei/**'
exclude 'dan200/computercraft/shared/integration/morered/**'
}
main.resources {
srcDir 'src/generated/resources'
}
@@ -72,6 +70,8 @@ minecraft {
source sourceSets.main
}
}
arg "-mixin.config=computercraft.mixins.json"
}
client {
@@ -105,9 +105,8 @@ minecraft {
}
}
testServer {
gameTestServer {
workingDirectory project.file('test-files/server')
parent runs.server
mods {
cctest {
@@ -129,6 +128,11 @@ minecraft {
accessTransformer file('src/main/resources/META-INF/accesstransformer.cfg')
accessTransformer file('src/testMod/resources/META-INF/accesstransformer.cfg')
}
mixin {
add sourceSets.main, 'computercraft.mixins.refmap.json'
}
repositories {
mavenCentral()
maven {
@@ -152,11 +156,13 @@ dependencies {
checkstyle "com.puppycrawl.tools:checkstyle:8.45"
minecraft "net.minecraftforge:forge:${mc_version}-${forge_version}"
annotationProcessor 'org.spongepowered:mixin:0.8.4:processor'
// compileOnly fg.deobf("mezz.jei:jei-1.17.1:8.0.0.14:api")
// runtimeOnly fg.deobf("mezz.jei:jei-1.17.1:8.0.0.14")
compileOnly fg.deobf("mezz.jei:jei-1.18.2:9.4.1.116:api")
// runtimeOnly fg.deobf("mezz.jei:jei-1.18.2:9.4.1.116")
shade 'org.squiddev:Cobalt:0.5.2-SNAPSHOT'
shade 'org.squiddev:Cobalt:0.5.5'
shade 'io.netty:netty-codec-http:4.1.76.Final'
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.7.0'
testImplementation 'org.junit.jupiter:junit-jupiter-params:5.7.0'
@@ -170,7 +176,7 @@ dependencies {
exclude group: "org.jetbrains", module: "annotations"
}
cctJavadoc 'cc.tweaked:cct-javadoc:1.4.2'
cctJavadoc 'cc.tweaked:cct-javadoc:1.4.6'
}
// Compile tasks
@@ -210,9 +216,13 @@ jar {
"Implementation-Version" : "${mod_version}",
"Implementation-Vendor" : "SquidDev",
"Implementation-Timestamp": new Date().format("yyyy-MM-dd'T'HH:mm:ssZ")
,
"MixinConfigs" : "computercraft.mixins.json",
])
}
duplicatesStrategy(DuplicatesStrategy.WARN)
from configurations.shade.collect { it.isDirectory() ? it : zipTree(it) }
}
@@ -230,9 +240,32 @@ processResources {
try {
hash = ["git", "-C", projectDir, "rev-parse", "HEAD"].execute().text.trim()
def blacklist = ['GitHub', 'dan200', 'Daniel Ratcliffe']
["git", "-C", projectDir, "log", "--format=tformat:%an%n%cn"].execute().text.split('\n').each {
if (!blacklist.contains(it)) contributors.add(it)
def blacklist = ['GitHub', 'Daniel Ratcliffe', 'Weblate']
// Extract all authors, commiters and co-authors from the git log.
def authors = ["git", "-C", projectDir, "log", "--format=tformat:%an <%ae>%n%cn <%ce>%n%(trailers:key=Co-authored-by,valueonly)"]
.execute().text.readLines().unique()
// We now pass this through git's mailmap to de-duplicate some authors.
def remapAuthors = ["git", "check-mailmap", "--stdin"].execute()
remapAuthors.withWriter { stdin ->
if (stdin !instanceof BufferedWriter) stdin = new BufferedWriter(stdin)
authors.forEach {
if (it == "") return
if (!it.endsWith(">")) it += ">" // Some commits have broken Co-Authored-By lines!
stdin.writeLine(it)
}
stdin.close()
}
// And finally extract out the actual name.
def emailRegex = ~/^([^<]+) <.+>$/
remapAuthors.text.readLines().forEach {
def matcher = it =~ emailRegex
matcher.find()
def name = matcher.group(1)
if (!blacklist.contains(name)) contributors.add(name)
}
} catch (Exception e) {
e.printStackTrace()
@@ -282,37 +315,51 @@ task rollup(type: Exec) {
commandLine mkCommand('"node_modules/.bin/rollup" --config rollup.config.js')
}
task minifyWeb(type: Exec, dependsOn: rollup) {
task illuaminateDocs(type: Exec, dependsOn: [rollup, luaJavadoc]) {
group = "build"
description = "Bundles JS into rollup"
inputs.file("$buildDir/rollup/index.js").withPropertyName("sources")
inputs.file("package-lock.json").withPropertyName("package-lock.json")
outputs.file("$buildDir/rollup/index.min.js").withPropertyName("output")
commandLine mkCommand('"node_modules/.bin/terser"' + " -o '$buildDir/rollup/index.min.js' '$buildDir/rollup/index.js'")
}
task illuaminateDocs(type: Exec, dependsOn: [minifyWeb, luaJavadoc]) {
group = "build"
description = "Bundles JS into rollup"
description = "Generates docs using Illuaminate"
inputs.files(fileTree("doc")).withPropertyName("docs")
inputs.files(fileTree("src/main/resources/data/computercraft/lua/rom")).withPropertyName("lua rom")
inputs.file("illuaminate.sexp").withPropertyName("illuaminate.sexp")
inputs.dir("$buildDir/docs/luaJavadoc")
inputs.file("$buildDir/rollup/index.min.js").withPropertyName("scripts")
inputs.file("$buildDir/rollup/index.js").withPropertyName("scripts")
inputs.file("src/web/styles.css").withPropertyName("styles")
outputs.dir("$buildDir/docs/lua")
commandLine mkCommand('"bin/illuaminate" doc-gen')
}
task docWebsite(type: Copy, dependsOn: [illuaminateDocs]) {
from 'doc'
include 'logo.png'
include 'images/**'
into "${project.docsDir}/lua"
task jsxDocs(type: Exec, dependsOn: [illuaminateDocs]) {
group = "build"
description = "Post-processes documentation to statically render some dynamic content."
inputs.files(fileTree("src/web")).withPropertyName("sources")
inputs.file("src/generated/export/index.json").withPropertyName("export")
inputs.file("package-lock.json").withPropertyName("package-lock.json")
inputs.file("tsconfig.json").withPropertyName("Typescript config")
inputs.files(fileTree("$buildDir/docs/lua"))
outputs.dir("$buildDir/docs/site")
commandLine mkCommand('"node_modules/.bin/ts-node" --esm src/web/transform.tsx')
}
task docWebsite(type: Copy, dependsOn: [jsxDocs]) {
from('doc') {
include 'logo.png'
include 'images/**'
}
from("$buildDir/rollup") {
exclude 'index.js'
}
from("$buildDir/docs/lua") {
exclude '**/*.html'
}
from("src/generated/export/items") {
into("images/items")
}
into "${project.docsDir}/site"
}
// Check tasks
@@ -373,69 +420,49 @@ task licenseFormatAPI(type: LicenseFormat)
}
}
task setupServer(type: Copy) {
group "test server"
description "Sets up the environment for the test server."
tasks.register("testServer", JavaExec.class).configure {
it.group('In-game tests')
it.description("Runs tests on a temporary Minecraft instance.")
it.dependsOn("prepareRunGameTestServer", "cleanTestServer", 'compileTestModJava')
from("src/testMod/server-files") {
include "eula.txt"
include "server.properties"
}
into "test-files/server"
// Copy from runTestServer. We do it in this slightly odd way as runTestServer
// isn't created until the task is configured (which is no good for us).
JavaExec exec = tasks.getByName("runGameTestServer")
exec.copyTo(it)
it.setClasspath(exec.getClasspath())
it.mainClass = exec.mainClass
it.setArgs(exec.getArgs())
// Jacoco and modlauncher don't play well together as the classes loaded in-game don't
// match up with those written to disk. We get Jacoco to dump all classes to disk, and
// use that when generating the report.
def coverageOut = new File(buildDir, "jacocoClassDump/testServer")
jacoco.applyTo(it)
it.jacoco.setIncludes(["dan200.computercraft.*"])
it.jacoco.setClassDumpDir(coverageOut)
it.outputs.dir(coverageOut)
// Older versions of modlauncher don't include a protection domain (and thus no code
// source). Jacoco skips such classes by default, so we need to explicitly include them.
it.jacoco.setIncludeNoLocationClasses(true)
}
["Client", "Server"].forEach { name ->
tasks.register("test$name", JavaExec.class).configure {
it.group('In-game tests')
it.description("Runs tests on a temporary Minecraft instance.")
it.dependsOn(setupServer, "prepareRunTest$name", "cleanTest$name", 'compileTestModJava')
tasks.register("jacocoTestServerReport", JacocoReport.class).configure {
it.group('In-game')
it.description("Generate coverage reports for testServer")
it.dependsOn("testServer")
// Copy from runTestServer. We do it in this slightly odd way as runTestServer
// isn't created until the task is configured (which is no good for us).
JavaExec exec = tasks.getByName("runTest$name")
exec.copyTo(it)
it.setClasspath(exec.getClasspath())
it.mainClass = exec.mainClass
it.setArgs(exec.getArgs())
it.executionData(new File(buildDir, "jacoco/testServer.exec"))
it.sourceDirectories.from(sourceSets.main.allJava.srcDirs)
it.classDirectories.from(new File(buildDir, "jacocoClassDump/testServer"))
it.systemProperty('forge.logging.console.level', 'info')
it.systemProperty('cctest.run', 'true')
// Jacoco and modlauncher don't play well together as the classes loaded in-game don't
// match up with those written to disk. We get Jacoco to dump all classes to disk, and
// use that when generating the report.
def coverageOut = new File(buildDir, "jacocoClassDump/test$name")
jacoco.applyTo(it)
it.jacoco.setIncludes(["dan200.computercraft.*"])
it.jacoco.setClassDumpDir(coverageOut)
it.outputs.dir(coverageOut)
// Older versions of modlauncher don't include a protection domain (and thus no code
// source). Jacoco skips such classes by default, so we need to explicitly include them.
it.jacoco.setIncludeNoLocationClasses(true)
}
tasks.register("jacocoTest${name}Report", JacocoReport.class).configure {
it.group('In-game')
it.description("Generate coverage reports for test$name")
it.dependsOn("test$name")
it.executionData(new File(buildDir, "jacoco/test${name}.exec"))
it.sourceDirectories.from(sourceSets.main.allJava.srcDirs)
it.classDirectories.from(new File(buildDir, "jacocoClassDump/test$name"))
it.reports {
xml.enabled true
html.enabled true
}
}
if (name != "Client" || project.findProperty('cc.tweaked.clientTests') == 'true') {
// Don't run client tests unless explicitly opted into them. They're a bit of a faff
// to run and pretty flakey.
check.dependsOn("jacocoTest${name}Report")
it.reports {
xml.enabled true
html.enabled true
}
}
check.dependsOn("jacocoTestServerReport")
// Upload tasks
@@ -479,7 +506,7 @@ task checkRelease {
}
check.dependsOn checkRelease
def isStable = false
def isStable = true
curseforge {
apiKey = project.hasProperty('curseForgeApiKey') ? project.curseForgeApiKey : ''
@@ -584,7 +611,7 @@ githubRelease {
.takeWhile { it != 'Type "help changelog" to see the full version history.' }
.join("\n").trim()
}))
prerelease isStable
prerelease !isStable
}
def uploadTasks = ["publish", "curseforge", "publishModrinth", "githubRelease"]

View File

@@ -83,7 +83,9 @@
<module name="JavadocBlockTagLocation" />
<module name="JavadocMethod"/>
<module name="JavadocType"/>
<module name="JavadocStyle" />
<module name="JavadocStyle">
<property name="checkHtml" value="false" />
</module>
<module name="NonEmptyAtclauseDescription" />
<module name="SingleLineJavadoc" />
<module name="SummaryJavadocCheck"/>

View File

@@ -51,5 +51,6 @@ exclude: |
src/generated|
src/test/resources/test-rom/data/json-parsing/|
src/testMod/server-files/|
config/idea/
config/idea/|
.*\.dfpwm
)

View File

@@ -2,7 +2,7 @@
module: [kind=event] modem_message
---
The @{modem_message} event is fired when a message is received on an open channel on any modem.
The @{modem_message} event is fired when a message is received on an open channel on any @{modem}.
## Return Values
1. @{string}: The event name.
@@ -10,11 +10,15 @@ The @{modem_message} event is fired when a message is received on an open channe
3. @{number}: The channel that the message was sent on.
4. @{number}: The reply channel set 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. @{number}: The distance between the sender and the receiver, in blocks.
## Example
Prints a message when one is sent:
Wraps a @{modem} peripheral, opens channel 0 for listening, and prints all received messages.
```lua
local modem = peripheral.find("modem") or error("No modem attached", 0)
modem.open(0)
while true do
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)))

View File

@@ -15,13 +15,11 @@ advanced turtles and pocket computers).
Several mouse events (@{mouse_click}, @{mouse_up}, @{mouse_scroll}) contain a "mouse button" code. This takes a
numerical value depending on which button on your mouse was last pressed when this event occurred.
<table class="pretty-table">
<!-- Our markdown parser doesn't work on tables!? Guess I'll have to roll my own soonish :/. -->
<tr><th>Button code</th><th>Mouse button</th></tr>
<tr><td align="right">1</td><td>Left button</td></tr>
<tr><td align="right">2</td><td>Middle button</td></tr>
<tr><td align="right">3</td><td>Right button</td></tr>
</table>
| Button Code | Mouse Button |
|------------:|---------------|
| 1 | Left button |
| 2 | Right button |
| 3 | Middle button |
## Example
Print the button and the coordinates whenever the mouse is clicked.

View File

@@ -0,0 +1,27 @@
---
module: [kind=event] speaker_audio_empty
see: speaker.playAudio To play audio using the speaker
---
## Return Values
1. @{string}: The event name.
2. @{string}: The name of the speaker which is available to play more audio.
## Example
This uses @{io.lines} to read audio data in blocks of 16KiB from "example_song.dfpwm", and then attempts to play it
using @{speaker.playAudio}. If the speaker's buffer is full, it waits for an event and tries again.
```lua {data-peripheral=speaker}
local dfpwm = require("cc.audio.dfpwm")
local speaker = peripheral.find("speaker")
local decoder = dfpwm.make_decoder()
for chunk in io.lines("data/example.dfpwm", 16 * 1024) do
local buffer = decoder(chunk)
while not speaker.playAudio(buffer) do
os.pullEvent("speaker_audio_empty")
end
end
```

View File

@@ -2,7 +2,12 @@
module: [kind=event] term_resize
---
The @{term_resize} event is fired when the main terminal is resized, mainly when a new tab is opened or closed in @{multishell}.
The @{term_resize} event is fired when the main terminal is resized. For instance:
- When a the tab bar is shown or hidden in @{multishell}.
- When the terminal is redirected to a monitor via the "monitor" program and the monitor is resized.
When this event fires, some parts of the terminal may have been moved or deleted. Simple terminal programs (those
not using @{term.setCursorPos}) can ignore this event, but more complex GUI programs should redraw the entire screen.
## Example
Prints :

99
doc/guides/local_ips.md Normal file
View File

@@ -0,0 +1,99 @@
---
module: [kind=guide] local_ips
---
# 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]]` entires 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"), wilcards ("*.pastebin.com") or CIDR notation ("127.0.0.0/8").
blacklist = ["127.0.0.0/8", "10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16", "fd00::/8"]
```
Remove everything inside the array, leaving the last line as `blacklist = []`. Then save the file and relaunch Minecraft.
Here's what it should look like after removing:
```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"), wilcards ("*.pastebin.com") or CIDR notation ("127.0.0.0/8").
blacklist = []
```
## Minecraft 1.12.2 and earlier {#mc-1.12}
On singleplayer, the configuration file is located at `.minecraft\config\ComputerCraft.cfg`. On multiplayer, the
configuration file is located at `<server folder>\config\ComputerCraft.cfg`. Look for lines that look like this:
```ini
# 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 explicitly allowed 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").
S:blocked_domains <
127.0.0.0/8
10.0.0.0/8
172.16.0.0/12
192.168.0.0/16
fd00::/8
>
```
Delete everything between the `<>`, leaving the last line as `S:blocked_domains = <>`. Then save the file and relaunch
Minecraft (Server).
Here's what it should look like after removing:
```ini
# 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 explicitly allowed 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").
S:blocked_domains <>
```

205
doc/guides/speaker_audio.md Normal file
View File

@@ -0,0 +1,205 @@
---
module: [kind=guide] speaker_audio
see: speaker.playAudio Play PCM audio using a speaker.
see: cc.audio.dfpwm Provides utilities for encoding and decoding DFPWM files.
---
# Playing audio with speakers
CC: Tweaked's speaker peripheral provides a powerful way to play any audio you like with the @{speaker.playAudio}
method. However, for people unfamiliar with digital audio, it's not the most intuitive thing to use. This guide provides
an introduction to digital audio, demonstrates how to play music with CC: Tweaked's speakers, and then briefly discusses
the more complex topic of audio processing.
## A short introduction to digital audio
When sound is recorded it is captured as an analogue signal, effectively the electrical version of a sound
wave. However, this signal is continuous, and so can't be used directly by a computer. Instead, we measure (or *sample*)
the amplitude of the wave many times a second and then *quantise* that amplitude, rounding it to the nearest
representable value.
This representation of sound - a long, uniformally sampled list of amplitudes is referred to as [Pulse-code
Modulation][PCM] (PCM). PCM can be thought of as the "standard" audio format, as it's incredibly easy to work with. For
instance, to mix two pieces of audio together, you can just add samples from the two tracks together and take the average.
CC: Tweaked's speakers also work with PCM audio. It plays back 48,000 samples a second, where each sample is an integer
between -128 and 127. This is more commonly referred to as 48kHz and an 8-bit resolution.
Let's now look at a quick example. We're going to generate a [Sine Wave] at 220Hz, which sounds like a low monotonous
hum. First we wrap our speaker peripheral, and then we fill a table (also referred to as a *buffer*) with 128×1024
samples - this is the maximum number of samples a speaker can accept in one go.
In order to fill this buffer, we need to do a little maths. We want to play 220 sine waves each second, where each sine
wave completes a full oscillation in 2π "units". This means one seconds worth of audio is 2×π×220 "units" long. We then
need to split this into 48k samples, basically meaning for each sample we move 2×π×220/48k "along" the sine curve.
```lua {data-peripheral=speaker}
local speaker = peripheral.find("speaker")
local buffer = {}
local t, dt = 0, 2 * math.pi * 220 / 48000
for i = 1, 128 * 1024 do
buffer[i] = math.floor(math.sin(t) * 127)
t = (t + dt) % (math.pi * 2)
end
speaker.playAudio(buffer)
```
## Streaming audio
You might notice that the above snippet only generates a short bit of audio - 2.7s seconds to be precise. While we could
try increasing the number of loop iterations, we'll get an error when we try to play it through the speaker: the sound
buffer is too large for it to handle.
Our 2.7 seconds of audio is stored in a table with over 130 _thousand_ elements. If we wanted to play a full minute of
sine waves (and why wouldn't you?), you'd need a table with almost 3 _million_. Suddenly you find these numbers adding
up very quickly, and these tables take up more and more memory.
Instead of building our entire song (well, sine wave) in one go, we can produce it in small batches, each of which get
passed off to @{speaker.playAudio} when the time is right. This allows us to build a _stream_ of audio, where we read
chunks of audio one at a time (either from a file or a tone generator like above), do some optional processing to each
one, and then play them.
Let's adapt our example from above to do that instead.
```lua {data-peripheral=speaker}
local speaker = peripheral.find("speaker")
local t, dt = 0, 2 * math.pi * 220 / 48000
while true do
local buffer = {}
for i = 1, 16 * 1024 * 8 do
buffer[i] = math.floor(math.sin(t) * 127)
t = (t + dt) % (math.pi * 2)
end
while not speaker.playAudio(buffer) do
os.pullEvent("speaker_audio_empty")
end
end
```
It looks pretty similar to before, aside from we've wrapped the generation and playing code in a while loop, and added a
rather odd loop with @{speaker.playAudio} and @{os.pullEvent}.
Let's talk about this loop, why do we need to keep calling @{speaker.playAudio}? Remember that what we're trying to do
here is avoid keeping too much audio in memory at once. However, if we're generating audio quicker than the speakers can
play it, we're not helping at all - all this audio is still hanging around waiting to be played!
In order to avoid this, the speaker rejects any new chunks of audio if its backlog is too large. When this happens,
@{speaker.playAudio} returns false. Once enough audio has played, and the backlog has been reduced, a
@{speaker_audio_empty} event is queued, and we can try to play our chunk once more.
## Storing audio
PCM is a fantastic way of representing audio when we want to manipulate it, but it's not very efficient when we want to
store it to disk. Compare the size of a WAV file (which uses PCM) to an equivalent MP3, it's often 5 times the size.
Instead, we store audio in special formats (or *codecs*) and then convert them to PCM when we need to do processing on
them.
Modern audio codecs use some incredibly impressive techniques to compress the audio as much as possible while preserving
sound quality. However, due to CC: Tweaked's limited processing power, it's not really possible to use these from your
computer. Instead, we need something much simpler.
DFPWM (Dynamic Filter Pulse Width Modulation) is the de facto standard audio format of the ComputerCraft (and
OpenComputers) world. Originally popularised by the addon mod [Computronics], CC:T now has built-in support for it with
the @{cc.audio.dfpwm} module. This allows you to read DFPWM files from disk, decode them to PCM, and then play them
using the speaker.
Let's dive in with an example, and we'll explain things afterwards:
```lua {data-peripheral=speaker}
local dfpwm = require("cc.audio.dfpwm")
local speaker = peripheral.find("speaker")
local decoder = dfpwm.make_decoder()
for chunk in io.lines("data/example.dfpwm", 16 * 1024) do
local buffer = decoder(chunk)
while not speaker.playAudio(buffer) do
os.pullEvent("speaker_audio_empty")
end
end
```
Once again, we see the @{speaker.playAudio}/@{speaker_audio_empty} loop. However, the rest of the program is a little
different.
First, we require the dfpwm module and call @{cc.audio.dfpwm.make_decoder} to construct a new decoder. This decoder
accepts blocks of DFPWM data and converts it to a list of 8-bit amplitudes, which we can then play with our speaker.
As mentioned above, @{speaker.playAudio} accepts at most 128×1024 samples in one go. DFPMW uses a single bit for each
sample, which means we want to process our audio in chunks of 16×1024 bytes (16KiB). In order to do this, we use
@{io.lines}, which provides a nice way to loop over chunks of a file. You can of course just use @{fs.open} and
@{fs.BinaryReadHandle.read} if you prefer.
## Processing audio
As mentioned near the beginning of this guide, PCM audio is pretty easy to work with as it's just a list of amplitudes.
You can mix together samples from different streams by adding their amplitudes, change the rate of playback by removing
samples, etc...
Let's put together a small demonstration here. We're going to add a small delay effect to the song above, so that you
hear a faint echo a second and a half later.
In order to do this, we'll follow a format similar to the previous example, decoding the audio and then playing it.
However, we'll also add some new logic between those two steps, which loops over every sample in our chunk of audio, and
adds the sample from 1.5 seconds ago to it.
For this, we'll need to keep track of the last 72k samples - exactly 1.5 seconds worth of audio. We can do this using a
[Ring Buffer], which helps makes things a little more efficient.
```lua {data-peripheral=speaker}
local dfpwm = require("cc.audio.dfpwm")
local speaker = peripheral.find("speaker")
-- Speakers play at 48kHz, so 1.5 seconds is 72k samples. We first fill our buffer
-- with 0s, as there's nothing to echo at the start of the track!
local samples_i, samples_n = 1, 48000 * 1.5
local samples = {}
for i = 1, samples_n do samples[i] = 0 end
local decoder = dfpwm.make_decoder()
for chunk in io.lines("data/example.dfpwm", 16 * 1024) do
local buffer = decoder(chunk)
for i = 1, #buffer do
local original_value = buffer[i]
-- Replace this sample with its current amplitude plus the amplitude from 1.5 seconds ago.
-- We scale both to ensure the resulting value is still between -128 and 127.
buffer[i] = original_value * 0.6 + samples[samples_i] * 0.4
-- Now store the current sample, and move the "head" of our ring buffer forward one place.
samples[samples_i] = original_value
samples_i = samples_i + 1
if samples_i > samples_n then samples_i = 1 end
end
while not speaker.playAudio(buffer) do
os.pullEvent("speaker_audio_empty")
end
-- The audio processing above can be quite slow and preparing the first batch of audio
-- may timeout the computer. We sleep to avoid this.
-- There's definitely better ways of handling this - this is just an example!
sleep(0.05)
end
```
:::note Confused?
Don't worry if you don't understand this example. It's quite advanced, and does use some ideas that this guide doesn't
cover. That said, don't be afraid to ask on [Discord] or [IRC] either!
:::
It's worth noting that the examples of audio processing we've mentioned here are about manipulating the _amplitude_ of
the wave. If you wanted to modify the _frequency_ (for instance, shifting the pitch), things get rather more complex.
For this, you'd need to use the [Fast Fourier transform][FFT] to convert the stream of amplitudes to frequencies,
process those, and then convert them back to amplitudes.
This is, I'm afraid, left as an exercise to the reader.
[Computronics]: https://github.com/Vexatos/Computronics/ "Computronics on GitHub"
[FFT]: https://en.wikipedia.org/wiki/Fast_Fourier_transform "Fast Fourier transform - Wikipedia"
[PCM]: https://en.wikipedia.org/wiki/Pulse-code_modulation "Pulse-code Modulation - Wikipedia"
[Ring Buffer]: https://en.wikipedia.org/wiki/Circular_buffer "Circular buffer - Wikipedia"
[Sine Wave]: https://en.wikipedia.org/wiki/Sine_wave "Sine wave - Wikipedia"
[Discord]: https://discord.computercraft.cc "The Minecraft Computer Mods Discord"
[IRC]: http://webchat.esper.net/?channels=computercraft "IRC webchat on EsperNet"

View File

@@ -0,0 +1,83 @@
---
module: [kind=guide] using_require
---
# Reusing code with require
A library is a collection of useful functions and other definitions which is stored separately to your main program. You
might want to create a library because you have some functions which are used in multiple programs, or just to split
your program into multiple more modular files.
Let's say we want to create a small library to make working with the @{term|terminal} a little easier. We'll provide two
functions: `reset`, which clears the terminal and sets the cursor to (1, 1), and `write_center`, which prints some text
in the middle of the screen.
Start off by creating a file called `more_term.lua`:
```lua {data-snippet=more_term}
local function reset()
term.clear()
term.setCursorPos(1, 1)
end
local function write_center(text)
local x, y = term.getCursorPos()
local width, height = term.getSize()
term.setCursorPos(math.floor((width - #text) / 2) + 1, y)
term.write(text)
end
return { reset = reset, write_center = write_center }
```
Now, what's going on here? We define our two functions as one might expect, and then at the bottom return a table with
the two functions. When we require this library, this table is what is returned. With that, we can then call the
original functions. Now create a new file, with the following:
```lua {data-mount=more_term:more_term.lua}
local more_term = require("more_term")
more_term.reset()
more_term.write_center("Hello, world!")
```
When run, this'll clear the screen and print some text in the middle of the first line.
## require in depth
While the previous section is a good introduction to how @{require} operates, there are a couple of remaining points
which are worth mentioning for more advanced usage.
### Libraries can return anything
In our above example, we return a table containing the functions we want to expose. However, it's worth pointing out
that you can return ''anything'' from your library - a table, a function or even just a string! @{require} treats them
all the same, and just returns whatever your library provides.
### Module resolution and the package path
In the above examples, we defined our library in a file, and @{require} read from it. While this is what you'll do most
of the time, it is possible to make @{require} look elsewhere for your library, such as downloading from a website or
loading from an in-memory library store.
As a result, the *module name* you pass to @{require} doesn't correspond to a file path. One common mistake is to load
code from a sub-directory using `require("folder/library")` or even `require("folder/library.lua")`, neither of which
will do quite what you expect.
When loading libraries (also referred to as *modules*) from files, @{require} searches along the *@{package.path|module
path}*. By default, this looks something like:
* `?.lua`
* `?/init.lua`
* `/rom/modules/main/?.lua`
* etc...
When you call `require("my_library")`, @{require} replaces the `?` in each element of the path with your module name, and
checks if the file exists. In this case, we'd look for `my_library.lua`, `my_library/init.lua`,
`/rom/modules/main/my_library.lua` and so on. Note that this works *relative to the current program*, so if your
program is actually called `folder/program`, then we'll look for `folder/my_library.lua`, etc...
One other caveat is loading libraries from sub-directories. For instance, say we have a file
`my/fancy/library.lua`. This can be loaded by using `require("my.fancy.library")` - the '.'s are replaced with '/'
before we start looking for the library.
## External links
There are several external resources which go into require in a little more detail:
- The [Lua Module tutorial](http://lua-users.org/wiki/ModulesTutorial) on the Lua wiki.
- [Lua's manual section on @{require}](https://www.lua.org/manual/5.1/manual.html#pdf-require).

View File

@@ -0,0 +1,95 @@
---
module: [kind=reference] feature_compat
---
# Lua 5.2/5.3 features in CC: Tweaked
CC: Tweaked is based off of the Cobalt Lua runtime, which uses Lua 5.1. However, Cobalt and CC:T implement additional features from Lua 5.2 and 5.3 (as well as some deprecated 5.0 features) that are not available in base 5.1. This page lists all of the compatibility for these newer versions.
## Lua 5.2
| Feature | Supported? | Notes |
|---------------------------------------------------------------|------------|-------------------------------------------------------------------|
| `goto`/labels | ❌ | |
| `_ENV` | 🔶 | The `_ENV` global points to `getfenv()`, but it cannot be set. |
| `\z` escape | ✔ | |
| `\xNN` escape | ✔ | |
| Hex literal fractional/exponent parts | ✔ | |
| Empty statements | ❌ | |
| `__len` metamethod | ✔ | |
| `__ipairs` metamethod | ❌ | |
| `__pairs` metamethod | ✔ | |
| `bit32` library | ✔ | |
| `collectgarbage` isrunning, generational, incremental options | ❌ | `collectgarbage` does not exist in CC:T. |
| New `load` syntax | ✔ | |
| `loadfile` mode parameter | ✔ | Supports both 5.1 and 5.2+ syntax. |
| Removed `loadstring` | 🔶 | Only if `disable_lua51_features` is enabled in the configuration. |
| Removed `getfenv`, `setfenv` | 🔶 | Only if `disable_lua51_features` is enabled in the configuration. |
| `rawlen` function | ✔ | |
| Negative index to `select` | ✔ | |
| Removed `unpack` | 🔶 | Only if `disable_lua51_features` is enabled in the configuration. |
| Arguments to `xpcall` | ❌ | |
| Second return value from `coroutine.running` | ❌ | |
| Removed `module` | ✔ | |
| `package.loaders` -> `package.searchers` | ❌ | |
| Second argument to loader functions | ✔ | |
| `package.config` | ✔ | |
| `package.searchpath` | ✔ | |
| Removed `package.seeall` | ✔ | |
| `string.dump` on functions with upvalues (blanks them out) | ✔ | |
| `string.rep` separator | ❌ | |
| `%g` match group | ❌ | |
| Removal of `%z` match group | ❌ | |
| Removed `table.maxn` | 🔶 | Only if `disable_lua51_features` is enabled in the configuration. |
| `table.pack`/`table.unpack` | ✔ | |
| `math.log` base argument | ✔ | |
| Removed `math.log10` | 🔶 | Only if `disable_lua51_features` is enabled in the configuration. |
| `*L` mode to `file:read` | ✔ | |
| `os.execute` exit type + return value | ❌ | `os.execute` does not exist in CC:T. |
| `os.exit` close argument | ❌ | `os.exit` does not exist in CC:T. |
| `istailcall` field in `debug.getinfo` | ❌ | |
| `nparams` field in `debug.getinfo` | ✔ | |
| `isvararg` field in `debug.getinfo` | ✔ | |
| `debug.getlocal` negative indices for varargs | ❌ | |
| `debug.getuservalue`/`debug.setuservalue` | ❌ | Userdata are rarely used in CC:T, so this is not necessary. |
| `debug.upvalueid` | ✔ | |
| `debug.upvaluejoin` | ✔ | |
| Tail call hooks | ❌ | |
| `=` prefix for chunks | ✔ | |
| Yield across C boundary | ✔ | |
| Removal of ambiguity error | ❌ | |
| Identifiers may no longer use locale-dependent letters | ✔ | |
| Ephemeron tables | ❌ | |
| Identical functions may be reused | ❌ | |
| Generational garbage collector | ❌ | Cobalt uses the built-in Java garbage collector. |
## Lua 5.3
| Feature | Supported? | Notes |
|---------------------------------------------------------------------------------------|------------|---------------------------|
| Integer subtype | ❌ | |
| Bitwise operators/floor division | ❌ | |
| `\u{XXX}` escape sequence | ✔ | |
| `utf8` library | ✔ | |
| removed `__ipairs` metamethod | ✔ | |
| `coroutine.isyieldable` | ❌ | |
| `string.dump` strip argument | ✔ | |
| `string.pack`/`string.unpack`/`string.packsize` | ✔ | |
| `table.move` | ❌ | |
| `math.atan2` -> `math.atan` | ❌ | |
| Removed `math.frexp`, `math.ldexp`, `math.pow`, `math.cosh`, `math.sinh`, `math.tanh` | ❌ | |
| `math.maxinteger`/`math.mininteger` | ❌ | |
| `math.tointeger` | ❌ | |
| `math.type` | ❌ | |
| `math.ult` | ❌ | |
| Removed `bit32` library | ❌ | |
| Remove `*` from `file:read` modes | ✔ | |
| Metamethods respected in `table.*`, `ipairs` | 🔶 | Only `__lt` is respected. |
## Lua 5.0
| Feature | Supported? | Notes |
|----------------------------------|------------|--------------------------------------------------|
| `arg` table | 🔶 | Only set in the shell - not used in functions. |
| `string.gfind` | ✔ | Equal to `string.gmatch`. |
| `table.getn` | ✔ | Equal to `#tbl`. |
| `table.setn` | ❌ | |
| `math.mod` | ✔ | Equal to `math.fmod`. |
| `table.foreach`/`table.foreachi` | ✔ | |
| `gcinfo` | ❌ | Cobalt uses the built-in Java garbage collector. |

View File

@@ -1,6 +1,4 @@
--- The FS API allows you to manipulate files and the filesystem.
--
-- @module fs
--- @module fs
--- Returns true if a path is mounted to the parent filesystem.
--

View File

@@ -12,16 +12,19 @@ rounded up to the nearest multiple of 0.05 seconds. If you are using coroutines
or the @{parallel|parallel API}, it will only pause execution of the current
thread, not the whole program.
**Note** Because sleep internally uses timers, it is a function that yields.
This means that you can use it to prevent "Too long without yielding" errors,
however, as the minimum sleep time is 0.05 seconds, it will slow your program
down.
:::tip
Because sleep internally uses timers, it is a function that yields. This means
that you can use it to prevent "Too long without yielding" errors, however, as
the minimum sleep time is 0.05 seconds, it will slow your program down.
:::
**Warning** Internally, this function queues and waits for a timer event (using
:::caution
Internally, this function queues and waits for a timer event (using
@{os.startTimer}), however it does not listen for any other events. This means
that any event that occurs while sleeping will be entirely discarded. If you
need to receive events while sleeping, consider using @{os.startTimer|timers},
or the @{parallel|parallel API}.
:::
@tparam number time The number of seconds to sleep for, rounded up to the
nearest multiple of 0.05.
@@ -59,7 +62,7 @@ function print(...) end
-- @usage printError("Something went wrong!")
function printError(...) end
--[[- Reads user input from the terminal, automatically handling arrow keys,
--[[- Reads user input from the terminal. This automatically handles arrow keys,
pasting, character replacement, history scrollback, auto-completion, and
default values.
@@ -107,10 +110,15 @@ the prompt.
]]
function read(replaceChar, history, completeFn, default) end
--- The ComputerCraft and Minecraft version of the current computer environment.
--- Stores the current ComputerCraft and Minecraft versions.
--
-- Outside of Minecraft (for instance, in an emulator) @{_HOST} will contain the
-- emulator's version instead.
--
-- For example, `ComputerCraft 1.93.0 (Minecraft 1.15.2)`.
-- @usage _HOST
-- @usage Print the current computer's environment.
--
-- print(_HOST)
-- @since 1.76
_HOST = _HOST

View File

@@ -1,14 +1,13 @@
--- The http library allows communicating with web servers, sending and
-- receiving data from them.
--- Make HTTP requests, sending and receiving data to a remote web server.
--
-- @module http
-- @since 1.1
-- @see local_ips To allow accessing servers running on your local network.
--- Asynchronously make a HTTP request to the given url.
--
-- This returns immediately, a [`http_success`](#http-success-event) or
-- [`http_failure`](#http-failure-event) will be queued once the request has
-- completed.
-- This returns immediately, a @{http_success} or @{http_failure} will be queued
-- once the request has completed.
--
-- @tparam string url The url to request
-- @tparam[opt] string body An optional string containing the body of the
@@ -112,9 +111,8 @@ function post(...) end
--- Asynchronously determine whether a URL can be requested.
--
-- If this returns `true`, one should also listen for [`http_check`
-- events](#http-check-event) which will container further information about
-- whether the URL is allowed or not.
-- If this returns `true`, one should also listen for @{http_check} which will
-- container further information about whether the URL is allowed or not.
--
-- @tparam string url The URL to check.
-- @treturn true When this url is not invalid. This does not imply that it is
@@ -128,9 +126,8 @@ function checkURLAsync(url) end
--- Determine whether a URL can be requested.
--
-- If this returns `true`, one should also listen for [`http_check`
-- events](#http-check-event) which will container further information about
-- whether the URL is allowed or not.
-- If this returns `true`, one should also listen for @{http_check} which will
-- container further information about whether the URL is allowed or not.
--
-- @tparam string url The URL to check.
-- @treturn true When this url is valid and can be requested via @{http.request}.
@@ -168,9 +165,8 @@ function websocket(url, headers) end
--- Asynchronously open a websocket.
--
-- This returns immediately, a [`websocket_success`](#websocket-success-event)
-- or [`websocket_failure`](#websocket-failure-event) will be queued once the
-- request has completed.
-- This returns immediately, a @{websocket_success} or @{websocket_failure}
-- will be queued once the request has completed.
--
-- @tparam string url The websocket url to connect to. This should have the
-- `ws://` or `wss://` protocol.

View File

@@ -1,10 +1,10 @@
org.gradle.jvmargs=-Xmx3G
# Mod properties
mod_version=1.99.0
mod_version=1.100.6
# Minecraft properties (update mods.toml when changing)
mc_version=1.18
mapping_version=2021.09.05
forge_version=38.0.0
mc_version=1.19
mapping_version=2022.03.13
forge_version=41.0.16
# NO SERIOUSLY, UPDATE mods.toml WHEN CHANGING

View File

@@ -1,8 +1,7 @@
; -*- mode: Lisp;-*-
(sources
/doc/stub/
/doc/events/
/doc/
/build/docs/luaJavadoc/
/src/main/resources/*/computercraft/lua/bios.lua
/src/main/resources/*/computercraft/lua/rom/
@@ -27,7 +26,9 @@
(module-kinds
(peripheral Peripherals)
(generic_peripheral "Generic Peripherals")
(event Events))
(event Events)
(guide Guides)
(reference Reference))
(library-path
/doc/stub/

1805
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -4,15 +4,26 @@
"description": "Website additions for tweaked.cc",
"author": "SquidDev",
"license": "BSD-3-Clause",
"type": "module",
"dependencies": {
"preact": "^10.5.5",
"tslib": "^2.0.3"
},
"devDependencies": {
"@rollup/plugin-typescript": "^8.2.5",
"@rollup/plugin-url": "^6.1.0",
"@types/glob": "^7.2.0",
"@types/react-dom": "^18.0.5",
"glob": "^8.0.3",
"react": "^18.1.0",
"react-dom": "^18.1.0",
"rehype": "^12.0.1",
"rehype-highlight": "^5.0.2",
"rehype-react": "^7.1.1",
"requirejs": "^2.3.6",
"rollup": "^2.33.1",
"rollup-plugin-terser": "^7.0.2",
"ts-node": "^10.8.0",
"typescript": "^4.0.5"
}
}

View File

@@ -1,7 +1,8 @@
import { readFileSync } from "fs";
import { readFileSync } from "fs";
import path from "path";
import typescript from "@rollup/plugin-typescript";
import url from '@rollup/plugin-url';
import { terser } from "rollup-plugin-terser";
const input = "src/web";
@@ -10,7 +11,7 @@ const requirejs = readFileSync("node_modules/requirejs/require.js");
export default {
input: [`${input}/index.tsx`],
output: {
file: "build/rollup/index.js",
dir: "build/rollup/",
// We bundle requirejs (and config) into the header. It's rather gross
// but also works reasonably well.
// Also suffix a ?v=${date} onto the end in the event we need to require a specific copy-cat version.
@@ -18,7 +19,7 @@ export default {
${requirejs}
require.config({
paths: { copycat: "https://copy-cat.squiddev.cc" },
urlArgs: function(id) { return id == "copycat/embed" ? "?v=20211127" : ""; }
urlArgs: function(id) { return id == "copycat/embed" ? "?v=20211221" : ""; }
});
`,
format: "amd",
@@ -33,12 +34,18 @@ export default {
plugins: [
typescript(),
url({
include: "**/*.dfpwm",
fileName: "[name]-[hash][extname]",
publicPath: "/",
}),
{
name: "cc-tweaked",
async transform(code, file) {
// Allow loading files in /mount.
const ext = path.extname(file);
return ext != '.tsx' && ext != '.ts' && path.dirname(file) === path.resolve(`${input}/mount`)
return ext != '.dfpwm' && path.dirname(file) === path.resolve(`${input}/mount`)
? `export default ${JSON.stringify(code)};\n`
: null;
},

760
src/generated/export/index.json generated Normal file
View File

@@ -0,0 +1,760 @@
{
"itemNames": {
"computercraft:cable": "Networking Cable",
"computercraft:computer_advanced": "Advanced Computer",
"computercraft:computer_command": "Command Computer",
"computercraft:computer_normal": "Computer",
"computercraft:disk": "Floppy Disk",
"computercraft:disk_drive": "Disk Drive",
"computercraft:monitor_advanced": "Advanced Monitor",
"computercraft:monitor_normal": "Monitor",
"computercraft:pocket_computer_advanced": "Advanced Pocket Computer",
"computercraft:pocket_computer_normal": "Pocket Computer",
"computercraft:printed_book": "Printed Book",
"computercraft:printed_page": "Printed Page",
"computercraft:printed_pages": "Printed Pages",
"computercraft:printer": "Printer",
"computercraft:speaker": "Speaker",
"computercraft:treasure_disk": "Floppy Disk",
"computercraft:turtle_advanced": "Advanced Turtle",
"computercraft:turtle_normal": "Turtle",
"computercraft:wired_modem": "Wired Modem",
"computercraft:wired_modem_full": "Wired Modem",
"computercraft:wireless_modem_advanced": "Ender Modem",
"computercraft:wireless_modem_normal": "Wireless Modem",
"minecraft:black_dye": "Black Dye",
"minecraft:blue_dye": "Blue Dye",
"minecraft:brown_dye": "Brown Dye",
"minecraft:chest": "Chest",
"minecraft:command_block": "Command Block",
"minecraft:cyan_dye": "Cyan Dye",
"minecraft:ender_eye": "Eye of Ender",
"minecraft:ender_pearl": "Ender Pearl",
"minecraft:glass_pane": "Glass Pane",
"minecraft:gold_block": "Block of Gold",
"minecraft:gold_ingot": "Gold Ingot",
"minecraft:golden_apple": "Golden Apple",
"minecraft:gray_dye": "Gray Dye",
"minecraft:green_dye": "Green Dye",
"minecraft:iron_ingot": "Iron Ingot",
"minecraft:leather": "Leather",
"minecraft:light_blue_dye": "Light Blue Dye",
"minecraft:light_gray_dye": "Light Gray Dye",
"minecraft:lime_dye": "Lime Dye",
"minecraft:magenta_dye": "Magenta Dye",
"minecraft:note_block": "Note Block",
"minecraft:orange_dye": "Orange Dye",
"minecraft:pink_dye": "Pink Dye",
"minecraft:purple_dye": "Purple Dye",
"minecraft:red_dye": "Red Dye",
"minecraft:redstone": "Redstone Dust",
"minecraft:stone": "Stone",
"minecraft:string": "String",
"minecraft:white_dye": "White Dye",
"minecraft:yellow_dye": "Yellow Dye"
},
"recipes": {
"computercraft:cable": {
"inputs": [
null,
[
"minecraft:stone"
],
null,
[
"minecraft:stone"
],
[
"minecraft:redstone"
],
[
"minecraft:stone"
],
null,
[
"minecraft:stone"
],
null
],
"output": "computercraft:cable",
"count": 6
},
"computercraft:computer_advanced": {
"inputs": [
[
"minecraft:gold_ingot"
],
[
"minecraft:gold_ingot"
],
[
"minecraft:gold_ingot"
],
[
"minecraft:gold_ingot"
],
[
"minecraft:redstone"
],
[
"minecraft:gold_ingot"
],
[
"minecraft:gold_ingot"
],
[
"minecraft:glass_pane"
],
[
"minecraft:gold_ingot"
]
],
"output": "computercraft:computer_advanced",
"count": 1
},
"computercraft:computer_advanced_upgrade": {
"inputs": [
[
"minecraft:gold_ingot"
],
[
"minecraft:gold_ingot"
],
[
"minecraft:gold_ingot"
],
[
"minecraft:gold_ingot"
],
[
"computercraft:computer_normal"
],
[
"minecraft:gold_ingot"
],
[
"minecraft:gold_ingot"
],
null,
[
"minecraft:gold_ingot"
]
],
"output": "computercraft:computer_advanced",
"count": 1
},
"computercraft:computer_command": {
"inputs": [
[
"minecraft:gold_ingot"
],
[
"minecraft:gold_ingot"
],
[
"minecraft:gold_ingot"
],
[
"minecraft:gold_ingot"
],
[
"minecraft:command_block"
],
[
"minecraft:gold_ingot"
],
[
"minecraft:gold_ingot"
],
[
"minecraft:glass_pane"
],
[
"minecraft:gold_ingot"
]
],
"output": "computercraft:computer_command",
"count": 1
},
"computercraft:computer_normal": {
"inputs": [
[
"minecraft:stone"
],
[
"minecraft:stone"
],
[
"minecraft:stone"
],
[
"minecraft:stone"
],
[
"minecraft:redstone"
],
[
"minecraft:stone"
],
[
"minecraft:stone"
],
[
"minecraft:glass_pane"
],
[
"minecraft:stone"
]
],
"output": "computercraft:computer_normal",
"count": 1
},
"computercraft:disk_drive": {
"inputs": [
[
"minecraft:stone"
],
[
"minecraft:stone"
],
[
"minecraft:stone"
],
[
"minecraft:stone"
],
[
"minecraft:redstone"
],
[
"minecraft:stone"
],
[
"minecraft:stone"
],
[
"minecraft:redstone"
],
[
"minecraft:stone"
]
],
"output": "computercraft:disk_drive",
"count": 1
},
"computercraft:monitor_advanced": {
"inputs": [
[
"minecraft:gold_ingot"
],
[
"minecraft:gold_ingot"
],
[
"minecraft:gold_ingot"
],
[
"minecraft:gold_ingot"
],
[
"minecraft:glass_pane"
],
[
"minecraft:gold_ingot"
],
[
"minecraft:gold_ingot"
],
[
"minecraft:gold_ingot"
],
[
"minecraft:gold_ingot"
]
],
"output": "computercraft:monitor_advanced",
"count": 4
},
"computercraft:monitor_normal": {
"inputs": [
[
"minecraft:stone"
],
[
"minecraft:stone"
],
[
"minecraft:stone"
],
[
"minecraft:stone"
],
[
"minecraft:glass_pane"
],
[
"minecraft:stone"
],
[
"minecraft:stone"
],
[
"minecraft:stone"
],
[
"minecraft:stone"
]
],
"output": "computercraft:monitor_normal",
"count": 1
},
"computercraft:pocket_computer_advanced": {
"inputs": [
[
"minecraft:gold_ingot"
],
[
"minecraft:gold_ingot"
],
[
"minecraft:gold_ingot"
],
[
"minecraft:gold_ingot"
],
[
"minecraft:golden_apple"
],
[
"minecraft:gold_ingot"
],
[
"minecraft:gold_ingot"
],
[
"minecraft:glass_pane"
],
[
"minecraft:gold_ingot"
]
],
"output": "computercraft:pocket_computer_advanced",
"count": 1
},
"computercraft:pocket_computer_advanced_upgrade": {
"inputs": [
[
"minecraft:gold_ingot"
],
[
"minecraft:gold_ingot"
],
[
"minecraft:gold_ingot"
],
[
"minecraft:gold_ingot"
],
[
"computercraft:pocket_computer_normal"
],
[
"minecraft:gold_ingot"
],
[
"minecraft:gold_ingot"
],
null,
[
"minecraft:gold_ingot"
]
],
"output": "computercraft:pocket_computer_advanced",
"count": 1
},
"computercraft:pocket_computer_normal": {
"inputs": [
[
"minecraft:stone"
],
[
"minecraft:stone"
],
[
"minecraft:stone"
],
[
"minecraft:stone"
],
[
"minecraft:golden_apple"
],
[
"minecraft:stone"
],
[
"minecraft:stone"
],
[
"minecraft:glass_pane"
],
[
"minecraft:stone"
]
],
"output": "computercraft:pocket_computer_normal",
"count": 1
},
"computercraft:printed_book": {
"inputs": [
[
"minecraft:leather"
],
[
"computercraft:printed_page"
],
[
"minecraft:string"
],
null,
null,
null,
null,
null,
null
],
"output": "computercraft:printed_book",
"count": 1
},
"computercraft:printed_pages": {
"inputs": [
[
"computercraft:printed_page"
],
[
"computercraft:printed_page"
],
[
"minecraft:string"
],
null,
null,
null,
null,
null,
null
],
"output": "computercraft:printed_pages",
"count": 1
},
"computercraft:printer": {
"inputs": [
[
"minecraft:stone"
],
[
"minecraft:stone"
],
[
"minecraft:stone"
],
[
"minecraft:stone"
],
[
"minecraft:redstone"
],
[
"minecraft:stone"
],
[
"minecraft:stone"
],
[
"minecraft:black_dye",
"minecraft:blue_dye",
"minecraft:brown_dye",
"minecraft:cyan_dye",
"minecraft:gray_dye",
"minecraft:green_dye",
"minecraft:light_blue_dye",
"minecraft:light_gray_dye",
"minecraft:lime_dye",
"minecraft:magenta_dye",
"minecraft:orange_dye",
"minecraft:pink_dye",
"minecraft:purple_dye",
"minecraft:red_dye",
"minecraft:white_dye",
"minecraft:yellow_dye"
],
[
"minecraft:stone"
]
],
"output": "computercraft:printer",
"count": 1
},
"computercraft:speaker": {
"inputs": [
[
"minecraft:stone"
],
[
"minecraft:stone"
],
[
"minecraft:stone"
],
[
"minecraft:stone"
],
[
"minecraft:note_block"
],
[
"minecraft:stone"
],
[
"minecraft:stone"
],
[
"minecraft:redstone"
],
[
"minecraft:stone"
]
],
"output": "computercraft:speaker",
"count": 1
},
"computercraft:turtle_advanced": {
"inputs": [
[
"minecraft:gold_ingot"
],
[
"minecraft:gold_ingot"
],
[
"minecraft:gold_ingot"
],
[
"minecraft:gold_ingot"
],
[
"computercraft:computer_advanced"
],
[
"minecraft:gold_ingot"
],
[
"minecraft:gold_ingot"
],
[
"minecraft:chest"
],
[
"minecraft:gold_ingot"
]
],
"output": "computercraft:turtle_advanced",
"count": 1
},
"computercraft:turtle_advanced_upgrade": {
"inputs": [
[
"minecraft:gold_ingot"
],
[
"minecraft:gold_ingot"
],
[
"minecraft:gold_ingot"
],
[
"minecraft:gold_ingot"
],
[
"computercraft:turtle_normal"
],
[
"minecraft:gold_ingot"
],
null,
[
"minecraft:gold_block"
],
null
],
"output": "computercraft:turtle_advanced",
"count": 1
},
"computercraft:turtle_normal": {
"inputs": [
[
"minecraft:iron_ingot"
],
[
"minecraft:iron_ingot"
],
[
"minecraft:iron_ingot"
],
[
"minecraft:iron_ingot"
],
[
"computercraft:computer_normal"
],
[
"minecraft:iron_ingot"
],
[
"minecraft:iron_ingot"
],
[
"minecraft:chest"
],
[
"minecraft:iron_ingot"
]
],
"output": "computercraft:turtle_normal",
"count": 1
},
"computercraft:wired_modem": {
"inputs": [
[
"minecraft:stone"
],
[
"minecraft:stone"
],
[
"minecraft:stone"
],
[
"minecraft:stone"
],
[
"minecraft:redstone"
],
[
"minecraft:stone"
],
[
"minecraft:stone"
],
[
"minecraft:stone"
],
[
"minecraft:stone"
]
],
"output": "computercraft:wired_modem",
"count": 1
},
"computercraft:wired_modem_full_from": {
"inputs": [
[
"computercraft:wired_modem"
],
null,
null,
null,
null,
null,
null,
null,
null
],
"output": "computercraft:wired_modem_full",
"count": 1
},
"computercraft:wired_modem_full_to": {
"inputs": [
[
"computercraft:wired_modem_full"
],
null,
null,
null,
null,
null,
null,
null,
null
],
"output": "computercraft:wired_modem",
"count": 1
},
"computercraft:wireless_modem_advanced": {
"inputs": [
[
"minecraft:gold_ingot"
],
[
"minecraft:gold_ingot"
],
[
"minecraft:gold_ingot"
],
[
"minecraft:gold_ingot"
],
[
"minecraft:ender_eye"
],
[
"minecraft:gold_ingot"
],
[
"minecraft:gold_ingot"
],
[
"minecraft:gold_ingot"
],
[
"minecraft:gold_ingot"
]
],
"output": "computercraft:wireless_modem_advanced",
"count": 1
},
"computercraft:wireless_modem_normal": {
"inputs": [
[
"minecraft:stone"
],
[
"minecraft:stone"
],
[
"minecraft:stone"
],
[
"minecraft:stone"
],
[
"minecraft:ender_pearl"
],
[
"minecraft:stone"
],
[
"minecraft:stone"
],
[
"minecraft:stone"
],
[
"minecraft:stone"
]
],
"output": "computercraft:wireless_modem_normal",
"count": 1
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 375 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 189 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 158 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 158 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 287 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 208 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 259 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 189 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 977 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 593 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 620 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 218 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 228 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 218 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 243 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 278 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 266 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 186 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 240 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 257 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 229 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 236 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 240 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 242 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 224 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 229 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 221 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 220 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 232 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 220 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 220 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 233 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 236 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 193 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 245 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 235 B

View File

@@ -22,8 +22,7 @@
"cable": "true"
}
}
],
"functions": []
]
},
{
"name": "wired_modem",
@@ -49,8 +48,7 @@
}
}
}
],
"functions": []
]
}
]
}

View File

@@ -29,8 +29,7 @@
}
]
}
],
"functions": []
]
}
]
}

View File

@@ -29,8 +29,7 @@
}
]
}
],
"functions": []
]
}
]
}

View File

@@ -29,8 +29,7 @@
}
]
}
],
"functions": []
]
}
]
}

View File

@@ -15,8 +15,7 @@
{
"condition": "minecraft:survives_explosion"
}
],
"functions": []
]
}
]
}

View File

@@ -15,8 +15,7 @@
{
"condition": "minecraft:survives_explosion"
}
],
"functions": []
]
}
]
}

View File

@@ -15,8 +15,7 @@
{
"condition": "minecraft:survives_explosion"
}
],
"functions": []
]
}
]
}

View File

@@ -15,8 +15,7 @@
{
"condition": "minecraft:survives_explosion"
}
],
"functions": []
]
}
]
}

View File

@@ -15,8 +15,7 @@
{
"condition": "minecraft:survives_explosion"
}
],
"functions": []
]
}
]
}

View File

@@ -29,8 +29,7 @@
}
]
}
],
"functions": []
]
}
]
}

View File

@@ -29,8 +29,7 @@
}
]
}
],
"functions": []
]
}
]
}

View File

@@ -15,8 +15,7 @@
{
"condition": "minecraft:survives_explosion"
}
],
"functions": []
]
}
]
}

View File

@@ -15,8 +15,7 @@
{
"condition": "minecraft:survives_explosion"
}
],
"functions": []
]
}
]
}

View File

@@ -15,8 +15,7 @@
{
"condition": "minecraft:survives_explosion"
}
],
"functions": []
]
}
]
}

View File

@@ -1,6 +1,6 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
* Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft;

View File

@@ -1,11 +1,12 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
* Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft;
import dan200.computercraft.api.ComputerCraftAPI.IComputerCraftAPI;
import dan200.computercraft.api.detail.IDetailProvider;
import dan200.computercraft.api.filesystem.IMount;
import dan200.computercraft.api.filesystem.IWritableMount;
import dan200.computercraft.api.lua.GenericSource;
@@ -24,13 +25,13 @@ import dan200.computercraft.shared.BundledRedstone;
import dan200.computercraft.shared.MediaProviders;
import dan200.computercraft.shared.Peripherals;
import dan200.computercraft.shared.peripheral.generic.GenericPeripheralProvider;
import dan200.computercraft.shared.peripheral.generic.data.DetailProviders;
import dan200.computercraft.shared.peripheral.modem.wireless.WirelessNetwork;
import dan200.computercraft.shared.util.IDAssigner;
import dan200.computercraft.shared.wired.WiredNode;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.packs.resources.ReloadableResourceManager;
import net.minecraft.server.packs.resources.ResourceManager;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.Level;
@@ -59,10 +60,12 @@ public final class ComputerCraftAPIImpl implements IComputerCraftAPI
public static InputStream getResourceFile( String domain, String subPath )
{
ReloadableResourceManager manager = (ReloadableResourceManager) ServerLifecycleHooks.getCurrentServer().getResourceManager();
var manager = ServerLifecycleHooks.getCurrentServer().getResourceManager();
var resource = manager.getResource( new ResourceLocation( domain, subPath ) ).orElse( null );
if( resource == null ) return null;
try
{
return manager.getResource( new ResourceLocation( domain, subPath ) ).getInputStream();
return resource.open();
}
catch( IOException ignored )
{
@@ -156,6 +159,12 @@ public final class ComputerCraftAPIImpl implements IComputerCraftAPI
ApiFactories.register( factory );
}
@Override
public <T> void registerDetailProvider( @Nonnull Class<T> type, @Nonnull IDetailProvider<T> provider )
{
DetailProviders.registerProvider( type, provider );
}
@Nonnull
@Override
public IWiredNode createWiredNodeForElement( @Nonnull IWiredElement element )

View File

@@ -1,10 +1,12 @@
/*
* This file is part of the public ComputerCraft API - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only.
* Copyright Daniel Ratcliffe, 2011-2022. This API may be redistributed unmodified and in full only.
* For help using the API, and posting your mods, visit the forums at computercraft.info.
*/
package dan200.computercraft.api;
import dan200.computercraft.api.detail.BlockReference;
import dan200.computercraft.api.detail.IDetailProvider;
import dan200.computercraft.api.filesystem.IMount;
import dan200.computercraft.api.filesystem.IWritableMount;
import dan200.computercraft.api.lua.GenericSource;
@@ -20,10 +22,12 @@ import dan200.computercraft.api.peripheral.IPeripheralProvider;
import dan200.computercraft.api.redstone.IBundledRedstoneProvider;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.Level;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.fluids.FluidStack;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
@@ -111,7 +115,7 @@ public final class ComputerCraftAPI
}
/**
* rers a peripheral provider to convert blocks into {@link IPeripheral} implementations.
* Registers a peripheral provider to convert blocks into {@link IPeripheral} implementations.
*
* @param provider The peripheral provider to register.
* @see IPeripheral
@@ -196,6 +200,20 @@ public final class ComputerCraftAPI
getInstance().registerAPIFactory( factory );
}
/**
* Registers a detail provider to provide additional details for blocks, fluids and items when inspected by methods
* such as {@code turtle.getItemDetail()} or {@code turtle.inspect()}.
*
* @param type The type of object that this provider can provide details for. Should be {@link BlockReference},
* {@link FluidStack} or {@link ItemStack}.
* @param provider The detail provider to register.
* @param <T> The type of object that this provider can provide details for.
*/
public static <T> void registerDetailProvider( @Nonnull Class<T> type, @Nonnull IDetailProvider<T> provider )
{
getInstance().registerDetailProvider( type, provider );
}
/**
* Construct a new wired node for a given wired element.
*
@@ -272,6 +290,8 @@ public final class ComputerCraftAPI
void registerAPIFactory( @Nonnull ILuaAPIFactory factory );
<T> void registerDetailProvider( @Nonnull Class<T> type, @Nonnull IDetailProvider<T> provider );
@Nonnull
IWiredNode createWiredNodeForElement( @Nonnull IWiredElement element );

View File

@@ -1,6 +1,6 @@
/*
* This file is part of the public ComputerCraft API - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only.
* Copyright Daniel Ratcliffe, 2011-2022. This API may be redistributed unmodified and in full only.
* For help using the API, and posting your mods, visit the forums at computercraft.info.
*/
package dan200.computercraft.api;
@@ -9,7 +9,7 @@ import dan200.computercraft.ComputerCraft;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.tags.BlockTags;
import net.minecraft.tags.ItemTags;
import net.minecraft.tags.Tag;
import net.minecraft.tags.TagKey;
import net.minecraft.world.item.Item;
import net.minecraft.world.level.block.Block;
@@ -20,47 +20,47 @@ public class ComputerCraftTags
{
public static class Items
{
public static final Tag.Named<Item> COMPUTER = make( "computer" );
public static final Tag.Named<Item> TURTLE = make( "turtle" );
public static final Tag.Named<Item> WIRED_MODEM = make( "wired_modem" );
public static final Tag.Named<Item> MONITOR = make( "monitor" );
public static final TagKey<Item> COMPUTER = make( "computer" );
public static final TagKey<Item> TURTLE = make( "turtle" );
public static final TagKey<Item> WIRED_MODEM = make( "wired_modem" );
public static final TagKey<Item> MONITOR = make( "monitor" );
private static Tag.Named<Item> make( String name )
private static TagKey<Item> make( String name )
{
return ItemTags.bind( new ResourceLocation( ComputerCraft.MOD_ID, name ).toString() );
return ItemTags.create( new ResourceLocation( ComputerCraft.MOD_ID, name ) );
}
}
public static class Blocks
{
public static final Tag.Named<Block> COMPUTER = make( "computer" );
public static final Tag.Named<Block> TURTLE = make( "turtle" );
public static final Tag.Named<Block> WIRED_MODEM = make( "wired_modem" );
public static final Tag.Named<Block> MONITOR = make( "monitor" );
public static final TagKey<Block> COMPUTER = make( "computer" );
public static final TagKey<Block> TURTLE = make( "turtle" );
public static final TagKey<Block> WIRED_MODEM = make( "wired_modem" );
public static final TagKey<Block> MONITOR = make( "monitor" );
/**
* Blocks which can be broken by any turtle tool.
*/
public static final Tag.Named<Block> TURTLE_ALWAYS_BREAKABLE = make( "turtle_always_breakable" );
public static final TagKey<Block> TURTLE_ALWAYS_BREAKABLE = make( "turtle_always_breakable" );
/**
* Blocks which can be broken by the default shovel tool.
*/
public static final Tag.Named<Block> TURTLE_SHOVEL_BREAKABLE = make( "turtle_shovel_harvestable" );
public static final TagKey<Block> TURTLE_SHOVEL_BREAKABLE = make( "turtle_shovel_harvestable" );
/**
* Blocks which can be broken with the default sword tool.
*/
public static final Tag.Named<Block> TURTLE_SWORD_BREAKABLE = make( "turtle_sword_harvestable" );
public static final TagKey<Block> TURTLE_SWORD_BREAKABLE = make( "turtle_sword_harvestable" );
/**
* Blocks which can be broken with the default hoe tool.
*/
public static final Tag.Named<Block> TURTLE_HOE_BREAKABLE = make( "turtle_hoe_harvestable" );
public static final TagKey<Block> TURTLE_HOE_BREAKABLE = make( "turtle_hoe_harvestable" );
private static Tag.Named<Block> make( String name )
private static TagKey<Block> make( String name )
{
return BlockTags.bind( new ResourceLocation( ComputerCraft.MOD_ID, name ).toString() );
return BlockTags.create( new ResourceLocation( ComputerCraft.MOD_ID, name ) );
}
}
}

View File

@@ -1,6 +1,6 @@
/*
* This file is part of the public ComputerCraft API - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only.
* Copyright Daniel Ratcliffe, 2011-2022. This API may be redistributed unmodified and in full only.
* For help using the API, and posting your mods, visit the forums at computercraft.info.
*/
package dan200.computercraft.api.client;

View File

@@ -0,0 +1,79 @@
/*
* This file is part of the public ComputerCraft API - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2022. This API may be redistributed unmodified and in full only.
* For help using the API, and posting your mods, visit the forums at computercraft.info.
*/
package dan200.computercraft.api.detail;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import javax.annotation.Nonnull;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
/**
* An item detail provider for {@link ItemStack}'s whose {@link Item} has a specific type.
*
* @param <T> The type the stack's item must have.
*/
public abstract class BasicItemDetailProvider<T> implements IDetailProvider<ItemStack>
{
private final Class<T> itemType;
private final String namespace;
/**
* Create a new item detail provider. Meta will be inserted into a new sub-map named as per {@code namespace}.
*
* @param itemType The type the stack's item must have.
* @param namespace The namespace to use for this provider.
*/
public BasicItemDetailProvider( String namespace, @Nonnull Class<T> itemType )
{
Objects.requireNonNull( itemType );
this.itemType = itemType;
this.namespace = namespace;
}
/**
* Create a new item detail provider. Meta will be inserted directly into the results.
*
* @param itemType The type the stack's item must have.
*/
public BasicItemDetailProvider( @Nonnull Class<T> itemType )
{
this( null, itemType );
}
/**
* Provide additional details for the given {@link Item} and {@link ItemStack}. This method is called by
* {@code turtle.getItemDetail()}. New properties should be added to the given {@link Map}, {@code data}.
*
* This method is always called on the server thread, so it is safe to interact with the world here, but you should
* take care to avoid long blocking operations as this will stall the server and other computers.
*
* @param data The full details to be returned for this item stack. New properties should be added to this map.
* @param stack The item stack to provide details for.
* @param item The item to provide details for.
*/
public abstract void provideDetails( @Nonnull Map<? super String, Object> data, @Nonnull ItemStack stack,
@Nonnull T item );
@Override
public void provideDetails( @Nonnull Map<? super String, Object> data, @Nonnull ItemStack stack )
{
Item item = stack.getItem();
if( !itemType.isInstance( item ) ) return;
// If `namespace` is specified, insert into a new data map instead of the existing one.
Map<? super String, Object> child = namespace == null ? data : new HashMap<>();
provideDetails( child, stack, itemType.cast( item ) );
if( namespace != null )
{
data.put( namespace, child );
}
}
}

View File

@@ -0,0 +1,35 @@
/*
* This file is part of the public ComputerCraft API - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2022. This API may be redistributed unmodified and in full only.
* For help using the API, and posting your mods, visit the forums at computercraft.info.
*/
package dan200.computercraft.api.detail;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/**
* A reference to a block in the world, used by block detail providers.
*
* @param level The level the block exists in.
* @param pos The position of the block.
* @param state The block state at this position.
* @param blockEntity The block entity at this position, if it exists.
*/
public record BlockReference(
@Nonnull Level level,
@Nonnull BlockPos pos,
@Nonnull BlockState state,
@Nullable BlockEntity blockEntity
)
{
public BlockReference( Level level, BlockPos pos )
{
this( level, pos, level.getBlockState( pos ), level.getBlockEntity( pos ) );
}
}

View File

@@ -0,0 +1,32 @@
/*
* This file is part of the public ComputerCraft API - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2022. This API may be redistributed unmodified and in full only.
* For help using the API, and posting your mods, visit the forums at computercraft.info.
*/
package dan200.computercraft.api.detail;
import javax.annotation.Nonnull;
import java.util.Map;
/**
* This interface is used to provide details about a block, fluid, or item.
*
* @param <T> The type of object that this provider can provide details for.
* @see dan200.computercraft.api.ComputerCraftAPI#registerDetailProvider(Class, IDetailProvider)
*/
@FunctionalInterface
public interface IDetailProvider<T>
{
/**
* Provide additional details for the given object. This method is called by functions such as
* {@code turtle.getItemDetail()} and {@code turtle.inspect()}. New properties should be added to the given
* {@link Map}, {@code data}.
*
* This method is always called on the server thread, so it is safe to interact with the world here, but you should
* take care to avoid long blocking operations as this will stall the server and other computers.
*
* @param data The full details to be returned. New properties should be added to this map.
* @param object The object to provide details for.
*/
void provideDetails( @Nonnull Map<? super String, Object> data, @Nonnull T object );
}

View File

@@ -1,6 +1,6 @@
/*
* This file is part of the public ComputerCraft API - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only.
* Copyright Daniel Ratcliffe, 2011-2022. This API may be redistributed unmodified and in full only.
* For help using the API, and posting your mods, visit the forums at computercraft.info.
*/
package dan200.computercraft.api.filesystem;

View File

@@ -1,6 +1,6 @@
/*
* This file is part of the public ComputerCraft API - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only.
* Copyright Daniel Ratcliffe, 2011-2022. This API may be redistributed unmodified and in full only.
* For help using the API, and posting your mods, visit the forums at computercraft.info.
*/
package dan200.computercraft.api.filesystem;

Some files were not shown because too many files have changed in this diff Show More