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

Compare commits

..

43 Commits

Author SHA1 Message Date
SquidDev
9134f243c1 Merge branch 'master' into mc-1.14.x 2020-06-15 22:05:02 +01:00
SquidDev
c0f3ca81fb Bump to 1.89.0 2020-06-15 21:37:08 +01:00
SquidDev
b9b8121be9 Expose tags for turtle.{inspect,getItemDetail}
This is simply exposed as a table from tag -> true. While this is less
natural than an array, it allows for easy esting of whether a tag is
present.

Closes #461
2020-06-01 11:17:05 +01:00
Lignum
014bf55cd4 Cherry pick several improvements from #455
- Use texture over texture2D - the latter was deprecated in GLSL 1.30.
 - Cache the tbo buffer - this saves an allocation when monitors update.

Closes #455. While the rest of the PR has some nice changes, it
performs signlificantly worse on my system.
2020-05-31 17:23:49 +01:00
Lignum
085ae2e74a Use an older version of GLSL (#459)
This ensures that the MVP matrix is available within the monitor
fragment shader, without requiring the ARB_compatibility extension.
2020-05-28 11:06:14 +01:00
Lignum
4ff33f165d Fetch MVP matrix in monitor shader instead (#454) 2020-05-25 11:19:03 +01:00
SquidDev
d929c02d2a Fix settings loading failing for defined settings
Yes, this was the only piece of code which wasn't tested :/. Fixes #457.
2020-05-24 12:16:51 +01:00
Jonathan Coates
d50a08a549 Rewrite monitor networking (#453)
This moves monitor networking into its own packet, rather than serialising
using NBT. This allows us to be more flexible with how monitors are
serialised.

We now compress terminal data using gzip. This reduces the packet size
of a max-sized-monitor from ~25kb to as little as 100b.

On my test set of images (what I would consider to be the extreme end of
the "reasonable" case), we have packets from 1.4kb bytes up to 12kb,
with a mean of 6kb. Even in the worst case, this is a 2x reduction in
packet size.

While this is a fantastic win for the common case, it is not abuse-proof.
One can create a terminal with high entropy (and so uncompressible). This
will still be close to the original packet size.

In order to prevent any other abuse, we also limit the amount of monitor
data a client can possibly receive to 1MB (configurable).
2020-05-20 08:44:44 +01:00
SquidDev
13de2c4dd0 Fix location of cc.require
Yay for 1.12->1.13 changes!
2020-05-15 10:28:35 +01:00
SquidDev
906280225e Merge branch 'master' into mc-1.14.x 2020-05-15 10:19:57 +01:00
SquidDev
161a5b4707 Document and test the redstone library
The tests may be a little agressive, but I wanted some sanity checks for
the 1.15 API rewrite.
2020-05-15 10:03:47 +01:00
SquidDev
c6b6b4479c Update changelog and fix doc typo 2020-05-14 19:23:57 +01:00
SquidDev
96e7b60285 Display function arguments and positions in the REPL
- cc.pretty.pretty now accepts two additional options:
   - function_args: Show function arguments
   - function_source: Show where functions are defined.
 - Expose the two options as lua.* settings (defaulting function_args to
   true, and function_source to false).
   These are then used in the Lua REPL.

Closes #361
2020-05-14 19:11:57 +01:00
SquidDev
086fccd997 Move the package library into a separate module
Hopefully this makes it a little easier for people to use in custom
shells (and anything else where it might be useful).
2020-05-14 17:27:50 +01:00
Jonathan Coates
e251dd066c Fix test failures 2020-05-13 15:27:50 +01:00
SquidDev
c60dcb4f5a Fix deprecated usage 2020-05-13 14:04:32 +01:00
SquidDev
4be0b15afa Merge branch 'master' into mc-1.14.x 2020-05-13 14:04:28 +01:00
SquidDev
a4ae36b6b3 Bump version to 1.88.0
There's probably some other stuff I'll get in before release, but let's
do this just in case.
2020-05-13 13:43:40 +01:00
SquidDev
ac075d9f53 Allow using command computers in survival mode
I'm really not a fan of this change, but it's gated behind a config
option and there's apparently sufficient demand that it's worthwhile.
Closes #442.
2020-05-13 10:26:59 +01:00
Lupus590
05d7be0362 Improvements to the various file system programs (rm, mv, rename) (#440)
This enforces several sanity checks before actually attempting
the move, allowing us to produce friendlier error messages.
2020-05-12 11:32:48 +01:00
SquidDev
9a71dc1a26 Copy across a bunch of 5.1/5.3 io tests
I've been meaning to do this for ages. Woops.
2020-05-11 18:05:40 +01:00
SquidDev
156023b154 Create more work for myself
This ensures no lines start with an empty line, and all files finish
with exactly one "\n".
2020-05-11 16:08:25 +01:00
SquidDev
6b3773a862 Run tests with coverage
- Use jacoco for Java-side coverage. Our Java coverage is /terrible
   (~10%), as we only really test the core libraries. Still a good thing
   to track for regressions though.

 - mcfly now tracks Lua side coverage. This works in several stages:
   - Replace loadfile to include the whole path
   - Add a debug hook which just tracks filename->(lines->count). This
     is then submitted to the Java test runner.
   - On test completion, we emit a luacov.report.out file.

   As the debug hook is inserted by mcfly, this does not include any
   computer startup (such as loading apis, or the root of bios.lua),
   despite they're executed.

   This would be possible to do (for instance, inject a custom header
   into bios.lua). However, we're not actually testing any of the
   behaviour of startup (aside from "does it not crash"), so I'm not
   sure whether to include it or not. Something I'll most likely
   re-evaluate.
2020-05-11 15:47:30 +01:00
Jonathan Coates
376d628cf0 Make the local Lua message a little shorter
Co-authored-by: exerro <benedict.allen2514@gmail.com>
2020-05-09 08:30:55 +01:00
Lupus590
44062ebd52 Allow lua REPL to warn about using local variables (#367)
`local varname = value` results in `varname` being inaccessible in
the next REPL input. This is often unintended and can lead to confusing
behaviour. We produce a warning when this occurs.
2020-05-08 16:07:33 +01:00
Jonathan Coates
5739285fc2 Finish off documentation for the commands API 2020-05-05 21:17:52 +01:00
Jonathan Coates
70b457ed18 Add a monitor renderer using TBOs (#443)
This uses the system described in #409, to render monitors in a more
efficient manner.

Each monitor is backed by a texture buffer object (TBO) which contains
a relatively compact encoding of the terminal state. This is then
rendered using a shader, which consumes the TBO and uses it to index
into main font texture.

As we're transmitting significantly less data to the GPU (only 3 bytes
per character), this effectively reduces any update lag to 0. FPS appears
to be up by a small fraction (10-15fps on my machine, to ~110), possibly
as we're now only drawing a single quad (though doing much more work in
the shader).

On my laptop, with its Intel integrated graphics card, I'm able to draw
120 full-sized monitors (with an effective resolution of 3972 x 2330) at
a consistent 60fps. Updates still cause a slight spike, but we always
remain above 30fps - a significant improvement over VBOs, where updates
would go off the chart.

Many thanks to @Lignum and @Lemmmy for devising this scheme, and helping
test and review it! ♥
2020-05-05 13:05:23 +01:00
SquidDev
6816931659 Merge branch 'master' into mc-1.14.x 2020-05-04 10:28:15 +01:00
SquidDev
1547ecbeb3 Fix incorrect palette serialisation 2020-05-04 10:26:33 +01:00
SquidDev
c28b468844 Update languages and language script 2020-05-04 09:57:38 +01:00
SquidDev
052cf8ee7d Merge branch 'master' into mc-1.14.x 2020-05-04 09:39:54 +01:00
SquidDev
550ada2f9e Restore previous behaviour for unknown colours
Unknown blit colours, such as " " will be translated to black for the
background or white for the foreground. This restores the behaviour from
before #412.
2020-05-04 09:15:23 +01:00
SquidDev
17b7727262 Improve serialisation of terminals
- Write to a PacketBuffer instead of generating an NBT tag. This is
   then converted to an NBT byte array when we send across the network.
 - Pack background/foreground colours into a single byte.

This derives from some work I did back in 2017, and some of the changes
made/planned in #409. However, this patch does not change how terminals
are represented, it simply makes the transfer more compact.

This makes the patch incredibly small (100 lines!), but also limited in
what improvements it can make compared with #409. We send 26626 bytes
for a full-sized monitor. While a 2x improvement over the previous 58558
bytes, there's a lot of room for improvement.
2020-05-03 10:38:31 +01:00
Jonathan Coates
4553e404b2 Merge pull request #437 from SquidDev-CC/feature/keep-ids
Preserve computer ids on unlabelled computers
2020-05-03 06:54:04 +01:00
Drew Lemmy
a565a571f9 Return the peripheral name when wrapping (#436) 2020-05-03 06:53:42 +01:00
SquidDev
fb64b6017b Add shell.execute
This functions the same as shell.run, but does not tokenise the
arguments. This allows us to pass command line arguments through to
another program without having to re-quote them.

Closes #417
2020-05-02 11:05:09 +01:00
SquidDev
ed4229ab70 Keep ids of unlabelled computers and turtles 2020-05-02 10:38:18 +01:00
SquidDev
3fb906ef6c Show computer/disk ids in the tool tip more often
- Remove the parenthesis around the text (so it's now
   "Computer ID: 12"), rather than "(Computer ID: 12").
 - Show the tooltip if the computer has an ID and no label (as well as
   when in advanced mode).
2020-05-02 10:38:17 +01:00
Jonathan Coates
e1663f3df0 Fix malformed doc comments 2020-05-01 08:50:44 +01:00
SquidDev
358289b5f9 Merge branch 'master' into mc-1.14.x 2020-04-29 17:37:36 +01:00
SquidDev
5eec24676f Prevent computers scanning peripherals twice 2020-04-29 17:37:02 +01:00
Jonathan Coates
447c3ab125 Clean up dance.lua
Not sure what keys.escape was doing there. That's very old.
2020-04-28 09:51:06 +01:00
Jonathan Coates
8fac68386e Fix usages of global variables
- Lint references to unknown fields of modules, excluding the keys and
   colours modules. This caught several silly errors in our stub files,
   but nothing else.
 - Lint on using unknown globals. This highlighted a couple of really
   silly mistakes. Fixes #427.
 - Add documentation for fs.attributes, fs.getCapacity and pocket, as
   they were not defined before.

Co-authored-by: JackMacWindows <jackmacwindowslinux@gmail.com>
2020-04-28 09:42:34 +01:00
132 changed files with 2880 additions and 880 deletions

View File

@@ -32,6 +32,9 @@ jobs:
name: CC-Tweaked
path: build/libs
- name: Upload Coverage
run: bash <(curl -s https://codecov.io/bash)
lint-lua:
name: Lint Lua
runs-on: ubuntu-latest

View File

@@ -17,6 +17,7 @@ buildscript {
plugins {
id "checkstyle"
id "jacoco"
id "com.github.hierynomus.license" version "0.15.0"
id "com.matthewprenger.cursegradle" version "1.3.0"
id "com.github.breadmoirai.github-release" version "2.2.4"
@@ -288,6 +289,15 @@ test {
}
}
jacocoTestReport {
reports {
xml.enabled true
html.enabled true
}
}
check.dependsOn jacocoTestReport
license {
mapping("java", "SLASHSTAR_STYLE")
strictCheck true

View File

@@ -1,6 +1,77 @@
--- Execute a specific command.
--
-- @tparam string command The command to execute.
-- @treturn boolean Whether the command executed successfully.
-- @treturn { string... } The output of this command, as a list of lines.
-- @treturn number|nil The number of "affected" objects, or `nil` if the command
-- failed. The definition of this varies from command to command.
-- @usage Set the block above the command computer to stone.
--
-- commands.exec("setblock ~ ~1 ~ minecraft:stone")
function exec(command) end
--- Asynchronously execute a command.
--
-- Unlike @{exec}, this will immediately return, instead of waiting for the
-- command to execute. This allows you to run multiple commands at the same
-- time.
--
-- When this command has finished executing, it will queue a `task_complete`
-- event containing the result of executing this command (what @{exec} would
-- return).
--
-- @tparam string command The command to execute.
-- @treturn number The "task id". When this command has been executed, it will
-- queue a `task_complete` event with a matching id.
-- @usage Asynchronously sets the block above the computer to stone.
--
-- commands.execAsync("~ ~1 ~ minecraft:stone")
-- @see parallel One may also use the parallel API to run multiple commands at
-- once.
function execAsync(commad) end
--- List all available commands which the computer has permission to execute.
--
-- @treturn { string... } A list of all available commands
function list() end
--- Get the position of the current command computer.
--
-- @treturn number This computer's x position.
-- @treturn number This computer's y position.
-- @treturn number This computer's z position.
-- @see gps.locate To get the position of a non-command computer.
function getBlockPosition() end
function getBlockInfos(min_x, min_y, min_z, max_x, max_y, max_z) end
--- Get some basic information about a block.
--
-- The returned table contains the current name, metadata and block state (as
-- with @{turtle.inspect}). If there is a tile entity for that block, its NBT
-- will also be returned.
--
-- @tparam number x The x position of the block to query.
-- @tparam number y The y position of the block to query.
-- @tparam number z The z position of the block to query.
-- @treturn table The given block's information.
-- @throws If the coordinates are not within the world, or are not currently
-- loaded.
function getBlockInfo(x, y, z) end
--- Get information about a range of blocks.
--
-- This returns the same information as @{getBlockInfo}, just for multiple
-- blocks at once.
--
-- Blocks are traversed by ascending y level, followed by z and x - the returned
-- table may be indexed using `x + z*width + y*depth*depth`.
--
-- @tparam number min_x The start x coordinate of the range to query.
-- @tparam number min_y The start y coordinate of the range to query.
-- @tparam number min_z The start z coordinate of the range to query.
-- @tparam number max_x The end x coordinate of the range to query.
-- @tparam number max_y The end y coordinate of the range to query.
-- @tparam number max_z The end z coordinate of the range to query.
-- @treturn { table... } A list of information about each block.
-- @throws If the coordinates are not within the world.
-- @throws If trying to get information about more than 4096 blocks.
function getBlockInfos(min_x, min_y, min_z, max_x, max_y, max_z) end

View File

@@ -19,6 +19,48 @@ function getFreeSpace(path) end
function find(pattern) end
function getDir(path) end
--- Returns true if a path is mounted to the parent filesystem.
--
-- The root filesystem "/" is considered a mount, along with disk folders and
-- the rom folder. Other programs (such as network shares) can exstend this to
-- make other mount types by correctly assigning their return value for getDrive.
--
-- @tparam string path The path to check.
-- @treturn boolean If the path is mounted, rather than a normal file/folder.
-- @throws If the path does not exist.
-- @see getDrive
function isDriveRoot(path) end
--- Get the capacity of the drive at the given path.
--
-- This may be used in conjunction with @{getFreeSpace} to determine what
-- percentage of this drive has been used.
--
-- @tparam string path The path of the drive to get.
-- @treturn number This drive's capacity. This will be 0 for "read-only" drives,
-- such as the ROM or treasure disks.
function getCapacity(path) end
--- Get attributes about a specific file or folder.
--
-- The returned attributes table contains information about the size of the
-- file, whether it is a directory, and when it was created and last modified.
--
-- The creation and modification times are given as the number of milliseconds
-- since the UNIX epoch. This may be given to @{os.date} in order to convert it
-- to more usable form.
--
-- @tparam string path The path to get attributes for.
-- @treturn { size = number, isDir = boolean, created = number, modified = number }
-- The resulting attributes.
-- @throws If the path does not exist.
-- @see getSize If you only care about the file's size.
-- @see isDir If you only care whether a path is a directory or not.
function attributes(path) end
-- Defined in bios.lua
function complete(sPath, sLocation, bIncludeFiles, bIncludeDirs) end
--- A file handle which can be read from.
--
-- @type ReadHandle

View File

@@ -15,3 +15,10 @@ function cancelTimer(id) end
function cancelAlarm(id) end
function epoch(timezone) end
function date(format, time) end
-- Defined in bios.lua
function loadAPI(path) end
function pullEvent(filter) end
function pullEventRaw(filter) end
function version() end
function run(env, path, ...) end

28
doc/stub/pocket.lua Normal file
View File

@@ -0,0 +1,28 @@
--[[-
Control the current pocket computer, adding or removing upgrades.
This API is only available on pocket computers. As such, you may use its
presence to determine what kind of computer you are using:
```lua
if pocket then
print("On a pocket computer")
else
print("On something else")
end
```
]]
--- Search the player's inventory for another upgrade, replacing the existing
-- one with that item if found.
--
-- This inventory search starts from the player's currently selected slot,
-- allowing you to prioritise upgrades.
--
-- @throws If an upgrade cannot be found.
function equipBack() end
--- Remove the pocket computer's current upgrade.
--
-- @throws If this pocket computer does not currently have an upgrade.
function unequipBack() end

View File

@@ -1,14 +1,120 @@
--[[- Interact with redstone attached to this computer.
The @{redstone} library exposes three "types" of redstone control:
- Binary input/output (@{setOutput}/@{getInput}): These simply check if a
redstone wire has any input or output. A signal strength of 1 and 15 are
treated the same.
- Analogue input/output (@{setAnalogueOutput}/@{getAnalogueInput}): These
work with the actual signal strength of the redstone wired, from 0 to 15.
- Bundled cables (@{setBundledOutput}/@{getBundledInput}): These interact with
"bundled" cables, such as those from Project:Red. These allow you to send
16 separate on/off signals. Each channel corresponds to a colour, with the
first being @{colors.white} and the last @{colors.black}.
Whenever a redstone input changes, a `redstone` event will be fired. This may
be used in or
This module may also be referred to as `rs`. For example, one may call
`rs.getSides()` instead of @{redstone.getSides}.
@module redstone
@usage Toggle the redstone signal above the computer every 0.5 seconds.
while true do
redstone.setOutput("top", not redstone.getOutput("top"))
sleep(0.5)
end
@usage Mimic a redstone comparator in [subtraction mode][comparator].
while true do
local rear = rs.getAnalogueInput("back")
local sides = math.max(rs.getAnalogueInput("left"), rs.getAnalogueInput("right"))
rs.setAnalogueOutput("front", math.max(rear - sides, 0))
os.pullEvent("redstone") -- Wait for a change to inputs.
end
[comparator]: https://minecraft.gamepedia.com/Redstone_Comparator#Subtract_signal_strength "Redstone Comparator on the Minecraft wiki."
]]
--- Returns a table containing the six sides of the computer. Namely, "top",
-- "bottom", "left", "right", "front" and "back".
--
-- @treturn { string... } A table of valid sides.
function getSides() end
--- Turn the redstone signal of a specific side on or off.
--
-- @tparam string side The side to set.
-- @tparam boolean on Whether the redstone signal should be on or off. When on,
-- a signal strength of 15 is emitted.
function setOutput(side, on) end
--- Get the current redstone output of a specific side.
--
-- @tparam string side The side to get.
-- @treturn boolean Whether the redstone output is on or off.
-- @see setOutput
function getOutput(side) end
--- Get the current redstone input of a specific side.
--
-- @tparam string side The side to get.
-- @treturn boolean Whether the redstone input is on or off.
function getInput(side) end
function setBundledOutput(side, output) end
function getBundledOutput(side) end
function getBundledInput(side) end
function testBundledInput(side, mask) end
--- Set the redstone signal strength for a specific side.
--
-- @tparam string side The side to set.
-- @tparam number value The signal strength, between 0 and 15.
-- @throws If `value` is not between 0 and 15.
function setAnalogOutput(side, value) end
setAnalogueOutput = setAnalogOutput
--- Get the redstone output signal strength for a specific side.
--
-- @tparam string side The side to get.
-- @treturn number The output signal strength, between 0 and 15.
-- @see setAnalogueOutput
function getAnalogOutput(sid) end
getAnalogueOutput = getAnalogOutput
--- Get the redstone input signal strength for a specific side.
--
-- @tparam string side The side to get.
-- @treturn number The input signal strength, between 0 and 15.
function getAnalogInput(side) end
getAnalogueInput = getAnaloguInput
getAnalogueInput = getAnalogInput
--- Set the bundled cable output for a specific side.
--
-- @tparam string side The side to set.
-- @tparam number The colour bitmask to set.
-- @see colors.subtract For removing a colour from the bitmask.
-- @see colors.combine For adding a colour to the bitmask.
function setBundledOutput(side, output) end
--- Get the bundled cable output for a specific side.
--
-- @tparam string side The side to get.
-- @treturn number The bundled cable's output.
function getBundledOutput(side) end
--- Get the bundled cable input for a specific side.
--
-- @tparam string side The side to get.
-- @treturn number The bundled cable's input.
-- @see testBundledInput To determine if a specific colour is set.
function getBundledInput(side) end
--- Determine if a specific combination of colours are on for the given side.
--
-- @tparam string side The side to test.
-- @tparam number mask The mask to test.
-- @see getBundledInput
-- @see colors.combine For adding a colour to the bitmask.
-- @usage Check if @{colors.white} and @{colors.black} are on for above the
-- computer.
--
-- print(redstone.testBundledInput("top", colors.combine(colors.white, colors.black)))
function testBundledInput(side, mask) end

View File

@@ -15,14 +15,14 @@ isColor = isColour
function getTextColour() end
getTextColor = getTextColor
function getBackgroundColour() end
getBackgroundColour = getBackgroundColour
getBackgroundColor = getBackgroundColour
function blit(text, text_colours, background_colours) end
function setPaletteColour(colour, ...) end
setPaletteColour = setPaletteColour
setPaletteColor = setPaletteColour
function getPaletteColour(colour, ...) end
getPaletteColour = getPaletteColour
getPaletteColor = getPaletteColour
function nativePaletteColour(colour) end
nativePaletteColour = nativePaletteColour
nativePaletteColor = nativePaletteColour
--- @type Redirect
local Redirect = {}

View File

@@ -1,5 +1,5 @@
# Mod properties
mod_version=1.87.1
mod_version=1.89.0
# Minecraft properties (update mods.toml when changing)
mc_version=1.14.4

View File

@@ -33,17 +33,27 @@
;; It's useful to name arguments for documentation, so we allow this. It'd
;; be good to find a compromise in the future, but this works for now.
-var:unused-arg
-var:unused-arg)
;; Some APIS (keys, colour and os mainly) are incomplete right now.
-var:unresolved-member)
(lint
(bracket-spaces
(call no-space)
(function-args no-space)
(parens no-space)
(table space)
(index no-space))))
(index no-space))
;; colours imports from colors, and we don't handle that right now.
;; keys is entirely dynamic, so we skip it.
(dynamic-modules colours keys)
(globals
:max
_CC_DEFAULT_SETTINGS
_CC_DISABLE_LUA51_FEATURES
;; Ideally we'd pick these up from bios.lua, but illuaminate currently
;; isn't smart enough.
sleep write printError read rs)))
;; We disable the unused global linter in bios.lua and the APIs. In the future
;; hopefully we'll get illuaminate to handle this.
@@ -60,17 +70,13 @@
;; Suppress warnings for currently undocumented modules.
(at
(/doc/stub/commands.lua
/doc/stub/fs.lua
(/doc/stub/fs.lua
/doc/stub/http.lua
/doc/stub/os.lua
/doc/stub/redstone.lua
/doc/stub/term.lua
/doc/stub/turtle.lua
/src/main/resources/*/computercraft/lua/rom/apis/command/commands.lua
/src/main/resources/*/computercraft/lua/rom/apis/io.lua
/src/main/resources/*/computercraft/lua/rom/apis/window.lua
/src/main/resources/*/computercraft/lua/rom/modules/main/cc/shell/completion.lua)
/src/main/resources/*/computercraft/lua/rom/apis/window.lua)
(linters -doc:undocumented -doc:undocumented-arg))
@@ -79,6 +85,11 @@
(/src/main/resources/*/computercraft/lua/rom/apis/textutils.lua
/src/main/resources/*/computercraft/lua/rom/modules/main/cc/completion.lua
/src/main/resources/*/computercraft/lua/rom/modules/main/cc/shell/completion.lua
/src/main/resources/*/computercraft/lua/rom/programs/advanced/multishell.lua
/src/main/resources/*/computercraft/lua/rom/programs/shell.lua)
(linters -doc:unresolved-reference))
(at /src/test/resources/test-rom
(lint
(globals
:max sleep write
cct_test describe expect howlci fail it pending stub)))

View File

@@ -17,6 +17,9 @@
{
"condition": "computercraft:block_named"
},
{
"condition": "computercraft:has_id"
},
{
"condition": "minecraft:inverted",
"term": {

View File

@@ -17,6 +17,9 @@
{
"condition": "computercraft:block_named"
},
{
"condition": "computercraft:has_id"
},
{
"condition": "minecraft:inverted",
"term": {

View File

@@ -17,6 +17,9 @@
{
"condition": "computercraft:block_named"
},
{
"condition": "computercraft:has_id"
},
{
"condition": "minecraft:inverted",
"term": {

View File

@@ -17,6 +17,9 @@
{
"condition": "computercraft:block_named"
},
{
"condition": "computercraft:has_id"
},
{
"condition": "minecraft:inverted",
"term": {

View File

@@ -65,7 +65,8 @@ public final class ComputerCraft
public static boolean disable_lua51_features = false;
public static String default_computer_settings = "";
public static boolean debug_enable = true;
public static boolean logPeripheralErrors = false;
public static boolean logPeripheralErrors = true;
public static boolean commandRequireCreative = true;
public static int computer_threads = 1;
public static long maxMainGlobalTime = TimeUnit.MILLISECONDS.toNanos( 10 );
@@ -90,6 +91,7 @@ public final class ComputerCraft
public static int modem_highAltitudeRangeDuringStorm = 384;
public static int maxNotesPerTick = 8;
public static MonitorRenderer monitorRenderer = MonitorRenderer.BEST;
public static long monitorBandwidth = 1_000_000;
public static boolean turtlesNeedFuel = true;
public static int turtleFuelLimit = 20000;

View File

@@ -50,15 +50,14 @@ public final class FixedWidthFontRenderer
{
}
private static float toGreyscale( double[] rgb )
public static float toGreyscale( double[] rgb )
{
return (float) ((rgb[0] + rgb[1] + rgb[2]) / 3);
}
private static int getColour( char c )
public static int getColour( char c, Colour def )
{
int i = "0123456789abcdef".indexOf( c );
return i < 0 ? 0 : 15 - i;
return 15 - Terminal.getColour( c, def );
}
private static void drawChar( BufferBuilder buffer, float x, float y, int index, float r, float g, float b )
@@ -92,7 +91,7 @@ public final class FixedWidthFontRenderer
private static void drawQuad( BufferBuilder buffer, float x, float y, float width, float height, Palette palette, boolean greyscale, char colourIndex )
{
double[] colour = palette.getColour( getColour( colourIndex ) );
double[] colour = palette.getColour( getColour( colourIndex, Colour.Black ) );
float r, g, b;
if( greyscale )
{
@@ -160,7 +159,7 @@ public final class FixedWidthFontRenderer
for( int i = 0; i < text.length(); i++ )
{
double[] colour = palette.getColour( getColour( textColour.charAt( i ) ) );
double[] colour = palette.getColour( getColour( textColour.charAt( i ), Colour.White ) );
float r, g, b;
if( greyscale )
{

View File

@@ -0,0 +1,156 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.client.render;
import com.google.common.base.Strings;
import com.mojang.blaze3d.platform.GLX;
import com.mojang.blaze3d.platform.TextureUtil;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.client.gui.FixedWidthFontRenderer;
import dan200.computercraft.shared.util.Palette;
import org.lwjgl.BufferUtils;
import org.lwjgl.opengl.GL13;
import org.lwjgl.opengl.GL20;
import java.io.IOException;
import java.io.InputStream;
import java.nio.FloatBuffer;
class MonitorTextureBufferShader
{
static final int TEXTURE_INDEX = GL13.GL_TEXTURE3;
private static final FloatBuffer PALETTE_BUFFER = BufferUtils.createFloatBuffer( 16 * 3 );
private static int uniformFont;
private static int uniformWidth;
private static int uniformHeight;
private static int uniformTbo;
private static int uniformPalette;
private static boolean initialised;
private static boolean ok;
private static int program;
static void setupUniform( int width, int height, Palette palette, boolean greyscale )
{
GLX.glUniform1i( uniformWidth, width );
GLX.glUniform1i( uniformHeight, height );
PALETTE_BUFFER.rewind();
for( int i = 0; i < 16; i++ )
{
double[] colour = palette.getColour( i );
if( greyscale )
{
float f = FixedWidthFontRenderer.toGreyscale( colour );
PALETTE_BUFFER.put( f ).put( f ).put( f );
}
else
{
PALETTE_BUFFER.put( (float) colour[0] ).put( (float) colour[1] ).put( (float) colour[2] );
}
}
PALETTE_BUFFER.flip();
GLX.glUniform3( uniformPalette, PALETTE_BUFFER );
}
static boolean use()
{
if( initialised )
{
if( ok ) GLX.glUseProgram( program );
return ok;
}
if( ok = load() )
{
GL20.glUseProgram( program );
GLX.glUniform1i( uniformFont, 0 );
GLX.glUniform1i( uniformTbo, TEXTURE_INDEX - GL13.GL_TEXTURE0 );
}
return ok;
}
private static boolean load()
{
initialised = true;
try
{
int vertexShader = loadShader( GL20.GL_VERTEX_SHADER, "assets/computercraft/shaders/monitor.vert" );
int fragmentShader = loadShader( GL20.GL_FRAGMENT_SHADER, "assets/computercraft/shaders/monitor.frag" );
program = GLX.glCreateProgram();
GLX.glAttachShader( program, vertexShader );
GLX.glAttachShader( program, fragmentShader );
GL20.glBindAttribLocation( program, 0, "v_pos" );
GLX.glLinkProgram( program );
boolean ok = GLX.glGetProgrami( program, GL20.GL_LINK_STATUS ) != 0;
String log = GLX.glGetProgramInfoLog( program, Short.MAX_VALUE ).trim();
if( !Strings.isNullOrEmpty( log ) )
{
ComputerCraft.log.warn( "Problems when linking monitor shader: {}", log );
}
GL20.glDetachShader( program, vertexShader );
GL20.glDetachShader( program, fragmentShader );
GLX.glDeleteShader( vertexShader );
GLX.glDeleteShader( fragmentShader );
if( !ok ) return false;
uniformFont = getUniformLocation( program, "u_font" );
uniformWidth = getUniformLocation( program, "u_width" );
uniformHeight = getUniformLocation( program, "u_height" );
uniformTbo = getUniformLocation( program, "u_tbo" );
uniformPalette = getUniformLocation( program, "u_palette" );
ComputerCraft.log.info( "Loaded monitor shader." );
return true;
}
catch( Exception e )
{
ComputerCraft.log.error( "Cannot load monitor shaders", e );
return false;
}
}
private static int loadShader( int kind, String path ) throws IOException
{
String contents;
try( InputStream stream = TileEntityMonitorRenderer.class.getClassLoader().getResourceAsStream( path ) )
{
if( stream == null ) throw new IllegalArgumentException( "Cannot find " + path );
contents = TextureUtil.readResourceAsString( stream );
}
int shader = GLX.glCreateShader( kind );
GLX.glShaderSource( shader, contents );
GLX.glCompileShader( shader );
boolean ok = GLX.glGetShaderi( shader, GL20.GL_COMPILE_STATUS ) != 0;
String log = GLX.glGetShaderInfoLog( shader, Short.MAX_VALUE ).trim();
if( !Strings.isNullOrEmpty( log ) )
{
ComputerCraft.log.warn( "Problems when loading monitor shader {}: {}", path, log );
}
if( !ok ) throw new IllegalStateException( "Cannot compile shader " + path );
return shader;
}
private static int getUniformLocation( int program, String name )
{
int uniform = GLX.glGetUniformLocation( program, name );
if( uniform == -1 ) throw new IllegalStateException( "Cannot find uniform " + name );
return uniform;
}
}

View File

@@ -10,26 +10,36 @@ import com.mojang.blaze3d.platform.GlStateManager;
import dan200.computercraft.client.FrameInfo;
import dan200.computercraft.client.gui.FixedWidthFontRenderer;
import dan200.computercraft.core.terminal.Terminal;
import dan200.computercraft.core.terminal.TextBuffer;
import dan200.computercraft.shared.peripheral.monitor.ClientMonitor;
import dan200.computercraft.shared.peripheral.monitor.MonitorRenderer;
import dan200.computercraft.shared.peripheral.monitor.TileMonitor;
import dan200.computercraft.shared.util.Colour;
import dan200.computercraft.shared.util.DirectionUtil;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.BufferBuilder;
import net.minecraft.client.renderer.GLAllocation;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.tileentity.TileEntityRenderer;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.client.renderer.vertex.VertexBuffer;
import net.minecraft.util.Direction;
import net.minecraft.util.math.BlockPos;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL13;
import org.lwjgl.opengl.GL15;
import org.lwjgl.opengl.GL31;
import javax.annotation.Nonnull;
import java.nio.ByteBuffer;
import static dan200.computercraft.client.gui.FixedWidthFontRenderer.*;
import static dan200.computercraft.shared.peripheral.monitor.TileMonitor.RENDER_MARGIN;
public class TileEntityMonitorRenderer extends TileEntityRenderer<TileMonitor>
{
private static final float MARGIN = (float) (TileMonitor.RENDER_MARGIN * 1.1);
private static ByteBuffer tboContents;
@Override
public void render( @Nonnull TileMonitor monitor, double posX, double posY, double posZ, float f, int i )
@@ -92,8 +102,8 @@ public class TileEntityMonitorRenderer extends TileEntityRenderer<TileMonitor>
if( terminal != null )
{
// Draw a terminal
double xScale = xSize / (terminal.getWidth() * FixedWidthFontRenderer.FONT_WIDTH);
double yScale = ySize / (terminal.getHeight() * FixedWidthFontRenderer.FONT_HEIGHT);
double xScale = xSize / (terminal.getWidth() * FONT_WIDTH);
double yScale = ySize / (terminal.getHeight() * FONT_HEIGHT);
GlStateManager.pushMatrix();
GlStateManager.scaled( (float) xScale, (float) -yScale, 1.0f );
@@ -142,6 +152,59 @@ public class TileEntityMonitorRenderer extends TileEntityRenderer<TileMonitor>
switch( renderer )
{
case TBO:
{
if( !MonitorTextureBufferShader.use() ) return;
Terminal terminal = monitor.getTerminal();
int width = terminal.getWidth(), height = terminal.getHeight();
int pixelWidth = width * FONT_WIDTH, pixelHeight = height * FONT_HEIGHT;
if( redraw )
{
int size = width * height * 3;
if( tboContents == null || tboContents.capacity() < size )
{
tboContents = GLAllocation.createDirectByteBuffer( size );
}
ByteBuffer monitorBuffer = tboContents;
monitorBuffer.position( 0 );
for( int y = 0; y < height; y++ )
{
TextBuffer text = terminal.getLine( y ), textColour = terminal.getTextColourLine( y ), background = terminal.getBackgroundColourLine( y );
for( int x = 0; x < width; x++ )
{
monitorBuffer.put( (byte) (text.charAt( x ) & 0xFF) );
monitorBuffer.put( (byte) getColour( textColour.charAt( x ), Colour.White ) );
monitorBuffer.put( (byte) getColour( background.charAt( x ), Colour.Black ) );
}
}
monitorBuffer.flip();
GLX.glBindBuffer( GL31.GL_TEXTURE_BUFFER, monitor.tboBuffer );
GLX.glBufferData( GL31.GL_TEXTURE_BUFFER, monitorBuffer, GL15.GL_STATIC_DRAW );
GLX.glBindBuffer( GL31.GL_TEXTURE_BUFFER, 0 );
}
// Bind TBO texture and set up the uniforms. We've already set up the main font above.
GlStateManager.activeTexture( MonitorTextureBufferShader.TEXTURE_INDEX );
GL11.glBindTexture( GL31.GL_TEXTURE_BUFFER, monitor.tboTexture );
GlStateManager.activeTexture( GL13.GL_TEXTURE0 );
MonitorTextureBufferShader.setupUniform( width, height, terminal.getPalette(), !monitor.isColour() );
buffer.begin( GL11.GL_TRIANGLE_STRIP, DefaultVertexFormats.POSITION );
buffer.pos( -xMargin, -yMargin, 0 ).endVertex();
buffer.pos( -xMargin, pixelHeight + yMargin, 0 ).endVertex();
buffer.pos( pixelWidth + xMargin, -yMargin, 0 ).endVertex();
buffer.pos( pixelWidth + xMargin, pixelHeight + yMargin, 0 ).endVertex();
tessellator.draw();
GLX.glUseProgram( 0 );
break;
}
case VBO:
{
VertexBuffer vbo = monitor.buffer;

View File

@@ -103,7 +103,7 @@ public class OSAPI implements ILuaAPI
double t = alarm.m_day * 24.0 + alarm.m_time;
if( now >= t )
{
queueLuaEvent( "alarm", new Object[] { entry.getKey() } );
queueLuaEvent( "alarm", new Object[] { entry.getIntKey() } );
it.remove();
}
}

View File

@@ -16,11 +16,11 @@ import static dan200.computercraft.api.lua.ArgumentHelper.*;
public class RedstoneAPI implements ILuaAPI
{
private IAPIEnvironment m_environment;
private final IAPIEnvironment environment;
public RedstoneAPI( IAPIEnvironment environment )
{
m_environment = environment;
this.environment = environment;
}
@Override
@@ -63,31 +63,31 @@ public class RedstoneAPI implements ILuaAPI
// setOutput
ComputerSide side = parseSide( args );
boolean output = getBoolean( args, 1 );
m_environment.setOutput( side, output ? 15 : 0 );
environment.setOutput( side, output ? 15 : 0 );
return null;
}
case 2: // getOutput
return new Object[] { m_environment.getOutput( parseSide( args ) ) > 0 };
return new Object[] { environment.getOutput( parseSide( args ) ) > 0 };
case 3: // getInput
return new Object[] { m_environment.getInput( parseSide( args ) ) > 0 };
return new Object[] { environment.getInput( parseSide( args ) ) > 0 };
case 4:
{
// setBundledOutput
ComputerSide side = parseSide( args );
int output = getInt( args, 1 );
m_environment.setBundledOutput( side, output );
environment.setBundledOutput( side, output );
return null;
}
case 5: // getBundledOutput
return new Object[] { m_environment.getBundledOutput( parseSide( args ) ) };
return new Object[] { environment.getBundledOutput( parseSide( args ) ) };
case 6: // getBundledInput
return new Object[] { m_environment.getBundledInput( parseSide( args ) ) };
return new Object[] { environment.getBundledInput( parseSide( args ) ) };
case 7:
{
// testBundledInput
ComputerSide side = parseSide( args );
int mask = getInt( args, 1 );
int input = m_environment.getBundledInput( side );
int input = environment.getBundledInput( side );
return new Object[] { (input & mask) == mask };
}
case 8:
@@ -100,15 +100,15 @@ public class RedstoneAPI implements ILuaAPI
{
throw new LuaException( "Expected number in range 0-15" );
}
m_environment.setOutput( side, output );
environment.setOutput( side, output );
return null;
}
case 10:
case 11: // getAnalogOutput/getAnalogueOutput
return new Object[] { m_environment.getOutput( parseSide( args ) ) };
return new Object[] { environment.getOutput( parseSide( args ) ) };
case 12:
case 13: // getAnalogInput/getAnalogueInput
return new Object[] { m_environment.getInput( parseSide( args ) ) };
return new Object[] { environment.getInput( parseSide( args ) ) };
default:
return null;
}

View File

@@ -37,12 +37,8 @@ public abstract class HandleGeneric implements ILuaObject
{
m_open = false;
Closeable closeable = m_closable;
if( closeable != null )
{
IoUtil.closeQuietly( closeable );
m_closable = null;
}
IoUtil.closeQuietly( m_closable );
m_closable = null;
}
/**

View File

@@ -106,7 +106,7 @@ public abstract class Resource<T extends Resource<T>> implements Closeable
protected static <T extends Closeable> T closeCloseable( T closeable )
{
if( closeable != null ) IoUtil.closeQuietly( closeable );
IoUtil.closeQuietly( closeable );
return null;
}

View File

@@ -221,7 +221,7 @@ public class Websocket extends Resource<Websocket>
WeakReference<WebsocketHandle> websocketHandleRef = websocketHandle;
WebsocketHandle websocketHandle = websocketHandleRef == null ? null : websocketHandleRef.get();
if( websocketHandle != null ) IoUtil.closeQuietly( websocketHandle );
IoUtil.closeQuietly( websocketHandle );
this.websocketHandle = null;
}

View File

@@ -366,8 +366,7 @@ public class FileSystem
Reference<?> ref;
while( (ref = m_openFileQueue.poll()) != null )
{
Closeable file = m_openFiles.remove( ref );
if( file != null ) IoUtil.closeQuietly( file );
IoUtil.closeQuietly( m_openFiles.remove( ref ) );
}
}
}

View File

@@ -5,18 +5,20 @@
*/
package dan200.computercraft.core.terminal;
import dan200.computercraft.shared.util.Colour;
import dan200.computercraft.shared.util.Palette;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.network.PacketBuffer;
public class Terminal
{
private static final String base16 = "0123456789abcdef";
private int m_cursorX;
private int m_cursorY;
private boolean m_cursorBlink;
private int m_cursorColour;
private int m_cursorBackgroundColour;
private int m_cursorX = 0;
private int m_cursorY = 0;
private boolean m_cursorBlink = false;
private int m_cursorColour = 0;
private int m_cursorBackgroundColour = 15;
private int m_width;
private int m_height;
@@ -25,9 +27,9 @@ public class Terminal
private TextBuffer[] m_textColour;
private TextBuffer[] m_backgroundColour;
private final Palette m_palette;
private final Palette m_palette = new Palette();
private boolean m_changed;
private boolean m_changed = false;
private final Runnable onChanged;
public Terminal( int width, int height )
@@ -41,9 +43,6 @@ public class Terminal
m_height = height;
onChanged = changedCallback;
m_cursorColour = 0;
m_cursorBackgroundColour = 15;
m_text = new TextBuffer[m_height];
m_textColour = new TextBuffer[m_height];
m_backgroundColour = new TextBuffer[m_height];
@@ -53,14 +52,6 @@ public class Terminal
m_textColour[i] = new TextBuffer( base16.charAt( m_cursorColour ), m_width );
m_backgroundColour[i] = new TextBuffer( base16.charAt( m_cursorBackgroundColour ), m_width );
}
m_cursorX = 0;
m_cursorY = 0;
m_cursorBlink = false;
m_changed = false;
m_palette = new Palette();
}
public synchronized void reset()
@@ -336,6 +327,62 @@ public class Terminal
m_changed = false;
}
public synchronized void write( PacketBuffer buffer )
{
buffer.writeInt( m_cursorX );
buffer.writeInt( m_cursorY );
buffer.writeBoolean( m_cursorBlink );
buffer.writeByte( m_cursorBackgroundColour << 4 | m_cursorColour );
for( int y = 0; y < m_height; y++ )
{
TextBuffer text = m_text[y];
TextBuffer textColour = m_textColour[y];
TextBuffer backColour = m_backgroundColour[y];
for( int x = 0; x < m_width; x++ )
{
buffer.writeByte( text.charAt( x ) & 0xFF );
buffer.writeByte( getColour(
backColour.charAt( x ), Colour.Black ) << 4 |
getColour( textColour.charAt( x ), Colour.White )
);
}
}
m_palette.write( buffer );
}
public synchronized void read( PacketBuffer buffer )
{
m_cursorX = buffer.readInt();
m_cursorY = buffer.readInt();
m_cursorBlink = buffer.readBoolean();
byte cursorColour = buffer.readByte();
m_cursorBackgroundColour = (cursorColour >> 4) & 0xF;
m_cursorColour = cursorColour & 0xF;
for( int y = 0; y < m_height; y++ )
{
TextBuffer text = m_text[y];
TextBuffer textColour = m_textColour[y];
TextBuffer backColour = m_backgroundColour[y];
for( int x = 0; x < m_width; x++ )
{
text.setChar( x, (char) (buffer.readByte() & 0xFF) );
byte colour = buffer.readByte();
backColour.setChar( x, base16.charAt( (colour >> 4) & 0xF ) );
textColour.setChar( x, base16.charAt( colour & 0xF ) );
}
}
m_palette.read( buffer );
setChanged();
}
public synchronized CompoundNBT writeToNBT( CompoundNBT nbt )
{
nbt.putInt( "term_cursorX", m_cursorX );
@@ -349,10 +396,8 @@ public class Terminal
nbt.putString( "term_textColour_" + n, m_textColour[n].toString() );
nbt.putString( "term_textBgColour_" + n, m_backgroundColour[n].toString() );
}
if( m_palette != null )
{
m_palette.writeToNBT( nbt );
}
m_palette.writeToNBT( nbt );
return nbt;
}
@@ -382,10 +427,15 @@ public class Terminal
m_backgroundColour[n].write( nbt.getString( "term_textBgColour_" + n ) );
}
}
if( m_palette != null )
{
m_palette.readFromNBT( nbt );
}
m_palette.readFromNBT( nbt );
setChanged();
}
public static int getColour( char c, Colour def )
{
if( c >= '0' && c <= '9' ) return c - '0';
if( c >= 'a' && c <= 'f' ) return c - 'a' + 10;
return 15 - def.ordinal();
}
}

View File

@@ -8,6 +8,7 @@ package dan200.computercraft.data;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.shared.data.BlockNamedEntityLootCondition;
import dan200.computercraft.shared.data.HasComputerIdLootCondition;
import dan200.computercraft.shared.data.PlayerCreativeLootCondition;
import net.minecraft.block.Block;
import net.minecraft.data.DataGenerator;
@@ -67,6 +68,7 @@ public class LootTables extends LootTableProvider
.addEntry( DynamicLootEntry.func_216162_a( new ResourceLocation( ComputerCraft.MOD_ID, "computer" ) ) )
.acceptCondition( Alternative.builder(
BlockNamedEntityLootCondition.builder(),
HasComputerIdLootCondition.builder(),
PlayerCreativeLootCondition.builder().inverted()
) )
).build() );

View File

@@ -13,6 +13,7 @@ import dan200.computercraft.ComputerCraft;
import dan200.computercraft.api.turtle.event.TurtleAction;
import dan200.computercraft.core.apis.AddressPredicate;
import dan200.computercraft.core.apis.http.websocket.Websocket;
import dan200.computercraft.shared.peripheral.monitor.MonitorRenderer;
import net.minecraftforge.common.ForgeConfigSpec;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.ModLoadingContext;
@@ -66,6 +67,7 @@ public final class Config
private static final ConfigValue<Integer> modemRangeDuringStorm;
private static final ConfigValue<Integer> modemHighAltitudeRangeDuringStorm;
private static final ConfigValue<Integer> maxNotesPerTick;
private static final ConfigValue<Integer> monitorBandwidth;
private static final ConfigValue<Boolean> turtlesNeedFuel;
private static final ConfigValue<Integer> turtleFuelLimit;
@@ -74,7 +76,10 @@ public final class Config
private static final ConfigValue<Boolean> turtlesCanPush;
private static final ConfigValue<List<? extends String>> turtleDisabledActions;
private static final ForgeConfigSpec spec;
private static final ConfigValue<MonitorRenderer> monitorRenderer;
private static final ForgeConfigSpec commonSpec;
private static final ForgeConfigSpec clientSpec;
private Config() {}
@@ -226,6 +231,16 @@ public final class Config
.comment( "Maximum amount of notes a speaker can play at once" )
.defineInRange( "max_notes_per_tick", ComputerCraft.maxNotesPerTick, 1, Integer.MAX_VALUE );
monitorBandwidth = builder
.comment( "The limit to how much monitor data can be sent *per tick*. Note:\n" +
" - Bandwidth is measured before compression, so the data sent to the client is smaller.\n" +
" - This ignores the number of players a packet is sent to. Updating a monitor for one player consumes " +
"the same bandwidth limit as sending to 20.\n" +
" - A full sized monitor sends ~25kb of data. So the default (1MB) allows for ~40 monitors to be updated " +
"in a single tick. \n" +
"Set to 0 to disable." )
.defineInRange( "monitor_bandwidth", (int) ComputerCraft.monitorBandwidth, 0, Integer.MAX_VALUE );
builder.pop();
}
@@ -260,12 +275,20 @@ public final class Config
builder.pop();
}
spec = builder.build();
commonSpec = builder.build();
Builder clientBuilder = new Builder();
monitorRenderer = clientBuilder
.comment( "The renderer to use for monitors. Generally this should be kept at \"best\" - if " +
"monitors have performance issues, you may wish to experiment with alternative renderers." )
.defineEnum( "monitor_renderer", MonitorRenderer.BEST );
clientSpec = clientBuilder.build();
}
public static void load()
{
ModLoadingContext.get().registerConfig( ModConfig.Type.COMMON, spec );
ModLoadingContext.get().registerConfig( ModConfig.Type.COMMON, commonSpec );
ModLoadingContext.get().registerConfig( ModConfig.Type.CLIENT, clientSpec );
}
public static void sync()
@@ -305,6 +328,7 @@ public final class Config
ComputerCraft.modem_highAltitudeRange = modemHighAltitudeRange.get();
ComputerCraft.modem_rangeDuringStorm = modemRangeDuringStorm.get();
ComputerCraft.modem_highAltitudeRangeDuringStorm = modemHighAltitudeRangeDuringStorm.get();
ComputerCraft.monitorBandwidth = monitorBandwidth.get();
// Turtles
ComputerCraft.turtlesNeedFuel = turtlesNeedFuel.get();
@@ -315,6 +339,9 @@ public final class Config
ComputerCraft.turtleDisabledActions.clear();
for( String value : turtleDisabledActions.get() ) ComputerCraft.turtleDisabledActions.add( getAction( value ) );
// Client
ComputerCraft.monitorRenderer = monitorRenderer.get();
}
@SubscribeEvent

View File

@@ -6,7 +6,7 @@
package dan200.computercraft.shared.common;
import dan200.computercraft.core.terminal.Terminal;
import net.minecraft.nbt.CompoundNBT;
import dan200.computercraft.shared.network.client.TerminalState;
public class ClientTerminal implements ITerminal
{
@@ -46,14 +46,13 @@ public class ClientTerminal implements ITerminal
return m_colour;
}
public void readDescription( CompoundNBT nbt )
public void read( TerminalState state )
{
m_colour = nbt.getBoolean( "colour" );
if( nbt.contains( "terminal" ) )
m_colour = state.colour;
if( state.hasTerminal() )
{
CompoundNBT terminal = nbt.getCompound( "terminal" );
resizeTerminal( terminal.getInt( "term_width" ), terminal.getInt( "term_height" ) );
m_terminal.readFromNBT( terminal );
resizeTerminal( state.width, state.height );
state.apply( m_terminal );
}
else
{

View File

@@ -6,7 +6,7 @@
package dan200.computercraft.shared.common;
import dan200.computercraft.core.terminal.Terminal;
import net.minecraft.nbt.CompoundNBT;
import dan200.computercraft.shared.network.client.TerminalState;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -69,8 +69,6 @@ public class ServerTerminal implements ITerminal
return m_terminalChangedLastFrame;
}
// ITerminal implementation
@Override
public Terminal getTerminal()
{
@@ -83,18 +81,8 @@ public class ServerTerminal implements ITerminal
return m_colour;
}
// Networking stuff
public void writeDescription( CompoundNBT nbt )
public TerminalState write()
{
nbt.putBoolean( "colour", m_colour );
if( m_terminal != null )
{
CompoundNBT terminal = new CompoundNBT();
terminal.putInt( "term_width", m_terminal.getWidth() );
terminal.putInt( "term_height", m_terminal.getHeight() );
m_terminal.writeToNBT( terminal );
nbt.put( "terminal", terminal );
}
return new TerminalState( m_colour, m_terminal );
}
}

View File

@@ -120,6 +120,11 @@ public class TileCommandComputer extends TileComputer
@Override
public boolean isUsable( PlayerEntity player, boolean ignoreRange )
{
return isUsable( player ) && super.isUsable( player, ignoreRange );
}
public static boolean isUsable( PlayerEntity player )
{
MinecraftServer server = player.getServer();
if( server == null || !server.isCommandBlockEnabled() )
@@ -127,14 +132,12 @@ public class TileCommandComputer extends TileComputer
player.sendStatusMessage( new TranslationTextComponent( "advMode.notEnabled" ), true );
return false;
}
else if( !player.canUseCommandBlock() )
else if( ComputerCraft.commandRequireCreative ? !player.canUseCommandBlock() : !server.getPlayerList().canSendCommands( player.getGameProfile() ) )
{
player.sendStatusMessage( new TranslationTextComponent( "advMode.notAllowed" ), true );
return false;
}
else
{
return super.isUsable( player, ignoreRange );
}
return true;
}
}

