Add base class for network interface devices.

This commit is contained in:
Florian Nücke
2022-01-13 10:47:40 +01:00
parent fe7fc442aa
commit 3fe23f68ce
2 changed files with 174 additions and 135 deletions

View File

@@ -0,0 +1,171 @@
package li.cil.oc2.common.bus.device.item;
import com.google.common.eventbus.Subscribe;
import li.cil.oc2.api.bus.device.ItemDevice;
import li.cil.oc2.api.bus.device.vm.VMDevice;
import li.cil.oc2.api.bus.device.vm.VMDeviceLoadResult;
import li.cil.oc2.api.bus.device.vm.context.VMContext;
import li.cil.oc2.api.bus.device.vm.event.VMInitializingEvent;
import li.cil.oc2.api.bus.device.vm.event.VMPausingEvent;
import li.cil.oc2.api.bus.device.vm.event.VMResumingRunningEvent;
import li.cil.oc2.api.capabilities.NetworkInterface;
import li.cil.oc2.common.bus.device.util.IdentityProxy;
import li.cil.oc2.common.bus.device.util.OptionalAddress;
import li.cil.oc2.common.bus.device.util.OptionalInterrupt;
import li.cil.oc2.common.capabilities.Capabilities;
import li.cil.oc2.common.serialization.NBTSerialization;
import li.cil.oc2.common.util.NBTTagIds;
import li.cil.sedna.device.virtio.VirtIONetworkDevice;
import net.minecraft.core.Direction;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.item.ItemStack;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.capabilities.ICapabilityProvider;
import net.minecraftforge.common.util.LazyOptional;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public abstract class AbstractNetworkInterfaceItemDevice extends IdentityProxy<ItemStack> implements VMDevice, ItemDevice, ICapabilityProvider {
private static final String DEVICE_TAG_NAME = "device";
private static final String ADDRESS_TAG_NAME = "address";
private static final String INTERRUPT_TAG_NAME = "interrupt";
///////////////////////////////////////////////////////////////
private VirtIONetworkDevice device;
private final NetworkInterface networkInterface = new NetworkInterfaceImpl();
private boolean isRunning;
private final OptionalAddress address = new OptionalAddress();
private final OptionalInterrupt interrupt = new OptionalInterrupt();
private CompoundTag deviceTag;
///////////////////////////////////////////////////////////////
protected AbstractNetworkInterfaceItemDevice(final ItemStack identity) {
super(identity);
}
///////////////////////////////////////////////////////////////
@Nonnull
@Override
public <T> LazyOptional<T> getCapability(final Capability<T> cap, @Nullable final Direction side) {
if (cap == Capabilities.NETWORK_INTERFACE) {
return LazyOptional.of(() -> networkInterface).cast();
}
return LazyOptional.empty();
}
@Override
public VMDeviceLoadResult mount(final VMContext context) {
device = new VirtIONetworkDevice(context.getMemoryMap());
if (!address.claim(context, device)) {
return VMDeviceLoadResult.fail();
}
if (interrupt.claim(context)) {
device.getInterrupt().set(interrupt.getAsInt(), context.getInterruptController());
} else {
return VMDeviceLoadResult.fail();
}
if (deviceTag != null) {
NBTSerialization.deserialize(deviceTag, device);
}
context.getEventBus().register(this);
return VMDeviceLoadResult.success();
}
@Override
public void unmount() {
suspend();
isRunning = false;
address.clear();
interrupt.clear();
}
@Override
public void suspend() {
device = null;
}
@Subscribe
public void handleInitializingEvent(final VMInitializingEvent event) {
isRunning = true;
}
@Subscribe
public void handlePausingEvent(final VMPausingEvent event) {
isRunning = false;
}
@Subscribe
public void handleResumingRunningEvent(final VMResumingRunningEvent event) {
isRunning = true;
}
@Override
public CompoundTag serializeNBT() {
final CompoundTag tag = new CompoundTag();
if (device != null) {
deviceTag = NBTSerialization.serialize(device);
}
if (deviceTag != null) {
tag.put(DEVICE_TAG_NAME, deviceTag);
}
if (address.isPresent()) {
tag.putLong(ADDRESS_TAG_NAME, address.getAsLong());
}
if (interrupt.isPresent()) {
tag.putInt(INTERRUPT_TAG_NAME, interrupt.getAsInt());
}
return tag;
}
@Override
public void deserializeNBT(final CompoundTag tag) {
if (tag.contains(DEVICE_TAG_NAME, NBTTagIds.TAG_COMPOUND)) {
deviceTag = tag.getCompound(DEVICE_TAG_NAME);
}
if (tag.contains(ADDRESS_TAG_NAME, NBTTagIds.TAG_LONG)) {
address.set(tag.getLong(ADDRESS_TAG_NAME));
}
if (tag.contains(INTERRUPT_TAG_NAME, NBTTagIds.TAG_INT)) {
interrupt.set(tag.getInt(INTERRUPT_TAG_NAME));
}
}
///////////////////////////////////////////////////////////////
protected NetworkInterface getNetworkInterface() {
return networkInterface;
}
///////////////////////////////////////////////////////////////
private final class NetworkInterfaceImpl implements NetworkInterface {
@Override
public byte[] readEthernetFrame() {
if (device != null && isRunning) {
return device.readEthernetFrame();
} else {
return null;
}
}
@Override
public void writeEthernetFrame(final NetworkInterface source, final byte[] frame, final int timeToLive) {
if (device != null && isRunning) {
device.writeEthernetFrame(frame);
}
}
}
}

