added command block, note block and rim carriage controller drivers (moved from oc core)

This commit is contained in:
Florian Nücke 2014-02-06 15:11:05 +01:00
parent d39cdd40a4
commit 338f898a85
9 changed files with 340 additions and 4 deletions

View File

@ -6,6 +6,7 @@ import li.cil.oc.driver.Registry;
import li.cil.oc.driver.buildcraft.HandlerBuildCraft;
import li.cil.oc.driver.enderstorage.HandlerEnderStorage;
import li.cil.oc.driver.ic2.HandlerIndustrialCraft2;
import li.cil.oc.driver.redstoneinmotion.HandlerRedstoneInMotion;
import li.cil.oc.driver.thermalexpansion.HandlerThermalExpansion;
import li.cil.oc.driver.vanilla.HandlerVanilla;
@ -19,6 +20,7 @@ public class OpenComponents {
Registry.add(new HandlerBuildCraft());
Registry.add(new HandlerEnderStorage());
Registry.add(new HandlerIndustrialCraft2());
Registry.add(new HandlerRedstoneInMotion());
Registry.add(new HandlerThermalExpansion());
Registry.add(new HandlerVanilla());
}

View File

@ -8,7 +8,13 @@ public abstract class TileEntityDriver implements li.cil.oc.api.driver.Block {
@Override
public boolean worksWith(final World world, final int x, final int y, final int z) {
final Class<?> filter = getFilterClass();
if (filter == null) {
// This can happen if filter classes are deduced by reflection and
// the class in question is not present.
return false;
}
final TileEntity tileEntity = world.getBlockTileEntity(x, y, z);
return tileEntity != null && getFilterClass().isAssignableFrom(tileEntity.getClass());
return tileEntity != null && filter.isAssignableFrom(tileEntity.getClass());
}
}

View File

@ -42,7 +42,7 @@ public final class DriverFrequencyOwner extends TileEntityDriver {
}
final String owner = (String) Reflection.get(tileEntity, "owner");
if (owner == null || owner.isEmpty() || "global".equals(owner)) {
Reflection.invoke(tileEntity, "setFreq", frequency);
Reflection.tryInvoke(tileEntity, "setFreq", frequency);
} else {
return new Object[]{false, "cannot change frequency of owned storage"};
}

View File