View File

@@ -277,7 +277,7 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT
if( offset.equals( neighbour ) )
{
updateSideInput( computer, dir, offset );
break;
return;
}
}

View File

@@ -35,4 +35,3 @@ public enum ComputerState implements IStringSerializable
return name;
}
}

View File

@@ -154,9 +154,7 @@ public class ServerComputer extends ServerTerminal implements IComputer, IComput
protected NetworkMessage createTerminalPacket()
{
CompoundNBT tagCompound = new CompoundNBT();
writeDescription( tagCompound );
return new ComputerTerminalClientMessage( getInstanceID(), tagCompound );
return new ComputerTerminalClientMessage( getInstanceID(), write() );
}
public void broadcastState( boolean force )

View File

@@ -6,6 +6,7 @@
package dan200.computercraft.shared.computer.inventory;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.shared.computer.blocks.TileCommandComputer;
import dan200.computercraft.shared.computer.core.ComputerFamily;
import dan200.computercraft.shared.computer.core.IContainerComputer;
import dan200.computercraft.shared.computer.core.ServerComputer;
@@ -14,8 +15,6 @@ import dan200.computercraft.shared.network.container.ViewComputerContainerData;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.inventory.container.ContainerType;
import net.minecraft.server.MinecraftServer;
import net.minecraft.util.text.TranslationTextComponent;
import javax.annotation.Nonnull;
@@ -48,18 +47,9 @@ public class ContainerViewComputer extends ContainerComputerBase implements ICon
}
// If we're a command computer then ensure we're in creative
if( computer.getFamily() == ComputerFamily.Command )
if( computer.getFamily() == ComputerFamily.Command && !TileCommandComputer.isUsable( player ) )
{
MinecraftServer server = player.getServer();
if( server == null || !server.isCommandBlockEnabled() )
{
return false;
}
else if( !player.canUseCommandBlock() )
{
player.sendStatusMessage( new TranslationTextComponent( "advMode.notAllowed" ), false );
return false;
}
return false;
}
return true;