View File

@@ -1,48 +1,15 @@
package li.cil.oc2.common.bus.device.item;
import com.google.common.eventbus.Subscribe;
import li.cil.oc2.api.bus.device.ItemDevice;
import li.cil.oc2.api.bus.device.vm.VMDevice;
import li.cil.oc2.api.bus.device.vm.VMDeviceLoadResult;
import li.cil.oc2.api.bus.device.vm.context.VMContext;
import li.cil.oc2.api.bus.device.vm.event.VMPausingEvent;
import li.cil.oc2.api.bus.device.vm.event.VMResumingRunningEvent;
import li.cil.oc2.api.capabilities.NetworkInterface;
import li.cil.oc2.common.bus.device.util.IdentityProxy;
import li.cil.oc2.common.bus.device.util.OptionalAddress;
import li.cil.oc2.common.bus.device.util.OptionalInterrupt;
import li.cil.oc2.common.capabilities.Capabilities;
import li.cil.oc2.common.item.NetworkInterfaceCardItem;
import li.cil.oc2.common.serialization.NBTSerialization;
import li.cil.oc2.common.util.NBTTagIds;
import li.cil.sedna.device.virtio.VirtIONetworkDevice;
import net.minecraft.core.Direction;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.item.ItemStack;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.capabilities.ICapabilityProvider;
import net.minecraftforge.common.util.LazyOptional;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public final class NetworkInterfaceCardItemDevice extends IdentityProxy<ItemStack> implements VMDevice, ItemDevice, ICapabilityProvider {
private static final String DEVICE_TAG_NAME = "device";
private static final String ADDRESS_TAG_NAME = "address";
private static final String INTERRUPT_TAG_NAME = "interrupt";
///////////////////////////////////////////////////////////////
private VirtIONetworkDevice device;
private final NetworkInterface networkInterface = new NetworkInterfaceImpl();
private boolean isRunning;
private final OptionalAddress address = new OptionalAddress();
private final OptionalInterrupt interrupt = new OptionalInterrupt();
private CompoundTag deviceTag;
///////////////////////////////////////////////////////////////
public final class NetworkInterfaceCardItemDevice extends AbstractNetworkInterfaceItemDevice {
public NetworkInterfaceCardItemDevice(final ItemStack identity) {
super(identity);
}
@@ -52,109 +19,10 @@ public final class NetworkInterfaceCardItemDevice extends IdentityProxy<ItemStac
@Nonnull
@Override
public <T> LazyOptional<T> getCapability(final Capability<T> cap, @Nullable final Direction side) {
if (cap == Capabilities.NETWORK_INTERFACE && NetworkInterfaceCardItem.getSideConfiguration(identity, side)) {
return LazyOptional.of(() -> networkInterface).cast();
if (NetworkInterfaceCardItem.getSideConfiguration(identity, side)) {
return super.getCapability(cap, side);
}
return LazyOptional.empty();
}
@Override
public VMDeviceLoadResult mount(final VMContext context) {
device = new VirtIONetworkDevice(context.getMemoryMap());
if (!address.claim(context, device)) {
return VMDeviceLoadResult.fail();
}
if (interrupt.claim(context)) {
device.getInterrupt().set(interrupt.getAsInt(), context.getInterruptController());
} else {
return VMDeviceLoadResult.fail();
}
if (deviceTag != null) {
NBTSerialization.deserialize(deviceTag, device);
}
context.getEventBus().register(this);
return VMDeviceLoadResult.success();
}
@Override
public void unmount() {
suspend();
isRunning = false;
address.clear();
interrupt.clear();
}
@Override
public void suspend() {
device = null;
}
@Subscribe
public void handlePausingEvent(final VMPausingEvent event) {
isRunning = false;
}
@Subscribe
public void handleResumingRunningEvent(final VMResumingRunningEvent event) {
isRunning = true;
}
@Override
public CompoundTag serializeNBT() {
final CompoundTag tag = new CompoundTag();
if (device != null) {
deviceTag = NBTSerialization.serialize(device);
}
if (deviceTag != null) {
tag.put(DEVICE_TAG_NAME, deviceTag);
}
if (address.isPresent()) {
tag.putLong(ADDRESS_TAG_NAME, address.getAsLong());
}
if (interrupt.isPresent()) {
tag.putInt(INTERRUPT_TAG_NAME, interrupt.getAsInt());
}
return tag;
}
@Override
public void deserializeNBT(final CompoundTag tag) {
if (tag.contains(DEVICE_TAG_NAME, NBTTagIds.TAG_COMPOUND)) {
deviceTag = tag.getCompound(DEVICE_TAG_NAME);
}
if (tag.contains(ADDRESS_TAG_NAME, NBTTagIds.TAG_LONG)) {
address.set(tag.getLong(ADDRESS_TAG_NAME));
}
if (tag.contains(INTERRUPT_TAG_NAME, NBTTagIds.TAG_INT)) {
interrupt.set(tag.getInt(INTERRUPT_TAG_NAME));
}
}
///////////////////////////////////////////////////////////////
private final class NetworkInterfaceImpl implements NetworkInterface {
@Override
public byte[] readEthernetFrame() {
if (device != null && isRunning) {
return device.readEthernetFrame();
} else {
return null;
}
}
@Override
public void writeEthernetFrame(final NetworkInterface source, final byte[] frame, final int timeToLive) {
if (device != null && isRunning) {
device.writeEthernetFrame(frame);
}
}
}
}