mirror of
https://github.com/SquidDev-CC/CC-Tweaked
synced 2024-12-14 12:10:30 +00:00
Merge branch 'mc-1.16.x' into mc-1.17.x
This commit is contained in:
commit
f794ce42ab
@ -174,7 +174,7 @@ dependencies {
|
|||||||
testModImplementation sourceSets.main.output
|
testModImplementation sourceSets.main.output
|
||||||
testModExtra 'org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.5.21'
|
testModExtra 'org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.5.21'
|
||||||
|
|
||||||
cctJavadoc 'cc.tweaked:cct-javadoc:1.4.4'
|
cctJavadoc 'cc.tweaked:cct-javadoc:1.4.5'
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compile tasks
|
// Compile tasks
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
module: [kind=event] modem_message
|
module: [kind=event] modem_message
|
||||||
---
|
---
|
||||||
|
|
||||||
The @{modem_message} event is fired when a message is received on an open channel on any modem.
|
The @{modem_message} event is fired when a message is received on an open channel on any @{modem}.
|
||||||
|
|
||||||
## Return Values
|
## Return Values
|
||||||
1. @{string}: The event name.
|
1. @{string}: The event name.
|
||||||
@ -10,11 +10,15 @@ The @{modem_message} event is fired when a message is received on an open channe
|
|||||||
3. @{number}: The channel that the message was sent on.
|
3. @{number}: The channel that the message was sent on.
|
||||||
4. @{number}: The reply channel set by the sender.
|
4. @{number}: The reply channel set by the sender.
|
||||||
5. @{any}: The message as sent by the sender.
|
5. @{any}: The message as sent by the sender.
|
||||||
6. @{number}: The distance between the sender and the receiver, in blocks (decimal).
|
6. @{number}: The distance between the sender and the receiver, in blocks.
|
||||||
|
|
||||||
## Example
|
## Example
|
||||||
Prints a message when one is sent:
|
Wraps a @{modem} peripheral, opens channel 0 for listening, and prints all received messages.
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
|
local modem = peripheral.find("modem") or error("No modem attached", 0)
|
||||||
|
modem.open(0)
|
||||||
|
|
||||||
while true do
|
while true do
|
||||||
local event, side, channel, replyChannel, message, distance = os.pullEvent("modem_message")
|
local event, side, channel, replyChannel, message, distance = os.pullEvent("modem_message")
|
||||||
print(("Message received on side %s on channel %d (reply to %d) from %f blocks away with message %s"):format(side, channel, replyChannel, distance, tostring(message)))
|
print(("Message received on side %s on channel %d (reply to %d) from %f blocks away with message %s"):format(side, channel, replyChannel, distance, tostring(message)))
|
||||||
|
83
doc/guides/using_require.md
Normal file
83
doc/guides/using_require.md
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
---
|
||||||
|
module: [kind=guide] using_require
|
||||||
|
---
|
||||||
|
|
||||||
|
# Reusing code with require
|
||||||
|
A library is a collection of useful functions and other definitions which is stored separately to your main program. You
|
||||||
|
might want to create a library because you have some functions which are used in multiple programs, or just to split
|
||||||
|
your program into multiple more modular files.
|
||||||
|
|
||||||
|
Let's say we want to create a small library to make working with the @{term|terminal} a little easier. We'll provide two
|
||||||
|
functions: `reset`, which clears the terminal and sets the cursor to (1, 1), and `write_center`, which prints some text
|
||||||
|
in the middle of the screen.
|
||||||
|
|
||||||
|
Start off by creating a file called `more_term.lua`:
|
||||||
|
|
||||||
|
```lua {data-snippet=more_term}
|
||||||
|
local function reset()
|
||||||
|
term.clear()
|
||||||
|
term.setCursorPos(1, 1)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function write_center(text)
|
||||||
|
local x, y = term.getCursorPos()
|
||||||
|
local width, height = term.getSize()
|
||||||
|
term.setCursorPos(math.floor((width - #text) / 2) + 1, y)
|
||||||
|
term.write(text)
|
||||||
|
end
|
||||||
|
|
||||||
|
return { reset = reset, write_center = write_center }
|
||||||
|
```
|
||||||
|
|
||||||
|
Now, what's going on here? We define our two functions as one might expect, and then at the bottom return a table with
|
||||||
|
the two functions. When we require this library, this table is what is returned. With that, we can then call the
|
||||||
|
original functions. Now create a new file, with the following:
|
||||||
|
|
||||||
|
```lua {data-mount=more_term:more_term.lua}
|
||||||
|
local more_term = require("more_term")
|
||||||
|
more_term.reset()
|
||||||
|
more_term.write_center("Hello, world!")
|
||||||
|
```
|
||||||
|
|
||||||
|
When run, this'll clear the screen and print some text in the middle of the first line.
|
||||||
|
|
||||||
|
## require in depth
|
||||||
|
While the previous section is a good introduction to how @{require} operates, there are a couple of remaining points
|
||||||
|
which are worth mentioning for more advanced usage.
|
||||||
|
|
||||||
|
### Libraries can return anything
|
||||||
|
In our above example, we return a table containing the functions we want to expose. However, it's worth pointing out
|
||||||
|
that you can return ''anything'' from your library - a table, a function or even just a string! @{require} treats them
|
||||||
|
all the same, and just returns whatever your library provides.
|
||||||
|
|
||||||
|
### Module resolution and the package path
|
||||||
|
In the above examples, we defined our library in a file, and @{require} read from it. While this is what you'll do most
|
||||||
|
of the time, it is possible to make @{require} look elsewhere for your library, such as downloading from a website or
|
||||||
|
loading from an in-memory library store.
|
||||||
|
|
||||||
|
As a result, the *module name* you pass to @{require} doesn't correspond to a file path. One common mistake is to load
|
||||||
|
code from a sub-directory using `require("folder/library")` or even `require("folder/library.lua")`, neither of which
|
||||||
|
will do quite what you expect.
|
||||||
|
|
||||||
|
When loading libraries (also referred to as *modules*) from files, @{require} searches along the *@{package.path|module
|
||||||
|
path}*. By default, this looks something like:
|
||||||
|
|
||||||
|
* `?.lua`
|
||||||
|
* `?/init.lua`
|
||||||
|
* `/rom/modules/main/?.lua`
|
||||||
|
* etc...
|
||||||
|
|
||||||
|
When you call `require("my_library")`, @{require} replaces the `?` in each element of the path with your module name, and
|
||||||
|
checks if the file exists. In this case, we'd look for `my_library.lua`, `my_library/init.lua`,
|
||||||
|
`/rom/modules/main/my_library.lua` and so on. Note that this works *relative to the current program*, so if your
|
||||||
|
program is actually called `folder/program`, then we'll look for `folder/my_library.lua`, etc...
|
||||||
|
|
||||||
|
One other caveat is loading libraries from sub-directories. For instance, say we have a file
|
||||||
|
`my/fancy/library.lua`. This can be loaded by using `require("my.fancy.library")` - the '.'s are replaced with '/'
|
||||||
|
before we start looking for the library.
|
||||||
|
|
||||||
|
## External links
|
||||||
|
There are several external resources which go into require in a little more detail:
|
||||||
|
|
||||||
|
- The [Lua Module tutorial](http://lua-users.org/wiki/ModulesTutorial) on the Lua wiki.
|
||||||
|
- [Lua's manual section on @{require}](https://www.lua.org/manual/5.1/manual.html#pdf-require).
|
@ -12,16 +12,19 @@ rounded up to the nearest multiple of 0.05 seconds. If you are using coroutines
|
|||||||
or the @{parallel|parallel API}, it will only pause execution of the current
|
or the @{parallel|parallel API}, it will only pause execution of the current
|
||||||
thread, not the whole program.
|
thread, not the whole program.
|
||||||
|
|
||||||
**Note** Because sleep internally uses timers, it is a function that yields.
|
:::tip
|
||||||
This means that you can use it to prevent "Too long without yielding" errors,
|
Because sleep internally uses timers, it is a function that yields. This means
|
||||||
however, as the minimum sleep time is 0.05 seconds, it will slow your program
|
that you can use it to prevent "Too long without yielding" errors, however, as
|
||||||
down.
|
the minimum sleep time is 0.05 seconds, it will slow your program down.
|
||||||
|
:::
|
||||||
|
|
||||||
**Warning** Internally, this function queues and waits for a timer event (using
|
:::caution
|
||||||
|
Internally, this function queues and waits for a timer event (using
|
||||||
@{os.startTimer}), however it does not listen for any other events. This means
|
@{os.startTimer}), however it does not listen for any other events. This means
|
||||||
that any event that occurs while sleeping will be entirely discarded. If you
|
that any event that occurs while sleeping will be entirely discarded. If you
|
||||||
need to receive events while sleeping, consider using @{os.startTimer|timers},
|
need to receive events while sleeping, consider using @{os.startTimer|timers},
|
||||||
or the @{parallel|parallel API}.
|
or the @{parallel|parallel API}.
|
||||||
|
:::
|
||||||
|
|
||||||
@tparam number time The number of seconds to sleep for, rounded up to the
|
@tparam number time The number of seconds to sleep for, rounded up to the
|
||||||
nearest multiple of 0.05.
|
nearest multiple of 0.05.
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
org.gradle.jvmargs=-Xmx3G
|
org.gradle.jvmargs=-Xmx3G
|
||||||
|
|
||||||
# Mod properties
|
# Mod properties
|
||||||
mod_version=1.99.1
|
mod_version=1.100.0
|
||||||
|
|
||||||
# Minecraft properties (update mods.toml when changing)
|
# Minecraft properties (update mods.toml when changing)
|
||||||
mc_version=1.17.1
|
mc_version=1.17.1
|
||||||
|
@ -5,9 +5,8 @@
|
|||||||
*/
|
*/
|
||||||
package dan200.computercraft.api.lua;
|
package dan200.computercraft.api.lua;
|
||||||
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import static dan200.computercraft.api.lua.LuaValues.*;
|
import static dan200.computercraft.api.lua.LuaValues.*;
|
||||||
|
@ -115,7 +115,9 @@ class DfpwmStream implements AudioStream
|
|||||||
}
|
}
|
||||||
|
|
||||||
result.flip();
|
result.flip();
|
||||||
return result;
|
|
||||||
|
// This is naughty, but ensures we're not enqueuing empty buffers when the stream is exhausted.
|
||||||
|
return result.remaining() == 0 ? null : result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -123,4 +125,9 @@ class DfpwmStream implements AudioStream
|
|||||||
{
|
{
|
||||||
buffers.clear();
|
buffers.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isEmpty()
|
||||||
|
{
|
||||||
|
return buffers.isEmpty();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,8 +27,20 @@ public class SpeakerInstance
|
|||||||
|
|
||||||
public synchronized void pushAudio( ByteBuf buffer )
|
public synchronized void pushAudio( ByteBuf buffer )
|
||||||
{
|
{
|
||||||
if( currentStream == null ) currentStream = new DfpwmStream();
|
SpeakerSound sound = this.sound;
|
||||||
|
|
||||||
|
DfpwmStream stream = currentStream;
|
||||||
|
if( stream == null ) stream = currentStream = new DfpwmStream();
|
||||||
|
boolean exhausted = stream.isEmpty();
|
||||||
currentStream.push( buffer );
|
currentStream.push( buffer );
|
||||||
|
|
||||||
|
// If we've got nothing left in the buffer, enqueue an additional one just in case.
|
||||||
|
if( exhausted && sound != null && sound.stream == stream && sound.channel != null )
|
||||||
|
{
|
||||||
|
sound.executor.execute( () -> {
|
||||||
|
if( !sound.channel.stopped() ) sound.channel.pumpBuffers( 1 );
|
||||||
|
} );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void playAudio( Vec3 position, float volume )
|
public void playAudio( Vec3 position, float volume )
|
||||||
|
@ -26,12 +26,14 @@ public class SpeakerManager
|
|||||||
@SubscribeEvent
|
@SubscribeEvent
|
||||||
public static void playStreaming( PlayStreamingSourceEvent event )
|
public static void playStreaming( PlayStreamingSourceEvent event )
|
||||||
{
|
{
|
||||||
if( !(event.getSound() instanceof SpeakerSound) ) return;
|
if( !(event.getSound() instanceof SpeakerSound sound) ) return;
|
||||||
SpeakerSound sound = (SpeakerSound) event.getSound();
|
|
||||||
if( sound.stream == null ) return;
|
if( sound.stream == null ) return;
|
||||||
|
|
||||||
event.getSource().attachBufferStream( sound.stream );
|
event.getSource().attachBufferStream( sound.stream );
|
||||||
event.getSource().play();
|
event.getSource().play();
|
||||||
|
|
||||||
|
sound.channel = event.getSource();
|
||||||
|
sound.executor = event.getManager().executor;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static SpeakerInstance getSound( UUID source )
|
public static SpeakerInstance getSound( UUID source )
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
package dan200.computercraft.client.sound;
|
package dan200.computercraft.client.sound;
|
||||||
|
|
||||||
|
import com.mojang.blaze3d.audio.Channel;
|
||||||
import net.minecraft.client.resources.sounds.AbstractSoundInstance;
|
import net.minecraft.client.resources.sounds.AbstractSoundInstance;
|
||||||
import net.minecraft.client.resources.sounds.TickableSoundInstance;
|
import net.minecraft.client.resources.sounds.TickableSoundInstance;
|
||||||
import net.minecraft.client.sounds.AudioStream;
|
import net.minecraft.client.sounds.AudioStream;
|
||||||
@ -13,9 +14,12 @@ import net.minecraft.sounds.SoundSource;
|
|||||||
import net.minecraft.world.phys.Vec3;
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
|
|
||||||
public class SpeakerSound extends AbstractSoundInstance implements TickableSoundInstance
|
public class SpeakerSound extends AbstractSoundInstance implements TickableSoundInstance
|
||||||
{
|
{
|
||||||
|
Channel channel;
|
||||||
|
Executor executor;
|
||||||
DfpwmStream stream;
|
DfpwmStream stream;
|
||||||
|
|
||||||
SpeakerSound( ResourceLocation sound, DfpwmStream stream, Vec3 position, float volume, float pitch )
|
SpeakerSound( ResourceLocation sound, DfpwmStream stream, Vec3 position, float volume, float pitch )
|
||||||
|
@ -30,7 +30,36 @@ import java.util.OptionalLong;
|
|||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The FS API allows you to manipulate files and the filesystem.
|
* The FS API provides access to the computer's files and filesystem, allowing you to manipulate files, directories and
|
||||||
|
* paths. This includes:
|
||||||
|
*
|
||||||
|
* <ul>
|
||||||
|
* <li>**Reading and writing files:** Call {@link #open} to obtain a file "handle", which can be used to read from or
|
||||||
|
* write to a file.</li>
|
||||||
|
* <li>**Path manipulation:** {@link #combine}, {@link #getName} and {@link #getDir} allow you to manipulate file
|
||||||
|
* paths, joining them together or extracting components.</li>
|
||||||
|
* <li>**Querying paths:** For instance, checking if a file exists, or whether it's a directory. See {@link #getSize},
|
||||||
|
* {@link #exists}, {@link #isDir}, {@link #isReadOnly} and {@link #attributes}.</li>
|
||||||
|
* <li>**File and directory manipulation:** For instance, moving or copying files. See {@link #makeDir}, {@link #move},
|
||||||
|
* {@link #copy} and {@link #delete}.</li>
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* :::note
|
||||||
|
* All functions in the API work on absolute paths, and do not take the @{shell.dir|current directory} into account.
|
||||||
|
* You can use @{shell.resolve} to convert a relative path into an absolute one.
|
||||||
|
* :::
|
||||||
|
*
|
||||||
|
* ## Mounts
|
||||||
|
* While a computer can only have one hard drive and filesystem, other filesystems may be "mounted" inside it. For
|
||||||
|
* instance, the {@link dan200.computercraft.shared.peripheral.diskdrive.DiskDrivePeripheral drive peripheral} mounts
|
||||||
|
* its disk's contents at {@code "disk/"}, {@code "disk1/"}, etc...
|
||||||
|
*
|
||||||
|
* You can see which mount a path belongs to with the {@link #getDrive} function. This returns {@code "hdd"} for the
|
||||||
|
* computer's main filesystem ({@code "/"}), {@code "rom"} for the rom ({@code "rom/"}).
|
||||||
|
*
|
||||||
|
* Most filesystems have a limited capacity, operations which would cause that capacity to be reached (such as writing
|
||||||
|
* an incredibly large file) will fail. You can see a mount's capacity with {@link #getCapacity} and the remaining
|
||||||
|
* space with {@link #getFreeSpace}.
|
||||||
*
|
*
|
||||||
* @cc.module fs
|
* @cc.module fs
|
||||||
*/
|
*/
|
||||||
@ -440,6 +469,12 @@ public class FSAPI implements ILuaAPI
|
|||||||
* @return The name of the drive that the file is on; e.g. {@code hdd} for local files, or {@code rom} for ROM files.
|
* @return The name of the drive that the file is on; e.g. {@code hdd} for local files, or {@code rom} for ROM files.
|
||||||
* @throws LuaException If the path doesn't exist.
|
* @throws LuaException If the path doesn't exist.
|
||||||
* @cc.treturn string The name of the drive that the file is on; e.g. {@code hdd} for local files, or {@code rom} for ROM files.
|
* @cc.treturn string The name of the drive that the file is on; e.g. {@code hdd} for local files, or {@code rom} for ROM files.
|
||||||
|
* @cc.usage Print the drives of a couple of mounts:
|
||||||
|
*
|
||||||
|
* <pre>{@code
|
||||||
|
* print("/: " .. fs.getDrive("/"))
|
||||||
|
* print("/rom/: " .. fs.getDrive("rom"))
|
||||||
|
* }</pre>
|
||||||
*/
|
*/
|
||||||
@LuaFunction
|
@LuaFunction
|
||||||
public final Object[] getDrive( String path ) throws LuaException
|
public final Object[] getDrive( String path ) throws LuaException
|
||||||
|
@ -22,7 +22,7 @@ import dan200.computercraft.core.computer.ComputerSide;
|
|||||||
* as those from Project:Red. These allow you to send 16 separate on/off signals. Each channel corresponds to a
|
* 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}.
|
* colour, with the first being @{colors.white} and the last @{colors.black}.
|
||||||
*
|
*
|
||||||
* Whenever a redstone input changes, a {@code redstone} event will be fired. This may be used instead of repeativly
|
* Whenever a redstone input changes, a @{event!redstone} event will be fired. This may be used instead of repeativly
|
||||||
* polling.
|
* polling.
|
||||||
*
|
*
|
||||||
* This module may also be referred to as {@code rs}. For example, one may call {@code rs.getSides()} instead of
|
* This module may also be referred to as {@code rs}. For example, one may call {@code rs.getSides()} instead of
|
||||||
|
@ -19,10 +19,10 @@ import javax.annotation.Nonnull;
|
|||||||
*
|
*
|
||||||
* This works with energy storage blocks, as well as generators and machines which consume energy.
|
* This works with energy storage blocks, as well as generators and machines which consume energy.
|
||||||
*
|
*
|
||||||
* <blockquote>
|
* :::note
|
||||||
* <strong>Note:</strong> Due to limitations with Forge's energy API, it is not possible to measure throughput (i.e. RF
|
* Due to limitations with Forge's energy API, it is not possible to measure throughput (i.e. RF
|
||||||
* used/generated per tick).
|
* used/generated per tick).
|
||||||
* </blockquote>
|
* :::
|
||||||
*
|
*
|
||||||
* @cc.module energy_storage
|
* @cc.module energy_storage
|
||||||
*/
|
*/
|
||||||
|
@ -21,9 +21,60 @@ import java.util.HashSet;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The modem peripheral allows you to send messages between computers.
|
* Modems allow you to send messages between computers over long distances.
|
||||||
|
*
|
||||||
|
* :::tip
|
||||||
|
* Modems provide a fairly basic set of methods, which makes them very flexible but often hard to work with. The
|
||||||
|
* {@literal @}{rednet} API is built on top of modems, and provides a more user-friendly interface.
|
||||||
|
* :::
|
||||||
|
*
|
||||||
|
* ## Sending and receiving messages
|
||||||
|
* Modems operate on a series of channels, a bit like frequencies on a radio. Any modem can send a message on a
|
||||||
|
* particular channel, but only those which have {@link #open opened} the channel and are "listening in" can receive
|
||||||
|
* messages.
|
||||||
|
*
|
||||||
|
* Channels are represented as an integer between 0 and 65535 inclusive. These channels don't have any defined meaning,
|
||||||
|
* though some APIs or programs will assign a meaning to them. For instance, the @{gps} module sends all its messages on
|
||||||
|
* channel 65534 (@{gps.CHANNEL_GPS}), while @{rednet} uses channels equal to the computer's ID.
|
||||||
|
*
|
||||||
|
* - Sending messages is done with the {@link #transmit(int, int, Object)} message.
|
||||||
|
* - Receiving messages is done by listening to the @{modem_message} event.
|
||||||
|
*
|
||||||
|
* ## Types of modem
|
||||||
|
* CC: Tweaked comes with three kinds of modem, with different capabilities.
|
||||||
|
*
|
||||||
|
* <ul>
|
||||||
|
* <li><strong>Wireless modems:</strong> Wireless modems can send messages to any other wireless modem. They can be placed next to a
|
||||||
|
* computer, or equipped as a pocket computer or turtle upgrade.
|
||||||
|
*
|
||||||
|
* Wireless modems have a limited range, only sending messages to modems within 64 blocks. This range increases
|
||||||
|
* linearly once the modem is above y=96, to a maximum of 384 at world height.</li>
|
||||||
|
* <li><strong>Ender modems:</strong> These are upgraded versions of normal wireless modems. They do not have a distance
|
||||||
|
* limit, and can send messages between dimensions.</li>
|
||||||
|
* <li><strong>Wired modems:</strong> These send messages to other any other wired modems connected to the same network
|
||||||
|
* (using <em>Networking Cable</em>). They also can be used to attach additional peripherals to a computer.</li></ul>
|
||||||
*
|
*
|
||||||
* @cc.module modem
|
* @cc.module modem
|
||||||
|
* @cc.see modem_message Queued when a modem receives a message on an {@link #open(int) open channel}.
|
||||||
|
* @cc.see rednet A networking API built on top of the modem peripheral.
|
||||||
|
* @cc.usage Wrap a modem and a message on channel 15, requesting a response on channel 43. Then wait for a message to
|
||||||
|
* arrive on channel 43 and print it.
|
||||||
|
*
|
||||||
|
* <pre>{@code
|
||||||
|
* local modem = peripheral.find("modem") or error("No modem attached", 0)
|
||||||
|
* modem.open(43) -- Open 43 so we can receive replies
|
||||||
|
*
|
||||||
|
* -- Send our message
|
||||||
|
* modem.transmit(15, 43, "Hello, world!")
|
||||||
|
*
|
||||||
|
* -- And wait for a reply
|
||||||
|
* local event, side, channel, replyChannel, message, distance
|
||||||
|
* repeat
|
||||||
|
* event, side, channel, replyChannel, message, distance = os.pullEvent("modem_message")
|
||||||
|
* until channel == 43
|
||||||
|
*
|
||||||
|
* print("Received a reply: " .. tostring(message))
|
||||||
|
* }</pre>
|
||||||
*/
|
*/
|
||||||
public abstract class ModemPeripheral implements IPeripheral, IPacketSender, IPacketReceiver
|
public abstract class ModemPeripheral implements IPeripheral, IPacketSender, IPacketReceiver
|
||||||
{
|
{
|
||||||
@ -157,12 +208,23 @@ public abstract class ModemPeripheral implements IPeripheral, IPacketSender, IPa
|
|||||||
* Sends a modem message on a certain channel. Modems listening on the channel will queue a {@code modem_message}
|
* Sends a modem message on a certain channel. Modems listening on the channel will queue a {@code modem_message}
|
||||||
* event on adjacent computers.
|
* event on adjacent computers.
|
||||||
*
|
*
|
||||||
* <blockquote><strong>Note:</strong> The channel does not need be open to send a message.</blockquote>
|
* :::note
|
||||||
|
* The channel does not need be open to send a message.
|
||||||
|
* :::
|
||||||
*
|
*
|
||||||
* @param channel The channel to send messages on.
|
* @param channel The channel to send messages on.
|
||||||
* @param replyChannel The channel that responses to this message should be sent on.
|
* @param replyChannel The channel that responses to this message should be sent on. This can be the same as
|
||||||
* @param payload The object to send. This can be a boolean, string, number, or table.
|
* {@code channel} or entirely different. The channel must have been {@link #open opened} on
|
||||||
|
* the sending computer in order to receive the replies.
|
||||||
|
* @param payload The object to send. This can be any primitive type (boolean, number, string) as well as
|
||||||
|
* tables. Other types (like functions), as well as metatables, will not be transmitted.
|
||||||
* @throws LuaException If the channel is out of range.
|
* @throws LuaException If the channel is out of range.
|
||||||
|
* @cc.usage Wrap a modem and a message on channel 15, requesting a response on channel 43.
|
||||||
|
*
|
||||||
|
* <pre>{@code
|
||||||
|
* local modem = peripheral.find("modem") or error("No modem attached", 0)
|
||||||
|
* modem.transmit(15, 43, "Hello, world!")
|
||||||
|
* }</pre>
|
||||||
*/
|
*/
|
||||||
@LuaFunction
|
@LuaFunction
|
||||||
public final void transmit( int channel, int replyChannel, Object payload ) throws LuaException
|
public final void transmit( int channel, int replyChannel, Object payload ) throws LuaException
|
||||||
|
@ -80,8 +80,9 @@ public abstract class WiredModemPeripheral extends ModemPeripheral implements IW
|
|||||||
* If this computer is attached to the network, it _will not_ be included in
|
* If this computer is attached to the network, it _will not_ be included in
|
||||||
* this list.
|
* this list.
|
||||||
*
|
*
|
||||||
* <blockquote><strong>Important:</strong> This function only appears on wired modems. Check {@link #isWireless}
|
* :::note
|
||||||
* returns false before calling it.</blockquote>
|
* This function only appears on wired modems. Check {@link #isWireless} returns false before calling it.
|
||||||
|
* :::
|
||||||
*
|
*
|
||||||
* @param computer The calling computer.
|
* @param computer The calling computer.
|
||||||
* @return Remote peripheral names on the network.
|
* @return Remote peripheral names on the network.
|
||||||
@ -95,8 +96,9 @@ public abstract class WiredModemPeripheral extends ModemPeripheral implements IW
|
|||||||
/**
|
/**
|
||||||
* Determine if a peripheral is available on this wired network.
|
* Determine if a peripheral is available on this wired network.
|
||||||
*
|
*
|
||||||
* <blockquote><strong>Important:</strong> This function only appears on wired modems. Check {@link #isWireless}
|
* :::note
|
||||||
* returns false before calling it.</blockquote>
|
* This function only appears on wired modems. Check {@link #isWireless} returns false before calling it.
|
||||||
|
* :::
|
||||||
*
|
*
|
||||||
* @param computer The calling computer.
|
* @param computer The calling computer.
|
||||||
* @param name The peripheral's name.
|
* @param name The peripheral's name.
|
||||||
@ -112,8 +114,9 @@ public abstract class WiredModemPeripheral extends ModemPeripheral implements IW
|
|||||||
/**
|
/**
|
||||||
* Get the type of a peripheral is available on this wired network.
|
* Get the type of a peripheral is available on this wired network.
|
||||||
*
|
*
|
||||||
* <blockquote><strong>Important:</strong> This function only appears on wired modems. Check {@link #isWireless}
|
* :::note
|
||||||
* returns false before calling it.</blockquote>
|
* This function only appears on wired modems. Check {@link #isWireless} returns false before calling it.
|
||||||
|
* :::
|
||||||
*
|
*
|
||||||
* @param computer The calling computer.
|
* @param computer The calling computer.
|
||||||
* @param name The peripheral's name.
|
* @param name The peripheral's name.
|
||||||
@ -132,8 +135,9 @@ public abstract class WiredModemPeripheral extends ModemPeripheral implements IW
|
|||||||
/**
|
/**
|
||||||
* Check a peripheral is of a particular type.
|
* Check a peripheral is of a particular type.
|
||||||
*
|
*
|
||||||
* <blockquote><strong>Important:</strong> This function only appears on wired modems. Check {@link #isWireless}
|
* :::note
|
||||||
* returns false before calling it.</blockquote>
|
* This function only appears on wired modems. Check {@link #isWireless} returns false before calling it.
|
||||||
|
* :::
|
||||||
*
|
*
|
||||||
* @param computer The calling computer.
|
* @param computer The calling computer.
|
||||||
* @param name The peripheral's name.
|
* @param name The peripheral's name.
|
||||||
@ -153,8 +157,9 @@ public abstract class WiredModemPeripheral extends ModemPeripheral implements IW
|
|||||||
/**
|
/**
|
||||||
* Get all available methods for the remote peripheral with the given name.
|
* Get all available methods for the remote peripheral with the given name.
|
||||||
*
|
*
|
||||||
* <blockquote><strong>Important:</strong> This function only appears on wired modems. Check {@link #isWireless}
|
* :::note
|
||||||
* returns false before calling it.</blockquote>
|
* This function only appears on wired modems. Check {@link #isWireless} returns false before calling it.
|
||||||
|
* :::
|
||||||
*
|
*
|
||||||
* @param computer The calling computer.
|
* @param computer The calling computer.
|
||||||
* @param name The peripheral's name.
|
* @param name The peripheral's name.
|
||||||
@ -174,8 +179,9 @@ public abstract class WiredModemPeripheral extends ModemPeripheral implements IW
|
|||||||
/**
|
/**
|
||||||
* Call a method on a peripheral on this wired network.
|
* Call a method on a peripheral on this wired network.
|
||||||
*
|
*
|
||||||
* <blockquote><strong>Important:</strong> This function only appears on wired modems. Check {@link #isWireless}
|
* :::note
|
||||||
* returns false before calling it.</blockquote>
|
* This function only appears on wired modems. Check {@link #isWireless} returns false before calling it.
|
||||||
|
* :::
|
||||||
*
|
*
|
||||||
* @param computer The calling computer.
|
* @param computer The calling computer.
|
||||||
* @param context The Lua context we're executing in.
|
* @param context The Lua context we're executing in.
|
||||||
@ -204,8 +210,9 @@ public abstract class WiredModemPeripheral extends ModemPeripheral implements IW
|
|||||||
* may be used by other computers on the network to wrap this computer as a
|
* may be used by other computers on the network to wrap this computer as a
|
||||||
* peripheral.
|
* peripheral.
|
||||||
*
|
*
|
||||||
* <blockquote><strong>Important:</strong> This function only appears on wired modems. Check {@link #isWireless}
|
* :::note
|
||||||
* returns false before calling it.</blockquote>
|
* This function only appears on wired modems. Check {@link #isWireless} returns false before calling it.
|
||||||
|
* :::
|
||||||
*
|
*
|
||||||
* @return The current computer's name.
|
* @return The current computer's name.
|
||||||
* @cc.treturn string|nil The current computer's name on the wired network.
|
* @cc.treturn string|nil The current computer's name on the wired network.
|
||||||
|
@ -7,6 +7,7 @@ package dan200.computercraft.shared.peripheral.speaker;
|
|||||||
|
|
||||||
import dan200.computercraft.api.lua.LuaException;
|
import dan200.computercraft.api.lua.LuaException;
|
||||||
import dan200.computercraft.api.lua.LuaTable;
|
import dan200.computercraft.api.lua.LuaTable;
|
||||||
|
import dan200.computercraft.shared.util.PauseAwareTimer;
|
||||||
import net.minecraft.util.Mth;
|
import net.minecraft.util.Mth;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
@ -27,7 +28,7 @@ class DfpwmState
|
|||||||
* The minimum size of the client's audio buffer. Once we have less than this on the client, we should send another
|
* The minimum size of the client's audio buffer. Once we have less than this on the client, we should send another
|
||||||
* batch of audio.
|
* batch of audio.
|
||||||
*/
|
*/
|
||||||
private static final long CLIENT_BUFFER = (long) (SECOND * 1.5);
|
private static final long CLIENT_BUFFER = (long) (SECOND * 0.5);
|
||||||
|
|
||||||
private static final int PREC = 10;
|
private static final int PREC = 10;
|
||||||
|
|
||||||
@ -36,7 +37,7 @@ class DfpwmState
|
|||||||
private boolean previousBit = false;
|
private boolean previousBit = false;
|
||||||
|
|
||||||
private boolean unplayed = true;
|
private boolean unplayed = true;
|
||||||
private long clientEndTime = System.nanoTime();
|
private long clientEndTime = PauseAwareTimer.getTime();
|
||||||
private float pendingVolume = 1.0f;
|
private float pendingVolume = 1.0f;
|
||||||
private ByteBuffer pendingAudio;
|
private ByteBuffer pendingAudio;
|
||||||
|
|
||||||
@ -107,7 +108,7 @@ class DfpwmState
|
|||||||
|
|
||||||
boolean isPlaying()
|
boolean isPlaying()
|
||||||
{
|
{
|
||||||
return unplayed || clientEndTime >= System.nanoTime();
|
return unplayed || clientEndTime >= PauseAwareTimer.getTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
float getVolume()
|
float getVolume()
|
||||||
|
@ -17,6 +17,7 @@ import dan200.computercraft.shared.network.client.SpeakerAudioClientMessage;
|
|||||||
import dan200.computercraft.shared.network.client.SpeakerMoveClientMessage;
|
import dan200.computercraft.shared.network.client.SpeakerMoveClientMessage;
|
||||||
import dan200.computercraft.shared.network.client.SpeakerPlayClientMessage;
|
import dan200.computercraft.shared.network.client.SpeakerPlayClientMessage;
|
||||||
import dan200.computercraft.shared.network.client.SpeakerStopClientMessage;
|
import dan200.computercraft.shared.network.client.SpeakerStopClientMessage;
|
||||||
|
import dan200.computercraft.shared.util.PauseAwareTimer;
|
||||||
import net.minecraft.ResourceLocationException;
|
import net.minecraft.ResourceLocationException;
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.network.protocol.game.ClientboundCustomSoundPacket;
|
import net.minecraft.network.protocol.game.ClientboundCustomSoundPacket;
|
||||||
@ -119,7 +120,7 @@ public abstract class SpeakerPeripheral implements IPeripheral
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
long now = System.nanoTime();
|
long now = PauseAwareTimer.getTime();
|
||||||
if( sound != null )
|
if( sound != null )
|
||||||
{
|
{
|
||||||
lastPlayTime = clock;
|
lastPlayTime = clock;
|
||||||
@ -342,7 +343,7 @@ public abstract class SpeakerPeripheral implements IPeripheral
|
|||||||
// TODO: Use ArgumentHelpers instead?
|
// TODO: Use ArgumentHelpers instead?
|
||||||
int length = audio.length();
|
int length = audio.length();
|
||||||
if( length <= 0 ) throw new LuaException( "Cannot play empty audio" );
|
if( length <= 0 ) throw new LuaException( "Cannot play empty audio" );
|
||||||
if( length > 1024 * 16 * 8 ) throw new LuaException( "Audio data is too large" );
|
if( length > 128 * 1024 ) throw new LuaException( "Audio data is too large" );
|
||||||
|
|
||||||
DfpwmState state;
|
DfpwmState state;
|
||||||
synchronized( lock )
|
synchronized( lock )
|
||||||
@ -387,17 +388,7 @@ public abstract class SpeakerPeripheral implements IPeripheral
|
|||||||
computers.remove( computer );
|
computers.remove( computer );
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final class PendingSound
|
private record PendingSound(ResourceLocation location, float volume, float pitch)
|
||||||
{
|
{
|
||||||
final ResourceLocation location;
|
|
||||||
final float volume;
|
|
||||||
final float pitch;
|
|
||||||
|
|
||||||
private PendingSound( ResourceLocation location, float volume, float pitch )
|
|
||||||
{
|
|
||||||
this.location = location;
|
|
||||||
this.volume = volume;
|
|
||||||
this.pitch = pitch;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,6 @@ import dan200.computercraft.shared.common.IColouredItem;
|
|||||||
import dan200.computercraft.shared.computer.core.ClientComputer;
|
import dan200.computercraft.shared.computer.core.ClientComputer;
|
||||||
import dan200.computercraft.shared.computer.core.ComputerFamily;
|
import dan200.computercraft.shared.computer.core.ComputerFamily;
|
||||||
import dan200.computercraft.shared.computer.core.ComputerState;
|
import dan200.computercraft.shared.computer.core.ComputerState;
|
||||||
import dan200.computercraft.shared.computer.core.ServerComputer;
|
|
||||||
import dan200.computercraft.shared.computer.items.IComputerItem;
|
import dan200.computercraft.shared.computer.items.IComputerItem;
|
||||||
import dan200.computercraft.shared.network.container.ComputerContainerData;
|
import dan200.computercraft.shared.network.container.ComputerContainerData;
|
||||||
import dan200.computercraft.shared.pocket.apis.PocketAPI;
|
import dan200.computercraft.shared.pocket.apis.PocketAPI;
|
||||||
@ -34,6 +33,7 @@ import net.minecraft.world.InteractionHand;
|
|||||||
import net.minecraft.world.InteractionResult;
|
import net.minecraft.world.InteractionResult;
|
||||||
import net.minecraft.world.InteractionResultHolder;
|
import net.minecraft.world.InteractionResultHolder;
|
||||||
import net.minecraft.world.entity.Entity;
|
import net.minecraft.world.entity.Entity;
|
||||||
|
import net.minecraft.world.entity.item.ItemEntity;
|
||||||
import net.minecraft.world.entity.player.Player;
|
import net.minecraft.world.entity.player.Player;
|
||||||
import net.minecraft.world.item.CreativeModeTab;
|
import net.minecraft.world.item.CreativeModeTab;
|
||||||
import net.minecraft.world.item.Item;
|
import net.minecraft.world.item.Item;
|
||||||
@ -80,53 +80,65 @@ public class ItemPocketComputer extends Item implements IComputerItem, IMedia, I
|
|||||||
PocketUpgrades.getVanillaUpgrades().map( x -> create( -1, null, -1, x ) ).forEach( stacks::add );
|
PocketUpgrades.getVanillaUpgrades().map( x -> create( -1, null, -1, x ) ).forEach( stacks::add );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean tick( @Nonnull ItemStack stack, @Nonnull Level world, @Nonnull Entity entity, @Nonnull PocketServerComputer computer )
|
||||||
|
{
|
||||||
|
IPocketUpgrade upgrade = getUpgrade( stack );
|
||||||
|
|
||||||
|
computer.setLevel( world );
|
||||||
|
computer.updateValues( entity, stack, upgrade );
|
||||||
|
|
||||||
|
boolean changed = false;
|
||||||
|
|
||||||
|
// Sync ID
|
||||||
|
int id = computer.getID();
|
||||||
|
if( id != getComputerID( stack ) )
|
||||||
|
{
|
||||||
|
changed = true;
|
||||||
|
setComputerID( stack, id );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sync label
|
||||||
|
String label = computer.getLabel();
|
||||||
|
if( !Objects.equal( label, getLabel( stack ) ) )
|
||||||
|
{
|
||||||
|
changed = true;
|
||||||
|
setLabel( stack, label );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update pocket upgrade
|
||||||
|
if( upgrade != null ) upgrade.update( computer, computer.getPeripheral( ComputerSide.BACK ) );
|
||||||
|
|
||||||
|
return changed;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void inventoryTick( @Nonnull ItemStack stack, Level world, @Nonnull Entity entity, int slotNum, boolean selected )
|
public void inventoryTick( @Nonnull ItemStack stack, Level world, @Nonnull Entity entity, int slotNum, boolean selected )
|
||||||
{
|
{
|
||||||
if( !world.isClientSide )
|
if( !world.isClientSide )
|
||||||
{
|
{
|
||||||
// Server side
|
Container inventory = entity instanceof Player player ? player.getInventory() : null;
|
||||||
Container inventory = entity instanceof Player ? ((Player) entity).getInventory() : null;
|
PocketServerComputer computer = createServerComputer( world, entity, inventory, stack );
|
||||||
PocketServerComputer computer = createServerComputer( world, inventory, entity, stack );
|
computer.keepAlive();
|
||||||
if( computer != null )
|
|
||||||
{
|
|
||||||
IPocketUpgrade upgrade = getUpgrade( stack );
|
|
||||||
|
|
||||||
// Ping computer
|
boolean changed = tick( stack, world, entity, computer );
|
||||||
computer.keepAlive();
|
if( changed && inventory != null ) inventory.setChanged();
|
||||||
computer.setLevel( world );
|
|
||||||
computer.updateValues( entity, stack, upgrade );
|
|
||||||
|
|
||||||
// Sync ID
|
|
||||||
int id = computer.getID();
|
|
||||||
if( id != getComputerID( stack ) )
|
|
||||||
{
|
|
||||||
setComputerID( stack, id );
|
|
||||||
if( inventory != null ) inventory.setChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sync label
|
|
||||||
String label = computer.getLabel();
|
|
||||||
if( !Objects.equal( label, getLabel( stack ) ) )
|
|
||||||
{
|
|
||||||
setLabel( stack, label );
|
|
||||||
if( inventory != null ) inventory.setChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update pocket upgrade
|
|
||||||
if( upgrade != null )
|
|
||||||
{
|
|
||||||
upgrade.update( computer, computer.getPeripheral( ComputerSide.BACK ) );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Client side
|
|
||||||
createClientComputer( stack );
|
createClientComputer( stack );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onEntityItemUpdate( ItemStack stack, ItemEntity entity )
|
||||||
|
{
|
||||||
|
if( entity.level.isClientSide ) return false;
|
||||||
|
|
||||||
|
PocketServerComputer computer = getServerComputer( stack );
|
||||||
|
if( computer != null && tick( stack, entity.level, entity, computer ) ) entity.setItem( stack.copy() );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
@Override
|
@Override
|
||||||
public InteractionResultHolder<ItemStack> use( Level world, Player player, @Nonnull InteractionHand hand )
|
public InteractionResultHolder<ItemStack> use( Level world, Player player, @Nonnull InteractionHand hand )
|
||||||
@ -134,22 +146,18 @@ public class ItemPocketComputer extends Item implements IComputerItem, IMedia, I
|
|||||||
ItemStack stack = player.getItemInHand( hand );
|
ItemStack stack = player.getItemInHand( hand );
|
||||||
if( !world.isClientSide )
|
if( !world.isClientSide )
|
||||||
{
|
{
|
||||||
PocketServerComputer computer = createServerComputer( world, player.getInventory(), player, stack );
|
PocketServerComputer computer = createServerComputer( world, player, player.getInventory(), stack );
|
||||||
|
computer.turnOn();
|
||||||
|
|
||||||
boolean stop = false;
|
boolean stop = false;
|
||||||
if( computer != null )
|
IPocketUpgrade upgrade = getUpgrade( stack );
|
||||||
|
if( upgrade != null )
|
||||||
{
|
{
|
||||||
computer.turnOn();
|
computer.updateValues( player, stack, upgrade );
|
||||||
|
stop = upgrade.onRightClick( world, computer, computer.getPeripheral( ComputerSide.BACK ) );
|
||||||
IPocketUpgrade upgrade = getUpgrade( stack );
|
|
||||||
if( upgrade != null )
|
|
||||||
{
|
|
||||||
computer.updateValues( player, stack, upgrade );
|
|
||||||
stop = upgrade.onRightClick( world, computer, computer.getPeripheral( ComputerSide.BACK ) );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if( !stop && computer != null )
|
if( !stop )
|
||||||
{
|
{
|
||||||
boolean isTypingOnly = hand == InteractionHand.OFF_HAND;
|
boolean isTypingOnly = hand == InteractionHand.OFF_HAND;
|
||||||
new ComputerContainerData( computer ).open( player, new PocketComputerMenuProvider( computer, stack, this, hand, isTypingOnly ) );
|
new ComputerContainerData( computer ).open( player, new PocketComputerMenuProvider( computer, stack, this, hand, isTypingOnly ) );
|
||||||
@ -207,17 +215,17 @@ public class ItemPocketComputer extends Item implements IComputerItem, IMedia, I
|
|||||||
return super.getCreatorModId( stack );
|
return super.getCreatorModId( stack );
|
||||||
}
|
}
|
||||||
|
|
||||||
public PocketServerComputer createServerComputer( final Level world, Container inventory, Entity entity, @Nonnull ItemStack stack )
|
@Nonnull
|
||||||
|
public PocketServerComputer createServerComputer( Level world, Entity entity, @Nullable Container inventory, @Nonnull ItemStack stack )
|
||||||
{
|
{
|
||||||
if( world.isClientSide ) return null;
|
if( world.isClientSide ) throw new IllegalStateException( "Cannot call createServerComputer on the client" );
|
||||||
|
|
||||||
PocketServerComputer computer;
|
PocketServerComputer computer;
|
||||||
int instanceID = getInstanceID( stack );
|
int instanceID = getInstanceID( stack );
|
||||||
int sessionID = getSessionID( stack );
|
int sessionID = getSessionID( stack );
|
||||||
int correctSessionID = ComputerCraft.serverComputerRegistry.getSessionID();
|
int correctSessionID = ComputerCraft.serverComputerRegistry.getSessionID();
|
||||||
|
|
||||||
if( instanceID >= 0 && sessionID == correctSessionID &&
|
if( instanceID >= 0 && sessionID == correctSessionID && ComputerCraft.serverComputerRegistry.contains( instanceID ) )
|
||||||
ComputerCraft.serverComputerRegistry.contains( instanceID ) )
|
|
||||||
{
|
{
|
||||||
computer = (PocketServerComputer) ComputerCraft.serverComputerRegistry.get( instanceID );
|
computer = (PocketServerComputer) ComputerCraft.serverComputerRegistry.get( instanceID );
|
||||||
}
|
}
|
||||||
@ -235,13 +243,7 @@ public class ItemPocketComputer extends Item implements IComputerItem, IMedia, I
|
|||||||
computerID = ComputerCraftAPI.createUniqueNumberedSaveDir( world, "computer" );
|
computerID = ComputerCraftAPI.createUniqueNumberedSaveDir( world, "computer" );
|
||||||
setComputerID( stack, computerID );
|
setComputerID( stack, computerID );
|
||||||
}
|
}
|
||||||
computer = new PocketServerComputer(
|
computer = new PocketServerComputer( world, computerID, getLabel( stack ), instanceID, getFamily() );
|
||||||
world,
|
|
||||||
computerID,
|
|
||||||
getLabel( stack ),
|
|
||||||
instanceID,
|
|
||||||
getFamily()
|
|
||||||
);
|
|
||||||
computer.updateValues( entity, stack, getUpgrade( stack ) );
|
computer.updateValues( entity, stack, getUpgrade( stack ) );
|
||||||
computer.addAPI( new PocketAPI( computer ) );
|
computer.addAPI( new PocketAPI( computer ) );
|
||||||
ComputerCraft.serverComputerRegistry.add( instanceID, computer );
|
ComputerCraft.serverComputerRegistry.add( instanceID, computer );
|
||||||
@ -251,15 +253,17 @@ public class ItemPocketComputer extends Item implements IComputerItem, IMedia, I
|
|||||||
return computer;
|
return computer;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ServerComputer getServerComputer( @Nonnull ItemStack stack )
|
@Nullable
|
||||||
|
public static PocketServerComputer getServerComputer( @Nonnull ItemStack stack )
|
||||||
{
|
{
|
||||||
int session = getSessionID( stack );
|
int session = getSessionID( stack );
|
||||||
if( session != ComputerCraft.serverComputerRegistry.getSessionID() ) return null;
|
if( session != ComputerCraft.serverComputerRegistry.getSessionID() ) return null;
|
||||||
|
|
||||||
int instanceID = getInstanceID( stack );
|
int instanceID = getInstanceID( stack );
|
||||||
return instanceID >= 0 ? ComputerCraft.serverComputerRegistry.get( instanceID ) : null;
|
return instanceID >= 0 ? (PocketServerComputer) ComputerCraft.serverComputerRegistry.get( instanceID ) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
public static ClientComputer createClientComputer( @Nonnull ItemStack stack )
|
public static ClientComputer createClientComputer( @Nonnull ItemStack stack )
|
||||||
{
|
{
|
||||||
int instanceID = getInstanceID( stack );
|
int instanceID = getInstanceID( stack );
|
||||||
@ -274,6 +278,7 @@ public class ItemPocketComputer extends Item implements IComputerItem, IMedia, I
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
private static ClientComputer getClientComputer( @Nonnull ItemStack stack )
|
private static ClientComputer getClientComputer( @Nonnull ItemStack stack )
|
||||||
{
|
{
|
||||||
int instanceID = getInstanceID( stack );
|
int instanceID = getInstanceID( stack );
|
||||||
|
@ -22,8 +22,50 @@ import java.util.Map;
|
|||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The turtle API allows you to control your turtle.
|
* Turtles are a robotic device, which can break and place blocks, attack mobs, and move about the world. They have
|
||||||
|
* an internal inventory of 16 slots, allowing them to store blocks they have broken or would like to place.
|
||||||
*
|
*
|
||||||
|
* ## Movement
|
||||||
|
* Turtles are capable of moving throug the world. As turtles are blocks themselves, they are confined to Minecraft's
|
||||||
|
* grid, moving a single block at a time.
|
||||||
|
*
|
||||||
|
* {@literal @}{turtle.forward} and @{turtle.back} move the turtle in the direction it is facing, while @{turtle.up} and
|
||||||
|
* {@literal @}{turtle.down} move it up and down (as one might expect!). In order to move left or right, you first need
|
||||||
|
* to turn the turtle using @{turtle.turnLeft}/@{turtle.turnRight} and then move forward or backwards.
|
||||||
|
*
|
||||||
|
* :::info
|
||||||
|
* The name "turtle" comes from [Turtle graphics], which originated from the Logo programming language. Here you'd move
|
||||||
|
* a turtle with various commands like "move 10" and "turn left", much like ComputerCraft's turtles!
|
||||||
|
* :::
|
||||||
|
*
|
||||||
|
* Moving a turtle (though not turning it) consumes *fuel*. If a turtle does not have any @{turtle.refuel|fuel}, it
|
||||||
|
* won't move, and the movement functions will return @{false}. If your turtle isn't going anywhere, the first thing to
|
||||||
|
* check is if you've fuelled your turtle.
|
||||||
|
*
|
||||||
|
* :::tip Handling errors
|
||||||
|
* Many turtle functions can fail in various ways. For instance, a turtle cannot move forward if there's already a block
|
||||||
|
* there. Instead of erroring, functions which can fail either return @{true} if they succeed, or @{false} and some
|
||||||
|
* error message if they fail.
|
||||||
|
*
|
||||||
|
* Unexpected failures can often lead to strange behaviour. It's often a good idea to check the return values of these
|
||||||
|
* functions, or wrap them in @{assert} (for instance, use `assert(turtle.forward())` rather than `turtle.forward()`),
|
||||||
|
* so the program doesn't misbehave.
|
||||||
|
* :::
|
||||||
|
*
|
||||||
|
* ## Turtle upgrades
|
||||||
|
* While a normal turtle can move about the world and place blocks, its functionality is limited. Thankfully, turtles
|
||||||
|
* can be upgraded with *tools* and @{peripheral|peripherals}. Turtles have two upgrade slots, one on the left and right
|
||||||
|
* sides. Upgrades can be equipped by crafting a turtle with the upgrade, or calling the @{turtle.equipLeft}/@{turtle.equipRight}
|
||||||
|
* functions.
|
||||||
|
*
|
||||||
|
* Turtle tools allow you to break blocks (@{turtle.dig}) and attack entities (@{turtle.attack}). Some tools are more
|
||||||
|
* suitable to a task than others. For instance, a diamond pickaxe can break every block, while a sword does more
|
||||||
|
* damage. Other tools have more niche use-cases, for instance hoes can til dirt.
|
||||||
|
*
|
||||||
|
* Peripherals (such as the @{modem|wireless modem} or @{speaker}) can also be equipped as upgrades. These are then
|
||||||
|
* accessible by accessing the `"left"` or `"right"` peripheral.
|
||||||
|
*
|
||||||
|
* [Turtle Graphics]: https://en.wikipedia.org/wiki/Turtle_graphics "Turtle graphics"
|
||||||
* @cc.module turtle
|
* @cc.module turtle
|
||||||
* @cc.since 1.3
|
* @cc.since 1.3
|
||||||
*/
|
*/
|
||||||
|
@ -31,7 +31,6 @@ import net.minecraft.resources.ResourceLocation;
|
|||||||
import net.minecraft.tags.FluidTags;
|
import net.minecraft.tags.FluidTags;
|
||||||
import net.minecraft.world.Container;
|
import net.minecraft.world.Container;
|
||||||
import net.minecraft.world.entity.Entity;
|
import net.minecraft.world.entity.Entity;
|
||||||
import net.minecraft.world.entity.EntitySelector;
|
|
||||||
import net.minecraft.world.entity.MoverType;
|
import net.minecraft.world.entity.MoverType;
|
||||||
import net.minecraft.world.item.DyeColor;
|
import net.minecraft.world.item.DyeColor;
|
||||||
import net.minecraft.world.level.Level;
|
import net.minecraft.world.level.Level;
|
||||||
@ -39,6 +38,7 @@ import net.minecraft.world.level.block.Block;
|
|||||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||||
import net.minecraft.world.level.block.state.BlockState;
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
import net.minecraft.world.level.material.FluidState;
|
import net.minecraft.world.level.material.FluidState;
|
||||||
|
import net.minecraft.world.level.material.PushReaction;
|
||||||
import net.minecraft.world.phys.AABB;
|
import net.minecraft.world.phys.AABB;
|
||||||
import net.minecraft.world.phys.Vec3;
|
import net.minecraft.world.phys.Vec3;
|
||||||
import net.minecraftforge.items.IItemHandlerModifiable;
|
import net.minecraftforge.items.IItemHandlerModifiable;
|
||||||
@ -48,6 +48,7 @@ import javax.annotation.Nonnull;
|
|||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
import static dan200.computercraft.shared.common.IColouredItem.NBT_COLOUR;
|
import static dan200.computercraft.shared.common.IColouredItem.NBT_COLOUR;
|
||||||
import static dan200.computercraft.shared.util.WaterloggableHelpers.WATERLOGGED;
|
import static dan200.computercraft.shared.util.WaterloggableHelpers.WATERLOGGED;
|
||||||
@ -65,6 +66,8 @@ public class TurtleBrain implements ITurtleAccess
|
|||||||
|
|
||||||
private static final int ANIM_DURATION = 8;
|
private static final int ANIM_DURATION = 8;
|
||||||
|
|
||||||
|
public static final Predicate<Entity> PUSHABLE_ENTITY = entity -> !entity.isSpectator() && entity.getPistonPushReaction() != PushReaction.IGNORE;
|
||||||
|
|
||||||
private TileTurtle owner;
|
private TileTurtle owner;
|
||||||
private ComputerProxy proxy;
|
private ComputerProxy proxy;
|
||||||
private GameProfile owningPlayer;
|
private GameProfile owningPlayer;
|
||||||
@ -886,7 +889,7 @@ public class TurtleBrain implements ITurtleAccess
|
|||||||
}
|
}
|
||||||
|
|
||||||
AABB aabb = new AABB( minX, minY, minZ, maxX, maxY, maxZ );
|
AABB aabb = new AABB( minX, minY, minZ, maxX, maxY, maxZ );
|
||||||
List<Entity> list = world.getEntitiesOfClass( Entity.class, aabb, EntitySelector.NO_SPECTATORS );
|
List<Entity> list = world.getEntitiesOfClass( Entity.class, aabb, PUSHABLE_ENTITY );
|
||||||
if( !list.isEmpty() )
|
if( !list.isEmpty() )
|
||||||
{
|
{
|
||||||
double pushStep = 1.0f / ANIM_DURATION;
|
double pushStep = 1.0f / ANIM_DURATION;
|
||||||
|
@ -0,0 +1,53 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of ComputerCraft - http://www.computercraft.info
|
||||||
|
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
|
||||||
|
* Send enquiries to dratcliffe@gmail.com
|
||||||
|
*/
|
||||||
|
package dan200.computercraft.shared.util;
|
||||||
|
|
||||||
|
import net.minecraft.Util;
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraftforge.api.distmarker.Dist;
|
||||||
|
import net.minecraftforge.event.TickEvent;
|
||||||
|
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||||
|
import net.minecraftforge.fml.common.Mod;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A monotonically increasing clock which accounts for the game being paused.
|
||||||
|
*/
|
||||||
|
@Mod.EventBusSubscriber( Dist.CLIENT )
|
||||||
|
public final class PauseAwareTimer
|
||||||
|
{
|
||||||
|
private static boolean paused;
|
||||||
|
private static long pauseTime;
|
||||||
|
private static long pauseOffset;
|
||||||
|
|
||||||
|
private PauseAwareTimer()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public static long getTime()
|
||||||
|
{
|
||||||
|
return (paused ? pauseTime : Util.getNanos()) - pauseOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SubscribeEvent
|
||||||
|
public static void tick( TickEvent.RenderTickEvent event )
|
||||||
|
{
|
||||||
|
if( event.phase != TickEvent.Phase.START ) return;
|
||||||
|
|
||||||
|
boolean isPaused = Minecraft.getInstance().isPaused();
|
||||||
|
if( isPaused == paused ) return;
|
||||||
|
|
||||||
|
if( isPaused )
|
||||||
|
{
|
||||||
|
pauseTime = Util.getNanos();
|
||||||
|
paused = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pauseOffset += Util.getNanos() - pauseTime;
|
||||||
|
paused = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -7,3 +7,7 @@ public net.minecraft.client.gui.components.ChatComponent m_93787_(Lnet/minecraft
|
|||||||
public net.minecraft.client.gui.components.ChatComponent m_93803_(I)V # removeById
|
public net.minecraft.client.gui.components.ChatComponent m_93803_(I)V # removeById
|
||||||
# NoTermComputerScreen
|
# NoTermComputerScreen
|
||||||
public net.minecraft.client.Minecraft f_91080_ # screen
|
public net.minecraft.client.Minecraft f_91080_ # screen
|
||||||
|
|
||||||
|
# SpeakerInstance/SpeakerManager
|
||||||
|
public com.mojang.blaze3d.audio.Channel m_83652_(I)V # pumpBuffers
|
||||||
|
public net.minecraft.client.sounds.SoundEngine f_120223_ # executor
|
||||||
|
@ -1,16 +1,18 @@
|
|||||||
--- The Disk API allows you to interact with disk drives.
|
--[[- The Disk API allows you to interact with disk drives.
|
||||||
--
|
|
||||||
-- These functions can operate on locally attached or remote disk drives. To use
|
These functions can operate on locally attached or remote disk drives. To use a
|
||||||
-- a locally attached drive, specify “side” as one of the six sides
|
locally attached drive, specify “side” as one of the six sides (e.g. `left`); to
|
||||||
-- (e.g. `left`); to use a remote disk drive, specify its name as printed when
|
use a remote disk drive, specify its name as printed when enabling its modem
|
||||||
-- enabling its modem (e.g. `drive_0`).
|
(e.g. `drive_0`).
|
||||||
--
|
|
||||||
-- **Note:** All computers (except command computers), turtles and pocket
|
:::tip
|
||||||
-- computers can be placed within a disk drive to access it's internal storage
|
All computers (except command computers), turtles and pocket computers can be
|
||||||
-- like a disk.
|
placed within a disk drive to access it's internal storage like a disk.
|
||||||
--
|
:::
|
||||||
-- @module disk
|
|
||||||
-- @since 1.2
|
@module disk
|
||||||
|
@since 1.2
|
||||||
|
]]
|
||||||
|
|
||||||
local function isDrive(name)
|
local function isDrive(name)
|
||||||
if type(name) ~= "string" then
|
if type(name) ~= "string" then
|
||||||
|
@ -1,27 +1,30 @@
|
|||||||
--- The GPS API provides a method for turtles and computers to retrieve their
|
--[[- The GPS API provides a method for turtles and computers to retrieve their
|
||||||
-- own locations.
|
own locations.
|
||||||
--
|
|
||||||
-- It broadcasts a PING message over @{rednet} and wait for responses. In order
|
It broadcasts a PING message over @{rednet} and wait for responses. In order for
|
||||||
-- for this system to work, there must be at least 4 computers used as gps hosts
|
this system to work, there must be at least 4 computers used as gps hosts which
|
||||||
-- which will respond and allow trilateration. Three of these hosts should be in
|
will respond and allow trilateration. Three of these hosts should be in a plane,
|
||||||
-- a plane, and the fourth should be either above or below the other three. The
|
and the fourth should be either above or below the other three. The three in a
|
||||||
-- three in a plane should not be in a line with each other. You can set up
|
plane should not be in a line with each other. You can set up hosts using the
|
||||||
-- hosts using the gps program.
|
gps program.
|
||||||
--
|
|
||||||
-- **Note**: When entering in the coordinates for the host you need to put in
|
:::note
|
||||||
-- the `x`, `y`, and `z` coordinates of the computer, not the modem, as all
|
When entering in the coordinates for the host you need to put in the `x`, `y`,
|
||||||
-- rednet distances are measured from the block the computer is in.
|
and `z` coordinates of the computer, not the modem, as all modem distances are
|
||||||
--
|
measured from the block the computer is in.
|
||||||
-- Also note that you may choose which axes x, y, or z refers to - so long as
|
:::
|
||||||
-- your systems have the same definition as any GPS servers that're in range, it
|
|
||||||
-- works just the same. For example, you might build a GPS cluster according to
|
Also note that you may choose which axes x, y, or z refers to - so long as your
|
||||||
-- [this tutorial][1], using z to account for height, or you might use y to
|
systems have the same definition as any GPS servers that're in range, it works
|
||||||
-- account for height in the way that Minecraft's debug screen displays.
|
just the same. For example, you might build a GPS cluster according to [this
|
||||||
--
|
tutorial][1], using z to account for height, or you might use y to account for
|
||||||
-- [1]: http://www.computercraft.info/forums2/index.php?/topic/3088-how-to-guide-gps-global-position-system/
|
height in the way that Minecraft's debug screen displays.
|
||||||
--
|
|
||||||
-- @module gps
|
[1]: http://www.computercraft.info/forums2/index.php?/topic/3088-how-to-guide-gps-global-position-system/
|
||||||
-- @since 1.31
|
|
||||||
|
@module gps
|
||||||
|
@since 1.31
|
||||||
|
]]
|
||||||
|
|
||||||
local expect = dofile("rom/modules/main/cc/expect.lua").expect
|
local expect = dofile("rom/modules/main/cc/expect.lua").expect
|
||||||
|
|
||||||
|
@ -2,13 +2,13 @@
|
|||||||
|
|
||||||
Functions are not actually executed simultaniously, but rather this API will
|
Functions are not actually executed simultaniously, but rather this API will
|
||||||
automatically switch between them whenever they yield (eg whenever they call
|
automatically switch between them whenever they yield (eg whenever they call
|
||||||
@{coroutine.yield}, or functions that call that - eg `os.pullEvent` - or
|
@{coroutine.yield}, or functions that call that - eg @{os.pullEvent} - or
|
||||||
functions that call that, etc - basically, anything that causes the function
|
functions that call that, etc - basically, anything that causes the function
|
||||||
to "pause").
|
to "pause").
|
||||||
|
|
||||||
Each function executed in "parallel" gets its own copy of the event queue,
|
Each function executed in "parallel" gets its own copy of the event queue,
|
||||||
and so "event consuming" functions (again, mostly anything that causes the
|
and so "event consuming" functions (again, mostly anything that causes the
|
||||||
script to pause - eg `sleep`, `rednet.receive`, most of the `turtle` API,
|
script to pause - eg @{os.sleep}, @{rednet.receive}, most of the @{turtle} API,
|
||||||
etc) can safely be used in one without affecting the event queue accessed by
|
etc) can safely be used in one without affecting the event queue accessed by
|
||||||
the other.
|
the other.
|
||||||
|
|
||||||
|
@ -66,7 +66,7 @@ type.
|
|||||||
What is a peripheral type though? This is a string which describes what a
|
What is a peripheral type though? This is a string which describes what a
|
||||||
peripheral is, and so what functions are available on it. For instance, speakers
|
peripheral is, and so what functions are available on it. For instance, speakers
|
||||||
are just called `"speaker"`, and monitors `"monitor"`. Some peripherals might
|
are just called `"speaker"`, and monitors `"monitor"`. Some peripherals might
|
||||||
have more than one type; a Minecraft chest is both a `"minecraft:chest"` and
|
have more than one type - a Minecraft chest is both a `"minecraft:chest"` and
|
||||||
`"inventory"`.
|
`"inventory"`.
|
||||||
|
|
||||||
You can get all the types a peripheral has with @{peripheral.getType}, and check
|
You can get all the types a peripheral has with @{peripheral.getType}, and check
|
||||||
|
@ -1,21 +1,48 @@
|
|||||||
--- The Rednet API allows systems to communicate between each other without
|
--[[- The Rednet API allows computers to communicate between each other by using
|
||||||
-- using redstone. It serves as a wrapper for the modem API, offering ease of
|
@{modem|modems}. It provides a layer of abstraction on top of the main @{modem}
|
||||||
-- functionality (particularly in regards to repeating signals) with some
|
peripheral, making it slightly easier to use.
|
||||||
-- expense of fine control.
|
|
||||||
--
|
## Basic usage
|
||||||
-- In order to send and receive data, a modem (either wired, wireless, or ender)
|
In order to send a message between two computers, each computer must have a
|
||||||
-- is required. The data reaches any possible destinations immediately after
|
modem on one of its sides (or in the case of pocket computers and turtles, the
|
||||||
-- sending it, but is range limited.
|
modem must be equipped as an upgrade). The two computers should then call
|
||||||
--
|
@{rednet.open}, which sets up the modems ready to send and receive messages.
|
||||||
-- Rednet also allows you to use a "protocol" - simple string names indicating
|
|
||||||
-- what messages are about. Receiving systems may filter messages according to
|
Once rednet is opened, you can send messages using @{rednet.send} and receive
|
||||||
-- their protocols, thereby automatically ignoring incoming messages which don't
|
them using @{rednet.receive}. It's also possible to send a message to _every_
|
||||||
-- specify an identical string. It's also possible to @{rednet.lookup|lookup}
|
rednet-using computer using @{rednet.broadcast}.
|
||||||
-- which systems in the area use certain protocols, hence making it easier to
|
|
||||||
-- determine where given messages should be sent in the first place.
|
:::caution Network security
|
||||||
--
|
|
||||||
-- @module rednet
|
While rednet provides a friendly way to send messages to specific computers, it
|
||||||
-- @since 1.2
|
doesn't provide any guarantees about security. Other computers could be
|
||||||
|
listening in to your messages, or even pretending to send messages from other computers!
|
||||||
|
|
||||||
|
If you're playing on a multi-player server (or at least one where you don't
|
||||||
|
trust other players), it's worth encrypting or signing your rednet messages.
|
||||||
|
:::
|
||||||
|
|
||||||
|
## Protocols and hostnames
|
||||||
|
Several rednet messages accept "protocol"s - simple string names describing what
|
||||||
|
a message is about. When sending messages using @{rednet.send} and
|
||||||
|
@{rednet.broadcast}, you can optionally specify a protocol for the message. This
|
||||||
|
same protocol can then be given to @{rednet.receive}, to ignore all messages not
|
||||||
|
using this protocol.
|
||||||
|
|
||||||
|
It's also possible to look-up computers based on protocols, providing a basic
|
||||||
|
system for service discovery and [DNS]. A computer can advertise that it
|
||||||
|
supports a particular protocol with @{rednet.host}, also providing a friendly
|
||||||
|
"hostname". Other computers may then find all computers which support this
|
||||||
|
protocol using @{rednet.lookup}.
|
||||||
|
|
||||||
|
[DNS]: https://en.wikipedia.org/wiki/Domain_Name_System "Domain Name System"
|
||||||
|
|
||||||
|
@module rednet
|
||||||
|
@since 1.2
|
||||||
|
@see rednet_message Queued when a rednet message is received.
|
||||||
|
@see modem Rednet is built on top of the modem peripheral. Modems provide a more
|
||||||
|
bare-bones but flexible interface.
|
||||||
|
]]
|
||||||
|
|
||||||
local expect = dofile("rom/modules/main/cc/expect.lua").expect
|
local expect = dofile("rom/modules/main/cc/expect.lua").expect
|
||||||
|
|
||||||
@ -46,9 +73,17 @@ This will open the modem on two channels: one which has the same
|
|||||||
|
|
||||||
@tparam string modem The name of the modem to open.
|
@tparam string modem The name of the modem to open.
|
||||||
@throws If there is no such modem with the given name
|
@throws If there is no such modem with the given name
|
||||||
@usage Open a wireless modem on the back of the computer.
|
@usage Open rednet on the back of the computer, allowing you to send and receive
|
||||||
|
rednet messages using it.
|
||||||
|
|
||||||
rednet.open("back")
|
rednet.open("back")
|
||||||
|
|
||||||
|
@usage Open rednet on all attached modems. This abuses the "filter" argument to
|
||||||
|
@{peripheral.find}.
|
||||||
|
|
||||||
|
peripheral.find("modem", rednet.open)
|
||||||
|
@see rednet.close
|
||||||
|
@see rednet.isOpen
|
||||||
]]
|
]]
|
||||||
function open(modem)
|
function open(modem)
|
||||||
expect(1, modem, "string")
|
expect(1, modem, "string")
|
||||||
@ -65,6 +100,7 @@ end
|
|||||||
-- @tparam[opt] string modem The side the modem exists on. If not given, all
|
-- @tparam[opt] string modem The side the modem exists on. If not given, all
|
||||||
-- open modems will be closed.
|
-- open modems will be closed.
|
||||||
-- @throws If there is no such modem with the given name
|
-- @throws If there is no such modem with the given name
|
||||||
|
-- @see rednet.open
|
||||||
function close(modem)
|
function close(modem)
|
||||||
expect(1, modem, "string", "nil")
|
expect(1, modem, "string", "nil")
|
||||||
if modem then
|
if modem then
|
||||||
@ -90,6 +126,7 @@ end
|
|||||||
-- modems will be checked.
|
-- modems will be checked.
|
||||||
-- @treturn boolean If the given modem is open.
|
-- @treturn boolean If the given modem is open.
|
||||||
-- @since 1.31
|
-- @since 1.31
|
||||||
|
-- @see rednet.open
|
||||||
function isOpen(modem)
|
function isOpen(modem)
|
||||||
expect(1, modem, "string", "nil")
|
expect(1, modem, "string", "nil")
|
||||||
if modem then
|
if modem then
|
||||||
@ -109,15 +146,17 @@ function isOpen(modem)
|
|||||||
end
|
end
|
||||||
|
|
||||||
--[[- Allows a computer or turtle with an attached modem to send a message
|
--[[- Allows a computer or turtle with an attached modem to send a message
|
||||||
intended for a system with a specific ID. At least one such modem must first
|
intended for a sycomputer with a specific ID. At least one such modem must first
|
||||||
be @{rednet.open|opened} before sending is possible.
|
be @{rednet.open|opened} before sending is possible.
|
||||||
|
|
||||||
Assuming the target was in range and also had a correctly opened modem, it
|
Assuming the target was in range and also had a correctly opened modem, the
|
||||||
may then use @{rednet.receive} to collect the message.
|
target computer may then use @{rednet.receive} to collect the message.
|
||||||
|
|
||||||
@tparam number recipient The ID of the receiving computer.
|
@tparam number recipient The ID of the receiving computer.
|
||||||
@param message The message to send. This should not contain coroutines or
|
@param message The message to send. Like with @{modem.transmit}, this can
|
||||||
functions, as they will be converted to @{nil}.
|
contain any primitive type (numbers, booleans and strings) as well as
|
||||||
|
tables. Other types (like functions), as well as metatables, will not be
|
||||||
|
transmitted.
|
||||||
@tparam[opt] string protocol The "protocol" to send this message under. When
|
@tparam[opt] string protocol The "protocol" to send this message under. When
|
||||||
using @{rednet.receive} one can filter to only receive messages sent under a
|
using @{rednet.receive} one can filter to only receive messages sent under a
|
||||||
particular protocol.
|
particular protocol.
|
||||||
@ -174,16 +213,19 @@ function send(recipient, message, protocol)
|
|||||||
return sent
|
return sent
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Broadcasts a string message over the predefined @{CHANNEL_BROADCAST}
|
--[[- Broadcasts a string message over the predefined @{CHANNEL_BROADCAST}
|
||||||
-- channel. The message will be received by every device listening to rednet.
|
channel. The message will be received by every device listening to rednet.
|
||||||
--
|
|
||||||
-- @param message The message to send. This should not contain coroutines or
|
@param message The message to send. This should not contain coroutines or
|
||||||
-- functions, as they will be converted to @{nil}.
|
functions, as they will be converted to @{nil}. @tparam[opt] string protocol
|
||||||
-- @tparam[opt] string protocol The "protocol" to send this message under. When
|
The "protocol" to send this message under. When using @{rednet.receive} one can
|
||||||
-- using @{rednet.receive} one can filter to only receive messages sent under a
|
filter to only receive messages sent under a particular protocol.
|
||||||
-- particular protocol.
|
@see rednet.receive
|
||||||
-- @see rednet.receive
|
@changed 1.6 Added protocol parameter.
|
||||||
-- @changed 1.6 Added protocol parameter.
|
@usage Broadcast the words "Hello, world!" to every computer using rednet.
|
||||||
|
|
||||||
|
rednet.broadcast("Hello, world!")
|
||||||
|
]]
|
||||||
function broadcast(message, protocol)
|
function broadcast(message, protocol)
|
||||||
expect(2, protocol, "string", "nil")
|
expect(2, protocol, "string", "nil")
|
||||||
send(CHANNEL_BROADCAST, message, protocol)
|
send(CHANNEL_BROADCAST, message, protocol)
|
||||||
@ -263,25 +305,25 @@ function receive(protocol_filter, timeout)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Register the system as "hosting" the desired protocol under the specified
|
--[[- Register the system as "hosting" the desired protocol under the specified
|
||||||
-- name. If a rednet @{rednet.lookup|lookup} is performed for that protocol (and
|
name. If a rednet @{rednet.lookup|lookup} is performed for that protocol (and
|
||||||
-- maybe name) on the same network, the registered system will automatically
|
maybe name) on the same network, the registered system will automatically
|
||||||
-- respond via a background process, hence providing the system performing the
|
respond via a background process, hence providing the system performing the
|
||||||
-- lookup with its ID number.
|
lookup with its ID number.
|
||||||
--
|
|
||||||
-- Multiple computers may not register themselves on the same network as having
|
Multiple computers may not register themselves on the same network as having the
|
||||||
-- the same names against the same protocols, and the title `localhost` is
|
same names against the same protocols, and the title `localhost` is specifically
|
||||||
-- specifically reserved. They may, however, share names as long as their hosted
|
reserved. They may, however, share names as long as their hosted protocols are
|
||||||
-- protocols are different, or if they only join a given network after
|
different, or if they only join a given network after "registering" themselves
|
||||||
-- "registering" themselves before doing so (eg while offline or part of a
|
before doing so (eg while offline or part of a different network).
|
||||||
-- different network).
|
|
||||||
--
|
@tparam string protocol The protocol this computer provides.
|
||||||
-- @tparam string protocol The protocol this computer provides.
|
@tparam string hostname The name this protocol exposes for the given protocol.
|
||||||
-- @tparam string hostname The name this protocol exposes for the given protocol.
|
@throws If trying to register a hostname which is reserved, or currently in use.
|
||||||
-- @throws If trying to register a hostname which is reserved, or currently in use.
|
@see rednet.unhost
|
||||||
-- @see rednet.unhost
|
@see rednet.lookup
|
||||||
-- @see rednet.lookup
|
@since 1.6
|
||||||
-- @since 1.6
|
]]
|
||||||
function host(protocol, hostname)
|
function host(protocol, hostname)
|
||||||
expect(1, protocol, "string")
|
expect(1, protocol, "string")
|
||||||
expect(2, hostname, "string")
|
expect(2, hostname, "string")
|
||||||
@ -306,21 +348,38 @@ function unhost(protocol)
|
|||||||
hostnames[protocol] = nil
|
hostnames[protocol] = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Search the local rednet network for systems @{rednet.host|hosting} the
|
--[[- Search the local rednet network for systems @{rednet.host|hosting} the
|
||||||
-- desired protocol and returns any computer IDs that respond as "registered"
|
desired protocol and returns any computer IDs that respond as "registered"
|
||||||
-- against it.
|
against it.
|
||||||
--
|
|
||||||
-- If a hostname is specified, only one ID will be returned (assuming an exact
|
If a hostname is specified, only one ID will be returned (assuming an exact
|
||||||
-- match is found).
|
match is found).
|
||||||
--
|
|
||||||
-- @tparam string protocol The protocol to search for.
|
@tparam string protocol The protocol to search for.
|
||||||
-- @tparam[opt] string hostname The hostname to search for.
|
@tparam[opt] string hostname The hostname to search for.
|
||||||
--
|
|
||||||
-- @treturn[1] { number }|nil A list of computer IDs hosting the given
|
@treturn[1] number... A list of computer IDs hosting the given protocol.
|
||||||
-- protocol, or @{nil} if none exist.
|
@treturn[2] number|nil The computer ID with the provided hostname and protocol,
|
||||||
-- @treturn[2] number|nil The computer ID with the provided hostname and protocol,
|
or @{nil} if none exists.
|
||||||
-- or @{nil} if none exists.
|
@since 1.6
|
||||||
-- @since 1.6
|
@usage Find all computers which are hosting the `"chat"` protocol.
|
||||||
|
|
||||||
|
local computers = {rednet.lookup("chat")}
|
||||||
|
print(#computers .. " computers available to chat")
|
||||||
|
for _, computer in pairs(computers) do
|
||||||
|
print("Computer #" .. computer)
|
||||||
|
end
|
||||||
|
|
||||||
|
@usage Find a computer hosting the `"chat"` protocol with a hostname of `"my_host"`.
|
||||||
|
|
||||||
|
local id = rednet.lookup("chat", "my_host")
|
||||||
|
if id then
|
||||||
|
print("Found my_host at computer #" .. id)
|
||||||
|
else
|
||||||
|
printError("Cannot find my_host")
|
||||||
|
end
|
||||||
|
|
||||||
|
]]
|
||||||
function lookup(protocol, hostname)
|
function lookup(protocol, hostname)
|
||||||
expect(1, protocol, "string")
|
expect(1, protocol, "string")
|
||||||
expect(2, hostname, "string", "nil")
|
expect(2, hostname, "string", "nil")
|
||||||
|
@ -108,39 +108,48 @@ local function makePagedScroll(_term, _nFreeLines)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Prints a given string to the display.
|
--[[- Prints a given string to the display.
|
||||||
--
|
|
||||||
-- If the action can be completed without scrolling, it acts much the same as
|
If the action can be completed without scrolling, it acts much the same as
|
||||||
-- @{print}; otherwise, it will throw up a "Press any key to continue" prompt at
|
@{print}; otherwise, it will throw up a "Press any key to continue" prompt at
|
||||||
-- the bottom of the display. Each press will cause it to scroll down and write
|
the bottom of the display. Each press will cause it to scroll down and write a
|
||||||
-- a single line more before prompting again, if need be.
|
single line more before prompting again, if need be.
|
||||||
--
|
|
||||||
-- @tparam string _sText The text to print to the screen.
|
@tparam string text The text to print to the screen.
|
||||||
-- @tparam[opt] number _nFreeLines The number of lines which will be
|
@tparam[opt] number free_lines The number of lines which will be
|
||||||
-- automatically scrolled before the first prompt appears (meaning _nFreeLines +
|
automatically scrolled before the first prompt appears (meaning free_lines +
|
||||||
-- 1 lines will be printed). This can be set to the terminal's height - 2 to
|
1 lines will be printed). This can be set to the cursor's y position - 2 to
|
||||||
-- always try to fill the screen. Defaults to 0, meaning only one line is
|
always try to fill the screen. Defaults to 0, meaning only one line is
|
||||||
-- displayed before prompting.
|
displayed before prompting.
|
||||||
-- @treturn number The number of lines printed.
|
@treturn number The number of lines printed.
|
||||||
-- @usage
|
|
||||||
-- local width, height = term.getSize()
|
@usage Generates several lines of text and then prints it, paging once the
|
||||||
-- textutils.pagedPrint(("This is a rather verbose dose of repetition.\n"):rep(30), height - 2)
|
bottom of the terminal is reached.
|
||||||
function pagedPrint(_sText, _nFreeLines)
|
|
||||||
expect(2, _nFreeLines, "number", "nil")
|
local lines = {}
|
||||||
|
for i = 1, 30 do lines[i] = ("This is line #%d"):format(i) end
|
||||||
|
local message = table.concat(lines, "\n")
|
||||||
|
|
||||||
|
local width, height = term.getCursorPos()
|
||||||
|
textutils.pagedPrint(message, height - 2)
|
||||||
|
]]
|
||||||
|
function pagedPrint(text, free_lines)
|
||||||
|
expect(2, free_lines, "number", "nil")
|
||||||
-- Setup a redirector
|
-- Setup a redirector
|
||||||
local oldTerm = term.current()
|
local oldTerm = term.current()
|
||||||
local newTerm = {}
|
local newTerm = {}
|
||||||
for k, v in pairs(oldTerm) do
|
for k, v in pairs(oldTerm) do
|
||||||
newTerm[k] = v
|
newTerm[k] = v
|
||||||
end
|
end
|
||||||
newTerm.scroll = makePagedScroll(oldTerm, _nFreeLines)
|
|
||||||
|
newTerm.scroll = makePagedScroll(oldTerm, free_lines)
|
||||||
term.redirect(newTerm)
|
term.redirect(newTerm)
|
||||||
|
|
||||||
-- Print the text
|
-- Print the text
|
||||||
local result
|
local result
|
||||||
local ok, err = pcall(function()
|
local ok, err = pcall(function()
|
||||||
if _sText ~= nil then
|
if text ~= nil then
|
||||||
result = print(_sText)
|
result = print(text)
|
||||||
else
|
else
|
||||||
result = print()
|
result = print()
|
||||||
end
|
end
|
||||||
@ -214,32 +223,45 @@ local function tabulateCommon(bPaged, ...)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Prints tables in a structured form.
|
--[[- Prints tables in a structured form.
|
||||||
--
|
|
||||||
-- This accepts multiple arguments, either a table or a number. When
|
This accepts multiple arguments, either a table or a number. When
|
||||||
-- encountering a table, this will be treated as a table row, with each column
|
encountering a table, this will be treated as a table row, with each column
|
||||||
-- width being auto-adjusted.
|
width being auto-adjusted.
|
||||||
--
|
|
||||||
-- When encountering a number, this sets the text color of the subsequent rows to it.
|
When encountering a number, this sets the text color of the subsequent rows to it.
|
||||||
--
|
|
||||||
-- @tparam {string...}|number ... The rows and text colors to display.
|
@tparam {string...}|number ... The rows and text colors to display.
|
||||||
-- @usage textutils.tabulate(colors.orange, { "1", "2", "3" }, colors.lightBlue, { "A", "B", "C" })
|
@since 1.3
|
||||||
-- @since 1.3
|
@usage
|
||||||
|
|
||||||
|
textutils.tabulate(
|
||||||
|
colors.orange, { "1", "2", "3" },
|
||||||
|
colors.lightBlue, { "A", "B", "C" }
|
||||||
|
)
|
||||||
|
]]
|
||||||
function tabulate(...)
|
function tabulate(...)
|
||||||
return tabulateCommon(false, ...)
|
return tabulateCommon(false, ...)
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Prints tables in a structured form, stopping and prompting for input should
|
--[[- Prints tables in a structured form, stopping and prompting for input should
|
||||||
-- the result not fit on the terminal.
|
the result not fit on the terminal.
|
||||||
--
|
|
||||||
-- This functions identically to @{textutils.tabulate}, but will prompt for user
|
This functions identically to @{textutils.tabulate}, but will prompt for user
|
||||||
-- input should the whole output not fit on the display.
|
input should the whole output not fit on the display.
|
||||||
--
|
|
||||||
-- @tparam {string...}|number ... The rows and text colors to display.
|
@tparam {string...}|number ... The rows and text colors to display.
|
||||||
-- @usage textutils.tabulate(colors.orange, { "1", "2", "3" }, colors.lightBlue, { "A", "B", "C" })
|
@see textutils.tabulate
|
||||||
-- @see textutils.tabulate
|
@see textutils.pagedPrint
|
||||||
-- @see textutils.pagedPrint
|
@since 1.3
|
||||||
-- @since 1.3
|
|
||||||
|
@usage Generates a long table, tabulates it, and prints it to the screen.
|
||||||
|
|
||||||
|
local rows = {}
|
||||||
|
for i = 1, 30 do rows[i] = {("Row #%d"):format(i), math.random(1, 400)} end
|
||||||
|
|
||||||
|
textutils.tabulate(colors.orange, {"Column", "Value"}, colors.lightBlue, table.unpack(rows))
|
||||||
|
]]
|
||||||
function pagedTabulate(...)
|
function pagedTabulate(...)
|
||||||
return tabulateCommon(true, ...)
|
return tabulateCommon(true, ...)
|
||||||
end
|
end
|
||||||
@ -692,11 +714,11 @@ saving in a file or pretty-printing.
|
|||||||
@throws If the object contains a value which cannot be
|
@throws If the object contains a value which cannot be
|
||||||
serialised. This includes functions and tables which appear multiple
|
serialised. This includes functions and tables which appear multiple
|
||||||
times.
|
times.
|
||||||
@see cc.pretty.pretty An alternative way to display a table, often more suitable for
|
@see cc.pretty.pretty_print An alternative way to display a table, often more
|
||||||
pretty printing.
|
suitable for pretty printing.
|
||||||
@since 1.3
|
@since 1.3
|
||||||
@changed 1.97.0 Added `opts` argument.
|
@changed 1.97.0 Added `opts` argument.
|
||||||
@usage Pretty print a basic table.
|
@usage Serialise a basic table.
|
||||||
|
|
||||||
textutils.serialise({ 1, 2, 3, a = 1, ["another key"] = { true } })
|
textutils.serialise({ 1, 2, 3, a = 1, ["another key"] = { true } })
|
||||||
|
|
||||||
|
@ -1,6 +1,4 @@
|
|||||||
--- The turtle API allows you to control your turtle.
|
--- @module turtle
|
||||||
--
|
|
||||||
-- @module turtle
|
|
||||||
|
|
||||||
if not turtle then
|
if not turtle then
|
||||||
error("Cannot load turtle API on computer", 2)
|
error("Cannot load turtle API on computer", 2)
|
||||||
@ -8,9 +6,8 @@ end
|
|||||||
|
|
||||||
--- The builtin turtle API, without any generated helper functions.
|
--- The builtin turtle API, without any generated helper functions.
|
||||||
--
|
--
|
||||||
-- Generally you should not need to use this table - it only exists for
|
-- @deprecated Historically this table behaved differently to the main turtle API, but this is no longer the base. You
|
||||||
-- backwards compatibility reasons.
|
-- should not need to use it.
|
||||||
-- @deprecated
|
|
||||||
native = turtle.native or turtle
|
native = turtle.native or turtle
|
||||||
|
|
||||||
local function addCraftMethod(object)
|
local function addCraftMethod(object)
|
||||||
|
@ -1,3 +1,15 @@
|
|||||||
|
# New features in CC: Tweaked 1.100.0
|
||||||
|
|
||||||
|
* Speakers can now play arbitrary PCM audio.
|
||||||
|
* Add support for encoding and decoding DFPWM streams, with the `cc.audio.dfpwm` module.
|
||||||
|
* Wired modems now only render breaking progress for the part which is being broken.
|
||||||
|
* Various documentation improvements.
|
||||||
|
|
||||||
|
Several bug fixes:
|
||||||
|
* Fix the "repeat" program not repeating broadcast rednet messages.
|
||||||
|
* Fix the drag-and-drop upload functionality writing empty files.
|
||||||
|
* Prevent turtles from pushing non-pushable entities.
|
||||||
|
|
||||||
# New features in CC: Tweaked 1.99.1
|
# New features in CC: Tweaked 1.99.1
|
||||||
|
|
||||||
* Add package.searchpath to the cc.require API. (MCJack123)
|
* Add package.searchpath to the cc.require API. (MCJack123)
|
||||||
|
@ -6,7 +6,7 @@ Uses LuaJ from http://luaj.sourceforge.net/
|
|||||||
The ComputerCraft 1.76 update was sponsored by MinecraftU and Deep Space.
|
The ComputerCraft 1.76 update was sponsored by MinecraftU and Deep Space.
|
||||||
Visit http://www.minecraftu.org and http://www.deepspace.me/space-cadets to find out more.
|
Visit http://www.minecraftu.org and http://www.deepspace.me/space-cadets to find out more.
|
||||||
|
|
||||||
Join the ComputerCraft community online at http://www.computercraft.info
|
Join the ComputerCraft community online at https://computercraft.cc
|
||||||
Follow @DanTwoHundred on Twitter!
|
Follow @DanTwoHundred on Twitter!
|
||||||
|
|
||||||
To help contribute to ComputerCraft, browse the source code at https://github.com/dan200/ComputerCraft.
|
To help contribute to ComputerCraft, browse the source code at https://github.com/dan200/ComputerCraft.
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
New features in CC: Tweaked 1.99.1
|
New features in CC: Tweaked 1.100.0
|
||||||
|
|
||||||
* Add package.searchpath to the cc.require API. (MCJack123)
|
* Speakers can now play arbitrary PCM audio.
|
||||||
* Provide a more efficient way for the Java API to consume Lua tables in certain restricted cases.
|
* Add support for encoding and decoding DFPWM streams, with the `cc.audio.dfpwm` module.
|
||||||
|
* Wired modems now only render breaking progress for the part which is being broken.
|
||||||
|
* Various documentation improvements.
|
||||||
|
|
||||||
Several bug fixes:
|
Several bug fixes:
|
||||||
* Fix keys being "sticky" when opening the off-hand pocket computer GUI.
|
* Fix the "repeat" program not repeating broadcast rednet messages.
|
||||||
* Correctly handle broken coroutine managers resuming Java code with a `nil` event.
|
* Fix the drag-and-drop upload functionality writing empty files.
|
||||||
* Prevent computer buttons stealing focus from the terminal.
|
* Prevent turtles from pushing non-pushable entities.
|
||||||
* Fix a class cast exception when a monitor is malformed in ways I do not quite understand.
|
|
||||||
|
|
||||||
Type "help changelog" to see the full version history.
|
Type "help changelog" to see the full version history.
|
||||||
|
@ -36,7 +36,7 @@ local encoder = dfpwm.make_encoder()
|
|||||||
local decoder = dfpwm.make_decoder()
|
local decoder = dfpwm.make_decoder()
|
||||||
|
|
||||||
local out = fs.open("speedy.dfpwm", "wb")
|
local out = fs.open("speedy.dfpwm", "wb")
|
||||||
for input in io.lines("my_audio_track.dfpwm", 16 * 1024 * 2) do
|
for input in io.lines("data/example.dfpwm", 16 * 1024 * 2) do
|
||||||
local decoded = decoder(input)
|
local decoded = decoder(input)
|
||||||
local output = {}
|
local output = {}
|
||||||
|
|
||||||
|
@ -224,8 +224,8 @@ end
|
|||||||
|
|
||||||
--- Display a document on the terminal.
|
--- Display a document on the terminal.
|
||||||
--
|
--
|
||||||
-- @tparam Doc doc The document to render
|
-- @tparam Doc doc The document to render
|
||||||
-- @tparam[opt] number ribbon_frac The maximum fraction of the width that we should write in.
|
-- @tparam[opt=0.6] number ribbon_frac The maximum fraction of the width that we should write in.
|
||||||
local function write(doc, ribbon_frac)
|
local function write(doc, ribbon_frac)
|
||||||
if getmetatable(doc) ~= Doc then expect(1, doc, "document") end
|
if getmetatable(doc) ~= Doc then expect(1, doc, "document") end
|
||||||
expect(2, ribbon_frac, "number", "nil")
|
expect(2, ribbon_frac, "number", "nil")
|
||||||
@ -286,8 +286,8 @@ end
|
|||||||
|
|
||||||
--- Display a document on the terminal with a trailing new line.
|
--- Display a document on the terminal with a trailing new line.
|
||||||
--
|
--
|
||||||
-- @tparam Doc doc The document to render.
|
-- @tparam Doc doc The document to render.
|
||||||
-- @tparam[opt] number ribbon_frac The maximum fraction of the width that we should write in.
|
-- @tparam[opt=0.6] number ribbon_frac The maximum fraction of the width that we should write in.
|
||||||
local function print(doc, ribbon_frac)
|
local function print(doc, ribbon_frac)
|
||||||
if getmetatable(doc) ~= Doc then expect(1, doc, "document") end
|
if getmetatable(doc) ~= Doc then expect(1, doc, "document") end
|
||||||
expect(2, ribbon_frac, "number", "nil")
|
expect(2, ribbon_frac, "number", "nil")
|
||||||
@ -297,10 +297,10 @@ end
|
|||||||
|
|
||||||
--- Render a document, converting it into a string.
|
--- Render a document, converting it into a string.
|
||||||
--
|
--
|
||||||
-- @tparam Doc doc The document to render.
|
-- @tparam Doc doc The document to render.
|
||||||
-- @tparam[opt] number width The maximum width of this document. Note that long strings will not be wrapped to
|
-- @tparam[opt] number width The maximum width of this document. Note that long strings will not be wrapped to fit
|
||||||
-- fit this width - it is only used for finding the best layout.
|
-- this width - it is only used for finding the best layout.
|
||||||
-- @tparam[opt] number ribbon_frac The maximum fraction of the width that we should write in.
|
-- @tparam[opt=0.6] number ribbon_frac The maximum fraction of the width that we should write in.
|
||||||
-- @treturn string The rendered document as a string.
|
-- @treturn string The rendered document as a string.
|
||||||
local function render(doc, width, ribbon_frac)
|
local function render(doc, width, ribbon_frac)
|
||||||
if getmetatable(doc) ~= Doc then expect(1, doc, "document") end
|
if getmetatable(doc) ~= Doc then expect(1, doc, "document") end
|
||||||
@ -483,7 +483,7 @@ Controls how various properties are displayed.
|
|||||||
- `function_args`: Show the arguments to a function if known (`false` by default).
|
- `function_args`: Show the arguments to a function if known (`false` by default).
|
||||||
- `function_source`: Show where the function was defined, instead of
|
- `function_source`: Show where the function was defined, instead of
|
||||||
`function: xxxxxxxx` (`false` by default).
|
`function: xxxxxxxx` (`false` by default).
|
||||||
@tparam[opt] number ribbon_frac The maximum fraction of the width that we should write in.
|
@tparam[opt=0.6] number ribbon_frac The maximum fraction of the width that we should write in.
|
||||||
|
|
||||||
@usage Display a table on the screen.
|
@usage Display a table on the screen.
|
||||||
|
|
||||||
|
@ -1,22 +1,24 @@
|
|||||||
--- This provides a pure Lua implementation of the builtin @{require} function
|
--[[- This provides a pure Lua implementation of the builtin @{require} function
|
||||||
-- and @{package} library.
|
and @{package} library.
|
||||||
--
|
|
||||||
-- Generally you do not need to use this module - it is injected into the
|
Generally you do not need to use this module - it is injected into the every
|
||||||
-- every program's environment. However, it may be useful when building a
|
program's environment. However, it may be useful when building a custom shell or
|
||||||
-- custom shell or when running programs yourself.
|
when running programs yourself.
|
||||||
--
|
|
||||||
-- @module cc.require
|
@module cc.require
|
||||||
-- @since 1.88.0
|
@since 1.88.0
|
||||||
-- @usage Construct the package and require function, and insert them into a
|
@see using_require For an introduction on how to use @{require}.
|
||||||
-- custom environment.
|
@usage Construct the package and require function, and insert them into a
|
||||||
--
|
custom environment.
|
||||||
-- local r = require "cc.require"
|
|
||||||
-- local env = setmetatable({}, { __index = _ENV })
|
local r = require "cc.require"
|
||||||
-- env.require, env.package = r.make(env, "/")
|
local env = setmetatable({}, { __index = _ENV })
|
||||||
--
|
env.require, env.package = r.make(env, "/")
|
||||||
-- -- Now we have our own require function, separate to the original.
|
|
||||||
-- local r2 = env.require "cc.require"
|
-- Now we have our own require function, separate to the original.
|
||||||
-- print(r, r2)
|
local r2 = env.require "cc.require"
|
||||||
|
print(r, r2)
|
||||||
|
]]
|
||||||
|
|
||||||
local expect = require and require("cc.expect") or dofile("rom/modules/main/cc/expect.lua")
|
local expect = require and require("cc.expect") or dofile("rom/modules/main/cc/expect.lua")
|
||||||
local expect = expect.expect
|
local expect = expect.expect
|
||||||
|
@ -171,7 +171,7 @@ end
|
|||||||
local current_section = nil
|
local current_section = nil
|
||||||
local offset = 0
|
local offset = 0
|
||||||
|
|
||||||
--- Find the currently visible seciton, or nil if this document has no sections.
|
--- Find the currently visible section, or nil if this document has no sections.
|
||||||
--
|
--
|
||||||
-- This could potentially be a binary search, but right now it's not worth it.
|
-- This could potentially be a binary search, but right now it's not worth it.
|
||||||
local function find_section()
|
local function find_section()
|
||||||
|
@ -26,13 +26,14 @@ const Click = (options: { run: () => void }) =>
|
|||||||
|
|
||||||
type WindowProps = {};
|
type WindowProps = {};
|
||||||
|
|
||||||
type WindowState = {
|
type Example = {
|
||||||
visible: boolean,
|
files: { [file: string]: string },
|
||||||
|
|
||||||
example: string,
|
|
||||||
exampleIdx: number,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type WindowState = {
|
||||||
|
exampleIdx: number,
|
||||||
|
} & ({ visible: false, example: null } | { visible: true, example: Example })
|
||||||
|
|
||||||
type Touch = { clientX: number, clientY: number };
|
type Touch = { clientX: number, clientY: number };
|
||||||
|
|
||||||
class Window extends Component<WindowProps, WindowState> {
|
class Window extends Component<WindowProps, WindowState> {
|
||||||
@ -41,12 +42,14 @@ class Window extends Component<WindowProps, WindowState> {
|
|||||||
private top: number = 0;
|
private top: number = 0;
|
||||||
private dragging?: { downX: number, downY: number, initialX: number, initialY: number };
|
private dragging?: { downX: number, downY: number, initialX: number, initialY: number };
|
||||||
|
|
||||||
|
private snippets: { [file: string]: string } = {};
|
||||||
|
|
||||||
constructor(props: WindowProps, context: unknown) {
|
constructor(props: WindowProps, context: unknown) {
|
||||||
super(props, context);
|
super(props, context);
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
visible: false,
|
visible: false,
|
||||||
example: "",
|
example: null,
|
||||||
exampleIdx: 0,
|
exampleIdx: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -57,10 +60,16 @@ class Window extends Component<WindowProps, WindowState> {
|
|||||||
const element = elements[i] as HTMLElement;
|
const element = elements[i] as HTMLElement;
|
||||||
|
|
||||||
let example = element.innerText;
|
let example = element.innerText;
|
||||||
|
|
||||||
|
const snippet = element.getAttribute("data-snippet");
|
||||||
|
if (snippet) this.snippets[snippet] = example;
|
||||||
|
|
||||||
if (element.getAttribute("data-lua-kind") == "expr") {
|
if (element.getAttribute("data-lua-kind") == "expr") {
|
||||||
example = exprTemplate.replace("__expr__", example);
|
example = exprTemplate.replace("__expr__", example);
|
||||||
}
|
}
|
||||||
render(<Click run={this.runExample(example)} />, element);
|
|
||||||
|
const mount = element.getAttribute("data-mount");
|
||||||
|
render(<Click run={this.runExample(example, mount)} />, element);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,13 +85,13 @@ class Window extends Component<WindowProps, WindowState> {
|
|||||||
</div>
|
</div>
|
||||||
<div class="computer-container">
|
<div class="computer-container">
|
||||||
<Computer key={exampleIdx} files={{
|
<Computer key={exampleIdx} files={{
|
||||||
"example.lua": example, ...defaultFiles
|
...example!.files, ...defaultFiles
|
||||||
}} />
|
}} />
|
||||||
</div>
|
</div>
|
||||||
</div> : <div class="example-window example-window-hidden" />;
|
</div> : <div class="example-window example-window-hidden" />;
|
||||||
}
|
}
|
||||||
|
|
||||||
private runExample(example: string): () => void {
|
private runExample(example: string, mount: string | null): () => void {
|
||||||
return () => {
|
return () => {
|
||||||
if (!this.positioned) {
|
if (!this.positioned) {
|
||||||
this.positioned = true;
|
this.positioned = true;
|
||||||
@ -90,9 +99,17 @@ class Window extends Component<WindowProps, WindowState> {
|
|||||||
this.top = 20;
|
this.top = 20;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const files: { [file: string]: string } = { "example.lua": example };
|
||||||
|
if (mount !== null) {
|
||||||
|
for (const toMount of mount.split(",")) {
|
||||||
|
const [name, path] = toMount.split(":", 2);
|
||||||
|
files[path] = this.snippets[name] || "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
this.setState(({ exampleIdx }: WindowState) => ({
|
this.setState(({ exampleIdx }: WindowState) => ({
|
||||||
visible: true,
|
visible: true,
|
||||||
example: example,
|
example: { files },
|
||||||
exampleIdx: exampleIdx + 1,
|
exampleIdx: exampleIdx + 1,
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user