View File

@@ -19,9 +19,7 @@ public final class ComputerItemFactory
@Nonnull
public static ItemStack create( TileComputer tile )
{
String label = tile.getLabel();
int id = label != null ? tile.getComputerID() : -1;
return create( id, label, tile.getFamily() );
return create( tile.getComputerID(), tile.getLabel(), tile.getFamily() );
}
@Nonnull

View File

@@ -37,7 +37,7 @@ public abstract class ItemComputerBase extends BlockItem implements IComputerIte
@Override
public void addInformation( @Nonnull ItemStack stack, @Nullable World world, @Nonnull List<ITextComponent> list, @Nonnull ITooltipFlag options )
{
if( options.isAdvanced() )
if( options.isAdvanced() || getLabel( stack ) == null )
{
int id = getComputerID( stack );
if( id >= 0 )

View File

@@ -0,0 +1,48 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.shared.data;
import dan200.computercraft.shared.computer.blocks.IComputerTile;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.world.storage.loot.LootContext;
import net.minecraft.world.storage.loot.LootParameter;
import net.minecraft.world.storage.loot.LootParameters;
import net.minecraft.world.storage.loot.conditions.ILootCondition;
import javax.annotation.Nonnull;
import java.util.Collections;
import java.util.Set;
/**
* A loot condition which checks if the tile entity has has a non-0 ID.
*/
public final class HasComputerIdLootCondition implements ILootCondition
{
public static final HasComputerIdLootCondition INSTANCE = new HasComputerIdLootCondition();
private HasComputerIdLootCondition()
{
}
@Override
public boolean test( LootContext lootContext )
{
TileEntity tile = lootContext.get( LootParameters.BLOCK_ENTITY );
return tile instanceof IComputerTile && ((IComputerTile) tile).getComputerID() >= 0;
}
@Nonnull
@Override
public Set<LootParameter<?>> getRequiredParameters()
{
return Collections.singleton( LootParameters.BLOCK_ENTITY );
}
public static IBuilder builder()
{
return () -> INSTANCE;
}
}

View File

@@ -14,9 +14,11 @@ import net.minecraft.network.PacketBuffer;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World;
import net.minecraft.world.chunk.Chunk;
import net.minecraftforge.fml.network.NetworkDirection;
import net.minecraftforge.fml.network.NetworkEvent;
import net.minecraftforge.fml.network.NetworkRegistry;
import net.minecraftforge.fml.network.PacketDistributor;
import net.minecraftforge.fml.network.simple.SimpleChannel;
import net.minecraftforge.fml.server.ServerLifecycleHooks;
@@ -52,6 +54,7 @@ public final class NetworkHandler
registerMainThread( 12, ComputerDeletedClientMessage::new );
registerMainThread( 13, ComputerTerminalClientMessage::new );
registerMainThread( 14, PlayRecordClientMessage.class, PlayRecordClientMessage::new );
registerMainThread( 15, MonitorClientMessage.class, MonitorClientMessage::new );
}
public static void sendToPlayer( PlayerEntity player, NetworkMessage packet )
@@ -74,15 +77,13 @@ public final class NetworkHandler
public static void sendToAllAround( NetworkMessage packet, World world, Vec3d pos, double range )
{
for( ServerPlayerEntity player : ServerLifecycleHooks.getCurrentServer().getPlayerList().getPlayers() )
{
if( player.getEntityWorld() != world ) continue;
PacketDistributor.TargetPoint target = new PacketDistributor.TargetPoint( pos.x, pos.y, pos.z, range, world.getDimension().getType() );
network.send( PacketDistributor.NEAR.with( () -> target ), packet );
}
double x = pos.x - player.posX;
double y = pos.y - player.posY;
double z = pos.z - player.posZ;
if( x * x + y * y + z * z < range * range ) sendToPlayer( player, packet );
}
public static void sendToAllTracking( NetworkMessage packet, Chunk chunk )
{
network.send( PacketDistributor.TRACKING_CHUNK.with( () -> chunk ), packet );
}
/**

View File

@@ -5,7 +5,6 @@
*/
package dan200.computercraft.shared.network.client;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.network.PacketBuffer;
import net.minecraftforge.fml.network.NetworkEvent;
@@ -13,12 +12,12 @@ import javax.annotation.Nonnull;
public class ComputerTerminalClientMessage extends ComputerClientMessage
{
private CompoundNBT tag;
private TerminalState state;
public ComputerTerminalClientMessage( int instanceId, CompoundNBT tag )
public ComputerTerminalClientMessage( int instanceId, TerminalState state )
{
super( instanceId );
this.tag = tag;
this.state = state;
}
public ComputerTerminalClientMessage()
@@ -29,19 +28,19 @@ public class ComputerTerminalClientMessage extends ComputerClientMessage
public void toBytes( @Nonnull PacketBuffer buf )
{
super.toBytes( buf );
buf.writeCompoundTag( tag ); // TODO: Do we need to compress this?
state.write( buf );
}
@Override
public void fromBytes( @Nonnull PacketBuffer buf )
{
super.fromBytes( buf );
tag = buf.readCompoundTag();
state = new TerminalState( buf );
}
@Override
public void handle( NetworkEvent.Context context )
{
getComputer().readDescription( tag );
getComputer().read( state );
}
}

View File

@@ -0,0 +1,55 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.shared.network.client;
import dan200.computercraft.shared.network.NetworkMessage;
import dan200.computercraft.shared.peripheral.monitor.TileMonitor;
import net.minecraft.client.Minecraft;
import net.minecraft.client.entity.player.ClientPlayerEntity;
import net.minecraft.network.PacketBuffer;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.math.BlockPos;
import net.minecraftforge.fml.network.NetworkEvent;
import javax.annotation.Nonnull;
public class MonitorClientMessage implements NetworkMessage
{
private final BlockPos pos;
private final TerminalState state;
public MonitorClientMessage( BlockPos pos, TerminalState state )
{
this.pos = pos;
this.state = state;
}
public MonitorClientMessage( @Nonnull PacketBuffer buf )
{
pos = buf.readBlockPos();
state = new TerminalState( buf );
}
@Override
public void toBytes( @Nonnull PacketBuffer buf )
{
buf.writeBlockPos( pos );
state.write( buf );
}
@Override
public void handle( NetworkEvent.Context context )
{
ClientPlayerEntity player = Minecraft.getInstance().player;
if( player == null || player.world == null ) return;
TileEntity te = player.world.getTileEntity( pos );
if( !(te instanceof TileMonitor) ) return;
((TileMonitor) te).read( state );
}
}

View File

@@ -0,0 +1,183 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.shared.network.client;
import dan200.computercraft.core.terminal.Terminal;
import dan200.computercraft.shared.util.IoUtil;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufInputStream;
import io.netty.buffer.ByteBufOutputStream;
import io.netty.buffer.Unpooled;
import net.minecraft.network.PacketBuffer;
import javax.annotation.Nullable;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UncheckedIOException;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
/**
* A snapshot of a terminal's state.
*
* This is somewhat memory inefficient (we build a buffer, only to write it elsewhere), however it means we get a
* complete and accurate description of a terminal, which avoids a lot of complexities with resizing terminals, dirty
* states, etc...
*/
public class TerminalState
{
public final boolean colour;
public final int width;
public final int height;
private final boolean compress;
@Nullable
private final ByteBuf buffer;
private ByteBuf compressed;
public TerminalState( boolean colour, @Nullable Terminal terminal )
{
this( colour, terminal, true );
}
public TerminalState( boolean colour, @Nullable Terminal terminal, boolean compress )
{
this.colour = colour;
this.compress = compress;
if( terminal == null )
{
this.width = this.height = 0;
this.buffer = null;
}
else
{
this.width = terminal.getWidth();
this.height = terminal.getHeight();
ByteBuf buf = this.buffer = Unpooled.buffer();
terminal.write( new PacketBuffer( buf ) );
}
}
public TerminalState( PacketBuffer buf )
{
this.colour = buf.readBoolean();
this.compress = buf.readBoolean();
if( buf.readBoolean() )
{
this.width = buf.readVarInt();
this.height = buf.readVarInt();
int length = buf.readVarInt();
this.buffer = readCompressed( buf, length, compress );
}
else
{
this.width = this.height = 0;
this.buffer = null;
}
}
public void write( PacketBuffer buf )
{
buf.writeBoolean( colour );
buf.writeBoolean( compress );
buf.writeBoolean( buffer != null );
if( buffer != null )
{
buf.writeVarInt( width );
buf.writeVarInt( height );
ByteBuf sendBuffer = getCompressed();
buf.writeVarInt( sendBuffer.readableBytes() );
buf.writeBytes( sendBuffer, sendBuffer.readerIndex(), sendBuffer.readableBytes() );
}
}
public boolean hasTerminal()
{
return buffer != null;
}
public int size()
{
return buffer == null ? 0 : buffer.readableBytes();
}
public void apply( Terminal terminal )
{
if( buffer == null ) throw new NullPointerException( "buffer" );
terminal.read( new PacketBuffer( buffer ) );
}
private ByteBuf getCompressed()
{
if( buffer == null ) throw new NullPointerException( "buffer" );
if( !compress ) return buffer;
if( compressed != null ) return compressed;
ByteBuf compressed = Unpooled.directBuffer();
OutputStream stream = null;
try
{
stream = new GZIPOutputStream( new ByteBufOutputStream( compressed ) );
stream.write( buffer.array(), buffer.arrayOffset(), buffer.readableBytes() );
}
catch( IOException e )
{
throw new UncheckedIOException( e );
}
finally
{
IoUtil.closeQuietly( stream );
}
return this.compressed = compressed;
}
private static ByteBuf readCompressed( ByteBuf buf, int length, boolean compress )
{
if( compress )
{
ByteBuf buffer = Unpooled.buffer();
InputStream stream = null;
try
{
stream = new GZIPInputStream( new ByteBufInputStream( buf, length ) );
byte[] swap = new byte[8192];
while( true )
{
int bytes = stream.read( swap );
if( bytes == -1 ) break;
buffer.writeBytes( swap, 0, bytes );
}
}
catch( IOException e )
{
throw new UncheckedIOException( e );
}
finally
{
IoUtil.closeQuietly( stream );
}
return buffer;
}
else
{
ByteBuf buffer = Unpooled.buffer( length );
buf.readBytes( buffer, length );
return buffer;
}
}
}

View File

@@ -5,12 +5,18 @@
*/
package dan200.computercraft.shared.peripheral.monitor;
import com.mojang.blaze3d.platform.GLX;
import com.mojang.blaze3d.platform.GlStateManager;
import dan200.computercraft.client.gui.FixedWidthFontRenderer;
import dan200.computercraft.shared.common.ClientTerminal;
import net.minecraft.client.renderer.vertex.VertexBuffer;
import net.minecraft.util.math.BlockPos;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL15;
import org.lwjgl.opengl.GL30;
import org.lwjgl.opengl.GL31;
import java.util.HashSet;
import java.util.Iterator;
@@ -25,6 +31,8 @@ public final class ClientMonitor extends ClientTerminal
public long lastRenderFrame = -1;
public BlockPos lastRenderPos = null;
public int tboBuffer;
public int tboTexture;
public VertexBuffer buffer;
public ClientMonitor( boolean colour, TileMonitor origin )
@@ -50,6 +58,26 @@ public final class ClientMonitor extends ClientTerminal
{
switch( renderer )
{
case TBO:
{
if( tboBuffer != 0 ) return false;
deleteBuffers();
tboBuffer = GLX.glGenBuffers();
GLX.glBindBuffer( GL31.GL_TEXTURE_BUFFER, tboBuffer );
GL15.glBufferData( GL31.GL_TEXTURE_BUFFER, 0, GL15.GL_STATIC_DRAW );
tboTexture = GlStateManager.genTexture();
GL11.glBindTexture( GL31.GL_TEXTURE_BUFFER, tboTexture );
GL31.glTexBuffer( GL31.GL_TEXTURE_BUFFER, GL30.GL_R8, tboBuffer );
GL11.glBindTexture( GL31.GL_TEXTURE_BUFFER, 0 );
GLX.glBindBuffer( GL31.GL_TEXTURE_BUFFER, 0 );
addMonitor();
return true;
}
case VBO:
if( buffer != null ) return false;
@@ -73,6 +101,19 @@ public final class ClientMonitor extends ClientTerminal
private void deleteBuffers()
{
if( tboBuffer != 0 )
{
GLX.glDeleteBuffers( tboBuffer );
tboBuffer = 0;
}
if( tboTexture != 0 )
{
GlStateManager.deleteTexture( tboTexture );
tboTexture = 0;
}
if( buffer != null )
{
buffer.deleteGlBuffers();
@@ -83,7 +124,7 @@ public final class ClientMonitor extends ClientTerminal
@OnlyIn( Dist.CLIENT )
public void destroy()
{
if( buffer != null )
if( tboBuffer != 0 || buffer != null )
{
synchronized( allMonitors )
{

View File

@@ -6,12 +6,11 @@
package dan200.computercraft.shared.peripheral.monitor;
import com.mojang.blaze3d.platform.GLX;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.client.render.TileEntityMonitorRenderer;
import org.lwjgl.opengl.GL;
import javax.annotation.Nonnull;
import java.util.Locale;
/**
* The render type to use for monitors.
@@ -26,6 +25,13 @@ public enum MonitorRenderer
*/
BEST,
/**
* Render using texture buffer objects.
*
* @see org.lwjgl.opengl.GL31#glTexBuffer(int, int, int)
*/
TBO,
/**
* Render using VBOs.
*
@@ -33,37 +39,6 @@ public enum MonitorRenderer
*/
VBO;
private static final MonitorRenderer[] VALUES = values();
public static final String[] NAMES;
private final String displayName = "gui.computercraft:config.peripheral.monitor_renderer." + name().toLowerCase( Locale.ROOT );
static
{
NAMES = new String[VALUES.length];
for( int i = 0; i < VALUES.length; i++ ) NAMES[i] = VALUES[i].displayName();
}
public String displayName()
{
return displayName;
}
@Nonnull
public static MonitorRenderer ofString( String name )
{
for( MonitorRenderer backend : VALUES )
{
if( backend.displayName.equalsIgnoreCase( name ) || backend.name().equalsIgnoreCase( name ) )
{
return backend;
}
}
ComputerCraft.log.warn( "Unknown monitor renderer {}. Falling back to default.", name );
return BEST;
}
/**
* Get the current renderer to use.
*
@@ -77,15 +52,16 @@ public enum MonitorRenderer
{
case BEST:
return best();
case VBO:
if( !GLX.useVbo() )
case TBO:
checkCapabilities();
if( !textureBuffer )
{
ComputerCraft.log.warn( "VBOs are not supported on your graphics card. Falling back to default." );
ComputerCraft.log.warn( "Texture buffers are not supported on your graphics card. Falling back to default." );
ComputerCraft.monitorRenderer = BEST;
return best();
}
return VBO;
return TBO;
default:
return current;
}
@@ -93,6 +69,18 @@ public enum MonitorRenderer
private static MonitorRenderer best()
{
return VBO;
checkCapabilities();
return textureBuffer ? TBO : VBO;
}
private static boolean initialised = false;
private static boolean textureBuffer = false;
private static void checkCapabilities()
{
if( initialised ) return;
textureBuffer = GL.getCapabilities().OpenGL31;
initialised = true;
}
}

View File

@@ -0,0 +1,104 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.shared.peripheral.monitor;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.shared.network.NetworkHandler;
import dan200.computercraft.shared.network.client.MonitorClientMessage;
import dan200.computercraft.shared.network.client.TerminalState;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.ChunkPos;
import net.minecraft.world.World;
import net.minecraft.world.chunk.Chunk;
import net.minecraft.world.server.ServerWorld;
import net.minecraftforge.event.TickEvent;
import net.minecraftforge.event.world.ChunkWatchEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
import java.util.ArrayDeque;
import java.util.Queue;
@Mod.EventBusSubscriber( modid = ComputerCraft.MOD_ID )
public final class MonitorWatcher
{
private static final Queue<TileMonitor> watching = new ArrayDeque<>();
private MonitorWatcher()
{
}
static void enqueue( TileMonitor monitor )
{
if( monitor.enqueued ) return;
monitor.enqueued = true;
monitor.cached = null;
watching.add( monitor );
}
@SubscribeEvent
public static void onWatch( ChunkWatchEvent.Watch event )
{
ChunkPos chunkPos = event.getPos();
Chunk chunk = event.getWorld().getChunk( chunkPos.x, chunkPos.z );
if( chunk == null ) return;
for( TileEntity te : chunk.getTileEntityMap().values() )
{
// Find all origin monitors who are not already on the queue.
if( !(te instanceof TileMonitor) ) continue;
TileMonitor monitor = (TileMonitor) te;
ServerMonitor serverMonitor = getMonitor( monitor );
if( serverMonitor == null || monitor.enqueued ) continue;
// We use the cached terminal state if available - this is guaranteed to
TerminalState state = monitor.cached;
if( state == null ) state = monitor.cached = serverMonitor.write();
NetworkHandler.sendToPlayer( event.getPlayer(), new MonitorClientMessage( monitor.getPos(), state ) );
}
}
@SubscribeEvent
public static void onTick( TickEvent.ServerTickEvent event )
{
if( event.phase != TickEvent.Phase.END ) return;
long limit = ComputerCraft.monitorBandwidth;
boolean obeyLimit = limit > 0;
TileMonitor tile;
while( (!obeyLimit || limit > 0) && (tile = watching.poll()) != null )
{
tile.enqueued = false;
ServerMonitor monitor = getMonitor( tile );
if( monitor == null ) continue;
BlockPos pos = tile.getPos();
World world = tile.getWorld();
if( !(world instanceof ServerWorld) ) continue;
Chunk chunk = world.getChunkAt( pos );
if( !((ServerWorld) world).getChunkProvider().chunkManager.getTrackingPlayers( chunk.getPos(), false ).findAny().isPresent() )
{
continue;
}
TerminalState state = tile.cached = monitor.write();
NetworkHandler.sendToAllTracking( new MonitorClientMessage( pos, state ), chunk );
limit -= state.size();
}
}
private static ServerMonitor getMonitor( TileMonitor monitor )
{
return !monitor.isRemoved() && monitor.getXIndex() == 0 && monitor.getYIndex() == 0 ? monitor.getCachedServerMonitor() : null;
}
}

View File

@@ -12,6 +12,7 @@ import dan200.computercraft.api.peripheral.IPeripheralTile;
import dan200.computercraft.core.terminal.Terminal;
import dan200.computercraft.shared.common.ServerTerminal;
import dan200.computercraft.shared.common.TileGeneric;
import dan200.computercraft.shared.network.client.TerminalState;
import dan200.computercraft.shared.util.NamedTileEntityType;
import dan200.computercraft.shared.util.TickScheduler;
import net.minecraft.entity.player.PlayerEntity;
@@ -63,6 +64,10 @@ public class TileMonitor extends TileGeneric implements IPeripheralTile
private boolean m_destroyed = false;
private boolean visiting = false;
// MonitorWatcher state.
boolean enqueued;
TerminalState cached;
private int m_width = 1;
private int m_height = 1;
private int m_xIndex = 0;
@@ -170,7 +175,7 @@ public class TileMonitor extends TileGeneric implements IPeripheralTile
}
}
if( m_serverMonitor.pollTerminalChanged() ) updateBlock();
if( m_serverMonitor.pollTerminalChanged() ) MonitorWatcher.enqueue( this );
}
// IPeripheralTile implementation
@@ -249,16 +254,10 @@ public class TileMonitor extends TileGeneric implements IPeripheralTile
protected void writeDescription( @Nonnull CompoundNBT nbt )
{
super.writeDescription( nbt );
nbt.putInt( NBT_X, m_xIndex );
nbt.putInt( NBT_Y, m_yIndex );
nbt.putInt( NBT_WIDTH, m_width );
nbt.putInt( NBT_HEIGHT, m_height );
if( m_xIndex == 0 && m_yIndex == 0 && m_serverMonitor != null )
{
m_serverMonitor.writeDescription( nbt );
}
}
@Override
@@ -286,9 +285,8 @@ public class TileMonitor extends TileGeneric implements IPeripheralTile
if( m_xIndex == 0 && m_yIndex == 0 )
{
// If we're the origin terminal then read the description
// If we're the origin terminal then create it.
if( m_clientMonitor == null ) m_clientMonitor = new ClientMonitor( advanced, this );
m_clientMonitor.readDescription( nbt );
}
if( oldXIndex != m_xIndex || oldYIndex != m_yIndex ||
@@ -299,6 +297,20 @@ public class TileMonitor extends TileGeneric implements IPeripheralTile
}
}
public final void read( TerminalState state )
{
if( m_xIndex != 0 || m_yIndex != 0 )
{
ComputerCraft.log.warn( "Receiving monitor state for non-origin terminal at {}", getPos() );
return;
}
if( m_clientMonitor == null ) m_clientMonitor = new ClientMonitor( advanced, this );
m_clientMonitor.read( state );
}
// Sizing and placement stuff
private void updateBlockState()
{
getWorld().setBlockState( getPos(), getBlockState()

View File

@@ -154,4 +154,3 @@ public abstract class SpeakerPeripheral implements IPeripheral
return true;
}
}

View File

@@ -78,4 +78,3 @@ public class TileSpeaker extends TileGeneric implements ITickableTileEntity, IPe
}
}
}

View File

@@ -184,7 +184,7 @@ public class ItemPocketComputer extends Item implements IComputerItem, IMedia, I
@Override
public void addInformation( @Nonnull ItemStack stack, @Nullable World world, List<ITextComponent> list, ITooltipFlag flag )
{
if( flag.isAdvanced() )
if( flag.isAdvanced() || getLabel( stack ) == null )
{
int id = getComputerID( stack );
if( id >= 0 )

View File

@@ -20,6 +20,7 @@ import dan200.computercraft.shared.computer.core.IContainerComputer;
import dan200.computercraft.shared.computer.core.ServerComputer;
import dan200.computercraft.shared.data.BlockNamedEntityLootCondition;
import dan200.computercraft.shared.data.ConstantLootConditionSerializer;
import dan200.computercraft.shared.data.HasComputerIdLootCondition;
import dan200.computercraft.shared.data.PlayerCreativeLootCondition;
import dan200.computercraft.shared.media.items.RecordMedia;
import dan200.computercraft.shared.network.NetworkHandler;
@@ -72,6 +73,12 @@ public final class ComputerCraftProxyCommon
PlayerCreativeLootCondition.class,
PlayerCreativeLootCondition.INSTANCE
) );
LootConditionManager.registerCondition( ConstantLootConditionSerializer.of(
new ResourceLocation( ComputerCraft.MOD_ID, "has_id" ),
HasComputerIdLootCondition.class,
HasComputerIdLootCondition.INSTANCE
) );
}
private static void registerProviders()

View File

@@ -19,6 +19,7 @@ import dan200.computercraft.core.tracking.TrackingField;
import dan200.computercraft.shared.turtle.core.*;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.registries.ForgeRegistries;
@@ -31,8 +32,8 @@ import static dan200.computercraft.api.lua.ArgumentHelper.*;
public class TurtleAPI implements ILuaAPI
{
private IAPIEnvironment m_environment;
private ITurtleAccess m_turtle;
private final IAPIEnvironment m_environment;
private final ITurtleAccess m_turtle;
public TurtleAPI( IAPIEnvironment environment, ITurtleAccess turtle )
{
@@ -351,6 +352,10 @@ public class TurtleAPI implements ILuaAPI
table.put( "name", name );
table.put( "count", count );
Map<String, Boolean> tags = new HashMap<>();
for( ResourceLocation location : item.getTags() ) tags.put( location.toString(), true );
table.put( "tags", tags );
TurtleActionEvent event = new TurtleInspectItemEvent( m_turtle, stack, table );
if( MinecraftForge.EVENT_BUS.post( event ) ) return new Object[] { false, event.getFailureMessage() };

View File

@@ -14,6 +14,7 @@ import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.state.IProperty;
import net.minecraft.util.Direction;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraftforge.common.MinecraftForge;
@@ -64,6 +65,10 @@ public class TurtleInspectCommand implements ITurtleCommand
}
table.put( "state", stateTable );
Map<String, Boolean> tags = new HashMap<>();
for( ResourceLocation location : block.getTags() ) tags.put( location.toString(), true );
table.put( "tags", tags );
// Fire the event, exiting if it is cancelled
TurtlePlayer turtlePlayer = TurtlePlaceCommand.createPlayer( turtle, oldPosition, direction );
TurtleBlockEvent.Inspect event = new TurtleBlockEvent.Inspect( turtle, turtlePlayer, world, newPosition, state, table );

View File

@@ -6,6 +6,7 @@
package dan200.computercraft.shared.turtle.items;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.api.turtle.ITurtleAccess;
import dan200.computercraft.api.turtle.ITurtleUpgrade;
import dan200.computercraft.api.turtle.TurtleSide;
import dan200.computercraft.shared.computer.core.ComputerFamily;
@@ -22,18 +23,13 @@ public final class TurtleItemFactory
@Nonnull
public static ItemStack create( ITurtleTile turtle )
{
ITurtleUpgrade leftUpgrade = turtle.getAccess().getUpgrade( TurtleSide.Left );
ITurtleUpgrade rightUpgrade = turtle.getAccess().getUpgrade( TurtleSide.Right );
ITurtleAccess access = turtle.getAccess();
String label = turtle.getLabel();
if( label == null )
{
return create( -1, null, turtle.getColour(), turtle.getFamily(), leftUpgrade, rightUpgrade, 0, turtle.getOverlay() );
}
int id = turtle.getComputerID();
int fuelLevel = turtle.getAccess().getFuelLevel();
return create( id, label, turtle.getColour(), turtle.getFamily(), leftUpgrade, rightUpgrade, fuelLevel, turtle.getOverlay() );
return create(
turtle.getComputerID(), turtle.getLabel(), turtle.getColour(), turtle.getFamily(),
access.getUpgrade( TurtleSide.Left ), access.getUpgrade( TurtleSide.Right ),
access.getFuelLevel(), turtle.getOverlay()
);
}
@Nonnull

View File

@@ -5,6 +5,7 @@
*/
package dan200.computercraft.shared.util;
import javax.annotation.Nullable;
import java.io.Closeable;
import java.io.IOException;
@@ -12,11 +13,11 @@ public final class IoUtil
{
private IoUtil() {}
public static void closeQuietly( Closeable closeable )
public static void closeQuietly( @Nullable Closeable closeable )
{
try
{
closeable.close();
if( closeable != null ) closeable.close();
}
catch( IOException ignored )
{

View File

@@ -6,6 +6,7 @@
package dan200.computercraft.shared.util;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.network.PacketBuffer;
public class Palette
{
@@ -78,6 +79,22 @@ public class Palette
};
}
public void write( PacketBuffer buffer )
{
for( double[] colour : colours )
{
for( double channel : colour ) buffer.writeByte( (int) (channel * 0xFF) & 0xFF );
}
}
public void read( PacketBuffer buffer )
{
for( double[] colour : colours )
{
for( int i = 0; i < colour.length; i++ ) colour[i] = (buffer.readByte() & 0xFF) / 255.0;
}
}
public CompoundNBT writeToNBT( CompoundNBT nbt )
{
int[] rgb8 = new int[colours.length];

View File

@@ -6,4 +6,3 @@
"modem=true,peripheral=true": { "model": "computercraft:block/wired_modem_full_on_peripheral" }
}
}

View File

@@ -0,0 +1,55 @@
{
"block.computercraft.computer_normal": "Computer",
"block.computercraft.computer_advanced": "Avanceret Computer",
"block.computercraft.computer_command": "Kommandocomputer",
"block.computercraft.disk_drive": "Diskdrev",
"block.computercraft.printer": "Printer",
"block.computercraft.speaker": "Højttaler",
"block.computercraft.monitor_normal": "Skærm",
"block.computercraft.monitor_advanced": "Avanceret Skærm",
"block.computercraft.wireless_modem_normal": "Trådløst Modem",
"block.computercraft.wireless_modem_advanced": "Endermodem",
"block.computercraft.wired_modem": "Kablet Modem",
"block.computercraft.cable": "Netværkskabel",
"block.computercraft.turtle_normal": "Turtle",
"block.computercraft.turtle_normal.upgraded": "%s Turtle",
"block.computercraft.turtle_normal.upgraded_twice": "%s %s Turtle",
"block.computercraft.turtle_advanced": "Avanceret Turtle",
"block.computercraft.turtle_advanced.upgraded": "Avanceret %s Turtle",
"block.computercraft.turtle_advanced.upgraded_twice": "Avanceret %s %s Turtle",
"item.computercraft.disk": "Floppydisk",
"item.computercraft.treasure_disk": "Floppydisk",
"item.computercraft.printed_page": "Printet Side",
"item.computercraft.printed_pages": "Printede Sider",
"item.computercraft.printed_book": "Printet Bog",
"item.computercraft.pocket_computer_normal": "Lommecomputer",
"item.computercraft.pocket_computer_normal.upgraded": "%s Lommecomputer",
"item.computercraft.pocket_computer_advanced": "Avanceret Lommecomputer",
"item.computercraft.pocket_computer_advanced.upgraded": "Avanceret %s Lommecomputer",
"upgrade.minecraft.diamond_sword.adjective": "Kæmpende",
"upgrade.minecraft.diamond_shovel.adjective": "Gravende",
"upgrade.minecraft.diamond_pickaxe.adjective": "Brydende",
"upgrade.minecraft.diamond_axe.adjective": "Fældende",
"upgrade.minecraft.diamond_hoe.adjective": "Dyrkende",
"upgrade.minecraft.crafting_table.adjective": "Fremstillende",
"upgrade.computercraft.wireless_modem_normal.adjective": "Trådløs",
"upgrade.computercraft.wireless_modem_advanced.adjective": "Endertrådløs",
"upgrade.computercraft.speaker.adjective": "Larmende",
"chat.computercraft.wired_modem.peripheral_connected": "Perifer enhed \"%s\" koblet til netværk",
"chat.computercraft.wired_modem.peripheral_disconnected": "Perifer enhed \"%s\" koblet fra netværk",
"gui.computercraft.tooltip.copy": "Kopier til udklipsholder",
"gui.computercraft.tooltip.computer_id": "Computer-ID: %s",
"gui.computercraft.tooltip.disk_id": "Disk-ID: %s"
}

View File

@@ -1,48 +0,0 @@
tile.computercraft:computer.name=Computer
tile.computercraft:advanced_computer.name=Avanceret Computer
tile.computercraft:drive.name=Diskdrev
tile.computercraft:printer.name=Printer
tile.computercraft:monitor.name=Skærm
tile.computercraft:advanced_monitor.name=Avanceret Skærm
tile.computercraft:wireless_modem.name=Trådløst Modem
tile.computercraft:wired_modem.name=Kablet Modem
tile.computercraft:cable.name=Netværkskabel
tile.computercraft:command_computer.name=Kommandocomputer
tile.computercraft:advanced_modem.name=Endermodem
tile.computercraft:speaker.name=Højttaler
tile.computercraft:turtle.name=Turtle
tile.computercraft:turtle.upgraded.name=%s Turtle
tile.computercraft:turtle.upgraded_twice.name=%s %s Turtle
tile.computercraft:advanced_turtle.name=Avanceret Turtle
tile.computercraft:advanced_turtle.upgraded.name=Avanceret %s Turtle
tile.computercraft:advanced_turtle.upgraded_twice.name=Avanceret %s %s Turtle
item.computercraft:disk.name=Floppydisk
item.computercraft:treasure_disk.name=Floppydisk
item.computercraft:page.name=Printet Side
item.computercraft:pages.name=Printede Sider
item.computercraft:book.name=Printet Bog
item.computercraft:pocket_computer.name=Lommecomputer
item.computercraft:pocket_computer.upgraded.name=%s Lommecomputer
item.computercraft:advanced_pocket_computer.name=Avanceret Lommecomputer
item.computercraft:advanced_pocket_computer.upgraded.name=Avanceret %s Lommecomputer
upgrade.minecraft:diamond_sword.adjective=Kæmpende
upgrade.minecraft:diamond_shovel.adjective=Gravende
upgrade.minecraft:diamond_pickaxe.adjective=Brydende
upgrade.minecraft:diamond_axe.adjective=Fældende
upgrade.minecraft:diamond_hoe.adjective=Dyrkende
upgrade.computercraft:wireless_modem.adjective=Trådløs
upgrade.minecraft:crafting_table.adjective=Fremstillende
upgrade.computercraft:advanced_modem.adjective=Endertrådløs
upgrade.computercraft:speaker.adjective=Larmende
chat.computercraft.wired_modem.peripheral_connected=Perifer enhed "%s" koblet til netværk
chat.computercraft.wired_modem.peripheral_disconnected=Perifer enhed "%s" koblet fra netværk
# Misc tooltips
gui.computercraft.tooltip.copy=Kopier til udklipsholder
gui.computercraft.tooltip.computer_id=(Computer-ID: %s)
gui.computercraft.tooltip.disk_id=(Disk-ID: %s)

View File

@@ -141,8 +141,8 @@
"tracking_field.computercraft.coroutines_dead.name": "Koroutinen gelöscht",
"gui.computercraft.tooltip.copy": "In die Zwischenablage kopieren",
"gui.computercraft.tooltip.computer_id": "(Computer ID: %s)",
"gui.computercraft.tooltip.disk_id": "(Disketten ID: %s)",
"gui.computercraft.tooltip.computer_id": "Computer ID: %s",
"gui.computercraft.tooltip.disk_id": "Disketten ID: %s",
"gui.computercraft.config.computer_space_limit": "Speicherplatz von Computern (bytes)",
"gui.computercraft.config.floppy_space_limit": "Speicherplatz von Disketten (bytes)",

View File

@@ -143,8 +143,8 @@
"tracking_field.computercraft.coroutines_dead.name": "Coroutines disposed",
"gui.computercraft.tooltip.copy": "Copy to clipboard",
"gui.computercraft.tooltip.computer_id": "(Computer ID: %s)",
"gui.computercraft.tooltip.disk_id": "(Disk ID: %s)",
"gui.computercraft.tooltip.computer_id": "Computer ID: %s",
"gui.computercraft.tooltip.disk_id": "Disk ID: %s",
"gui.computercraft.config.computer_space_limit": "Computer space limit (bytes)",
"gui.computercraft.config.floppy_space_limit": "Floppy Disk space limit (bytes)",

View File

@@ -0,0 +1,185 @@
{
"itemGroup.computercraft": "컴퓨터크래프트",
"block.computercraft.computer_normal": "컴퓨터",
"block.computercraft.computer_advanced": "고급 컴퓨터",
"block.computercraft.computer_command": "명령 컴퓨터",
"block.computercraft.disk_drive": "디스크 드라이브",
"block.computercraft.printer": "프린터",
"block.computercraft.speaker": "스피커",
"block.computercraft.monitor_normal": "모니터",
"block.computercraft.monitor_advanced": "고급 모니터",
"block.computercraft.wireless_modem_normal": "무선 모뎀",
"block.computercraft.wireless_modem_advanced": "엔더 모뎀",
"block.computercraft.wired_modem": "유선 모뎀",
"block.computercraft.cable": "네트워크 케이블",
"block.computercraft.turtle_normal": "터틀",
"block.computercraft.turtle_normal.upgraded": "%s 터틀",
"block.computercraft.turtle_normal.upgraded_twice": "%s %s 터틀",
"block.computercraft.turtle_advanced": "고급 터틀",
"block.computercraft.turtle_advanced.upgraded": "고급 %s 터틀",
"block.computercraft.turtle_advanced.upgraded_twice": "고급 %s %s 터틀",
"item.computercraft.disk": "플로피 디스크",
"item.computercraft.treasure_disk": "플로피 디스크",
"item.computercraft.printed_page": "인쇄된 페이지",
"item.computercraft.printed_pages": "인쇄된 페이지 모음",
"item.computercraft.printed_book": "인쇄된 책",
"item.computercraft.pocket_computer_normal": "포켓 컴퓨터",
"item.computercraft.pocket_computer_normal.upgraded": "%s 포켓 컴퓨터",
"item.computercraft.pocket_computer_advanced": "고급 포켓 컴퓨터",
"item.computercraft.pocket_computer_advanced.upgraded": "고급 %s 포켓 컴퓨터",
"upgrade.minecraft.diamond_sword.adjective": "난투",
"upgrade.minecraft.diamond_shovel.adjective": "굴착",
"upgrade.minecraft.diamond_pickaxe.adjective": "채굴",
"upgrade.minecraft.diamond_axe.adjective": "벌목",
"upgrade.minecraft.diamond_hoe.adjective": "농업",
"upgrade.minecraft.crafting_table.adjective": "조합",
"upgrade.computercraft.wireless_modem_normal.adjective": "무선",
"upgrade.computercraft.wireless_modem_advanced.adjective": "엔더",
"upgrade.computercraft.speaker.adjective": "소음",
"chat.computercraft.wired_modem.peripheral_connected": "주변 \"%s\"이 네트워크에 연결되었습니다.",
"chat.computercraft.wired_modem.peripheral_disconnected": "주변 \"%s\"이 네트워크로부터 분리되었습니다.",
"commands.computercraft.synopsis": "컴퓨터를 제어하기 위한 다양한 명령어",
"commands.computercraft.desc": "/computercraft 명령어는 컴퓨터를 제어하고 상호작용하기 위한 다양한 디버깅 및 관리자 도구를 제공합니다.",
"commands.computercraft.help.synopsis": "특정 명령어에 대한 도움말을 제공하기",
"commands.computercraft.help.desc": "",
"commands.computercraft.help.no_children": "%s에는 하위 명령어가 없습니다.",
"commands.computercraft.help.no_command": "'%s'라는 명령어가 없습니다.",
"commands.computercraft.dump.synopsis": "컴퓨터의 상태를 보여주기",
"commands.computercraft.dump.desc": "모든 시스템의 상태 또는 한 시스템에 대한 특정 정보를 표시합니다. 컴퓨터의 인스턴스 ID(예: 123)나 컴퓨터 ID(예: #123) 또는 라벨(예: \"@My Computer\")을 지정할 수 있습니다.",
"commands.computercraft.dump.action": "이 컴퓨터에 대한 추가 정보를 봅니다.",
"commands.computercraft.shutdown.synopsis": "시스템을 원격으로 종료하기",
"commands.computercraft.shutdown.desc": "나열된 시스템 또는 지정된 시스템이 없는 경우 모두 종료합니다. 컴퓨터의 인스턴스 ID(예: 123)나 컴퓨터 ID(예: #123) 또는 라벨(예: \"@My Computer\")을 지정할 수 있습니다.",
"commands.computercraft.shutdown.done": "%s/%s 컴퓨터 시스템 종료",
"commands.computercraft.turn_on.synopsis": "시스템을 원격으로 실행하기",
"commands.computercraft.turn_on.desc": "나열된 컴퓨터를 실행합니다. 컴퓨터의 인스턴스 ID(예: 123)나 컴퓨터 ID(예: #123) 또는 라벨(예: \"@My Computer\")을 지정할 수 있습니다.",
"commands.computercraft.turn_on.done": "%s/%s 컴퓨터 시스템 실행",
"commands.computercraft.tp.synopsis": "특정 컴퓨터로 순간이동하기",
"commands.computercraft.tp.desc": "컴퓨터의 위치로 순간이동합니다. 컴퓨터의 인스턴스 ID(예: 123) 또는 컴퓨터 ID(예: #123)를 지정할 수 있습니다.",
"commands.computercraft.tp.action": "이 컴퓨터로 순간이동하기",
"commands.computercraft.tp.not_there": "월드에서 컴퓨터를 위치시킬 수 없습니다.",
"commands.computercraft.view.synopsis": "컴퓨터의 터미널을 보기",
"commands.computercraft.view.desc": "컴퓨터의 원격 제어를 허용하는 컴퓨터의 터미널을 엽니다. 이것은 터틀의 인벤토리에 대한 접근을 제공하지 않습니다. 컴퓨터의 인스턴스 ID(예: 123) 또는 컴퓨터 ID(예: #123)를 지정할 수 있습니다.",
"commands.computercraft.view.action": "이 컴퓨터를 봅니다.",
"commands.computercraft.view.not_player": "비플레이어한테 터미널을 열 수 없습니다.",
"commands.computercraft.track.synopsis": "컴퓨터의 실행 시간을 추적하기",
"commands.computercraft.track.desc": "컴퓨터가 실행되는 기간과 처리되는 이벤트 수를 추적합니다. 이는 /forge 트랙과 유사한 방법으로 정보를 제공하며 지연 로그에 유용할 수 있습니다.",
"commands.computercraft.track.start.synopsis": "모든 컴퓨터의 추적을 시작하기",
"commands.computercraft.track.start.desc": "모든 컴퓨터의 이벤트 및 실행 시간 추적을 시작합니다. 이는 이전 실행의 결과를 폐기할 것입니다.",
"commands.computercraft.track.start.stop": "%s을(를) 실행하여 추적을 중지하고 결과를 확인합니다.",
"commands.computercraft.track.stop.synopsis": "모든 컴퓨터의 추적을 중지하기",
"commands.computercraft.track.stop.desc": "모든 컴퓨터의 이벤트 및 실행 시간 추적을 중지합니다.",
"commands.computercraft.track.stop.action": "추적을 중지하려면 클릭하세요.",
"commands.computercraft.track.stop.not_enabled": "현재 추적하는 컴퓨터가 없습니다.",
"commands.computercraft.track.dump.synopsis": "최신 추적 결과를 덤프하기",
"commands.computercraft.track.dump.desc": "최신 컴퓨터 추적의 결과를 덤프합니다.",
"commands.computercraft.track.dump.no_timings": "사용가능한 시간이 없습니다.",
"commands.computercraft.track.dump.computer": "컴퓨터",
"commands.computercraft.reload.synopsis": "컴퓨터크래프트 구성파일을 리로드하기",
"commands.computercraft.reload.desc": "컴퓨터크래프트 구성파일을 리로드합니다.",
"commands.computercraft.reload.done": "리로드된 구성",
"commands.computercraft.queue.synopsis": "computer_command 이벤트를 명령 컴퓨터에 보내기",
"commands.computercraft.queue.desc": "computer_command 이벤트를 명령 컴퓨터로 전송하여 추가 인수를 전달합니다. 이는 대부분 지도 제작자를 위해 설계되었으며, 보다 컴퓨터 친화적인 버전의 /trigger 역할을 합니다. 어떤 플레이어든 명령을 실행할 수 있으며, 이는 텍스트 구성 요소의 클릭 이벤트를 통해 수행될 가능성이 가장 높습니다.",
"commands.computercraft.generic.no_position": "<no pos>",
"commands.computercraft.generic.position": "%s, %s, %s",
"commands.computercraft.generic.yes": "Y",
"commands.computercraft.generic.no": "N",
"commands.computercraft.generic.exception": "처리되지 않은 예외 (%s)",
"commands.computercraft.generic.additional_rows": "%d개의 추가 행...",
"argument.computercraft.computer.no_matching": "'%s'와 일치하는 컴퓨터가 없습니다.",
"argument.computercraft.computer.many_matching": "'%s'와 일치하는 여러 컴퓨터 (인스턴스 %s)",
"tracking_field.computercraft.tasks.name": "작업",
"tracking_field.computercraft.total.name": "전체 시간",
"tracking_field.computercraft.average.name": "평균 시간",
"tracking_field.computercraft.max.name": "최대 시간",
"tracking_field.computercraft.server_count.name": "서버 작업 수",
"tracking_field.computercraft.server_time.name": "서버 작업 시간",
"tracking_field.computercraft.peripheral.name": "주변 호출",
"tracking_field.computercraft.fs.name": "파일시스템 작업",
"tracking_field.computercraft.turtle.name": "터틀 작업",
"tracking_field.computercraft.http.name": "HTTP 요청",
"tracking_field.computercraft.http_upload.name": "HTTP 업로드",
"tracking_field.computercraft.http_download.name": "HTTT 다운로드",
"tracking_field.computercraft.websocket_incoming.name": "웹소켓 수신",
"tracking_field.computercraft.websocket_outgoing.name": "웹소켓 송신",
"tracking_field.computercraft.coroutines_created.name": "코루틴 생성됨",
"tracking_field.computercraft.coroutines_dead.name": "코루틴 처리됨",
"gui.computercraft.tooltip.copy": "클립보드에 복사",
"gui.computercraft.tooltip.computer_id": "컴퓨터 ID: %s",
"gui.computercraft.tooltip.disk_id": "디스크 ID: %s",
"gui.computercraft.config.computer_space_limit": "컴퓨터 공간 제한 (바이트)",
"gui.computercraft.config.floppy_space_limit": "플로피 디스크 공간 제한 (바이트)",
"gui.computercraft.config.maximum_open_files": "컴퓨터당 최대 파일 열기",
"gui.computercraft.config.disable_lua51_features": "Lua 5.1 기능 미사용",
"gui.computercraft.config.default_computer_settings": "기본 컴퓨터 설정",
"gui.computercraft.config.debug_enabled": "디버그 라이브러리 사용",
"gui.computercraft.config.log_computer_errors": "컴퓨터 오류 로그",
"gui.computercraft.config.execution": "실행",
"gui.computercraft.config.execution.computer_threads": "컴퓨터 쓰레드",
"gui.computercraft.config.execution.max_main_global_time": "전역 시간 당 서버 제한",
"gui.computercraft.config.execution.max_main_computer_time": "컴퓨터 시간 당 서버 제한",
"gui.computercraft.config.http": "HTTP",
"gui.computercraft.config.http.enabled": "HTTP API 사용하기",
"gui.computercraft.config.http.websocket_enabled": "웹소켓 사용",
"gui.computercraft.config.http.timeout": "타임아웃",
"gui.computercraft.config.http.max_requests": "최대 동시 요청 수",
"gui.computercraft.config.http.max_download": "최대 응답 크기",
"gui.computercraft.config.http.max_upload": "최대 요청 크기",
"gui.computercraft.config.http.max_websockets": "최대 동시 웹소켓 수",
"gui.computercraft.config.http.max_websocket_message": "최대 웹 포켓 메시지 크기",
"gui.computercraft.config.peripheral": "주변",
"gui.computercraft.config.peripheral.command_block_enabled": "명령 블록 주변 장치 사용",
"gui.computercraft.config.peripheral.modem_range": "모뎀 범위(기본값)",
"gui.computercraft.config.peripheral.modem_high_altitude_range": "모뎀 범위(높은 고도)",
"gui.computercraft.config.peripheral.modem_range_during_storm": "모뎀 범위(나쁜 날씨)",
"gui.computercraft.config.peripheral.modem_high_altitude_range_during_storm": "모뎀 범위(높은 고도, 나쁜 날씨)",
"gui.computercraft.config.peripheral.max_notes_per_tick": "컴퓨터가 한 번에 재생할 수 있는 최대 소리 수",
"gui.computercraft.config.turtle": "터틀",
"gui.computercraft.config.turtle.need_fuel": "연료 사용",
"gui.computercraft.config.turtle.normal_fuel_limit": "터틀 연료 제한",
"gui.computercraft.config.turtle.advanced_fuel_limit": "고급 터틀 연료 제한",
"gui.computercraft.config.turtle.obey_block_protection": "터틀이 블록 보호에 따르기",
"gui.computercraft.config.turtle.can_push": "터틀이 엔티티 밀어내기",
"gui.computercraft.config.turtle.disabled_actions": "터틀 액션 미사용",
"gui.computercraft.config.http.allowed_domains": "허용된 도메인",
"gui.computercraft.config.http.blocked_domains": "차단된 도메인"
}

View File

@@ -1,195 +0,0 @@
itemGroup.computercraft=컴퓨터크래프트
tile.computercraft:computer.name=컴퓨터
tile.computercraft:advanced_computer.name=고급 컴퓨터
tile.computercraft:drive.name=디스크 드라이브
tile.computercraft:printer.name=프린터
tile.computercraft:monitor.name=모니터
tile.computercraft:advanced_monitor.name=고급 모니터
tile.computercraft:wireless_modem.name=무선 모뎀
tile.computercraft:wired_modem.name=유선 모뎀
tile.computercraft:cable.name=네트워크 케이블
tile.computercraft:command_computer.name=명령 컴퓨터
tile.computercraft:advanced_modem.name=엔더 모뎀
tile.computercraft:speaker.name=스피커
tile.computercraft:turtle.name=터틀
tile.computercraft:turtle.upgraded.name=%s 터틀
tile.computercraft:turtle.upgraded_twice.name=%s %s 터틀
tile.computercraft:advanced_turtle.name=고급 터틀
tile.computercraft:advanced_turtle.upgraded.name=고급 %s 터틀
tile.computercraft:advanced_turtle.upgraded_twice.name=고급 %s %s 터틀
item.computercraft:disk.name=플로피 디스크
item.computercraft:treasure_disk.name=플로피 디스크
item.computercraft:page.name=인쇄된 페이지
item.computercraft:pages.name=인쇄된 페이지 모음
item.computercraft:book.name=인쇄된 책
item.computercraft:pocket_computer.name=포켓 컴퓨터
item.computercraft:pocket_computer.upgraded.name=%s 포켓 컴퓨터
item.computercraft:advanced_pocket_computer.name=고급 포켓 컴퓨터
item.computercraft:advanced_pocket_computer.upgraded.name=고급 %s 포켓 컴퓨터
upgrade.minecraft:diamond_sword.adjective=난투
upgrade.minecraft:diamond_shovel.adjective=굴착
upgrade.minecraft:diamond_pickaxe.adjective=채굴
upgrade.minecraft:diamond_axe.adjective=벌목
upgrade.minecraft:diamond_hoe.adjective=농업
upgrade.computercraft:wireless_modem.adjective=무선
upgrade.minecraft:crafting_table.adjective=조합
upgrade.computercraft:advanced_modem.adjective=엔더
upgrade.computercraft:speaker.adjective=소음
chat.computercraft.wired_modem.peripheral_connected=주변 "%s"이 네트워크에 연결되었습니다.
chat.computercraft.wired_modem.peripheral_disconnected=주변 "%s"이 네트워크로부터 분리되었습니다.
# Command descriptions, usage and any additional messages.
commands.computercraft.synopsis=컴퓨터를 제어하기 위한 다양한 명령어
commands.computercraft.desc=/computercraft 명령어는 컴퓨터를 제어하고 상호작용하기 위한 다양한 디버깅 및 관리자 도구를 제공합니다.
commands.computercraft.help.synopsis=특정 명령어에 대한 도움말을 제공하기
commands.computercraft.help.desc=
commands.computercraft.help.usage=[command]
commands.computercraft.help.no_children=%s에는 하위 명령어가 없습니다.
commands.computercraft.help.no_command='%s'라는 명령어가 없습니다.
commands.computercraft.dump.synopsis=컴퓨터의 상태를 보여주기
commands.computercraft.dump.desc=모든 시스템의 상태 또는 한 시스템에 대한 특정 정보를 표시합니다. 컴퓨터의 인스턴스 ID(예: 123)나 컴퓨터 ID(예: #123) 또는 라벨(예: "@My Computer")을 지정할 수 있습니다.
commands.computercraft.dump.usage=[id]
commands.computercraft.dump.action=이 컴퓨터에 대한 추가 정보를 봅니다.
commands.computercraft.shutdown.synopsis=시스템을 원격으로 종료하기
commands.computercraft.shutdown.desc=나열된 시스템 또는 지정된 시스템이 없는 경우 모두 종료합니다. 컴퓨터의 인스턴스 ID(예: 123)나 컴퓨터 ID(예: #123) 또는 라벨(예: "@My Computer")을 지정할 수 있습니다.
commands.computercraft.shutdown.usage=[ids...]
commands.computercraft.shutdown.done=%s/%s 컴퓨터 시스템 종료
commands.computercraft.turn_on.synopsis=시스템을 원격으로 실행하기
commands.computercraft.turn_on.desc=나열된 컴퓨터를 실행합니다. 컴퓨터의 인스턴스 ID(예: 123)나 컴퓨터 ID(예: #123) 또는 라벨(예: "@My Computer")을 지정할 수 있습니다.
commands.computercraft.turn_on.usage=[ids...]
commands.computercraft.turn_on.done=%s/%s 컴퓨터 시스템 실행
commands.computercraft.tp.synopsis=특정 컴퓨터로 순간이동하기
commands.computercraft.tp.desc=컴퓨터의 위치로 순간이동합니다. 컴퓨터의 인스턴스 ID(예: 123) 또는 컴퓨터 ID(예: #123)를 지정할 수 있습니다.
commands.computercraft.tp.usage=<id>
commands.computercraft.tp.action=이 컴퓨터로 순간이동하기
commands.computercraft.tp.not_entity=비플레이어한테 터미널을 열 수 없습니다.
commands.computercraft.tp.not_there=월드에서 컴퓨터를 위치시킬 수 없습니다.
commands.computercraft.view.synopsis=컴퓨터의 터미널을 보기
commands.computercraft.view.desc=컴퓨터의 원격 제어를 허용하는 컴퓨터의 터미널을 엽니다. 이것은 터틀의 인벤토리에 대한 접근을 제공하지 않습니다. 컴퓨터의 인스턴스 ID(예: 123) 또는 컴퓨터 ID(예: #123)를 지정할 수 있습니다.
commands.computercraft.view.usage=<id>
commands.computercraft.view.action=이 컴퓨터를 봅니다.
commands.computercraft.view.not_player=비플레이어한테 터미널을 열 수 없습니다.
commands.computercraft.track.synopsis=컴퓨터의 실행 시간을 추적하기
commands.computercraft.track.desc=컴퓨터가 실행되는 기간과 처리되는 이벤트 수를 추적합니다. 이는 /forge 트랙과 유사한 방법으로 정보를 제공하며 지연 로그에 유용할 수 있습니다.
commands.computercraft.track.start.synopsis=모든 컴퓨터의 추적을 시작하기
commands.computercraft.track.start.desc=모든 컴퓨터의 이벤트 및 실행 시간 추적을 시작합니다. 이는 이전 실행의 결과를 폐기할 것입니다.
commands.computercraft.track.start.usage=
commands.computercraft.track.start.stop=%s을(를) 실행하여 추적을 중지하고 결과를 확인합니다.
commands.computercraft.track.stop.synopsis=모든 컴퓨터의 추적을 중지하기
commands.computercraft.track.stop.desc=모든 컴퓨터의 이벤트 및 실행 시간 추적을 중지합니다.
commands.computercraft.track.stop.usage=
commands.computercraft.track.stop.action=추적을 중지하려면 클릭하세요.
commands.computercraft.track.stop.not_enabled=현재 추적하는 컴퓨터가 없습니다.
commands.computercraft.track.dump.synopsis=최신 추적 결과를 덤프하기
commands.computercraft.track.dump.desc=최신 컴퓨터 추적의 결과를 덤프합니다.
commands.computercraft.track.dump.usage=[kind]
commands.computercraft.track.dump.no_timings=사용가능한 시간이 없습니다.
commands.computercraft.track.dump.no_field=알 수 없는 필드 '%s'
commands.computercraft.track.dump.computer=컴퓨터
commands.computercraft.reload.synopsis=컴퓨터크래프트 구성파일을 리로드하기
commands.computercraft.reload.desc=컴퓨터크래프트 구성파일을 리로드합니다.
commands.computercraft.reload.usage=
commands.computercraft.reload.done=리로드된 구성
commands.computercraft.queue.synopsis=computer_command 이벤트를 명령 컴퓨터에 보내기
commands.computercraft.queue.desc=computer_command 이벤트를 명령 컴퓨터로 전송하여 추가 인수를 전달합니다. 이는 대부분 지도 제작자를 위해 설계되었으며, 보다 컴퓨터 친화적인 버전의 /trigger 역할을 합니다. 어떤 플레이어든 명령을 실행할 수 있으며, 이는 텍스트 구성 요소의 클릭 이벤트를 통해 수행될 가능성이 가장 높습니다.
commands.computercraft.queue.usage=<id> [args...]
commands.computercraft.generic.no_position=<no pos>
commands.computercraft.generic.position=%s, %s, %s
commands.computercraft.generic.yes=Y
commands.computercraft.generic.no=N
commands.computercraft.generic.exception=처리되지 않은 예외 (%s)
commands.computercraft.generic.additional_rows=%d개의 추가 행...
commands.computercraft.argument.no_matching='%s'와 일치하는 컴퓨터가 없습니다.
commands.computercraft.argument.many_matching='%s'와 일치하는 여러 컴퓨터 (인스턴스 %s)
commands.computercraft.argument.not_number='%s'는 숫자가 아닙니다.
# Names for the various tracking fields.
tracking_field.computercraft.tasks.name=작업
tracking_field.computercraft.total.name=전체 시간
tracking_field.computercraft.average.name=평균 시간
tracking_field.computercraft.max.name=최대 시간
tracking_field.computercraft.server_count.name=서버 작업 수
tracking_field.computercraft.server_time.name=서버 작업 시간
tracking_field.computercraft.peripheral.name=주변 호출
tracking_field.computercraft.fs.name=파일시스템 작업
tracking_field.computercraft.turtle.name=터틀 작업
tracking_field.computercraft.http.name=HTTP 요청
tracking_field.computercraft.http_upload.name=HTTP 업로드
tracking_field.computercraft.http_download.name=HTTT 다운로드
tracking_field.computercraft.websocket_incoming.name=웹소켓 수신
tracking_field.computercraft.websocket_outgoing.name=웹소켓 송신
tracking_field.computercraft.coroutines_created.name=코루틴 생성됨
tracking_field.computercraft.coroutines_dead.name=코루틴 처리됨
# Misc tooltips
gui.computercraft.tooltip.copy=클립보드에 복사
gui.computercraft.tooltip.computer_id=(컴퓨터 ID: %s)
gui.computercraft.tooltip.disk_id=(디스크 ID: %s)
# Config options
gui.computercraft:config.computer_space_limit=컴퓨터 공간 제한 (바이트)
gui.computercraft:config.floppy_space_limit=플로피 디스크 공간 제한 (바이트)
gui.computercraft:config.maximum_open_files=컴퓨터당 최대 파일 열기
gui.computercraft:config.disable_lua51_features=Lua 5.1 기능 미사용
gui.computercraft:config.default_computer_settings=기본 컴퓨터 설정
gui.computercraft:config.debug_enabled=디버그 라이브러리 사용
gui.computercraft:config.log_computer_errors=컴퓨터 오류 로그
gui.computercraft:config.execution=실행
gui.computercraft:config.execution.computer_threads=컴퓨터 쓰레드
gui.computercraft:config.execution.max_main_global_time=전역 시간 당 서버 제한
gui.computercraft:config.execution.max_main_computer_time=컴퓨터 시간 당 서버 제한
gui.computercraft:config.http=HTTP
gui.computercraft:config.http.enabled=HTTP API 사용하기
gui.computercraft:config.http.websocket_enabled=웹소켓 사용
gui.computercraft:config.http.allowed_domains=허용된 도메인
gui.computercraft:config.http.blocked_domains=차단된 도메인
gui.computercraft:config.http.timeout=타임아웃
gui.computercraft:config.http.max_requests=최대 동시 요청 수
gui.computercraft:config.http.max_download=최대 응답 크기
gui.computercraft:config.http.max_upload=최대 요청 크기
gui.computercraft:config.http.max_websockets=최대 동시 웹소켓 수
gui.computercraft:config.http.max_websocket_message=최대 웹 포켓 메시지 크기
gui.computercraft:config.peripheral=주변
gui.computercraft:config.peripheral.command_block_enabled=명령 블록 주변 장치 사용
gui.computercraft:config.peripheral.modem_range=모뎀 범위(기본값)
gui.computercraft:config.peripheral.modem_high_altitude_range=모뎀 범위(높은 고도)
gui.computercraft:config.peripheral.modem_range_during_storm=모뎀 범위(나쁜 날씨)
gui.computercraft:config.peripheral.modem_high_altitude_range_during_storm=모뎀 범위(높은 고도, 나쁜 날씨)
gui.computercraft:config.peripheral.max_notes_per_tick=컴퓨터가 한 번에 재생할 수 있는 최대 소리 수
gui.computercraft:config.turtle=터틀
gui.computercraft:config.turtle.need_fuel=연료 사용
gui.computercraft:config.turtle.normal_fuel_limit=터틀 연료 제한
gui.computercraft:config.turtle.advanced_fuel_limit=고급 터틀 연료 제한
gui.computercraft:config.turtle.obey_block_protection=터틀이 블록 보호에 따르기
gui.computercraft:config.turtle.can_push=터틀이 엔티티 밀어내기
gui.computercraft:config.turtle.disabled_actions=터틀 액션 미사용

View File

@@ -143,8 +143,8 @@
"tracking_field.computercraft.coroutines_dead.name": "协同处理",
"gui.computercraft.tooltip.copy": "复制到剪贴板",
"gui.computercraft.tooltip.computer_id": "(计算机ID: %s)",
"gui.computercraft.tooltip.disk_id": "(磁盘ID: %s)",
"gui.computercraft.tooltip.computer_id": "计算机ID: %s",
"gui.computercraft.tooltip.disk_id": "磁盘ID: %s",
"gui.computercraft.config.computer_space_limit": "计算机空间限制(字节)",
"gui.computercraft.config.floppy_space_limit": "软盘空间限制(字节)",

View File

@@ -1,195 +0,0 @@
itemGroup.computercraft=CC: Tweaked
tile.computercraft:computer.name=计算机
tile.computercraft:advanced_computer.name=高级计算机
tile.computercraft:drive.name=磁盘驱动器
tile.computercraft:printer.name=打印机
tile.computercraft:monitor.name=显示器
tile.computercraft:advanced_monitor.name=高级显示器
tile.computercraft:wireless_modem.name=无线调制解调器
tile.computercraft:wired_modem.name=有线调制解调器
tile.computercraft:cable.name=网络电缆
tile.computercraft:command_computer.name=命令电脑
tile.computercraft:advanced_modem.name=末影调制解调器
tile.computercraft:speaker.name=扬声器
tile.computercraft:turtle.name=海龟
tile.computercraft:turtle.upgraded.name=%s海龟
tile.computercraft:turtle.upgraded_twice.name=%s%s海龟
tile.computercraft:advanced_turtle.name=高级海龟
tile.computercraft:advanced_turtle.upgraded.name=高级%s海龟
tile.computercraft:advanced_turtle.upgraded_twice.name=高级%s%s海龟
item.computercraft:disk.name=软盘
item.computercraft:treasure_disk.name=软盘
item.computercraft:page.name=打印纸
item.computercraft:pages.name=打印纸
item.computercraft:book.name=打印书
item.computercraft:pocket_computer.name=手提计算机
item.computercraft:pocket_computer.upgraded.name=%s手提计算机
item.computercraft:advanced_pocket_computer.name=高级手提计算机
item.computercraft:advanced_pocket_computer.upgraded.name=高级%s手提计算机
upgrade.minecraft:diamond_sword.adjective=战斗
upgrade.minecraft:diamond_shovel.adjective=挖掘
upgrade.minecraft:diamond_pickaxe.adjective=采掘
upgrade.minecraft:diamond_axe.adjective=伐木
upgrade.minecraft:diamond_hoe.adjective=耕种
upgrade.computercraft:wireless_modem.adjective=无线
upgrade.minecraft:crafting_table.adjective=合成
upgrade.computercraft:advanced_modem.adjective=末影
upgrade.computercraft:speaker.adjective=喧闹
chat.computercraft.wired_modem.peripheral_connected=Peripheral "%s"连接到网络
chat.computercraft.wired_modem.peripheral_disconnected=Peripheral "%s"与网络断开连接
# Command descriptions, usage and any additional messages.
commands.computercraft.synopsis=各种控制计算机的命令.
commands.computercraft.desc=/computercraft命令提供各种调试和管理工具用于控制和与计算机交互.
commands.computercraft.help.synopsis=为特定的命令提供帮助
commands.computercraft.help.desc=
commands.computercraft.help.usage=[command]
commands.computercraft.help.no_children=%s没有子命令
commands.computercraft.help.no_command=没有这样的命令'%s'
commands.computercraft.dump.synopsis=显示计算机的状态.
commands.computercraft.dump.desc=显示所有计算机的状态或某台计算机的特定信息. 你可以指定计算机的实例id (例如. 123), 计算机id (例如. #123)或标签(例如. "@My Computer").
commands.computercraft.dump.usage=[id]
commands.computercraft.dump.action=查看有关此计算机的更多信息
commands.computercraft.shutdown.synopsis=远程关闭计算机.
commands.computercraft.shutdown.desc=关闭列出的计算机或全部计算机(如果未指定). 你可以指定计算机的实例id (例如. 123), 计算机id (例如. #123)或标签(例如. "@My Computer").
commands.computercraft.shutdown.usage=[ids...]
commands.computercraft.shutdown.done=关闭%s/%s计算机
commands.computercraft.turn_on.synopsis=远程打开计算机.
commands.computercraft.turn_on.desc=打开列出的计算机. 你可以指定计算机的实例id (例如. 123), 计算机id (例如. #123)或标签(例如. "@My Computer").
commands.computercraft.turn_on.usage=[ids...]
commands.computercraft.turn_on.done=打开%s/%s计算机
commands.computercraft.tp.synopsis=传送到特定的计算机.
commands.computercraft.tp.desc=传送到计算机的位置. 你可以指定计算机的实例id (例如. 123)或计算机id (例如. #123).
commands.computercraft.tp.usage=<id>
commands.computercraft.tp.action=传送到这台电脑
commands.computercraft.tp.not_entity=无法为非玩家打开终端
commands.computercraft.tp.not_there=无法在世界上定位电脑
commands.computercraft.view.synopsis=查看计算机的终端.
commands.computercraft.view.desc=打开计算机的终端,允许远程控制计算机. 这不提供对海龟库存的访问. 你可以指定计算机的实例id (例如. 123)或计算机id (例如. #123).
commands.computercraft.view.usage=<id>
commands.computercraft.view.action=查看此计算机
commands.computercraft.view.not_player=无法为非玩家打开终端
commands.computercraft.track.synopsis=跟踪计算机的执行时间.
commands.computercraft.track.desc=跟踪计算机执行的时间以及它们处理的事件数. 这以/forge track类似的方式呈现信息可用于诊断滞后.
commands.computercraft.track.start.synopsis=开始跟踪所有计算机
commands.computercraft.track.start.desc=开始跟踪所有计算机的执行时间和事件计数. 这将放弃先前运行的结果.
commands.computercraft.track.start.usage=
commands.computercraft.track.start.stop=运行%s以停止跟踪并查看结果
commands.computercraft.track.stop.synopsis=停止跟踪所有计算机
commands.computercraft.track.stop.desc=停止跟踪所有计算机的事件和执行时间
commands.computercraft.track.stop.usage=
commands.computercraft.track.stop.action=点击停止跟踪
commands.computercraft.track.stop.not_enabled=目前没有跟踪计算机
commands.computercraft.track.dump.synopsis=输出最新的跟踪结果
commands.computercraft.track.dump.desc=输出计算机跟踪的最新结果.
commands.computercraft.track.dump.usage=[kind]
commands.computercraft.track.dump.no_timings=没有时间可用
commands.computercraft.track.dump.no_field=未知字节'%s'
commands.computercraft.track.dump.computer=计算器
commands.computercraft.reload.synopsis=重新加载ComputerCraft配置文件
commands.computercraft.reload.desc=重新加载ComputerCraft配置文件
commands.computercraft.reload.usage=
commands.computercraft.reload.done=重新加载配置
commands.computercraft.queue.synopsis=将computer_command事件发送到命令计算机
commands.computercraft.queue.desc=发送computer_command事件到命令计算机,并传递其他参数. 这主要是为地图制作者设计的, 作为/trigger更加计算机友好的版本. 任何玩家都可以运行命令, 这很可能是通过文本组件的点击事件完成的.
commands.computercraft.queue.usage=<id> [args...]
commands.computercraft.generic.no_position=<无位置>
commands.computercraft.generic.position=%s, %s, %s
commands.computercraft.generic.yes=Y
commands.computercraft.generic.no=N
commands.computercraft.generic.exception=未处理的异常(%s)
commands.computercraft.generic.additional_rows=%d额外的行…
commands.computercraft.argument.no_matching=没有计算机匹配'%s'
commands.computercraft.argument.many_matching=多台计算机匹配'%s' (实例%s)
commands.computercraft.argument.not_number='%s'不是一个数字
# Names for the various tracking fields.
tracking_field.computercraft.tasks.name=任务
tracking_field.computercraft.total.name=总计时间
tracking_field.computercraft.average.name=平均时间
tracking_field.computercraft.max.name=最大时间
tracking_field.computercraft.server_count.name=服务器任务计数
tracking_field.computercraft.server_time.name=服务器任务时间
tracking_field.computercraft.peripheral.name=外围设备呼叫
tracking_field.computercraft.fs.name=文件系统操作
tracking_field.computercraft.turtle.name=海龟行动
tracking_field.computercraft.http.name=HTTP需求
tracking_field.computercraft.http_upload.name=HTTP上传
tracking_field.computercraft.http_download.name=HTTP下载
tracking_field.computercraft.websocket_incoming.name=Websocket传入
tracking_field.computercraft.websocket_outgoing.name=Websocket传出
tracking_field.computercraft.coroutines_created.name=协同创建
tracking_field.computercraft.coroutines_dead.name=协同处理
# Misc tooltips
gui.computercraft.tooltip.copy=复制到剪贴板
gui.computercraft.tooltip.computer_id=(计算机ID: %s)
gui.computercraft.tooltip.disk_id=(磁盘ID: %s)
# Config options
gui.computercraft:config.computer_space_limit=计算机空间限制(字节)
gui.computercraft:config.floppy_space_limit=软盘空间限制(字节)
gui.computercraft:config.maximum_open_files=每台计算机打开的最大文件数
gui.computercraft:config.disable_lua51_features=禁用Lua 5.1功能
gui.computercraft:config.default_computer_settings=默认计算机设置
gui.computercraft:config.debug_enabled=启用debug库
gui.computercraft:config.log_computer_errors=记录计算机错误
gui.computercraft:config.execution=执行
gui.computercraft:config.execution.computer_threads=计算机线程数
gui.computercraft:config.execution.max_main_global_time=服务器全局tick时间限制
gui.computercraft:config.execution.max_main_computer_time=服务器计算机tick时间限制
gui.computercraft:config.http=HTTP
gui.computercraft:config.http.enabled=启用HTTP API
gui.computercraft:config.http.websocket_enabled=启用websockets
gui.computercraft:config.http.whitelist=HTTP白名单
gui.computercraft:config.http.blacklist=HTTP黑名单
gui.computercraft:config.http.timeout=Timeout
gui.computercraft:config.http.max_requests=最大并发请求数
gui.computercraft:config.http.max_download=最大响应数据大小
gui.computercraft:config.http.max_upload=最大请求数据大小
gui.computercraft:config.http.max_websockets=最大并发websockets数
gui.computercraft:config.http.max_websocket_message=最大websockets消息大小
gui.computercraft:config.peripheral=外围设备
gui.computercraft:config.peripheral.command_block_enabled=启用命令方块外设
gui.computercraft:config.peripheral.modem_range=调制解调器范围(默认)
gui.computercraft:config.peripheral.modem_high_altitude_range=调制解调器范围(高海拔)
gui.computercraft:config.peripheral.modem_range_during_storm=调制解调器范围(恶劣天气)
gui.computercraft:config.peripheral.modem_high_altitude_range_during_storm=调制解调器范围(高海拔, 恶劣天气)
gui.computercraft:config.peripheral.max_notes_per_tick=计算机一次可以播放的最大音符数量
gui.computercraft:config.turtle=海龟
gui.computercraft:config.turtle.need_fuel=启用燃料
gui.computercraft:config.turtle.normal_fuel_limit=海龟燃料限制
gui.computercraft:config.turtle.advanced_fuel_limit=高级海龟燃料限制
gui.computercraft:config.turtle.obey_block_protection=海龟服从方块保护
gui.computercraft:config.turtle.can_push=海龟可以推动实体
gui.computercraft:config.turtle.disabled_actions=禁用海龟动作

View File

@@ -0,0 +1,40 @@
#version 140
#define FONT_WIDTH 6.0
#define FONT_HEIGHT 9.0
uniform sampler2D u_font;
uniform int u_width;
uniform int u_height;
uniform samplerBuffer u_tbo;
uniform vec3 u_palette[16];
in vec2 f_pos;
out vec4 colour;
vec2 texture_corner(int index) {
float x = 1.0 + float(index % 16) * (FONT_WIDTH + 2.0);
float y = 1.0 + float(index / 16) * (FONT_HEIGHT + 2.0);
return vec2(x, y);
}
void main() {
vec2 term_pos = vec2(f_pos.x / FONT_WIDTH, f_pos.y / FONT_HEIGHT);
vec2 corner = floor(term_pos);
ivec2 cell = ivec2(corner);
int index = 3 * (clamp(cell.x, 0, u_width - 1) + clamp(cell.y, 0, u_height - 1) * u_width);
// 1 if 0 <= x, y < width, height, 0 otherwise
vec2 outside = step(vec2(0.0, 0.0), vec2(cell)) * step(vec2(cell), vec2(float(u_width) - 1.0, float(u_height) - 1.0));
float mult = outside.x * outside.y;
int character = int(texelFetch(u_tbo, index).r * 255.0);
int fg = int(texelFetch(u_tbo, index + 1).r * 255.0);
int bg = int(texelFetch(u_tbo, index + 2).r * 255.0);
vec2 pos = (term_pos - corner) * vec2(FONT_WIDTH, FONT_HEIGHT);
vec4 img = texture(u_font, (texture_corner(character) + pos) / 256.0);
colour = vec4(mix(u_palette[bg], img.rgb * u_palette[fg], img.a * mult), 1.0);
}

View File

@@ -0,0 +1,10 @@
#version 130
in vec3 v_pos;
out vec2 f_pos;
void main() {
gl_Position = gl_ModelViewProjectionMatrix * vec4(v_pos.x, v_pos.y, 0, 1);
f_pos = v_pos.xy;
}

View File

@@ -797,6 +797,12 @@ function fs.complete(sPath, sLocation, bIncludeFiles, bIncludeDirs)
return tEmpty
end
function fs.isDriveRoot(sPath)
expect(1, sPath, "string")
-- Force the root directory to be a mount.
return fs.getDir(sPath) == ".." or fs.getDrive(sPath) ~= fs.getDrive(fs.getDir(sPath))
end
-- Load APIs
local bAPIError = false
local tApis = fs.list("rom/apis")
@@ -932,6 +938,23 @@ settings.define("motd.path", {
description = [[The path to load random messages from. Should be a colon (":") separated string of file paths.]],
type = "string",
})
settings.define("lua.warn_against_use_of_local", {
default = true,
description = [[Print a message when input in the Lua REPL starts with the word 'local'. Local variables defined in the Lua REPL are be inaccessable on the next input.]],
type = "boolean",
})
settings.define("lua.function_args", {
default = true,
description = "Show function arguments when printing functions.",
type = "boolean",
})
settings.define("lua.function_source", {
default = false,
description = "Show where a function was defined when printing functions.",
type = "boolean",
})
if term.isColour() then
settings.define("bios.use_multishell", {
default = true,

View File

@@ -12,6 +12,9 @@
-- [mc]: https://minecraft.gamepedia.com/Commands
--
-- @module commands
-- @usage Set the block above this computer to stone:
--
-- commands.setblock("~", "~1", "~", "minecraft:stone")
if not commands then
error("Cannot load command API on normal computer", 2)
@@ -97,4 +100,13 @@ for _, sCommandName in ipairs(native.list()) do
tAsync[sCommandName] = mk_command({ sCommandName }, bJSONIsNBT, native.execAsync)
end
end
--- A table containing asynchronous wrappers for all commands.
--
-- As with @{commands.execAsync}, this returns the "task id" of the enqueued
-- command.
-- @see execAsync
-- @usage Asynchronously sets the block above the computer to stone.
--
-- commands.async.setblock("~", "~1", "~", "minecraft:stone")
env.async = tAsync

View File

@@ -75,7 +75,10 @@ handleMetatable = {
if not handle.read then return nil, "file is not readable" end
local args = table.pack(...)
return function() return checkResult(self, self:read(table.unpack(args, 1, args.n))) end
return function()
if self._closed then error("file is already closed", 2) end
return checkResult(self, self:read(table.unpack(args, 1, args.n)))
end
end,
read = function(self, ...)
@@ -259,12 +262,13 @@ end
-- instead. In this case, the handle is not used.
--
-- @tparam[opt] string filename The name of the file to extract lines from
-- @param ... The argument to pass to @{Handle:read} for each line.
-- @treturn function():string|nil The line iterator.
-- @throws If the file cannot be opened for reading
--
-- @see Handle:lines
-- @see io.input
function lines(filename)
function lines(filename, ...)
expect(1, filename, "string", "nil")
if filename then
local ok, err = open(filename, "rb")
@@ -273,9 +277,9 @@ function lines(filename)
-- We set this magic flag to mark this file as being opened by io.lines and so should be
-- closed automatically
ok._autoclose = true
return ok:lines()
return ok:lines(...)
else
return currentInput:lines()
return currentInput:lines(...)
end
end
@@ -313,7 +317,7 @@ end
-- @throws If the provided filename cannot be opened for writing.
function output(file)
if type_of(file) == "string" then
local res, err = open(file, "w")
local res, err = open(file, "wb")
if not res then error(err, 2) end
currentOutput = res
elseif type_of(file) == "table" and getmetatable(file) == handleMetatable then

View File

@@ -64,24 +64,33 @@ function isPresent(name)
return false
end
--- Get the type of the peripheral with the given name.
--- Get the type of a wrapped peripheral, or a peripheral with the given name.
--
-- @tparam string name The name of the peripheral to find.
-- @tparam string|table peripheral The name of the peripheral to find, or a
-- wrapped peripheral instance.
-- @treturn string|nil The peripheral's type, or `nil` if it is not present.
function getType(name)
expect(1, name, "string")
if native.isPresent(name) then
return native.getType(name)
end
for n = 1, #sides do
local side = sides[n]
if native.getType(side) == "modem" and not native.call(side, "isWireless") and
native.call(side, "isPresentRemote", name)
then
return native.call(side, "getTypeRemote", name)
function getType(peripheral)
expect(1, peripheral, "string", "table")
if type(peripheral) == "string" then -- Peripheral name passed
if native.isPresent(peripheral) then
return native.getType(peripheral)
end
for n = 1, #sides do
local side = sides[n]
if native.getType(side) == "modem" and not native.call(side, "isWireless") and
native.call(side, "isPresentRemote", peripheral)
then
return native.call(side, "getTypeRemote", peripheral)
end
end
return nil
else
local mt = getmetatable(peripheral)
if not mt or mt.__name ~= "peripheral" or type(mt.type) ~= "string" then
error("bad argument #1 (table is not a peripheral)", 2)
end
return mt.type
end
return nil
end
--- Get all available methods for the peripheral with the given name.
@@ -105,6 +114,19 @@ function getMethods(name)
return nil
end
--- Get the name of a peripheral wrapped with @{peripheral.wrap}.
--
-- @tparam table peripheral The peripheral to get the name of.
-- @treturn string The name of the given peripheral.
function getName(peripheral)
expect(1, peripheral, "table")
local mt = getmetatable(peripheral)
if not mt or mt.__name ~= "peripheral" or type(mt.name) ~= "string" then
error("bad argument #1 (table is not a peripheral)", 2)
end
return mt.name
end
--- Call a method on the peripheral with the given name.
--
-- @tparam string name The name of the peripheral to invoke the method on.
@@ -148,7 +170,11 @@ function wrap(name)
return nil
end
local result = {}
local result = setmetatable({}, {
__name = "peripheral",
name = name,
type = peripheral.getType(name),
})
for _, method in ipairs(methods) do
result[method] = function(...)
return peripheral.call(name, method, ...)

View File

@@ -29,7 +29,7 @@ local tReceivedMessageTimeouts = {}
local tHostnames = {}
--- Opens a modem with the given @{peripheral} name, allowing it to send and
--- receive messages over rednet.
-- receive messages over rednet.
--
-- This will open the modem on two channels: one which has the same
-- @{os.getComputerID|ID} as the computer, and another on
@@ -246,7 +246,7 @@ function host(sProtocol, sHostname)
end
--- Stop @{rednet.host|hosting} a specific protocol, meaning it will no longer
--- respond to @{rednet.lookup} requests.
-- respond to @{rednet.lookup} requests.
--
-- @tparam string sProtocol The protocol to unregister your self from.
function unhost(sProtocol)
@@ -334,7 +334,11 @@ end
local bRunning = false
--- @local
--- Listen for modem messages and converts them into rednet messages, which may
-- then be @{receive|received}.
--
-- This is automatically started in the background on computer startup, and
-- should not be called manually.
function run()
if bRunning then
error("rednet is already running", 2)

View File

@@ -205,9 +205,9 @@ function load(sPath)
end
for k, v in pairs(tFile) do
local ty_v = type(k)
local ty_v = type(v)
if type(k) == "string" and (ty_v == "string" or ty_v == "number" or ty_v == "boolean" or ty_v == "table") then
local opt = details[name]
local opt = details[k]
if not opt or not opt.type or ty_v == opt.type then
set_value(k, v)
end

View File

@@ -5,7 +5,12 @@
if not turtle then
error("Cannot load turtle API on computer", 2)
end
native = turtle.native or turtle --- @local
--- The builtin turtle API, without any generated helper functions.
--
-- Generally you should not need to use this table - it only exists for
-- backwards compatibility reasons.
native = turtle.native or turtle
local function addCraftMethod(object)
if peripheral.getType("left") == "workbench" then

View File

@@ -1,3 +1,30 @@
# New features in CC: Tweaked 1.89.0
* Compress monitor data, reducing network traffic by a significant amount.
* Allow limiting the bandwidth monitor updates use.
* Several optimisations to monitor rendering (@Lignum).
* Expose block and item tags to turtle.inspect and turtle.getItemDetail.
And several bug fixes:
* Fix settings.load failing on defined settings.
# New features in CC: Tweaked 1.88.0
* Computers and turtles now preserve their ID when broken.
* Add `peripheral.getName` - returns the name of a wrapped peripheral.
* Reduce network overhead of monitors and terminals.
* Add a TBO backend for monitors, with a significant performance boost.
* The Lua REPL warns when declaring locals (lupus590, exerro)
* Add config to allow using command computers in survival.
* Add fs.isDriveRoot - checks if a path is the root of a drive.
* `cc.pretty` can now display a function's arguments and where it was defined. The Lua REPL will show arguments by default.
* Move the shell's `require`/`package` implementation to a separate `cc.require` module.
And several bug fixes:
* Fix io.lines not accepting arguments.
* Fix settings.load using an unknown global (MCJack123).
* Prevent computers scanning peripherals twice.
# New features in CC: Tweaked 1.87.1
* Fix blocks not dropping items in survival.

View File

@@ -1,4 +1,3 @@
ComputerCraft was created by Daniel "dan200" Ratcliffe, with additional code by Aaron "Cloudy" Mills.
Thanks to nitrogenfingers, GopherATL and RamiLego for program contributions.
Thanks to Mojang, the Forge team, and the MCP team.

View File

@@ -3,6 +3,7 @@ The peripheral API is for interacting with external peripheral devices. Type "he
Functions in the peripheral API:
peripheral.getNames()
peripheral.isPresent( name )
peripheral.getName( peripheral )
peripheral.getType( name )
peripheral.getMethods( name )
peripheral.call( name, methodName, param1, param2, etc )

View File

@@ -1,5 +1,11 @@
New features in CC: Tweaked 1.87.1
New features in CC: Tweaked 1.89.0
* Fix blocks not dropping items in survival.
* Compress monitor data, reducing network traffic by a significant amount.
* Allow limiting the bandwidth monitor updates use.
* Several optimisations to monitor rendering (@Lignum).
* Expose block and item tags to turtle.inspect and turtle.getItemDetail.
And several bug fixes:
* Fix settings.load failing on defined settings.
Type "help changelog" to see the full version history.

View File

@@ -19,8 +19,12 @@
-- local pretty = require "cc.pretty"
-- pretty.write(pretty.group(pretty.text("hello") .. pretty.space_line .. pretty.text("world")))
local expect = require "cc.expect".expect
local type, getmetatable, setmetatable, colours, str_write = type, getmetatable, setmetatable, colours, write
local expect = require "cc.expect"
local expect, field = expect.expect, expect.field
local type, getmetatable, setmetatable, colours, str_write, tostring = type, getmetatable, setmetatable, colours, write, tostring
local debug_info = type(debug) == "table" and type(debug.getinfo) == "function" and debug.getinfo
local debug_local = type(debug) == "table" and type(debug.getlocal) == "function" and debug.getlocal
--- @{table.insert} alternative, but with the length stored inline.
local function append(out, value)
@@ -343,13 +347,38 @@ local function key_compare(a, b)
return false
end
local function pretty_impl(obj, tracking)
local function show_function(fn, options)
local info = debug_info and debug_info(fn, "Su")
-- Include function source position if available
local name
if options.function_source and info and info.short_src and info.linedefined and info.linedefined >= 1 then
name = "function<" .. info.short_src .. ":" .. info.linedefined .. ">"
else
name = tostring(fn)
end
-- Include arguments if a Lua function and if available. Lua will report "C"
-- functions as variadic.
if options.function_args and info and info.what == "Lua" and info.nparams and debug_local then
local args = {}
for i = 1, info.nparams do args[i] = debug_local(fn, i) or "?" end
if info.isvararg then args[#args + 1] = "..." end
name = name .. "(" .. table.concat(args, ", ") .. ")"
end
return name
end
local function pretty_impl(obj, options, tracking)
local obj_type = type(obj)
if obj_type == "string" then
local formatted = ("%q"):format(obj):gsub("\\\n", "\\n")
return text(formatted, colours.red)
elseif obj_type == "number" then
return text(tostring(obj), colours.magenta)
elseif obj_type == "function" then
return text(show_function(obj, options), colours.lightGrey)
elseif obj_type ~= "table" or tracking[obj] then
return text(tostring(obj), colours.lightGrey)
elseif getmetatable(obj) ~= nil and getmetatable(obj).__tostring then
@@ -371,20 +400,20 @@ local function pretty_impl(obj, tracking)
local v = obj[k]
local ty = type(k)
if ty == "number" and k % 1 == 0 and k >= 1 and k <= length then
append(doc, pretty_impl(v, tracking))
append(doc, pretty_impl(v, options, tracking))
elseif ty == "string" and not keywords[k] and k:match("^[%a_][%a%d_]*$") then
append(doc, text(k .. " = "))
append(doc, pretty_impl(v, tracking))
append(doc, pretty_impl(v, options, tracking))
else
append(doc, obracket)
append(doc, pretty_impl(k, tracking))
append(doc, pretty_impl(k, options, tracking))
append(doc, cbracket)
append(doc, pretty_impl(v, tracking))
append(doc, pretty_impl(v, options, tracking))
end
end
tracking[obj] = nil
return group(concat(obrace, nest(2, concat(table.unpack(doc, 1, n))), space_line, cbrace))
return group(concat(obrace, nest(2, concat(table.unpack(doc, 1, doc.n))), space_line, cbrace))
end
end
@@ -393,12 +422,24 @@ end
-- This can then be rendered with @{write} or @{print}.
--
-- @param obj The object to pretty-print.
-- @tparam[opt] { function_args = boolean, function_source = boolean } options
-- Controls how various properties are displayed.
-- - `function_args`: Show the arguments to a function if known (`false` by default).
-- - `function_source`: Show where the function was defined, instead of
-- `function: xxxxxxxx` (`false` by default).
-- @treturn Doc The object formatted as a document.
-- @usage Display a table on the screen
-- local pretty = require "cc.pretty"
-- pretty.print(pretty.pretty({ 1, 2, 3 }))
local function pretty(obj)
return pretty_impl(obj, {})
local function pretty(obj, options)
expect(2, options, "table", "nil")
options = options or {}
local actual_options = {
function_source = field(options, "function_source", "boolean", "nil") or false,
function_args = field(options, "function_args", "boolean", "nil") or false,
}
return pretty_impl(obj, actual_options, {})
end
return {

View File

@@ -0,0 +1,121 @@
--- This provides a pure Lua implementation of the builtin @{require} function
-- and @{package} library.
--
-- Generally you do not need to use this module - it is injected into the
-- every program's environment. However, it may be useful when building a
-- custom shell or when running programs yourself.
--
-- @module cc.require
-- @usage Construct the package and require function, and insert them into a
-- custom environment.
--
-- local env = setmetatable({}, { __index = _ENV })
-- local r = require "cc.require"
-- env.require, env.package = r.make(env, "/")
local expect = require and require("cc.expect") or dofile("rom/modules/main/cc/expect.lua")
local expect = expect.expect
local function preload(package)
return function(name)
if package.preload[name] then
return package.preload[name]
else
return nil, "no field package.preload['" .. name .. "']"
end
end
end
local function from_file(package, env, dir)
return function(name)
local fname = string.gsub(name, "%.", "/")
local sError = ""
for pattern in string.gmatch(package.path, "[^;]+") do
local sPath = string.gsub(pattern, "%?", fname)
if sPath:sub(1, 1) ~= "/" then
sPath = fs.combine(dir, sPath)
end
if fs.exists(sPath) and not fs.isDir(sPath) then
local fnFile, sError = loadfile(sPath, nil, env)
if fnFile then
return fnFile, sPath
else
return nil, sError
end
else
if #sError > 0 then
sError = sError .. "\n "
end
sError = sError .. "no file '" .. sPath .. "'"
end
end
return nil, sError
end
end
local function make_require(package)
local sentinel = {}
return function(name)
expect(1, name, "string")
if package.loaded[name] == sentinel then
error("loop or previous error loading module '" .. name .. "'", 0)
end
if package.loaded[name] then
return package.loaded[name]
end
local sError = "module '" .. name .. "' not found:"
for _, searcher in ipairs(package.loaders) do
local loader = table.pack(searcher(name))
if loader[1] then
package.loaded[name] = sentinel
local result = loader[1](name, table.unpack(loader, 2, loader.n))
if result == nil then result = true end
package.loaded[name] = result
return result
else
sError = sError .. "\n " .. loader[2]
end
end
error(sError, 2)
end
end
--- Build an implementation of Lua's @{package} library, and a @{require}
-- function to load modules within it.
--
-- @tparam table env The environment to load packages into.
-- @tparam string dir The directory that relative packages are loaded from.
-- @treturn function The new @{require} function.
-- @treturn table The new @{package} library.
local function make_package(env, dir)
expect(1, env, "table")
expect(2, dir, "string")
local package = {}
package.loaded = {
_G = _G,
bit32 = bit32,
coroutine = coroutine,
math = math,
package = package,
string = string,
table = table,
}
package.path = "?;?.lua;?/init.lua;/rom/modules/main/?;/rom/modules/main/?.lua;/rom/modules/main/?/init.lua"
if turtle then
package.path = package.path .. ";/rom/modules/turtle/?;/rom/modules/turtle/?.lua;/rom/modules/turtle/?/init.lua"
elseif commands then
package.path = package.path .. ";/rom/modules/command/?;/rom/modules/command/?.lua;/rom/modules/command/?/init.lua"
end
package.config = "/\n;\n?\n!\n-"
package.preload = {}
package.loaders = { preload(package), from_file(package, env, dir) }
return make_require(package), package
end
return { make = make_package }

View File

@@ -141,12 +141,12 @@ return {
program = program,
-- Re-export various other functions
help = wrap(help.completeTopic),
choice = wrap(completion.choice),
peripheral = wrap(completion.peripheral),
side = wrap(completion.side),
setting = wrap(completion.setting),
command = wrap(completion.command),
help = wrap(help.completeTopic), --- Wraps @{help.completeTopic} as a @{build} compatible function.
choice = wrap(completion.choice), --- Wraps @{cc.completion.choice} as a @{build} compatible function.
peripheral = wrap(completion.peripheral), --- Wraps @{cc.completion.peripheral} as a @{build} compatible function.
side = wrap(completion.side), --- Wraps @{cc.completion.side} as a @{build} compatible function.
setting = wrap(completion.setting), --- Wraps @{cc.completion.setting} as a @{build} compatible function.
command = wrap(completion.command), --- Wraps @{cc.completion.command} as a @{build} compatible function.
build = build,
}

View File

@@ -1,4 +1,3 @@
if not shell.openTab then
printError("Requires multishell")
return

View File

@@ -1,4 +1,3 @@
if not shell.openTab then
printError("Requires multishell")
return

View File

@@ -1,4 +1,3 @@
local tArgs = { ... }
if #tArgs > 2 then
print("Usage: alias <alias> <program>")

View File

@@ -1,4 +1,3 @@
local tApis = {}
for k, v in pairs(_G) do
if type(k) == "string" and type(v) == "table" and k ~= "_G" then

View File

@@ -1,4 +1,3 @@
local tArgs = { ... }
if #tArgs < 1 then
print("Usage: cd <path>")

View File

@@ -1,4 +1,3 @@
if not commands then
printError("Requires a Command Computer.")
return

View File

@@ -1,4 +1,3 @@
local tArgs = { ... }
if not commands then
printError("Requires a Command Computer.")

View File

@@ -1,4 +1,3 @@
local tArgs = { ... }
if #tArgs < 2 then
print("Usage: cp <source> <destination>")

View File

@@ -9,9 +9,18 @@ for i = 1, args.n do
local files = fs.find(shell.resolve(args[i]))
if #files > 0 then
for _, file in ipairs(files) do
local ok, err = pcall(fs.delete, file)
if not ok then
printError((err:gsub("^pcall: ", "")))
if fs.isReadOnly(file) then
printError("Cannot delete read-only file /" .. file)
elseif fs.isDriveRoot(file) then
printError("Cannot delete mount /" .. file)
if fs.isDir(file) then
print("To delete its contents run rm /" .. fs.combine(file, "*"))
end
else
local ok, err = pcall(fs.delete, file)
if not ok then
printError((err:gsub("^pcall: ", "")))
end
end
end
else

View File

@@ -1,4 +1,3 @@
-- Get arguments
local tArgs = { ... }
if #tArgs == 0 then

View File

@@ -1,4 +1,3 @@
local tBiomes = {
"in a forest",
"in a pine forest",

View File

@@ -1,4 +1,3 @@
-- Display the start screen
local w, h = term.getSize()

View File

@@ -1,4 +1,3 @@
local function printUsage()
print("Usages:")
print("gps host")

View File

@@ -1,4 +1,3 @@
local function printUsage()
print("Usages:")
print("pastebin put <filename>")

View File

@@ -1,4 +1,3 @@
local function printUsage()
print("Usage:")
print("wget <url> [filename]")

View File

@@ -1,4 +1,3 @@
local sDrive = nil
local tArgs = { ... }
if #tArgs > 0 then

View File

@@ -1,4 +1,3 @@
local function printUsage()
print("Usages:")
print("label get")

View File

@@ -1,4 +1,3 @@
local tArgs = { ... }
-- Get all the files in the directory

View File

@@ -1,4 +1,3 @@
local tArgs = { ... }
if #tArgs > 0 then
print("This is an interactive Lua prompt.")
@@ -67,6 +66,13 @@ while bRunning do
if s:match("%S") and tCommandHistory[#tCommandHistory] ~= s then
table.insert(tCommandHistory, s)
end
if settings.get("lua.warn_against_use_of_local") and s:match("^%s*local%s+") then
if term.isColour() then
term.setTextColour(colours.yellow)
end
print("To access local variables in later inputs, remove the local keyword.")
term.setTextColour(colours.white)
end
local nForcePrint = 0
local func, e = load(s, "=lua", "t", tEnv)
@@ -89,7 +95,10 @@ while bRunning do
local n = 1
while n < tResults.n or n <= nForcePrint do
local value = tResults[n + 1]
local ok, serialised = pcall(pretty.pretty, value)
local ok, serialised = pcall(pretty.pretty, value, {
function_args = settings.get("lua.function_args"),
function_source = settings.get("lua.function_source"),
})
if ok then
pretty.print(serialised)
else

View File

@@ -28,7 +28,7 @@ local monitor = peripheral.wrap(sName)
local previousTerm = term.redirect(monitor)
local co = coroutine.create(function()
shell.run(sProgram, table.unpack(tArgs, 3))
(shell.execute or shell.run)(sProgram, table.unpack(tArgs, 3))
end)
local function resume(...)

View File

@@ -1,4 +1,3 @@
local tArgs = { ... }
if #tArgs < 2 then
print("Usage: mv <source> <destination>")
@@ -8,12 +7,35 @@ end
local sSource = shell.resolve(tArgs[1])
local sDest = shell.resolve(tArgs[2])
local tFiles = fs.find(sSource)
local function sanity_checks(source, dest)
if fs.exists(dest) then
printError("Destination exists")
return false
elseif fs.isReadOnly(dest) then
printError("Destination is read-only")
return false
elseif fs.isDriveRoot(source) then
printError("Cannot move mount /" .. source)
return false
elseif fs.isReadOnly(source) then
printError("Cannot move read-only file /" .. source)
return false
end
return true
end
if #tFiles > 0 then
for _, sFile in ipairs(tFiles) do
if fs.isDir(sDest) then
fs.move(sFile, fs.combine(sDest, fs.getName(sFile)))
local dest = fs.combine(sDest, fs.getName(sFile))
if sanity_checks(sFile, dest) then
fs.move(sFile, dest)
end
elseif #tFiles == 1 then
fs.move(sFile, sDest)
if sanity_checks(sFile, sDest) then
fs.move(sFile, sDest)
end
else
printError("Cannot overwrite file multiple times")
return

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