Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 22 additions & 6 deletions src/main/java/li/cil/oc2/api/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,12 +77,28 @@ This can be useful for various things. For example:
- Close and delete the file in `unmount()`.
- Close the file in `suspend()`.

### No Active Back-channel

Unlike some other computer mods (e.g. OpenComputers and ComputerCraft), there is no *active* back-channel in the
`RPCDevice` API. In other words, it is not possible for `RPCDevices` to raise events in the virtual machines. The only
way to provide data to the virtual machines is as values returned from exposed methods. Programs running in the virtual
machines will always have to poll for changed data.
### Subscriptions and Events

The `RPCDevice` API also lets devices raise events in the virtual machine, by implementing the `RPCEventSource`
interface. If using `ObjectDevice`, it will automatically notice if the wrapped object implements `RPCEventSource`; if
implementing `RPCDevice` directly you can either implement `RPCEventSource` on the same type, or override the
`asEventSource` method to return the actual event source. The VM will then be able to subscribe to events from the
device, which can be sent by calling `postEvent` on the `IEventSink` passed to `subscribe`. An example of this is
the built-in `RedstoneInterfaceBlockEntity` device.

#### Note: This is mostly a new feature and there are several caveats to keep in mind when using it.

- If subscriptions are used on or before OC2R version 2.2.12, they can cause a server crash if too many messages are
sent at once. To be safe, do not send any event in the same tick as another message, or depend on a later minimum
version of OC2R.
- Right now, if a lot of messages are sent and the VM does not listen for them, some may be dropped; in theory the VM
can detect this, but none of the existing libraries do (see next point). You cannot depend on the events being
reliably delivered, and must use some other communication channel if reliability is a requirement. A method call
should not have this issue unless the results and all the (subscribed to) events in that tick put together are more
than 4 KiB, though be aware that if the method call causes a state change, that might itself cause some events.
- The on-the-"wire" event and subscription format is probably stable, but the VM's userspace python and lua libraries do
not easily support them yet, and often silently discard events when expecting a different sort of message. Better
support is actively being worked on.

## The `BlockDeviceProvider` and `ItemDeviceProvider`

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ public ObjectDevice(final Object object) {
}

///////////////////////////////////////////////////////////////////
@Override
public RPCEventSource asEventSource() {
if (object instanceof RPCEventSource res) {
return res;
Expand Down
9 changes: 7 additions & 2 deletions src/main/java/li/cil/oc2/api/bus/device/rpc/IEventSink.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
/* SPDX-License-Identifier: MIT */

package li.cil.oc2.api.bus.device.rpc;
import com.google.gson.JsonElement;
import java.util.UUID;

/**
Expand All @@ -10,5 +9,11 @@
*/

public interface IEventSink {
void postEvent(UUID sourceid, JsonElement msg);
/**
* Hand a message to the event sink to process
*
* @param sourceid The UUID of the originator, usually given by {@link RPCEventSource#subscribe(IEventSink, UUID)}
* @param msg The message. Should be serializable with gson
*/
void postEvent(UUID sourceid, Object msg);
}
21 changes: 21 additions & 0 deletions src/main/java/li/cil/oc2/api/bus/device/rpc/RPCDevice.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@

import java.util.List;

import javax.annotation.Nullable;

/**
* Provides an interface for an RPC device, describing the methods that can be
* called on it and the type names it can be detected by/is compatible with.
Expand Down Expand Up @@ -72,6 +74,25 @@ public interface RPCDevice extends Device {
*/
List<RPCMethodGroup> getMethodGroups();

/**
* Get an {@link RPCEventSource} that handles events for this device, if any
*
* By default, returns {@code this} if it's an event source, but can be overriden if the event source and the device
* are different objects.
*
* @return An {@link RPCEventSource} that can be used for subscription and unsubscription, or {@code null} if
* subscriptions are not supported.
*/
@Nullable
default RPCEventSource asEventSource() {
if (this instanceof RPCEventSource res) {
return res;
}
else {
return null;
}
}

/**
* Called to start this device.
* <p>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@
import java.util.*;

/**
* Provides an interface for an RPC event source. Blocks which whish to provide
* push notifications via the /dev/hvc0 serial devices should implement this.
* Provides an interface for an RPC event source. Blocks which wish to provide
* push notifications via the RPC bus serial device should implement this.
* It is generally recommended to *also* provide documentation and a list of
* events by implementing DocumentedDevice and providing a listEvents() callback
* events by implementing {@link li.cil.oc2.api.bus.device.object.DocumentedDevice
* DocumentedDevice} and providing a {@code listEvents()} callback
* <p>
*/
public interface RPCEventSource {
Expand Down
Loading