@ -0,0 +1,184 @@
package li.cil.oc.driver.redstoneinmotion;
import li.cil.oc.api.network.Arguments;
import li.cil.oc.api.network.Callback;
import li.cil.oc.api.network.Context;
import li.cil.oc.api.network.ManagedEnvironment;
import li.cil.oc.driver.ManagedTileEntityEnvironment;
import li.cil.oc.driver.TileEntityDriver;
import li.cil.oc.util.Reflection;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.world.World;
import java.util.HashMap;
import java.util.Map;
public final class DriverCarriageController extends TileEntityDriver {
private static final Class<?> CarriageControllerEntity = Reflection.getClass("JAKJ.RedstoneInMotion.CarriageControllerEntity");
private static final Class<?> CarriageObstructionException = Reflection.getClass("JAKJ.RedstoneInMotion.CarriageObstructionException");
private static final Class<?> Directions = Reflection.getClass("JAKJ.RedstoneInMotion.Directions");
@Override
public Class<?> getFilterClass() {
return CarriageControllerEntity;
}
@Override
public ManagedEnvironment createEnvironment(final World world, final int x, final int y, final int z) {
return new Environment(world.getBlockTileEntity(x, y, z));
}
public static final class Environment extends ManagedTileEntityEnvironment<TileEntity> {
private boolean isAnchored;
// Arguments for an actual move, stored here until we hit the next
// call to update(). See below for more information as to why.
private boolean shouldMove;
private boolean isSimulating;
private int direction;
// Used to check whether we should send a success signal after loading.
private boolean isMoving;
// Used to delay success signals after a move to make sure the computer
// that triggered the move is reachable again.
private int signalDelay = 10;
public Environment(final TileEntity tileEntity) {
super(tileEntity, "carriage");
}
@Callback(direct = true)
public Object[] getAnchored(final Context context, final Arguments args) {
return new Object[]{isAnchored};
}
@Callback
public Object[] setAnchored(final Context context, final Arguments args) {
isAnchored = args.checkBoolean(0);
return new Object[]{isAnchored};
}
@Callback
public Object[] move(final Context context, final Arguments args) {
// We execute moves in the update() call to the environment instead
// of in here, because the move may cause the calling computer to
// be persisted - which is not possible while it has an active call
// (namely to this function).
direction = checkDirection(args);
isSimulating = args.count() > 1 && args.checkBoolean(1);
shouldMove = true;
context.pause(0.1);
return new Object[]{true};
}
@Callback
public Object[] simulate(final Context context, final Arguments args) {
// IMPORTANT: we have to do the simulation asynchronously, too,
// because that may also try to persist the computer that called us,
// and it must not be running when we do that.
direction = checkDirection(args);
isSimulating = true;
shouldMove = true;
context.pause(0.1);
return new Object[]{true};
}
@Override
public boolean canUpdate() {
return true;
}
@Override
public void update() {
if (node != null && node.network() != null && isMoving) {
--signalDelay;
if (signalDelay <= 0) {
isMoving = false;
node.sendToReachable("computer.signal", "carriage_moved", true);
}
}
if (shouldMove) {
shouldMove = false;
isMoving = true;
try {
Reflection.invoke(tileEntity, "SetupMotion", Directions.getEnumConstants()[direction], isSimulating, isAnchored);
Reflection.invoke(tileEntity, "Move");
if (isSimulating) {
node.sendToReachable("computer.signal", "carriage_moved", true);
}
} catch (final Throwable e) {
if (CarriageObstructionException != null && CarriageObstructionException.isAssignableFrom(e.getClass())) {
try {
final int x = (Integer) Reflection.get(e, "X");
final int y = (Integer) Reflection.get(e, "Y");
final int z = (Integer) Reflection.get(e, "Z");
node.sendToReachable("computer.signal", "carriage_moved", false, e.getMessage() != null ? e.getMessage() : e.toString(), x, y, z);
} catch (Throwable e2) {
node.sendToReachable("computer.signal", "carriage_moved", false, e2.getMessage() != null ? e2.getMessage() : e2.toString());
}
} else {
node.sendToReachable("computer.signal", "carriage_moved", false, e.getMessage() != null ? e.getMessage() : e.toString());
}
} finally {
// At this point we have already been saved if the move was
// successful, so we can safely always revert this to false.
isMoving = false;
}
}
}
@Override
public void load(final NBTTagCompound nbt) {
super.load(nbt);
isMoving = nbt.getBoolean("moving");
isAnchored = nbt.getBoolean("anchored");
}
@Override
public void save(final NBTTagCompound nbt) {
super.save(nbt);
nbt.setBoolean("moving", isMoving);
nbt.setBoolean("anchored", isAnchored);
}
private int checkDirection(final Arguments args) {
if (shouldMove || isMoving) {
throw new RuntimeException("already moving");
}
if (args.isString(0)) {
final String name = args.checkString(0).toLowerCase();
if (!sideNames.containsKey(name)) {
throw new IllegalArgumentException("invalid direction");
}
return sideNames.get(name);
} else {
final int index = args.checkInteger(0);
if (index < 0 || index > 5) {
throw new IllegalArgumentException("invalid direction");
}
return index;
}
}
private static final Map<String, Integer> sideNames;
static {
sideNames = new HashMap<String, Integer>();
sideNames.put("negy", 0);
sideNames.put("posy", 1);
sideNames.put("negz", 2);
sideNames.put("posz", 3);
sideNames.put("negx", 4);
sideNames.put("posx", 5);
sideNames.put("down", 0);
sideNames.put("up", 1);
sideNames.put("north", 2);
sideNames.put("south", 3);
sideNames.put("west", 4);
sideNames.put("east", 5);
}
}
}

View File

@ -0,0 +1,23 @@
package li.cil.oc.driver.redstoneinmotion;
import li.cil.oc.api.Driver;
import li.cil.oc.driver.IModHandler;
import net.minecraft.item.ItemStack;
import java.util.Map;
public final class HandlerRedstoneInMotion implements IModHandler {
@Override
public String getModId() {
return "JAKJ_RedstoneInMotion";
}
@Override
public void initialize() {
Driver.add(new DriverCarriageController());
}
@Override
public void populate(Map<String, Object> map, ItemStack stack) {
}
}

View File

@ -0,0 +1,46 @@
package li.cil.oc.driver.vanilla;
import li.cil.oc.api.network.Arguments;
import li.cil.oc.api.network.Callback;
import li.cil.oc.api.network.Context;
import li.cil.oc.api.network.ManagedEnvironment;
import li.cil.oc.driver.ManagedTileEntityEnvironment;
import li.cil.oc.driver.TileEntityDriver;
import net.minecraft.tileentity.TileEntityCommandBlock;
import net.minecraft.world.World;
public final class DriverCommandBlock extends TileEntityDriver {
@Override
public Class<?> getFilterClass() {
return TileEntityCommandBlock.class;
}
@Override
public ManagedEnvironment createEnvironment(final World world, final int x, final int y, final int z) {
return new Environment((TileEntityCommandBlock) world.getBlockTileEntity(x, y, z));
}
public static final class Environment extends ManagedTileEntityEnvironment<TileEntityCommandBlock> {
public Environment(final TileEntityCommandBlock tileEntity) {
super(tileEntity, "command_block");
}
@Callback(direct = true)
public Object[] getCommand(final Context context, final Arguments args) {
return new Object[]{tileEntity.getCommand()};
}
@Callback
public Object[] setCommand(final Context context, final Arguments args) {
tileEntity.setCommand(args.checkString(0));
tileEntity.getWorldObj().markBlockForUpdate(tileEntity.xCoord, tileEntity.yCoord, tileEntity.zCoord);
return new Object[]{true};
}
@Callback
public Object[] executeCommand(final Context context, final Arguments args) {
context.pause(0.1); // Make sure the command block has time to do its thing.
return new Object[]{tileEntity.executeCommandOnPowered(tileEntity.getWorldObj())};
}
}
}

View File

@ -0,0 +1,65 @@
package li.cil.oc.driver.vanilla;
import li.cil.oc.api.network.Arguments;
import li.cil.oc.api.network.Callback;
import li.cil.oc.api.network.Context;
import li.cil.oc.api.network.ManagedEnvironment;
import li.cil.oc.driver.ManagedTileEntityEnvironment;
import li.cil.oc.driver.TileEntityDriver;
import net.minecraft.block.material.Material;
import net.minecraft.tileentity.TileEntityNote;
import net.minecraft.world.World;
public final class DriverNoteBlock extends TileEntityDriver {
@Override
public Class<?> getFilterClass() {
return TileEntityNote.class;
}
@Override
public ManagedEnvironment createEnvironment(final World world, final int x, final int y, final int z) {
return new Environment((TileEntityNote) world.getBlockTileEntity(x, y, z));
}
public static final class Environment extends ManagedTileEntityEnvironment<TileEntityNote> {
public Environment(final TileEntityNote tileEntity) {
super(tileEntity, "note_block");
}
@Callback(direct = true)
public Object[] getPitch(final Context context, final Arguments args) {
return new Object[]{tileEntity.note + 1};
}
@Callback
public Object[] setPitch(final Context context, final Arguments args) {
setPitch(args.checkInteger(0));
return new Object[]{true};
}
@Callback
public Object[] trigger(final Context context, final Arguments args) {
if (args.count() > 0 && args.checkAny(0) != null) {
setPitch(args.checkInteger(0));
}
final World world = tileEntity.getWorldObj();
final int x = tileEntity.xCoord;
final int y = tileEntity.yCoord;
final int z = tileEntity.zCoord;
final Material material = world.getBlockMaterial(x, y + 1, z);
final boolean canTrigger = material == Material.air;
tileEntity.triggerNote(world, x, y, z);
return new Object[]{canTrigger};
}
private void setPitch(final int value) {
if (value < 1 || value > 25) {
throw new IllegalArgumentException("invalid pitch");
}
tileEntity.note = (byte) (value - 1);
tileEntity.onInventoryChanged();
}
}
}

View File

@ -16,12 +16,14 @@ public final class HandlerVanilla implements IModHandler {
public void initialize() {
Driver.add(new DriverBeacon());
Driver.add(new DriverBrewingStand());
Driver.add(new DriverCommandBlock());
Driver.add(new DriverComparator());
Driver.add(new DriverFluidHandler());
Driver.add(new DriverFluidTank());
Driver.add(new DriverFurnace());
Driver.add(new DriverInventory());
Driver.add(new DriverMobSpawner());
Driver.add(new DriverNoteBlock());
Driver.add(new DriverRecordPlayer());
Driver.add(new DriverSign());
}

View File

@ -36,7 +36,7 @@ public final class Reflection {
}
}
public static Object invoke(final Object instance, final String methodName, final Object... args) {
public static Object invoke(final Object instance, final String methodName, final Object... args) throws Throwable {
try {
outer:
for (Method method : instance.getClass().getMethods()) {
@ -63,9 +63,17 @@ public final class Reflection {
}
return null;
} catch (InvocationTargetException e) {
return null;
throw e.getCause();
} catch (IllegalAccessException e) {
return null;
}
}
public static Object tryInvoke(final Object instance, final String methodName, final Object... args) {
try {
return invoke(instance, methodName, args);
} catch (Throwable ignored) {
return null;
}
}
}