From c058dc27812112e4e2bab2e93b0c17c9be57ba3d Mon Sep 17 00:00:00 2001 From: AtomSponge Date: Wed, 14 Jan 2015 15:22:31 +0100 Subject: [PATCH 01/61] Add BloodMagic integration (Blood Altars, Master Ritual Stones and Blood Orbs) --- build.gradle | 5 ++ build.properties | 2 + .../scala/li/cil/oc/integration/Mods.scala | 3 + .../bloodmagic/ConverterBloodOrb.java | 30 +++++++ .../bloodmagic/DriverBloodAltar.java | 79 +++++++++++++++++++ .../bloodmagic/DriverMasterRitualStone.java | 69 ++++++++++++++++ .../bloodmagic/ModBloodMagic.scala | 15 ++++ 7 files changed, 203 insertions(+) create mode 100644 src/main/scala/li/cil/oc/integration/bloodmagic/ConverterBloodOrb.java create mode 100644 src/main/scala/li/cil/oc/integration/bloodmagic/DriverBloodAltar.java create mode 100644 src/main/scala/li/cil/oc/integration/bloodmagic/DriverMasterRitualStone.java create mode 100644 src/main/scala/li/cil/oc/integration/bloodmagic/ModBloodMagic.scala diff --git a/build.gradle b/build.gradle index b616fa42b..011f33e68 100644 --- a/build.gradle +++ b/build.gradle @@ -135,6 +135,10 @@ repositories { name 'Railcraft' artifactPattern "http://addons.cursecdn.com/files/${config.rc.cf}/[module]_[revision].[ext]" } + ivy { + name 'BloodMagic' + artifactPattern "http://addons.cursecdn.com/files/${config.bloodmagic.cf}/[module]-${config.minecraft.version}-[revision].[ext]" + } } configurations { @@ -169,6 +173,7 @@ dependencies { provided name: 'ComputerCraft', version: config.cc.version, ext: 'jar' provided name: 'EnderIO', version: config.eio.version, ext: 'jar' provided name: 'Railcraft', version: config.rc.version, ext: 'jar' + provided name: 'BloodMagic', version: config.bloodmagic.version, ext: 'jar' compile 'com.google.code.findbugs:jsr305:1.3.9' // Annotations used by google libs. diff --git a/build.properties b/build.properties index ed01060d2..1c71fd952 100644 --- a/build.properties +++ b/build.properties @@ -6,6 +6,8 @@ oc.subversion=dev ae2.version=rv1-stable-1 bc.version=6.2.6 +bloodmagic.cf=2223/203 +bloodmagic.version=1.3.0a-1 cc.cf=2216/236 cc.version=1.65 ccl.version=1.1.1.104 diff --git a/src/main/scala/li/cil/oc/integration/Mods.scala b/src/main/scala/li/cil/oc/integration/Mods.scala index 885a960a1..67b563827 100644 --- a/src/main/scala/li/cil/oc/integration/Mods.scala +++ b/src/main/scala/li/cil/oc/integration/Mods.scala @@ -67,6 +67,7 @@ object Mods { val Waila = new SimpleMod(IDs.Waila) val WirelessRedstoneCBE = new SimpleMod(IDs.WirelessRedstoneCBE) val WirelessRedstoneSVE = new SimpleMod(IDs.WirelessRedstoneSV) + val BloodMagic = new SimpleMod(IDs.BloodMagic) // ----------------------------------------------------------------------- // @@ -98,6 +99,7 @@ object Mods { integration.waila.ModWaila, integration.wrcbe.ModWRCBE, integration.wrsve.ModWRSVE, + integration.bloodmagic.ModBloodMagic, // Register the general IPeripheral driver last, if at all, to avoid it // being used rather than other more concrete implementations. @@ -171,6 +173,7 @@ object Mods { final val Waila = "Waila" final val WirelessRedstoneCBE = "WR-CBE|Core" final val WirelessRedstoneSV = "WirelessRedstoneCore" + final val BloodMagic = "AWWayofTime" } // ----------------------------------------------------------------------- // diff --git a/src/main/scala/li/cil/oc/integration/bloodmagic/ConverterBloodOrb.java b/src/main/scala/li/cil/oc/integration/bloodmagic/ConverterBloodOrb.java new file mode 100644 index 000000000..7d33b3dce --- /dev/null +++ b/src/main/scala/li/cil/oc/integration/bloodmagic/ConverterBloodOrb.java @@ -0,0 +1,30 @@ +package li.cil.oc.integration.bloodmagic; + +import WayofTime.alchemicalWizardry.api.items.interfaces.IBloodOrb; +import WayofTime.alchemicalWizardry.api.soulNetwork.SoulNetworkHandler; +import li.cil.oc.api.driver.Converter; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; + +import java.util.Map; + +public class ConverterBloodOrb implements Converter { + @Override + public void convert(Object value, Map output) { + if (value instanceof ItemStack) { + final ItemStack stack = (ItemStack) value; + final Item item = stack.getItem(); + if (item instanceof IBloodOrb) { + final IBloodOrb bloodOrb = (IBloodOrb) item; + final String ownerName = stack.stackTagCompound.getString("ownerName"); + final int maxOrbTier = SoulNetworkHandler.getCurrentMaxOrb(ownerName); + output.put("ownerName", ownerName); + output.put("networkOrbTier", maxOrbTier); + output.put("networkEssence", SoulNetworkHandler.getCurrentEssence(ownerName)); + output.put("maxNetworkEssence", SoulNetworkHandler.getMaximumForOrbTier(maxOrbTier)); + output.put("maxEssence", bloodOrb.getMaxEssence()); + output.put("orbTier", bloodOrb.getOrbLevel()); + } + } + } +} diff --git a/src/main/scala/li/cil/oc/integration/bloodmagic/DriverBloodAltar.java b/src/main/scala/li/cil/oc/integration/bloodmagic/DriverBloodAltar.java new file mode 100644 index 000000000..b1f72c588 --- /dev/null +++ b/src/main/scala/li/cil/oc/integration/bloodmagic/DriverBloodAltar.java @@ -0,0 +1,79 @@ +package li.cil.oc.integration.bloodmagic; + +import li.cil.oc.api.driver.NamedBlock; +import li.cil.oc.api.machine.Arguments; +import li.cil.oc.api.machine.Callback; +import li.cil.oc.api.machine.Context; +import li.cil.oc.api.network.ManagedEnvironment; +import li.cil.oc.api.prefab.DriverTileEntity; +import li.cil.oc.integration.ManagedTileEntityEnvironment; +import net.minecraft.world.World; +import WayofTime.alchemicalWizardry.api.tile.IBloodAltar; + +public class DriverBloodAltar extends DriverTileEntity { + @Override + public Class getTileEntityClass() { + return IBloodAltar.class; + } + + @Override + public ManagedEnvironment createEnvironment(World world, int x, int y, int z) { + return new Environment((IBloodAltar) world.getTileEntity(x, y, z)); + } + + public static final class Environment extends ManagedTileEntityEnvironment implements NamedBlock { + public Environment(final IBloodAltar tileEntity) { + super(tileEntity, "blood_altar"); + } + + @Override + public String preferredName() { + return "blood_altar"; + } + + @Override + public int priority() { + return 0; + } + + @Callback(doc = "function():number -- Get the capacity.") + public Object[] getCapacity(final Context context, final Arguments arguments) { + return new Object[]{tileEntity.getCapacity()}; + } + + @Callback(doc = "function():number -- Get the amount of blood currently contained by this altar.") + public Object[] getCurrentBlood(final Context context, final Arguments arguments) { + return new Object[]{tileEntity.getCurrentBlood()}; + } + + @Callback(doc = "function():number -- Get the current tier.") + public Object[] getTier(final Context context, final Arguments arguments) { + return new Object[]{tileEntity.getTier()}; + } + + @Callback(doc = "function():number -- Get the progress.") + public Object[] getProgress(final Context context, final Arguments arguments) { + return new Object[]{tileEntity.getProgress()}; + } + + @Callback(doc = "function():number -- Get the sacrifice multiplier.") + public Object[] getSacrificeMultiplier(final Context context, final Arguments arguments) { + return new Object[]{tileEntity.getCapacity()}; + } + + @Callback(doc = "function():number -- Get the self sacrifice multiplier.") + public Object[] getSelfSacrificeMultiplier(final Context context, final Arguments arguments) { + return new Object[]{tileEntity.getSelfSacrificeMultiplier()}; + } + + @Callback(doc = "function():number -- Get the orb multiplier.") + public Object[] getOrbMultiplier(final Context context, final Arguments arguments) { + return new Object[]{tileEntity.getOrbMultiplier()}; + } + + @Callback(doc = "function():number -- Get the dislocation multiplier.") + public Object[] getDislocationMultiplier(final Context context, final Arguments arguments) { + return new Object[]{tileEntity.getDislocationMultiplier()}; + } + } +} diff --git a/src/main/scala/li/cil/oc/integration/bloodmagic/DriverMasterRitualStone.java b/src/main/scala/li/cil/oc/integration/bloodmagic/DriverMasterRitualStone.java new file mode 100644 index 000000000..3168651dc --- /dev/null +++ b/src/main/scala/li/cil/oc/integration/bloodmagic/DriverMasterRitualStone.java @@ -0,0 +1,69 @@ +package li.cil.oc.integration.bloodmagic; + +import WayofTime.alchemicalWizardry.api.rituals.IMasterRitualStone; +import WayofTime.alchemicalWizardry.common.tileEntity.TEMasterStone; +import li.cil.oc.api.driver.NamedBlock; +import li.cil.oc.api.machine.Arguments; +import li.cil.oc.api.machine.Callback; +import li.cil.oc.api.machine.Context; +import li.cil.oc.api.network.ManagedEnvironment; +import li.cil.oc.api.prefab.DriverTileEntity; +import li.cil.oc.integration.ManagedTileEntityEnvironment; +import net.minecraft.world.World; + +public class DriverMasterRitualStone extends DriverTileEntity { + @Override + public Class getTileEntityClass() { + return IMasterRitualStone.class; + } + + @Override + public ManagedEnvironment createEnvironment(World world, int x, int y, int z) { + return new Environment((IMasterRitualStone) world.getTileEntity(x, y, z)); + } + + public static class Environment extends ManagedTileEntityEnvironment implements NamedBlock { + public Environment(IMasterRitualStone tileEntity) { + super(tileEntity, "master_ritual_stone"); + } + + @Override + public String preferredName() { + return "master_ritual_stone"; + } + + @Override + public int priority() { + return 0; + } + + @Callback(doc = "function():string -- Get the name of the player owning this master ritual stone.") + public Object[] getOwner(final Context context, final Arguments arguments) { + return new Object[]{tileEntity.getOwner()}; + } + + @Callback(doc = "function():string -- Get the current ritual.") + public Object[] getCurrentRitual(final Context context, final Arguments arguments) { + if (tileEntity instanceof TEMasterStone) { + TEMasterStone masterStone = (TEMasterStone) tileEntity; + return new Object[]{masterStone.getCurrentRitual()}; + } + return new Object[]{"internal error"}; + } + + @Callback(doc = "function():number -- Get the remaining cooldown.") + public Object[] getCooldown(final Context context, final Arguments arguments) { + return new Object[]{tileEntity.getCooldown()}; + } + + @Callback(doc = "function():number -- Get the running time.") + public Object[] getRunningTime(final Context context, final Arguments arguments) { + return new Object[]{tileEntity.getRunningTime()}; + } + + @Callback(doc = "function():boolean -- Get whether the tanks are empty.") + public Object[] areTanksEmpty(final Context context, final Arguments arguments) { + return new Object[]{tileEntity.areTanksEmpty()}; + } + } +} diff --git a/src/main/scala/li/cil/oc/integration/bloodmagic/ModBloodMagic.scala b/src/main/scala/li/cil/oc/integration/bloodmagic/ModBloodMagic.scala new file mode 100644 index 000000000..a7979a672 --- /dev/null +++ b/src/main/scala/li/cil/oc/integration/bloodmagic/ModBloodMagic.scala @@ -0,0 +1,15 @@ +package li.cil.oc.integration.bloodmagic + +import li.cil.oc.api.Driver +import li.cil.oc.integration.{Mods, ModProxy} + +object ModBloodMagic extends ModProxy { + override def getMod = Mods.BloodMagic + + override def initialize() { + Driver.add(new DriverBloodAltar) + Driver.add(new DriverMasterRitualStone) + + Driver.add(new ConverterBloodOrb) + } +} From 837e213afea4784ea16022443f951f1faf19b606 Mon Sep 17 00:00:00 2001 From: AtomSponge Date: Wed, 14 Jan 2015 17:12:15 +0100 Subject: [PATCH 02/61] Fix integration mod list .. which is apparently sorted alphabetically --- src/main/scala/li/cil/oc/integration/Mods.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/li/cil/oc/integration/Mods.scala b/src/main/scala/li/cil/oc/integration/Mods.scala index 67b563827..47ebccb93 100644 --- a/src/main/scala/li/cil/oc/integration/Mods.scala +++ b/src/main/scala/li/cil/oc/integration/Mods.scala @@ -21,6 +21,7 @@ object Mods { val AppliedEnergistics2 = new SimpleMod(IDs.AppliedEnergistics2, version = "@[rv1,)", providesPower = true) val BattleGear2 = new SimpleMod(IDs.BattleGear2) + val BloodMagic = new SimpleMod(IDs.BloodMagic) val BuildCraft = new SimpleMod(IDs.BuildCraft) val BuildCraftTiles = new SimpleMod(IDs.BuildCraftTiles) val BuildCraftTools = new SimpleMod(IDs.BuildCraftTools) @@ -67,7 +68,6 @@ object Mods { val Waila = new SimpleMod(IDs.Waila) val WirelessRedstoneCBE = new SimpleMod(IDs.WirelessRedstoneCBE) val WirelessRedstoneSVE = new SimpleMod(IDs.WirelessRedstoneSV) - val BloodMagic = new SimpleMod(IDs.BloodMagic) // ----------------------------------------------------------------------- // From b3c548388e2b96d52fe6fc96a9c67e687836f856 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Wed, 14 Jan 2015 17:14:14 +0100 Subject: [PATCH 03/61] That field was totally a method when I looked. Honest. Maybe. --- src/main/scala/li/cil/oc/common/asm/ClassTransformer.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/scala/li/cil/oc/common/asm/ClassTransformer.scala b/src/main/scala/li/cil/oc/common/asm/ClassTransformer.scala index 53338ee12..6561ec357 100644 --- a/src/main/scala/li/cil/oc/common/asm/ClassTransformer.scala +++ b/src/main/scala/li/cil/oc/common/asm/ClassTransformer.scala @@ -21,7 +21,7 @@ object ObfNames { final val Class_RenderLiving = Array("net/minecraft/client/renderer/entity/RenderLiving", "bok") final val Class_TileEntity = Array("net/minecraft/tileentity/TileEntity", "aor") final val Field_leashNBTTag = Array("leashNBTTag", "field_110170_bx", "bx") - final val Method_leashedToEntity = Array("leashedToEntity", "field_110168_bw", "bw") + final val Field_leashedToEntity = Array("leashedToEntity", "field_110168_bw", "bw") final val Method_recreateLeash = Array("recreateLeash", "func_110165_bF", "bP") final val Method_recreateLeashDesc = Array("()V") final val Method_renderHanging = Array("func_110827_b", "b") @@ -159,7 +159,7 @@ class ClassTransformer extends IClassTransformer { if varNode.getOpcode == Opcodes.ALOAD && varNode.`var` == 0 && fieldNode.getOpcode == Opcodes.GETFIELD && ObfNames.Field_leashNBTTag.contains(fieldNode.name) && jumpNode.getOpcode == Opcodes.IFNULL => - classNode.fields.find(field => ObfNames.Method_leashedToEntity.contains(field.name)) match { + classNode.fields.find(field => ObfNames.Field_leashedToEntity.contains(field.name)) match { case Some(field) => val toInject = new InsnList() toInject.add(new VarInsnNode(Opcodes.ALOAD, 0)) From 40de62056be4e84e61a623841b09b3a2a56dd11d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Wed, 14 Jan 2015 18:53:19 +0100 Subject: [PATCH 04/61] Added methods for raw text and color setting to TextBuffer API. --- src/main/java/li/cil/oc/api/API.java | 2 +- .../li/cil/oc/api/component/TextBuffer.java | 65 +++++++ .../li/cil/oc/client/PacketHandler.scala | 57 ++++++ .../scala/li/cil/oc/common/PacketType.scala | 3 + .../cil/oc/common/component/TextBuffer.scala | 175 ++++++++++++------ .../scala/li/cil/oc/server/PacketSender.scala | 45 +++++ .../scala/li/cil/oc/util/PackedColor.scala | 10 +- 7 files changed, 296 insertions(+), 61 deletions(-) diff --git a/src/main/java/li/cil/oc/api/API.java b/src/main/java/li/cil/oc/api/API.java index 7c4dbaebc..eec93c4d0 100644 --- a/src/main/java/li/cil/oc/api/API.java +++ b/src/main/java/li/cil/oc/api/API.java @@ -11,7 +11,7 @@ import li.cil.oc.api.detail.*; */ public class API { public static final String ID_OWNER = "OpenComputers|Core"; - public static final String VERSION = "4.2.0"; + public static final String VERSION = "4.2.1"; public static DriverAPI driver = null; public static FileSystemAPI fileSystem = null; diff --git a/src/main/java/li/cil/oc/api/component/TextBuffer.java b/src/main/java/li/cil/oc/api/component/TextBuffer.java index c7297c631..167bc937f 100644 --- a/src/main/java/li/cil/oc/api/component/TextBuffer.java +++ b/src/main/java/li/cil/oc/api/component/TextBuffer.java @@ -341,6 +341,71 @@ public interface TextBuffer extends ManagedEnvironment, Persistable { */ boolean isBackgroundFromPalette(int column, int row); + /** + * Overwrites a portion of the text in raw mode. + *

+ * This will copy the given char array into the buffer, starting at the + * specified column and row. The array is expected to be indexed row- + * first, i.e. the first dimension is the vertical axis, the second + * the horizontal. + *

+ * Important: this performs no checks as to whether something + * actually changed. It will always send the changed patch to clients. + * It will also not crop the specified array to the actually used range. + * In other words, this is not intended to be exposed as-is to user code, + * it should always be called with validated, and, as necessary, cropped + * values. + * + * @param column the horizontal index. + * @param row the vertical index. + * @param text the text to write. + */ + void rawSetText(int column, int row, char[][] text); + + /** + * Overwrites a portion of the foreground color information in raw mode. + *

+ * This will convert the specified RGB data (in 0xRRGGBB format) + * to the internal, packed representation and copy it into the buffer, + * starting at the specified column and row. The array is expected to be + * indexed row-first, i.e. the first dimension is the vertical axis, the + * second the horizontal. + *

+ * Important: this performs no checks as to whether something + * actually changed. It will always send the changed patch to clients. + * It will also not crop the specified array to the actually used range. + * In other words, this is not intended to be exposed as-is to user code, + * it should always be called with validated, and, as necessary, cropped + * values. + * + * @param column the horizontal index. + * @param row the vertical index. + * @param color the foreground color data to write. + */ + void rawSetForeground(int column, int row, int[][] color); + + /** + * Overwrites a portion of the background color information in raw mode. + *

+ * This will convert the specified RGB data (in 0xRRGGBB format) + * to the internal, packed representation and copy it into the buffer, + * starting at the specified column and row. The array is expected to be + * indexed row-first, i.e. the first dimension is the vertical axis, the + * second the horizontal. + *

+ * Important: this performs no checks as to whether something + * actually changed. It will always send the changed patch to clients. + * It will also not crop the specified array to the actually used range. + * In other words, this is not intended to be exposed as-is to user code, + * it should always be called with validated, and, as necessary, cropped + * values. + * + * @param column the horizontal index. + * @param row the vertical index. + * @param color the background color data to write. + */ + void rawSetBackground(int column, int row, int[][] color); + // ----------------------------------------------------------------------- // /** diff --git a/src/main/scala/li/cil/oc/client/PacketHandler.scala b/src/main/scala/li/cil/oc/client/PacketHandler.scala index 20177011e..da0dc4f38 100644 --- a/src/main/scala/li/cil/oc/client/PacketHandler.scala +++ b/src/main/scala/li/cil/oc/client/PacketHandler.scala @@ -370,6 +370,9 @@ object PacketHandler extends CommonPacketHandler { case PacketType.TextBufferMultiResolutionChange => onTextBufferMultiResolutionChange(p, buffer) case PacketType.TextBufferMultiMaxResolutionChange => onTextBufferMultiMaxResolutionChange(p, buffer) case PacketType.TextBufferMultiSet => onTextBufferMultiSet(p, buffer) + case PacketType.TextBufferMultiRawSetText => onTextBufferMultiRawSetText(p, buffer) + case PacketType.TextBufferMultiRawSetBackground => onTextBufferMultiRawSetBackground(p, buffer) + case PacketType.TextBufferMultiRawSetForeground => onTextBufferMultiRawSetForeground(p, buffer) case _ => // Invalid packet. } } @@ -441,6 +444,60 @@ object PacketHandler extends CommonPacketHandler { buffer.set(col, row, s, vertical) } + def onTextBufferMultiRawSetText(p: PacketParser, buffer: component.TextBuffer) { + val col = p.readInt() + val row = p.readInt() + + val rows = p.readShort() + val text = new Array[Array[Char]](rows) + for (y <- 0 until rows) { + val cols = p.readShort() + val line = new Array[Char](cols) + for (x <- 0 until cols) { + line(x) = p.readChar() + } + text(y) = line + } + + buffer.rawSetText(col, row, text) + } + + def onTextBufferMultiRawSetBackground(p: PacketParser, buffer: component.TextBuffer) { + val col = p.readInt() + val row = p.readInt() + + val rows = p.readShort() + val color = new Array[Array[Int]](rows) + for (y <- 0 until rows) { + val cols = p.readShort() + val line = new Array[Int](cols) + for (x <- 0 until cols) { + line(x) = p.readInt() + } + color(y) = line + } + + buffer.rawSetBackground(col, row, color) + } + + def onTextBufferMultiRawSetForeground(p: PacketParser, buffer: component.TextBuffer) { + val col = p.readInt() + val row = p.readInt() + + val rows = p.readShort() + val color = new Array[Array[Int]](rows) + for (y <- 0 until rows) { + val cols = p.readShort() + val line = new Array[Int](cols) + for (x <- 0 until cols) { + line(x) = p.readInt() + } + color(y) = line + } + + buffer.rawSetForeground(col, row, color) + } + def onScreenTouchMode(p: PacketParser) = p.readTileEntity[Screen]() match { case Some(t) => t.invertTouchMode = p.readBoolean() diff --git a/src/main/scala/li/cil/oc/common/PacketType.scala b/src/main/scala/li/cil/oc/common/PacketType.scala index f08c3d653..c925def9d 100644 --- a/src/main/scala/li/cil/oc/common/PacketType.scala +++ b/src/main/scala/li/cil/oc/common/PacketType.scala @@ -41,6 +41,9 @@ object PacketType extends Enumeration { TextBufferMultiResolutionChange, TextBufferMultiMaxResolutionChange, TextBufferMultiSet, + TextBufferMultiRawSetText, + TextBufferMultiRawSetBackground, + TextBufferMultiRawSetForeground, TextBufferPowerChange, ScreenTouchMode, ServerPresence, diff --git a/src/main/scala/li/cil/oc/common/component/TextBuffer.scala b/src/main/scala/li/cil/oc/common/component/TextBuffer.scala index 68c3e4953..ea65f0669 100644 --- a/src/main/scala/li/cil/oc/common/component/TextBuffer.scala +++ b/src/main/scala/li/cil/oc/common/component/TextBuffer.scala @@ -189,7 +189,7 @@ class TextBuffer(val host: EnvironmentHost) extends prefab.ManagedEnvironment wi if (height < 1) throw new IllegalArgumentException("height must be larger or equal to one") maxResolution = (width, height) fullyLitCost = computeFullyLitCost() - proxy.onScreenMaxResolutionChange(width, width) + proxy.onBufferMaxResolutionChange(width, width) } override def getMaximumWidth = maxResolution._1 @@ -205,7 +205,7 @@ class TextBuffer(val host: EnvironmentHost) extends prefab.ManagedEnvironment wi if (w < 1 || h < 1 || w > mw || h > mw || h * w > mw * mh) throw new IllegalArgumentException("unsupported resolution") // Always send to clients, their state might be dirty. - proxy.onScreenResolutionChange(w, h) + proxy.onBufferResolutionChange(w, h) if (data.size = (w, h)) { if (node != null) { node.sendToReachable("computer.signal", "screen_resized", Int.box(w), Int.box(h)) @@ -227,7 +227,7 @@ class TextBuffer(val host: EnvironmentHost) extends prefab.ManagedEnvironment wi if (depth.ordinal > maxDepth.ordinal) throw new IllegalArgumentException("unsupported depth") // Always send to clients, their state might be dirty. - proxy.onScreenDepthChange(depth) + proxy.onBufferDepthChange(depth) data.format = PackedColor.Depth.format(depth) } @@ -236,7 +236,7 @@ class TextBuffer(val host: EnvironmentHost) extends prefab.ManagedEnvironment wi override def setPaletteColor(index: Int, color: Int) = data.format match { case palette: PackedColor.MutablePaletteFormat => palette(index) = color - proxy.onScreenPaletteChange(index) + proxy.onBufferPaletteChange(index) case _ => throw new Exception("palette not available") } @@ -251,7 +251,7 @@ class TextBuffer(val host: EnvironmentHost) extends prefab.ManagedEnvironment wi val value = PackedColor.Color(color, isFromPalette) if (data.foreground != value) { data.foreground = value - proxy.onScreenColorChange() + proxy.onBufferColorChange() } } @@ -265,7 +265,7 @@ class TextBuffer(val host: EnvironmentHost) extends prefab.ManagedEnvironment wi val value = PackedColor.Color(color, isFromPalette) if (data.background != value) { data.background = value - proxy.onScreenColorChange() + proxy.onBufferColorChange() } } @@ -275,27 +275,28 @@ class TextBuffer(val host: EnvironmentHost) extends prefab.ManagedEnvironment wi def copy(col: Int, row: Int, w: Int, h: Int, tx: Int, ty: Int) = if (data.copy(col, row, w, h, tx, ty)) - proxy.onScreenCopy(col, row, w, h, tx, ty) + proxy.onBufferCopy(col, row, w, h, tx, ty) def fill(col: Int, row: Int, w: Int, h: Int, c: Char) = if (data.fill(col, row, w, h, c)) - proxy.onScreenFill(col, row, w, h, c) + proxy.onBufferFill(col, row, w, h, c) - def set(col: Int, row: Int, s: String, vertical: Boolean) = if (col < data.width && (col >= 0 || -col < s.length)) { - // Make sure the string isn't longer than it needs to be, in particular to - // avoid sending too much data to our clients. - val (x, y, truncated) = - if (vertical) { - if (row < 0) (col, 0, s.substring(-row)) - else (col, row, s.substring(0, math.min(s.length, data.height - row))) - } - else { - if (col < 0) (0, row, s.substring(-col)) - else (col, row, s.substring(0, math.min(s.length, data.width - col))) - } - if (data.set(x, y, truncated, vertical)) - proxy.onScreenSet(x, row, truncated, vertical) - } + def set(col: Int, row: Int, s: String, vertical: Boolean): Unit = + if (col < data.width && (col >= 0 || -col < s.length)) { + // Make sure the string isn't longer than it needs to be, in particular to + // avoid sending too much data to our clients. + val (x, y, truncated) = + if (vertical) { + if (row < 0) (col, 0, s.substring(-row)) + else (col, row, s.substring(0, math.min(s.length, data.height - row))) + } + else { + if (col < 0) (0, row, s.substring(-col)) + else (col, row, s.substring(0, math.min(s.length, data.width - col))) + } + if (data.set(x, y, truncated, vertical)) + proxy.onBufferSet(x, row, truncated, vertical) + } def get(col: Int, row: Int) = data.get(col, row) @@ -321,6 +322,40 @@ class TextBuffer(val host: EnvironmentHost) extends prefab.ManagedEnvironment wi override def isBackgroundFromPalette(column: Int, row: Int) = data.format.isFromPalette(PackedColor.extractBackground(color(column, row))) + override def rawSetText(col: Int, row: Int, text: Array[Array[Char]]): Unit = { + for (y <- row until ((row + text.length) min data.height)) { + val line = text(y - row) + Array.copy(line, 0, data.buffer(y), col, line.length min data.width) + } + proxy.onBufferRawSetText(col, row, text) + } + + override def rawSetBackground(col: Int, row: Int, color: Array[Array[Int]]): Unit = { + for (y <- row until ((row + color.length) min data.height)) { + val line = color(y - row) + for (x <- col until ((col + line.length) min data.width)) { + val packedBackground = data.color(row)(col) & 0x00FF + val packedForeground = (data.format.deflate(PackedColor.Color(line(x - col))) << PackedColor.ForegroundShift) & 0xFF00 + data.color(row)(col) = (packedForeground | packedBackground).toShort + } + } + // TODO Better for bandwidth to send packed shorts here. Would need a special case for handling on client, though... + proxy.onBufferRawSetBackground(col, row, color) + } + + override def rawSetForeground(col: Int, row: Int, color: Array[Array[Int]]): Unit = { + for (y <- row until ((row + color.length) min data.height)) { + val line = color(y - row) + for (x <- col until ((col + line.length) min data.width)) { + val packedBackground = data.format.deflate(PackedColor.Color(line(x - col))) & 0x00FF + val packedForeground = data.color(row)(col) & 0xFF00 + data.color(row)(col) = (packedForeground | packedBackground).toShort + } + } + // TODO Better for bandwidth to send packed shorts here. Would need a special case for handling on client, though... + proxy.onBufferRawSetForeground(col, row, color) + } + private def color(column: Int, row: Int) = { if (column < 0 || column >= getWidth || row < 0 || row >= getHeight) throw new IndexOutOfBoundsException() @@ -477,28 +512,40 @@ object TextBuffer { def render() = false - def onScreenColorChange(): Unit + def onBufferColorChange(): Unit - def onScreenCopy(col: Int, row: Int, w: Int, h: Int, tx: Int, ty: Int) { + def onBufferCopy(col: Int, row: Int, w: Int, h: Int, tx: Int, ty: Int) { owner.relativeLitArea = -1 } - def onScreenDepthChange(depth: ColorDepth): Unit + def onBufferDepthChange(depth: ColorDepth): Unit - def onScreenFill(col: Int, row: Int, w: Int, h: Int, c: Char) { + def onBufferFill(col: Int, row: Int, w: Int, h: Int, c: Char) { owner.relativeLitArea = -1 } - def onScreenPaletteChange(index: Int): Unit + def onBufferPaletteChange(index: Int): Unit - def onScreenResolutionChange(w: Int, h: Int) { + def onBufferResolutionChange(w: Int, h: Int) { owner.relativeLitArea = -1 } - def onScreenMaxResolutionChange(w: Int, h: Int) { + def onBufferMaxResolutionChange(w: Int, h: Int) { } - def onScreenSet(col: Int, row: Int, s: String, vertical: Boolean) { + def onBufferSet(col: Int, row: Int, s: String, vertical: Boolean) { + owner.relativeLitArea = -1 + } + + def onBufferRawSetText(col: Int, row: Int, text: Array[Array[Char]]) { + owner.relativeLitArea = -1 + } + + def onBufferRawSetBackground(col: Int, row: Int, color: Array[Array[Int]]) { + owner.relativeLitArea = -1 + } + + def onBufferRawSetForeground(col: Int, row: Int, color: Array[Array[Int]]) { owner.relativeLitArea = -1 } @@ -532,35 +579,35 @@ object TextBuffer { wasDirty } - override def onScreenColorChange() { + override def onBufferColorChange() { markDirty() } - override def onScreenCopy(col: Int, row: Int, w: Int, h: Int, tx: Int, ty: Int) { - super.onScreenCopy(col, row, w, h, tx, ty) + override def onBufferCopy(col: Int, row: Int, w: Int, h: Int, tx: Int, ty: Int) { + super.onBufferCopy(col, row, w, h, tx, ty) markDirty() } - override def onScreenDepthChange(depth: ColorDepth) { + override def onBufferDepthChange(depth: ColorDepth) { markDirty() } - override def onScreenFill(col: Int, row: Int, w: Int, h: Int, c: Char) { - super.onScreenFill(col, row, w, h, c) + override def onBufferFill(col: Int, row: Int, w: Int, h: Int, c: Char) { + super.onBufferFill(col, row, w, h, c) markDirty() } - override def onScreenPaletteChange(index: Int) { + override def onBufferPaletteChange(index: Int) { markDirty() } - override def onScreenResolutionChange(w: Int, h: Int) { - super.onScreenResolutionChange(w, h) + override def onBufferResolutionChange(w: Int, h: Int) { + super.onBufferResolutionChange(w, h) markDirty() } - override def onScreenSet(col: Int, row: Int, s: String, vertical: Boolean) { - super.onScreenSet(col, row, s, vertical) + override def onBufferSet(col: Int, row: Int, s: String, vertical: Boolean) { + super.onBufferSet(col, row, s, vertical) dirty = true } @@ -609,53 +656,71 @@ object TextBuffer { } class ServerProxy(val owner: TextBuffer) extends Proxy { - override def onScreenColorChange() { + override def onBufferColorChange() { owner.host.markChanged() owner.synchronized(ServerPacketSender.appendTextBufferColorChange(owner.pendingCommands, owner.data.foreground, owner.data.background)) } - override def onScreenCopy(col: Int, row: Int, w: Int, h: Int, tx: Int, ty: Int) { - super.onScreenCopy(col, row, w, h, tx, ty) + override def onBufferCopy(col: Int, row: Int, w: Int, h: Int, tx: Int, ty: Int) { + super.onBufferCopy(col, row, w, h, tx, ty) owner.host.markChanged() owner.synchronized(ServerPacketSender.appendTextBufferCopy(owner.pendingCommands, col, row, w, h, tx, ty)) } - override def onScreenDepthChange(depth: ColorDepth) { + override def onBufferDepthChange(depth: ColorDepth) { owner.host.markChanged() owner.synchronized(ServerPacketSender.appendTextBufferDepthChange(owner.pendingCommands, depth)) } - override def onScreenFill(col: Int, row: Int, w: Int, h: Int, c: Char) { - super.onScreenFill(col, row, w, h, c) + override def onBufferFill(col: Int, row: Int, w: Int, h: Int, c: Char) { + super.onBufferFill(col, row, w, h, c) owner.host.markChanged() owner.synchronized(ServerPacketSender.appendTextBufferFill(owner.pendingCommands, col, row, w, h, c)) } - override def onScreenPaletteChange(index: Int) { + override def onBufferPaletteChange(index: Int) { owner.host.markChanged() owner.synchronized(ServerPacketSender.appendTextBufferPaletteChange(owner.pendingCommands, index, owner.getPaletteColor(index))) } - override def onScreenResolutionChange(w: Int, h: Int) { - super.onScreenResolutionChange(w, h) + override def onBufferResolutionChange(w: Int, h: Int) { + super.onBufferResolutionChange(w, h) owner.host.markChanged() owner.synchronized(ServerPacketSender.appendTextBufferResolutionChange(owner.pendingCommands, w, h)) } - override def onScreenMaxResolutionChange(w: Int, h: Int) { + override def onBufferMaxResolutionChange(w: Int, h: Int) { if (owner.node.network != null) { - super.onScreenMaxResolutionChange(w, h) + super.onBufferMaxResolutionChange(w, h) owner.host.markChanged() owner.synchronized(ServerPacketSender.appendTextBufferMaxResolutionChange(owner.pendingCommands, w, h)) } } - override def onScreenSet(col: Int, row: Int, s: String, vertical: Boolean) { - super.onScreenSet(col, row, s, vertical) + override def onBufferSet(col: Int, row: Int, s: String, vertical: Boolean) { + super.onBufferSet(col, row, s, vertical) owner.host.markChanged() owner.synchronized(ServerPacketSender.appendTextBufferSet(owner.pendingCommands, col, row, s, vertical)) } + override def onBufferRawSetText(col: Int, row: Int, text: Array[Array[Char]]) { + super.onBufferRawSetText(col, row, text) + owner.host.markChanged() + owner.synchronized(ServerPacketSender.appendTextBufferRawSetText(owner.pendingCommands, col, row, text)) + } + + override def onBufferRawSetBackground(col: Int, row: Int, color: Array[Array[Int]]) { + super.onBufferRawSetBackground(col, row, color) + owner.host.markChanged() + owner.synchronized(ServerPacketSender.appendTextBufferRawSetBackground(owner.pendingCommands, col, row, color)) + } + + override def onBufferRawSetForeground(col: Int, row: Int, color: Array[Array[Int]]) { + super.onBufferRawSetForeground(col, row, color) + owner.host.markChanged() + owner.synchronized(ServerPacketSender.appendTextBufferRawSetForeground(owner.pendingCommands, col, row, color)) + } + override def keyDown(character: Char, code: Int, player: EntityPlayer) { sendToKeyboards("keyboard.keyDown", player, Char.box(character), Int.box(code)) } diff --git a/src/main/scala/li/cil/oc/server/PacketSender.scala b/src/main/scala/li/cil/oc/server/PacketSender.scala index 25240c607..b7981467e 100644 --- a/src/main/scala/li/cil/oc/server/PacketSender.scala +++ b/src/main/scala/li/cil/oc/server/PacketSender.scala @@ -402,6 +402,51 @@ object PacketSender { pb.writeBoolean(vertical) } + def appendTextBufferRawSetText(pb: PacketBuilder, col: Int, row: Int, text: Array[Array[Char]]) { + pb.writePacketType(PacketType.TextBufferMultiRawSetText) + + pb.writeInt(col) + pb.writeInt(row) + pb.writeShort(text.length.toShort) + for (y <- 0 until text.length.toShort) { + val line = text(y) + pb.writeShort(line.length.toShort) + for (x <- 0 until line.length.toShort) { + pb.writeChar(line(x)) + } + } + } + + def appendTextBufferRawSetBackground(pb: PacketBuilder, col: Int, row: Int, color: Array[Array[Int]]) { + pb.writePacketType(PacketType.TextBufferMultiRawSetBackground) + + pb.writeInt(col) + pb.writeInt(row) + pb.writeShort(color.length.toShort) + for (y <- 0 until color.length.toShort) { + val line = color(y) + pb.writeShort(line.length.toShort) + for (x <- 0 until line.length.toShort) { + pb.writeInt(line(x)) + } + } + } + + def appendTextBufferRawSetForeground(pb: PacketBuilder, col: Int, row: Int, color: Array[Array[Int]]) { + pb.writePacketType(PacketType.TextBufferMultiRawSetForeground) + + pb.writeInt(col) + pb.writeInt(row) + pb.writeShort(color.length.toShort) + for (y <- 0 until color.length.toShort) { + val line = color(y) + pb.writeShort(line.length.toShort) + for (x <- 0 until line.length.toShort) { + pb.writeInt(line(x)) + } + } + } + def sendTextBufferInit(address: String, value: NBTTagCompound, player: EntityPlayerMP) { val pb = new CompressedPacketBuilder(PacketType.TextBufferInit) diff --git a/src/main/scala/li/cil/oc/util/PackedColor.scala b/src/main/scala/li/cil/oc/util/PackedColor.scala index 668a077ae..8496eb867 100644 --- a/src/main/scala/li/cil/oc/util/PackedColor.scala +++ b/src/main/scala/li/cil/oc/util/PackedColor.scala @@ -165,16 +165,16 @@ object PackedColor { case class Color(value: Int, isPalette: Boolean = false) // Colors are packed: 0xFFBB (F = foreground, B = background) - private val fgShift = 8 - private val bgMask = 0x000000FF + val ForegroundShift = 8 + val BackgroundMask = 0x000000FF def pack(foreground: Color, background: Color, format: ColorFormat) = { - (((format.deflate(foreground) & 0xFF) << fgShift) | (format.deflate(background) & 0xFF)).toShort + (((format.deflate(foreground) & 0xFF) << ForegroundShift) | (format.deflate(background) & 0xFF)).toShort } - def extractForeground(color: Short) = (color & 0xFFFF) >>> fgShift + def extractForeground(color: Short) = (color & 0xFFFF) >>> ForegroundShift - def extractBackground(color: Short) = color & bgMask + def extractBackground(color: Short) = color & BackgroundMask def unpackForeground(color: Short, format: ColorFormat) = format.inflate(extractForeground(color)) From 8ec145e149baf2862e6d7c37ca1e8948edd8e894 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Wed, 14 Jan 2015 19:25:25 +0100 Subject: [PATCH 05/61] Should fix potential AIOOBE in server rack's analyzer logic. --- src/main/scala/li/cil/oc/common/tileentity/ServerRack.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/li/cil/oc/common/tileentity/ServerRack.scala b/src/main/scala/li/cil/oc/common/tileentity/ServerRack.scala index cfcd61e63..0aa7b1799 100644 --- a/src/main/scala/li/cil/oc/common/tileentity/ServerRack.scala +++ b/src/main/scala/li/cil/oc/common/tileentity/ServerRack.scala @@ -239,7 +239,7 @@ class ServerRack extends traits.PowerAcceptor with traits.Hub with traits.PowerB val l = 2 / 16.0 val h = 14 / 16.0 val slot = (((1 - hitY) - l) / (h - l) * 4).toInt - Some(math.max(0, math.min(servers.length, slot))) + Some(math.max(0, math.min(servers.length - 1, slot))) } else None } From 68ce35f1360b2464bd18cf821b6978170943c283 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Wed, 14 Jan 2015 20:11:20 +0100 Subject: [PATCH 06/61] Better. --- src/main/resources/assets/opencomputers/lang/en_US.lang | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/assets/opencomputers/lang/en_US.lang b/src/main/resources/assets/opencomputers/lang/en_US.lang index 935b1c3a8..6356e7e98 100644 --- a/src/main/resources/assets/opencomputers/lang/en_US.lang +++ b/src/main/resources/assets/opencomputers/lang/en_US.lang @@ -302,7 +302,7 @@ oc:tooltip.UpgradePiston=This upgrade is very pushy. It allows moving blocks, si oc:tooltip.UpgradeSign=Allows reading text on and writing text to signs. oc:tooltip.UpgradeSolarGenerator=Can be used to generate energy from sunlight on the go. Requires a clear line of sight to the sky above the device. Generates energy at %s%% of the speed of a Stirling Engine. oc:tooltip.UpgradeTank=This upgrade provides a tank for fluid storage for robots and drones. Without one of these, they will not be able to store fluids internally. -oc:tooltip.UpgradeTankController=This upgrade allows the robots and drones more control in how they interacts with external tanks, and allows them to transfer fluids into and out of fluid tank items in their inventory. +oc:tooltip.UpgradeTankController=This upgrade allows robots and drones more control in how they interacts with external tanks, and allows them to transfer fluids into and out of fluid tank items in their inventory. oc:tooltip.UpgradeTractorBeam=Equips a device with extremely advanced technology, nicknamed the "Item Magnet". Allows the device to pick up items anywhere within 3 blocks of its location. oc:tooltip.WirelessNetworkCard=Allows wireless sending of network messages in addition to normal ones. You can adjust the §fsignal strength§7 to control how far messages are sent. Higher signal strength results in higher energy consumption. oc:tooltip.WorldSensorCard=Allows reading out information about the world, such as its gravity and whether it has a breathable atmosphere. Use results at own risk. The manufacturer takes no responsibility for bodily or material harm caused by decisions made upon the cards' outputs. We have lawyers. And money. Don't even try. From 77c9a44b03037a8205bd3f5542d6460c798ba3d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Wed, 14 Jan 2015 20:18:45 +0100 Subject: [PATCH 07/61] ... faster, stronger... no wait. Just sorting. --- src/main/scala/li/cil/oc/integration/Mods.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/scala/li/cil/oc/integration/Mods.scala b/src/main/scala/li/cil/oc/integration/Mods.scala index 47ebccb93..3206bd980 100644 --- a/src/main/scala/li/cil/oc/integration/Mods.scala +++ b/src/main/scala/li/cil/oc/integration/Mods.scala @@ -73,6 +73,7 @@ object Mods { val Proxies = Array( integration.appeng.ModAppEng, + integration.bloodmagic.ModBloodMagic, integration.buildcraft.tools.ModBuildCraftAPITools, integration.buildcraft.tiles.ModBuildCraftAPITiles, integration.buildcraft.transport.ModBuildCraftAPITransport, @@ -99,7 +100,6 @@ object Mods { integration.waila.ModWaila, integration.wrcbe.ModWRCBE, integration.wrsve.ModWRSVE, - integration.bloodmagic.ModBloodMagic, // Register the general IPeripheral driver last, if at all, to avoid it // being used rather than other more concrete implementations. @@ -133,6 +133,7 @@ object Mods { object IDs { final val AppliedEnergistics2 = "appliedenergistics2" final val BattleGear2 = "battlegear2" + final val BloodMagic = "AWWayofTime" final val BuildCraft = "BuildCraft|Core" final val BuildCraftPower = "BuildCraftAPI|power" final val BuildCraftTiles = "BuildCraftAPI|tiles" @@ -173,7 +174,6 @@ object Mods { final val Waila = "Waila" final val WirelessRedstoneCBE = "WR-CBE|Core" final val WirelessRedstoneSV = "WirelessRedstoneCore" - final val BloodMagic = "AWWayofTime" } // ----------------------------------------------------------------------- // From a24154e3c3db20667c47362af1aeeb84b854e762 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Wed, 14 Jan 2015 20:53:04 +0100 Subject: [PATCH 08/61] Properly checking if a liquid block is a still block when draining, fixes #810. Reworked world draining (via tank upgrades e.g.) to also respect `IFluidBlock`. --- .../component/traits/TankWorldControl.scala | 43 +++++++++++++------ 1 file changed, 30 insertions(+), 13 deletions(-) diff --git a/src/main/scala/li/cil/oc/server/component/traits/TankWorldControl.scala b/src/main/scala/li/cil/oc/server/component/traits/TankWorldControl.scala index 9c9b0825f..36e03182e 100644 --- a/src/main/scala/li/cil/oc/server/component/traits/TankWorldControl.scala +++ b/src/main/scala/li/cil/oc/server/component/traits/TankWorldControl.scala @@ -7,8 +7,10 @@ import li.cil.oc.util.ExtendedArguments._ import li.cil.oc.util.ExtendedBlock._ import li.cil.oc.util.ExtendedWorld._ import li.cil.oc.util.ResultWrapper.result +import net.minecraft.block.BlockLiquid import net.minecraftforge.fluids.FluidRegistry import net.minecraftforge.fluids.FluidStack +import net.minecraftforge.fluids.IFluidBlock import net.minecraftforge.fluids.IFluidHandler trait TankWorldControl extends TankAware with WorldAware with SideRestricted { @@ -50,26 +52,41 @@ trait TankWorldControl extends TankAware with WorldAware with SideRestricted { case stack: FluidStack => val drained = handler.drain(facing.getOpposite, new FluidStack(stack, amount), true) if ((drained != null && drained.amount > 0) || amount == 0) { - tank.fill(drained, true) - result(true, drained.amount) + val filled = tank.fill(drained, true) + result(true, filled) } else result(Unit, "incompatible or no fluid") case _ => val transferred = tank.fill(handler.drain(facing.getOpposite, amount, true), true) result(transferred > 0, transferred) } - case _ => - val block = world.getBlock(blockPos) - val fluid = FluidRegistry.lookupFluidForBlock(block) - if (fluid == null) { + case _ => world.getBlock(blockPos) match { + case fluidBlock: IFluidBlock if fluidBlock.canDrain(world, blockPos.x, blockPos.y, blockPos.z) => + val drained = fluidBlock.drain(world, blockPos.x, blockPos.y, blockPos.z, false) + if ((drained != null && drained.amount > 0) && (drained.amount <= amount || amount == 0)) { + if (drained.amount <= amount) { + val filled = tank.fill(fluidBlock.drain(world, blockPos.x, blockPos.y, blockPos.z, true), true) + result(true, filled) + } + else /* if (amount == 0) */ { + result(true, 0) + } + } + else result(Unit, "tank is full") + case liquidBlock: BlockLiquid if world.getBlockMetadata(blockPos) == 0 => + val fluid = FluidRegistry.lookupFluidForBlock(liquidBlock) + if (fluid == null) { + result(Unit, "incompatible or no fluid") + } + else if (tank.fill(new FluidStack(fluid, 1000), false) == 1000) { + tank.fill(new FluidStack(fluid, 1000), true) + world.setBlockToAir(blockPos) + result(true, 1000) + } + else result(Unit, "tank is full") + case _ => result(Unit, "incompatible or no fluid") - } - else if (tank.fill(new FluidStack(fluid, 1000), false) == 1000) { - tank.fill(new FluidStack(fluid, 1000), true) - world.setBlockToAir(blockPos) - result(true, 1000) - } - else result(Unit, "tank is full") + } } else result(Unit, "incompatible or no fluid") } From f1a054e6e093addcebea9f865bce40204d516908 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Wed, 14 Jan 2015 23:27:32 +0100 Subject: [PATCH 09/61] Fixed manually set max resolution on text buffers not saving. --- src/main/scala/li/cil/oc/common/component/TextBuffer.scala | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/main/scala/li/cil/oc/common/component/TextBuffer.scala b/src/main/scala/li/cil/oc/common/component/TextBuffer.scala index ea65f0669..3bb9186bb 100644 --- a/src/main/scala/li/cil/oc/common/component/TextBuffer.scala +++ b/src/main/scala/li/cil/oc/common/component/TextBuffer.scala @@ -438,6 +438,11 @@ class TextBuffer(val host: EnvironmentHost) extends prefab.ManagedEnvironment wi if (nbt.hasKey(Settings.namespace + "hasPower")) { hasPower = nbt.getBoolean(Settings.namespace + "hasPower") } + if (nbt.hasKey(Settings.namespace + "maxWidth") && nbt.hasKey(Settings.namespace + "maxHeight")) { + val maxWidth = nbt.getInteger(Settings.namespace + "maxWidth") + val maxHeight = nbt.getInteger(Settings.namespace + "maxHeight") + maxResolution = (maxWidth, maxHeight) + } } // Null check for Waila (and other mods that may call this client side). @@ -463,6 +468,8 @@ class TextBuffer(val host: EnvironmentHost) extends prefab.ManagedEnvironment wi SaveHandler.scheduleSave(host, nbt, node.address + "_buffer", data.save _) nbt.setBoolean(Settings.namespace + "isOn", isDisplaying) nbt.setBoolean(Settings.namespace + "hasPower", hasPower) + nbt.setInteger(Settings.namespace + "maxWidth", maxResolution._1) + nbt.setInteger(Settings.namespace + "maxHeight", maxResolution._2) } } From c99750f88ea6e845dc6ba25382cdad91d30abec3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Wed, 14 Jan 2015 23:56:33 +0100 Subject: [PATCH 10/61] Fixed robots not dropping the contents of their tool and container slots. I'm so sorry! --- src/main/scala/li/cil/oc/common/tileentity/Robot.scala | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/scala/li/cil/oc/common/tileentity/Robot.scala b/src/main/scala/li/cil/oc/common/tileentity/Robot.scala index 63c6e6a5b..7e1e11c71 100644 --- a/src/main/scala/li/cil/oc/common/tileentity/Robot.scala +++ b/src/main/scala/li/cil/oc/common/tileentity/Robot.scala @@ -738,8 +738,13 @@ class Robot extends traits.Computer with traits.PowerInformation with IFluidHand override def dropSlot(slot: Int, count: Int, direction: Option[ForgeDirection]) = InventoryUtils.dropSlot(BlockPosition(x, y, z, world), dynamicInventory, slot, count, direction) - override def dropAllSlots() = + override def dropAllSlots() = { + InventoryUtils.dropSlot(BlockPosition(x, y, z, world), this, 0, Int.MaxValue) + for (slot <- containerSlots) { + InventoryUtils.dropSlot(BlockPosition(x, y, z, world), this, slot, Int.MaxValue) + } InventoryUtils.dropAllSlots(BlockPosition(x, y, z, world), dynamicInventory) + } // ----------------------------------------------------------------------- // From b13e72fd1b639d2739e14432f25dee2982931cd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Thu, 15 Jan 2015 01:04:33 +0100 Subject: [PATCH 11/61] Unified GUI handling in blocks a little. --- .../li/cil/oc/common/block/Adapter.scala | 17 ++-------- .../li/cil/oc/common/block/Assembler.scala | 19 ++--------- .../scala/li/cil/oc/common/block/Case.scala | 23 +++++-------- .../li/cil/oc/common/block/Charger.scala | 31 +++++++---------- .../li/cil/oc/common/block/Disassembler.scala | 19 ++--------- .../li/cil/oc/common/block/DiskDrive.scala | 34 ++++++++----------- .../scala/li/cil/oc/common/block/Raid.scala | 21 ++---------- .../scala/li/cil/oc/common/block/Screen.scala | 5 +-- .../li/cil/oc/common/block/ServerRack.scala | 19 ++--------- .../scala/li/cil/oc/common/block/Switch.scala | 23 ++----------- .../li/cil/oc/common/block/traits/GUI.scala | 22 ++++++++++++ 11 files changed, 77 insertions(+), 156 deletions(-) create mode 100644 src/main/scala/li/cil/oc/common/block/traits/GUI.scala diff --git a/src/main/scala/li/cil/oc/common/block/Adapter.scala b/src/main/scala/li/cil/oc/common/block/Adapter.scala index 57745744a..5deabb33a 100644 --- a/src/main/scala/li/cil/oc/common/block/Adapter.scala +++ b/src/main/scala/li/cil/oc/common/block/Adapter.scala @@ -1,15 +1,13 @@ package li.cil.oc.common.block -import li.cil.oc.OpenComputers import li.cil.oc.common.GuiType import li.cil.oc.common.tileentity import net.minecraft.block.Block -import net.minecraft.entity.player.EntityPlayer import net.minecraft.world.IBlockAccess import net.minecraft.world.World import net.minecraftforge.common.util.ForgeDirection -class Adapter extends SimpleBlock { +class Adapter extends SimpleBlock with traits.GUI { override protected def customTextures = Array( None, Some("AdapterTop"), @@ -21,23 +19,14 @@ class Adapter extends SimpleBlock { // ----------------------------------------------------------------------- // + override def guiType = GuiType.Adapter + override def hasTileEntity(metadata: Int) = true override def createTileEntity(world: World, metadata: Int) = new tileentity.Adapter() // ----------------------------------------------------------------------- // - override def onBlockActivated(world: World, x: Int, y: Int, z: Int, player: EntityPlayer, - side: ForgeDirection, hitX: Float, hitY: Float, hitZ: Float) = { - if (!player.isSneaking) { - if (!world.isRemote) { - player.openGui(OpenComputers, GuiType.Adapter.id, world, x, y, z) - } - true - } - else false - } - override def onNeighborBlockChange(world: World, x: Int, y: Int, z: Int, block: Block) = world.getTileEntity(x, y, z) match { case adapter: tileentity.Adapter => adapter.neighborChanged() diff --git a/src/main/scala/li/cil/oc/common/block/Assembler.scala b/src/main/scala/li/cil/oc/common/block/Assembler.scala index 917e4e30f..577097d21 100644 --- a/src/main/scala/li/cil/oc/common/block/Assembler.scala +++ b/src/main/scala/li/cil/oc/common/block/Assembler.scala @@ -1,17 +1,15 @@ package li.cil.oc.common.block -import li.cil.oc.OpenComputers import li.cil.oc.Settings import li.cil.oc.client.Textures import li.cil.oc.common.GuiType import li.cil.oc.common.tileentity import net.minecraft.client.renderer.texture.IIconRegister -import net.minecraft.entity.player.EntityPlayer import net.minecraft.world.IBlockAccess import net.minecraft.world.World import net.minecraftforge.common.util.ForgeDirection -class Assembler extends SimpleBlock with traits.SpecialBlock with traits.PowerAcceptor with traits.StateAware { +class Assembler extends SimpleBlock with traits.SpecialBlock with traits.PowerAcceptor with traits.StateAware with traits.GUI { setLightLevel(0.34f) override protected def customTextures = Array( @@ -36,20 +34,9 @@ class Assembler extends SimpleBlock with traits.SpecialBlock with traits.PowerAc override def energyThroughput = Settings.get.assemblerRate + override def guiType = GuiType.Assembler + override def hasTileEntity(metadata: Int) = true override def createTileEntity(world: World, metadata: Int) = new tileentity.Assembler() - - // ----------------------------------------------------------------------- // - - override def onBlockActivated(world: World, x: Int, y: Int, z: Int, player: EntityPlayer, - side: ForgeDirection, hitX: Float, hitY: Float, hitZ: Float) = { - if (!player.isSneaking) { - if (!world.isRemote) { - player.openGui(OpenComputers, GuiType.Assembler.id, world, x, y, z) - } - true - } - else false - } } diff --git a/src/main/scala/li/cil/oc/common/block/Case.scala b/src/main/scala/li/cil/oc/common/block/Case.scala index 03c3fce69..14b7bdd4e 100644 --- a/src/main/scala/li/cil/oc/common/block/Case.scala +++ b/src/main/scala/li/cil/oc/common/block/Case.scala @@ -4,7 +4,6 @@ import java.util import cpw.mods.fml.relauncher.Side import cpw.mods.fml.relauncher.SideOnly -import li.cil.oc.OpenComputers import li.cil.oc.Settings import li.cil.oc.common.GuiType import li.cil.oc.common.tileentity @@ -21,7 +20,7 @@ import net.minecraft.world.IBlockAccess import net.minecraft.world.World import net.minecraftforge.common.util.ForgeDirection -class Case(val tier: Int) extends RedstoneAware with traits.PowerAcceptor with traits.StateAware { +class Case(val tier: Int) extends RedstoneAware with traits.PowerAcceptor with traits.StateAware with traits.GUI { private val iconsOn = new Array[IIcon](6) // ----------------------------------------------------------------------- // @@ -73,28 +72,22 @@ class Case(val tier: Int) extends RedstoneAware with traits.PowerAcceptor with t override def energyThroughput = Settings.get.caseRate(tier) + override def guiType = GuiType.Case + override def createTileEntity(world: World, metadata: Int) = new tileentity.Case(tier) // ----------------------------------------------------------------------- // override def onBlockActivated(world: World, x: Int, y: Int, z: Int, player: EntityPlayer, side: ForgeDirection, hitX: Float, hitY: Float, hitZ: Float) = { - if (!player.isSneaking && !Wrench.holdsApplicableWrench(player, BlockPosition(x, y, z))) { - if (!world.isRemote) { - player.openGui(OpenComputers, GuiType.Case.id, world, x, y, z) + if (player.isSneaking) { + if (!world.isRemote) world.getTileEntity(x, y, z) match { + case computer: tileentity.Case if !computer.machine.isRunning => computer.machine.start() + case _ => } true } - else if (player.getCurrentEquippedItem == null) { - if (!world.isRemote) { - world.getTileEntity(x, y, z) match { - case computer: tileentity.Case if !computer.machine.isRunning => computer.machine.start() - case _ => - } - } - true - } - else false + else super.onBlockActivated(world, x, y, z, player, side, hitX, hitY, hitZ) } override def removedByPlayer(world: World, player: EntityPlayer, x: Int, y: Int, z: Int, willHarvest: Boolean) = diff --git a/src/main/scala/li/cil/oc/common/block/Charger.scala b/src/main/scala/li/cil/oc/common/block/Charger.scala index 9f2d44854..d317ba944 100644 --- a/src/main/scala/li/cil/oc/common/block/Charger.scala +++ b/src/main/scala/li/cil/oc/common/block/Charger.scala @@ -1,6 +1,5 @@ package li.cil.oc.common.block -import li.cil.oc.OpenComputers import li.cil.oc.Settings import li.cil.oc.client.Textures import li.cil.oc.common.GuiType @@ -15,7 +14,7 @@ import net.minecraft.world.IBlockAccess import net.minecraft.world.World import net.minecraftforge.common.util.ForgeDirection -class Charger extends RedstoneAware with traits.PowerAcceptor with traits.StateAware { +class Charger extends RedstoneAware with traits.PowerAcceptor with traits.StateAware with traits.GUI { override protected def customTextures = Array( None, None, @@ -35,6 +34,8 @@ class Charger extends RedstoneAware with traits.PowerAcceptor with traits.StateA override def energyThroughput = Settings.get.chargerRate + override def guiType = GuiType.Charger + override def createTileEntity(world: World, metadata: Int) = new tileentity.Charger() // ----------------------------------------------------------------------- // @@ -44,26 +45,18 @@ class Charger extends RedstoneAware with traits.PowerAcceptor with traits.StateA // ----------------------------------------------------------------------- // override def onBlockActivated(world: World, x: Int, y: Int, z: Int, player: EntityPlayer, side: ForgeDirection, hitX: Float, hitY: Float, hitZ: Float) = - world.getTileEntity(x, y, z) match { + if (Wrench.holdsApplicableWrench(player, BlockPosition(x, y, z))) world.getTileEntity(x, y, z) match { case charger: tileentity.Charger => - if (Wrench.holdsApplicableWrench(player, BlockPosition(x, y, z))) { - if (!world.isRemote) { - charger.invertSignal = !charger.invertSignal - charger.chargeSpeed = 1.0 - charger.chargeSpeed - PacketSender.sendChargerState(charger) - Wrench.wrenchUsed(player, BlockPosition(x, y, z)) - } - true + if (!world.isRemote) { + charger.invertSignal = !charger.invertSignal + charger.chargeSpeed = 1.0 - charger.chargeSpeed + PacketSender.sendChargerState(charger) + Wrench.wrenchUsed(player, BlockPosition(x, y, z)) } - else if (!player.isSneaking) { - if (!world.isRemote) { - player.openGui(OpenComputers, GuiType.Charger.id, world, x, y, z) - } - true - } - else false - case _ => super.onBlockActivated(world, x, y, z, player, side, hitX, hitY, hitZ) + true + case _ => false } + else super.onBlockActivated(world, x, y, z, player, side, hitX, hitY, hitZ) override def onNeighborBlockChange(world: World, x: Int, y: Int, z: Int, block: Block) { world.getTileEntity(x, y, z) match { diff --git a/src/main/scala/li/cil/oc/common/block/Disassembler.scala b/src/main/scala/li/cil/oc/common/block/Disassembler.scala index 7fcfcb567..aecf9fb00 100644 --- a/src/main/scala/li/cil/oc/common/block/Disassembler.scala +++ b/src/main/scala/li/cil/oc/common/block/Disassembler.scala @@ -1,6 +1,5 @@ package li.cil.oc.common.block -import li.cil.oc.OpenComputers import li.cil.oc.Settings import li.cil.oc.client.Textures import li.cil.oc.common.GuiType @@ -10,9 +9,8 @@ import net.minecraft.client.renderer.texture.IIconRegister import net.minecraft.entity.player.EntityPlayer import net.minecraft.item.ItemStack import net.minecraft.world.World -import net.minecraftforge.common.util.ForgeDirection -class Disassembler extends SimpleBlock with traits.PowerAcceptor with traits.StateAware { +class Disassembler extends SimpleBlock with traits.PowerAcceptor with traits.StateAware with traits.GUI { override protected def customTextures = Array( None, Some("DisassemblerTop"), @@ -38,20 +36,9 @@ class Disassembler extends SimpleBlock with traits.PowerAcceptor with traits.Sta override def energyThroughput = Settings.get.disassemblerRate + override def guiType = GuiType.Disassembler + override def hasTileEntity(metadata: Int) = true override def createTileEntity(world: World, metadata: Int) = new tileentity.Disassembler() - - // ----------------------------------------------------------------------- // - - override def onBlockActivated(world: World, x: Int, y: Int, z: Int, player: EntityPlayer, - side: ForgeDirection, hitX: Float, hitY: Float, hitZ: Float) = { - if (!player.isSneaking) { - if (!world.isRemote) { - player.openGui(OpenComputers, GuiType.Disassembler.id, world, x, y, z) - } - true - } - else false - } } diff --git a/src/main/scala/li/cil/oc/common/block/DiskDrive.scala b/src/main/scala/li/cil/oc/common/block/DiskDrive.scala index 7281c625c..358a1297f 100644 --- a/src/main/scala/li/cil/oc/common/block/DiskDrive.scala +++ b/src/main/scala/li/cil/oc/common/block/DiskDrive.scala @@ -1,6 +1,5 @@ package li.cil.oc.common.block -import li.cil.oc.OpenComputers import li.cil.oc.common.GuiType import li.cil.oc.common.tileentity import li.cil.oc.integration.Mods @@ -10,7 +9,7 @@ import net.minecraft.item.ItemStack import net.minecraft.world.World import net.minecraftforge.common.util.ForgeDirection -class DiskDrive extends SimpleBlock { +class DiskDrive extends SimpleBlock with traits.GUI { override protected def customTextures = Array( None, None, @@ -31,6 +30,8 @@ class DiskDrive extends SimpleBlock { // ----------------------------------------------------------------------- // + override def guiType = GuiType.DiskDrive + override def hasTileEntity(metadata: Int) = true override def createTileEntity(world: World, metadata: Int) = new tileentity.DiskDrive() @@ -49,30 +50,23 @@ class DiskDrive extends SimpleBlock { override def onBlockActivated(world: World, x: Int, y: Int, z: Int, player: EntityPlayer, side: ForgeDirection, hitX: Float, hitY: Float, hitZ: Float) = { - world.getTileEntity(x, y, z) match { + // Behavior: sneaking -> Insert[+Eject], not sneaking -> GUI. + if (player.isSneaking) world.getTileEntity(x, y, z) match { case drive: tileentity.DiskDrive => - // Behavior: sneaking -> Insert[+Eject], not sneaking -> GUI. - if (!player.isSneaking) { + val isDiskInDrive = drive.getStackInSlot(0) != null + val isHoldingDisk = drive.isItemValidForSlot(0, player.getCurrentEquippedItem) + if (isDiskInDrive) { if (!world.isRemote) { - player.openGui(OpenComputers, GuiType.DiskDrive.id, world, x, y, z) + drive.dropSlot(0, 1, Option(drive.facing)) } - true } - else { - val isDiskInDrive = drive.getStackInSlot(0) != null - val isHoldingDisk = drive.isItemValidForSlot(0, player.getCurrentEquippedItem) - if (isDiskInDrive) { - if (!world.isRemote) { - drive.dropSlot(0, 1, Option(drive.facing)) - } - } - if (isHoldingDisk) { - // Insert the disk. - drive.setInventorySlotContents(0, player.inventory.decrStackSize(player.inventory.currentItem, 1)) - } - isDiskInDrive || isHoldingDisk + if (isHoldingDisk) { + // Insert the disk. + drive.setInventorySlotContents(0, player.inventory.decrStackSize(player.inventory.currentItem, 1)) } + isDiskInDrive || isHoldingDisk case _ => false } + else super.onBlockActivated(world, x, y, z, player, side, hitX, hitY, hitZ) } } diff --git a/src/main/scala/li/cil/oc/common/block/Raid.scala b/src/main/scala/li/cil/oc/common/block/Raid.scala index 1b47e6c08..321958eaa 100644 --- a/src/main/scala/li/cil/oc/common/block/Raid.scala +++ b/src/main/scala/li/cil/oc/common/block/Raid.scala @@ -1,13 +1,10 @@ package li.cil.oc.common.block -import li.cil.oc.OpenComputers import li.cil.oc.common.GuiType import li.cil.oc.common.tileentity -import net.minecraft.entity.player.EntityPlayer import net.minecraft.world.World -import net.minecraftforge.common.util.ForgeDirection -class Raid extends SimpleBlock { +class Raid extends SimpleBlock with traits.GUI { override protected def customTextures = Array( None, None, @@ -19,6 +16,8 @@ class Raid extends SimpleBlock { // ----------------------------------------------------------------------- // + override def guiType = GuiType.Raid + override def hasTileEntity(metadata: Int) = true override def createTileEntity(world: World, metadata: Int) = new tileentity.Raid() @@ -32,18 +31,4 @@ class Raid extends SimpleBlock { case raid: tileentity.Raid if raid.presence.forall(ok => ok) => 15 case _ => 0 } - - // ----------------------------------------------------------------------- // - - override def onBlockActivated(world: World, x: Int, y: Int, z: Int, player: EntityPlayer, - side: ForgeDirection, hitX: Float, hitY: Float, hitZ: Float) = { - world.getTileEntity(x, y, z) match { - case drive: tileentity.Raid if !player.isSneaking => - if (!world.isRemote) { - player.openGui(OpenComputers, GuiType.Raid.id, world, x, y, z) - } - true - case _ => false - } - } } diff --git a/src/main/scala/li/cil/oc/common/block/Screen.scala b/src/main/scala/li/cil/oc/common/block/Screen.scala index 130951915..daead40b5 100644 --- a/src/main/scala/li/cil/oc/common/block/Screen.scala +++ b/src/main/scala/li/cil/oc/common/block/Screen.scala @@ -328,8 +328,8 @@ class Screen(val tier: Int) extends RedstoneAware { side: ForgeDirection, hitX: Float, hitY: Float, hitZ: Float) = rightClick(world, x, y, z, player, side, hitX, hitY, hitZ, force = false) def rightClick(world: World, x: Int, y: Int, z: Int, player: EntityPlayer, - side: ForgeDirection, hitX: Float, hitY: Float, hitZ: Float, force: Boolean) = - if (Wrench.holdsApplicableWrench(player, BlockPosition(x, y, z))) false + side: ForgeDirection, hitX: Float, hitY: Float, hitZ: Float, force: Boolean) = { + if (Wrench.holdsApplicableWrench(player, BlockPosition(x, y, z)) && getValidRotations(world, x, y, z).contains(side) && !force) false else world.getTileEntity(x, y, z) match { case screen: tileentity.Screen if screen.hasKeyboard && (force || player.isSneaking == screen.invertTouchMode) => // Yep, this GUI is actually purely client side. We could skip this @@ -343,6 +343,7 @@ class Screen(val tier: Int) extends RedstoneAware { screen.click(player, hitX, hitY, hitZ) case _ => false } + } override def onEntityWalking(world: World, x: Int, y: Int, z: Int, entity: Entity) = if (!world.isRemote) world.getTileEntity(x, y, z) match { diff --git a/src/main/scala/li/cil/oc/common/block/ServerRack.scala b/src/main/scala/li/cil/oc/common/block/ServerRack.scala index 15d004700..3178c851d 100644 --- a/src/main/scala/li/cil/oc/common/block/ServerRack.scala +++ b/src/main/scala/li/cil/oc/common/block/ServerRack.scala @@ -2,18 +2,16 @@ package li.cil.oc.common.block import cpw.mods.fml.relauncher.Side import cpw.mods.fml.relauncher.SideOnly -import li.cil.oc.OpenComputers import li.cil.oc.Settings import li.cil.oc.client.Textures import li.cil.oc.common.GuiType import li.cil.oc.common.tileentity import net.minecraft.client.renderer.texture.IIconRegister -import net.minecraft.entity.player.EntityPlayer import net.minecraft.world.IBlockAccess import net.minecraft.world.World import net.minecraftforge.common.util.ForgeDirection -class ServerRack extends RedstoneAware with traits.SpecialBlock with traits.PowerAcceptor with traits.StateAware { +class ServerRack extends RedstoneAware with traits.SpecialBlock with traits.PowerAcceptor with traits.StateAware with traits.GUI { override protected def customTextures = Array( None, None, @@ -47,20 +45,9 @@ class ServerRack extends RedstoneAware with traits.SpecialBlock with traits.Powe override def energyThroughput = Settings.get.serverRackRate + override def guiType = GuiType.Rack + override def hasTileEntity(metadata: Int) = true override def createTileEntity(world: World, metadata: Int) = new tileentity.ServerRack() - - // ----------------------------------------------------------------------- // - - override def onBlockActivated(world: World, x: Int, y: Int, z: Int, player: EntityPlayer, - side: ForgeDirection, hitX: Float, hitY: Float, hitZ: Float) = { - if (!player.isSneaking) { - if (!world.isRemote) { - player.openGui(OpenComputers, GuiType.Rack.id, world, x, y, z) - } - true - } - else false - } } diff --git a/src/main/scala/li/cil/oc/common/block/Switch.scala b/src/main/scala/li/cil/oc/common/block/Switch.scala index 841c047b0..fb4d4514b 100644 --- a/src/main/scala/li/cil/oc/common/block/Switch.scala +++ b/src/main/scala/li/cil/oc/common/block/Switch.scala @@ -1,16 +1,13 @@ package li.cil.oc.common.block -import li.cil.oc.OpenComputers import li.cil.oc.Settings import li.cil.oc.client.Textures import li.cil.oc.common.GuiType import li.cil.oc.common.tileentity import net.minecraft.client.renderer.texture.IIconRegister -import net.minecraft.entity.player.EntityPlayer import net.minecraft.world.World -import net.minecraftforge.common.util.ForgeDirection -class Switch extends SimpleBlock { +class Switch extends SimpleBlock with traits.GUI { override protected def customTextures = Array( None, Some("SwitchTop"), @@ -27,23 +24,9 @@ class Switch extends SimpleBlock { // ----------------------------------------------------------------------- // + override def guiType = GuiType.Switch + override def hasTileEntity(metadata: Int) = true override def createTileEntity(world: World, metadata: Int) = new tileentity.Switch() - - // ----------------------------------------------------------------------- // - - override def onBlockActivated(world: World, x: Int, y: Int, z: Int, player: EntityPlayer, - side: ForgeDirection, hitX: Float, hitY: Float, hitZ: Float) = { - world.getTileEntity(x, y, z) match { - case switch: tileentity.Switch => - if (!player.isSneaking) { - if (!world.isRemote) { - player.openGui(OpenComputers, GuiType.Switch.id, world, x, y, z) - } - true - } - else false - } - } } diff --git a/src/main/scala/li/cil/oc/common/block/traits/GUI.scala b/src/main/scala/li/cil/oc/common/block/traits/GUI.scala new file mode 100644 index 000000000..3c34b2722 --- /dev/null +++ b/src/main/scala/li/cil/oc/common/block/traits/GUI.scala @@ -0,0 +1,22 @@ +package li.cil.oc.common.block.traits + +import li.cil.oc.OpenComputers +import li.cil.oc.common.GuiType +import li.cil.oc.common.block.SimpleBlock +import net.minecraft.entity.player.EntityPlayer +import net.minecraft.world.World +import net.minecraftforge.common.util.ForgeDirection + +trait GUI extends SimpleBlock { + def guiType: GuiType.EnumVal + + override def onBlockActivated(world: World, x: Int, y: Int, z: Int, player: EntityPlayer, side: ForgeDirection, hitX: Float, hitY: Float, hitZ: Float) = { + if (!player.isSneaking) { + if (!world.isRemote) { + player.openGui(OpenComputers, guiType.id, world, x, y, z) + } + true + } + else super.onBlockActivated(world, x, y, z, player, side, hitX, hitY, hitZ) + } +} From 3dec0b24eb60d78a42269873e1763fe7e9b0e660 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Thu, 15 Jan 2015 12:59:22 +0100 Subject: [PATCH 12/61] Reworked redstone logic a little. Moved computer signal generation to component (i.e. redstone cards) and only sending an internal message from blocks (e.g. computer cases). Pulled wireless trait out of other component logic which allows creating it on its own, e.g. for tablets and drones. --- .../scala/li/cil/oc/common/EventHandler.scala | 2 +- .../scala/li/cil/oc/common/block/Case.scala | 2 - .../cil/oc/common/tileentity/Redstone.scala | 6 +- .../cil/oc/common/tileentity/ServerRack.scala | 2 +- .../common/tileentity/traits/Computer.scala | 2 +- .../DriverBlockEnvironments.scala | 2 +- .../opencomputers/DriverRedstoneCard.scala | 33 ++++++---- .../opencomputers/ModOpenComputers.scala | 2 +- .../wrsve/WirelessRedstoneSVE.scala | 31 ++++----- .../li/cil/oc/server/component/Redstone.scala | 61 ++++-------------- .../oc/server/component/RedstoneBundled.scala | 15 +++-- .../oc/server/component/RedstoneVanilla.scala | 63 +++++++++++++++++++ .../server/component/RedstoneWireless.scala | 11 ++-- 13 files changed, 137 insertions(+), 95 deletions(-) create mode 100644 src/main/scala/li/cil/oc/server/component/RedstoneVanilla.scala diff --git a/src/main/scala/li/cil/oc/common/EventHandler.scala b/src/main/scala/li/cil/oc/common/EventHandler.scala index 22f109d68..2060b74f7 100644 --- a/src/main/scala/li/cil/oc/common/EventHandler.scala +++ b/src/main/scala/li/cil/oc/common/EventHandler.scala @@ -85,7 +85,7 @@ object EventHandler { def scheduleWirelessRedstone(rs: server.component.RedstoneWireless) { if (SideTracker.isServer) pending.synchronized { - pending += (() => if (!rs.owner.isInvalid) { + pending += (() => if (rs.node.network != null) { util.WirelessRedstone.addReceiver(rs) util.WirelessRedstone.updateOutput(rs) }) diff --git a/src/main/scala/li/cil/oc/common/block/Case.scala b/src/main/scala/li/cil/oc/common/block/Case.scala index 14b7bdd4e..e3d1dc6a1 100644 --- a/src/main/scala/li/cil/oc/common/block/Case.scala +++ b/src/main/scala/li/cil/oc/common/block/Case.scala @@ -7,8 +7,6 @@ import cpw.mods.fml.relauncher.SideOnly import li.cil.oc.Settings import li.cil.oc.common.GuiType import li.cil.oc.common.tileentity -import li.cil.oc.integration.util.Wrench -import li.cil.oc.util.BlockPosition import li.cil.oc.util.Color import li.cil.oc.util.Rarity import li.cil.oc.util.Tooltip diff --git a/src/main/scala/li/cil/oc/common/tileentity/Redstone.scala b/src/main/scala/li/cil/oc/common/tileentity/Redstone.scala index 8dda0180d..9e48604ab 100644 --- a/src/main/scala/li/cil/oc/common/tileentity/Redstone.scala +++ b/src/main/scala/li/cil/oc/common/tileentity/Redstone.scala @@ -11,7 +11,11 @@ import net.minecraft.nbt.NBTTagCompound import net.minecraftforge.common.util.ForgeDirection class Redstone extends Environment with BundledRedstoneAware { - val instance = if (BundledRedstone.isAvailable) new component.Redstone[BundledRedstoneAware](this) with component.RedstoneBundled else new component.Redstone(this) + val instance = + if (BundledRedstone.isAvailable) + new component.Redstone.Bundled(this) + else + new component.Redstone.Vanilla(this) val node = instance.node if (node != null) { node.setVisibility(Visibility.Network) diff --git a/src/main/scala/li/cil/oc/common/tileentity/ServerRack.scala b/src/main/scala/li/cil/oc/common/tileentity/ServerRack.scala index 0aa7b1799..e2b988277 100644 --- a/src/main/scala/li/cil/oc/common/tileentity/ServerRack.scala +++ b/src/main/scala/li/cil/oc/common/tileentity/ServerRack.scala @@ -509,7 +509,7 @@ class ServerRack extends traits.PowerAcceptor with traits.Hub with traits.PowerB override protected def onRedstoneInputChanged(side: ForgeDirection) { super.onRedstoneInputChanged(side) servers collect { - case Some(server) => server.machine.signal("redstone_changed", server.machine.node.address, Int.box(toLocal(side).ordinal())) + case Some(server) => server.machine.node.sendToNeighbors("redstone.changed", toLocal(side)) } } diff --git a/src/main/scala/li/cil/oc/common/tileentity/traits/Computer.scala b/src/main/scala/li/cil/oc/common/tileentity/traits/Computer.scala index d1df55479..300f68b46 100644 --- a/src/main/scala/li/cil/oc/common/tileentity/traits/Computer.scala +++ b/src/main/scala/li/cil/oc/common/tileentity/traits/Computer.scala @@ -206,7 +206,7 @@ trait Computer extends Environment with ComponentInventory with Rotatable with B override protected def onRedstoneInputChanged(side: ForgeDirection) { super.onRedstoneInputChanged(side) - machine.signal("redstone_changed", machine.node.address, Int.box(toLocal(side).ordinal())) + machine.node.sendToNeighbors("redstone.changed", toLocal(side)) } // ----------------------------------------------------------------------- // diff --git a/src/main/scala/li/cil/oc/integration/opencomputers/DriverBlockEnvironments.scala b/src/main/scala/li/cil/oc/integration/opencomputers/DriverBlockEnvironments.scala index e61c816da..b82e6a645 100644 --- a/src/main/scala/li/cil/oc/integration/opencomputers/DriverBlockEnvironments.scala +++ b/src/main/scala/li/cil/oc/integration/opencomputers/DriverBlockEnvironments.scala @@ -32,7 +32,7 @@ object DriverBlockEnvironments extends driver.Block with EnvironmentAware { else if (isOneOf(block.field_150939_a, "case1", "case2", "case3", "caseCreative", "microcontroller")) classOf[Machine] else if (isOneOf(block.field_150939_a, "hologram1", "hologram2")) classOf[tileentity.Hologram] else if (isOneOf(block.field_150939_a, "motionSensor")) classOf[tileentity.MotionSensor] - else if (isOneOf(block.field_150939_a, "redstone")) if (BundledRedstone.isAvailable) classOf[component.Redstone.Bundled] else classOf[component.Redstone.Simple] + else if (isOneOf(block.field_150939_a, "redstone")) if (BundledRedstone.isAvailable) classOf[component.Redstone.Bundled] else classOf[component.Redstone.Vanilla] else if (isOneOf(block.field_150939_a, "screen1")) classOf[common.component.TextBuffer].asInstanceOf[Class[_ <: Environment]] else if (isOneOf(block.field_150939_a, "screen2", "screen3")) classOf[common.component.Screen] else if (isOneOf(block.field_150939_a, "robot")) classOf[component.robot.Robot].asInstanceOf[Class[_ <: Environment]] diff --git a/src/main/scala/li/cil/oc/integration/opencomputers/DriverRedstoneCard.scala b/src/main/scala/li/cil/oc/integration/opencomputers/DriverRedstoneCard.scala index d950e69b1..8ccfda205 100644 --- a/src/main/scala/li/cil/oc/integration/opencomputers/DriverRedstoneCard.scala +++ b/src/main/scala/li/cil/oc/integration/opencomputers/DriverRedstoneCard.scala @@ -19,16 +19,22 @@ import net.minecraft.item.ItemStack object DriverRedstoneCard extends Item with HostAware with EnvironmentAware { override def worksWith(stack: ItemStack) = isOneOf(stack, api.Items.get("redstoneCard1"), api.Items.get("redstoneCard2")) - override def createEnvironment(stack: ItemStack, host: EnvironmentHost) = + override def createEnvironment(stack: ItemStack, host: EnvironmentHost) = { + val isAdvanced = tier(stack) == Tier.Two + val hasBundled = BundledRedstone.isAvailable && isAdvanced + val hasWireless = WirelessRedstone.isAvailable && isAdvanced host match { - case redstone: BundledRedstoneAware if BundledRedstone.isAvailable && tier(stack) == Tier.Two => - if (WirelessRedstone.isAvailable) new component.Redstone.BundledWireless(redstone) + case redstone: BundledRedstoneAware if hasBundled => + if (hasWireless) new component.Redstone.BundledWireless(redstone) else new component.Redstone.Bundled(redstone) case redstone: RedstoneAware => - if (tier(stack) == Tier.Two && WirelessRedstone.isAvailable) new component.Redstone.Wireless(redstone) - else new component.Redstone.Simple(redstone) - case _ => null + if (hasWireless) new component.Redstone.VanillaWireless(redstone) + else new component.Redstone.Vanilla(redstone) + case _ => + if (hasWireless) new component.Redstone.Wireless(host) + else null } + } override def slot(stack: ItemStack) = Slot.Card @@ -38,15 +44,16 @@ object DriverRedstoneCard extends Item with HostAware with EnvironmentAware { case _ => Tier.One } - override def providedEnvironment(stack: ItemStack): Class[_ <: Environment] = - if (stack.getItemDamage == api.Items.get("redstoneCard1").createItemStack(1).getItemDamage) - classOf[component.Redstone[RedstoneAware]] - else if (BundledRedstone.isAvailable) { - if (WirelessRedstone.isAvailable) classOf[component.Redstone.BundledWireless] + override def providedEnvironment(stack: ItemStack): Class[_ <: Environment] = { + val isAdvanced = tier(stack) == Tier.Two + val hasBundled = BundledRedstone.isAvailable && isAdvanced + val hasWireless = WirelessRedstone.isAvailable && isAdvanced + if (hasBundled) { + if (hasWireless) classOf[component.Redstone.BundledWireless] else classOf[component.Redstone.Bundled] } else { - if (WirelessRedstone.isAvailable) classOf[component.Redstone.Wireless] - else classOf[component.Redstone.Simple] + classOf[component.Redstone.Vanilla] } + } } diff --git a/src/main/scala/li/cil/oc/integration/opencomputers/ModOpenComputers.scala b/src/main/scala/li/cil/oc/integration/opencomputers/ModOpenComputers.scala index 2e4231d83..13b461b8b 100644 --- a/src/main/scala/li/cil/oc/integration/opencomputers/ModOpenComputers.scala +++ b/src/main/scala/li/cil/oc/integration/opencomputers/ModOpenComputers.scala @@ -127,7 +127,6 @@ object ModOpenComputers extends ModProxy { "keyboard", "lanCard", "redstoneCard1", - "redstoneCard2", // TODO Move back down to wireless section once wireless redstone can work on its own. "screen1", "angelUpgrade", "craftingUpgrade", @@ -174,6 +173,7 @@ object ModOpenComputers extends ModProxy { "leashUpgrade") if (!WirelessRedstone.isAvailable) { + blacklistHost(classOf[internal.Drone], "redstoneCard2") blacklistHost(classOf[internal.Tablet], "redstoneCard2") } diff --git a/src/main/scala/li/cil/oc/integration/wrsve/WirelessRedstoneSVE.scala b/src/main/scala/li/cil/oc/integration/wrsve/WirelessRedstoneSVE.scala index bce44a695..c56db9c27 100644 --- a/src/main/scala/li/cil/oc/integration/wrsve/WirelessRedstoneSVE.scala +++ b/src/main/scala/li/cil/oc/integration/wrsve/WirelessRedstoneSVE.scala @@ -2,6 +2,7 @@ package li.cil.oc.integration.wrsve import li.cil.oc.integration.util.WirelessRedstone.WirelessRedstoneSystem import li.cil.oc.server.component.RedstoneWireless +import li.cil.oc.util.BlockPosition import net.minecraft.world.World import scala.language.reflectiveCalls @@ -9,15 +10,15 @@ import scala.language.reflectiveCalls object WirelessRedstoneSVE extends WirelessRedstoneSystem { private val ether = try { Option(Class.forName("net.slimevoid.wirelessredstone.ether.RedstoneEther").getMethod("getInstance").invoke(null).asInstanceOf[ { - def addTransmitter(world: World, x: Int, y: Int, z: Int, frequency: AnyRef) + def addTransmitter(world: World, x: Int, y: Int, z: Int, frequency: AnyRef): Unit - def remTransmitter(world: World, x: Int, y: Int, z: Int, frequency: AnyRef) + def remTransmitter(world: World, x: Int, y: Int, z: Int, frequency: AnyRef): Unit - def addReceiver(world: World, x: Int, y: Int, z: Int, frequency: AnyRef) + def addReceiver(world: World, x: Int, y: Int, z: Int, frequency: AnyRef): Unit - def remReceiver(world: World, x: Int, y: Int, z: Int, frequency: AnyRef) + def remReceiver(world: World, x: Int, y: Int, z: Int, frequency: AnyRef): Unit - def setTransmitterState(world: World, x: Int, y: Int, z: Int, frequency: AnyRef, state: Boolean) + def setTransmitterState(world: World, x: Int, y: Int, z: Int, frequency: AnyRef, state: Boolean): Unit def getFreqState(world: World, frequency: AnyRef): Boolean }]) @@ -27,25 +28,25 @@ object WirelessRedstoneSVE extends WirelessRedstoneSystem { } def removeTransmitter(rs: RedstoneWireless) { - val te = rs.owner - ether.foreach(_.remTransmitter(te.world, te.x, te.y, te.z, rs.wirelessFrequency.toString)) + val blockPos = BlockPosition(rs.redstone) + ether.foreach(_.remTransmitter(rs.redstone.world, blockPos.x, blockPos.y, blockPos.z, rs.wirelessFrequency.toString)) } def addReceiver(rs: RedstoneWireless) { - val te = rs.owner - ether.foreach(_.addReceiver(te.world, te.x, te.y, te.z, rs.wirelessFrequency.toString)) + val blockPos = BlockPosition(rs.redstone) + ether.foreach(_.addReceiver(rs.redstone.world, blockPos.x, blockPos.y, blockPos.z, rs.wirelessFrequency.toString)) } def removeReceiver(rs: RedstoneWireless) { - val te = rs.owner - ether.foreach(_.remReceiver(te.world, te.x, te.y, te.z, rs.wirelessFrequency.toString)) + val blockPos = BlockPosition(rs.redstone) + ether.foreach(_.remReceiver(rs.redstone.world, blockPos.x, blockPos.y, blockPos.z, rs.wirelessFrequency.toString)) } def updateOutput(rs: RedstoneWireless) { - val te = rs.owner - ether.foreach(_.addTransmitter(te.world, te.x, te.y, te.z, rs.wirelessFrequency.toString)) - ether.foreach(_.setTransmitterState(te.world, te.x, te.y, te.z, rs.wirelessFrequency.toString, rs.wirelessOutput)) + val blockPos = BlockPosition(rs.redstone) + ether.foreach(_.addTransmitter(rs.redstone.world, blockPos.x, blockPos.y, blockPos.z, rs.wirelessFrequency.toString)) + ether.foreach(_.setTransmitterState(rs.redstone.world, blockPos.x, blockPos.y, blockPos.z, rs.wirelessFrequency.toString, rs.wirelessOutput)) } - def getInput(rs: RedstoneWireless) = ether.fold(false)(_.getFreqState(rs.owner.world, rs.wirelessFrequency.toString)) + def getInput(rs: RedstoneWireless) = ether.fold(false)(_.getFreqState(rs.redstone.world, rs.wirelessFrequency.toString)) } diff --git a/src/main/scala/li/cil/oc/server/component/Redstone.scala b/src/main/scala/li/cil/oc/server/component/Redstone.scala index 1d1908613..4347c8d5b 100644 --- a/src/main/scala/li/cil/oc/server/component/Redstone.scala +++ b/src/main/scala/li/cil/oc/server/component/Redstone.scala @@ -1,62 +1,25 @@ package li.cil.oc.server.component -import li.cil.oc.api.Network -import li.cil.oc.api.machine.Arguments -import li.cil.oc.api.machine.Callback -import li.cil.oc.api.machine.Context -import li.cil.oc.api.network._ -import li.cil.oc.api.prefab +import li.cil.oc.api.driver.EnvironmentHost import li.cil.oc.common.tileentity.traits.BundledRedstoneAware import li.cil.oc.common.tileentity.traits.RedstoneAware import li.cil.oc.server.component -import net.minecraftforge.common.util.ForgeDirection - -class Redstone[+Owner <: RedstoneAware](val owner: Owner) extends prefab.ManagedEnvironment { - override val node = Network.newNode(this, Visibility.Network). - withComponent("redstone", Visibility.Neighbors). - create() - - // ----------------------------------------------------------------------- // - - @Callback(direct = true, doc = """function(side:number):number -- Get the redstone input on the specified side.""") - def getInput(context: Context, args: Arguments): Array[AnyRef] = { - val side = checkSide(args, 0) - result(owner.input(side)) - } - - @Callback(direct = true, doc = """function(side:number):number -- Get the redstone output on the specified side.""") - def getOutput(context: Context, args: Arguments): Array[AnyRef] = { - val side = checkSide(args, 0) - result(owner.output(side)) - } - - @Callback(doc = """function(side:number, value:number):number -- Set the redstone output on the specified side.""") - def setOutput(context: Context, args: Arguments): Array[AnyRef] = { - val side = checkSide(args, 0) - val value = args.checkInteger(1) - owner.output(side, value) - context.pause(0.1) - result(owner.output(side)) - } - - // ----------------------------------------------------------------------- // - - protected def checkSide(args: Arguments, index: Int) = { - val side = args.checkInteger(index) - if (side < 0 || side > 5) - throw new IllegalArgumentException("invalid side") - owner.toGlobal(ForgeDirection.getOrientation(side)) - } -} object Redstone { - class Simple(redstone: RedstoneAware) extends component.Redstone[RedstoneAware](redstone) + class Vanilla(val redstone: EnvironmentHost with RedstoneAware) + extends component.RedstoneVanilla - class Bundled(redstone: BundledRedstoneAware) extends component.Redstone[BundledRedstoneAware](redstone) with component.RedstoneBundled + class Bundled(val redstone: EnvironmentHost with BundledRedstoneAware) + extends component.RedstoneVanilla with component.RedstoneBundled - class Wireless(redstone: RedstoneAware) extends Simple(redstone) with component.RedstoneWireless + class Wireless(val redstone: EnvironmentHost) + extends component.RedstoneWireless - class BundledWireless(redstone: BundledRedstoneAware) extends Bundled(redstone) with component.RedstoneWireless + class VanillaWireless(val redstone: EnvironmentHost with RedstoneAware) + extends component.RedstoneVanilla with component.RedstoneWireless + + class BundledWireless(val redstone: EnvironmentHost with BundledRedstoneAware) + extends component.RedstoneVanilla with component.RedstoneBundled with component.RedstoneWireless } diff --git a/src/main/scala/li/cil/oc/server/component/RedstoneBundled.scala b/src/main/scala/li/cil/oc/server/component/RedstoneBundled.scala index b6b2b2ebc..02b3312eb 100644 --- a/src/main/scala/li/cil/oc/server/component/RedstoneBundled.scala +++ b/src/main/scala/li/cil/oc/server/component/RedstoneBundled.scala @@ -1,23 +1,26 @@ package li.cil.oc.server.component +import li.cil.oc.api.driver.EnvironmentHost import li.cil.oc.api.machine.Arguments import li.cil.oc.api.machine.Callback import li.cil.oc.api.machine.Context import li.cil.oc.common.tileentity.traits.BundledRedstoneAware -trait RedstoneBundled extends Redstone[BundledRedstoneAware] { +trait RedstoneBundled extends RedstoneVanilla { + override def redstone: EnvironmentHost with BundledRedstoneAware + @Callback(direct = true, doc = """function(side:number, color:number):number -- Get the bundled redstone input on the specified side and with the specified color.""") def getBundledInput(context: Context, args: Arguments): Array[AnyRef] = { val side = checkSide(args, 0) val color = checkColor(args, 1) - result(owner.bundledInput(side, color)) + result(redstone.bundledInput(side, color)) } @Callback(direct = true, doc = """function(side:number, color:number):number -- Get the bundled redstone output on the specified side and with the specified color.""") def getBundledOutput(context: Context, args: Arguments): Array[AnyRef] = { val side = checkSide(args, 0) val color = checkColor(args, 1) - result(owner.bundledOutput(side, color)) + result(redstone.bundledOutput(side, color)) } @Callback(doc = """function(side:number, color:number, value:number):number -- Set the bundled redstone output on the specified side and with the specified color.""") @@ -26,7 +29,7 @@ trait RedstoneBundled extends Redstone[BundledRedstoneAware] { if (args.isTable(1)) { val table = args.checkTable(1) (0 to 15).map(color => (color, table.get(color))).foreach { - case (color, number: Number) => owner.bundledOutput(side, color, number.intValue()) + case (color, number: Number) => redstone.bundledOutput(side, color, number.intValue()) case _ => } context.pause(0.1) @@ -35,9 +38,9 @@ trait RedstoneBundled extends Redstone[BundledRedstoneAware] { else { val color = checkColor(args, 1) val value = args.checkInteger(2) - owner.bundledOutput(side, color, value) + redstone.bundledOutput(side, color, value) context.pause(0.1) - result(owner.bundledOutput(side, color)) + result(redstone.bundledOutput(side, color)) } } diff --git a/src/main/scala/li/cil/oc/server/component/RedstoneVanilla.scala b/src/main/scala/li/cil/oc/server/component/RedstoneVanilla.scala new file mode 100644 index 000000000..aabcc2855 --- /dev/null +++ b/src/main/scala/li/cil/oc/server/component/RedstoneVanilla.scala @@ -0,0 +1,63 @@ +package li.cil.oc.server.component + +import li.cil.oc.api.Network +import li.cil.oc.api.driver.EnvironmentHost +import li.cil.oc.api.machine.Arguments +import li.cil.oc.api.machine.Callback +import li.cil.oc.api.machine.Context +import li.cil.oc.api.network._ +import li.cil.oc.api.prefab +import li.cil.oc.common.tileentity.traits.BundledRedstoneAware +import li.cil.oc.common.tileentity.traits.RedstoneAware +import li.cil.oc.server.component +import net.minecraftforge.common.util.ForgeDirection + +trait RedstoneVanilla extends prefab.ManagedEnvironment { + override val node = Network.newNode(this, Visibility.Network). + withComponent("redstone", Visibility.Neighbors). + create() + + def redstone: EnvironmentHost with RedstoneAware + + // ----------------------------------------------------------------------- // + + @Callback(direct = true, doc = """function(side:number):number -- Get the redstone input on the specified side.""") + def getInput(context: Context, args: Arguments): Array[AnyRef] = { + val side = checkSide(args, 0) + result(redstone.input(side)) + } + + @Callback(direct = true, doc = """function(side:number):number -- Get the redstone output on the specified side.""") + def getOutput(context: Context, args: Arguments): Array[AnyRef] = { + val side = checkSide(args, 0) + result(redstone.output(side)) + } + + @Callback(doc = """function(side:number, value:number):number -- Set the redstone output on the specified side.""") + def setOutput(context: Context, args: Arguments): Array[AnyRef] = { + val side = checkSide(args, 0) + val value = args.checkInteger(1) + redstone.output(side, value) + context.pause(0.1) + result(redstone.output(side)) + } + + // ----------------------------------------------------------------------- // + + override def onMessage(message: Message): Unit = { + super.onMessage(message) + if (message.name == "redstone.changed") message.data match { + case Array(side: ForgeDirection) => node.sendToReachable("computer.signal", "redstone_changed", Int.box(side.ordinal())) + case _ => + } + } + + // ----------------------------------------------------------------------- // + + protected def checkSide(args: Arguments, index: Int) = { + val side = args.checkInteger(index) + if (side < 0 || side > 5) + throw new IllegalArgumentException("invalid side") + redstone.toGlobal(ForgeDirection.getOrientation(side)) + } +} diff --git a/src/main/scala/li/cil/oc/server/component/RedstoneWireless.scala b/src/main/scala/li/cil/oc/server/component/RedstoneWireless.scala index 546ab1bb4..8b35769e9 100644 --- a/src/main/scala/li/cil/oc/server/component/RedstoneWireless.scala +++ b/src/main/scala/li/cil/oc/server/component/RedstoneWireless.scala @@ -4,12 +4,13 @@ import codechicken.lib.vec.Vector3 import codechicken.wirelessredstone.core.WirelessReceivingDevice import codechicken.wirelessredstone.core.WirelessTransmittingDevice import cpw.mods.fml.common.Optional +import li.cil.oc.api.driver.EnvironmentHost import li.cil.oc.api.machine.Arguments import li.cil.oc.api.machine.Callback import li.cil.oc.api.machine.Context import li.cil.oc.api.network._ +import li.cil.oc.api.prefab import li.cil.oc.common.EventHandler -import li.cil.oc.common.tileentity.traits.RedstoneAware import li.cil.oc.integration.Mods import li.cil.oc.integration.util import net.minecraft.nbt.NBTTagCompound @@ -18,7 +19,9 @@ import net.minecraft.nbt.NBTTagCompound new Optional.Interface(iface = "codechicken.wirelessredstone.core.WirelessReceivingDevice", modid = Mods.IDs.WirelessRedstoneCBE), new Optional.Interface(iface = "codechicken.wirelessredstone.core.WirelessTransmittingDevice", modid = Mods.IDs.WirelessRedstoneCBE) )) -trait RedstoneWireless extends Redstone[RedstoneAware] with WirelessReceivingDevice with WirelessTransmittingDevice { +trait RedstoneWireless extends prefab.ManagedEnvironment with WirelessReceivingDevice with WirelessTransmittingDevice { + def redstone: EnvironmentHost + var wirelessFrequency = 0 var wirelessInput = false @@ -79,10 +82,10 @@ trait RedstoneWireless extends Redstone[RedstoneAware] with WirelessReceivingDev } @Optional.Method(modid = Mods.IDs.WirelessRedstoneCBE) - override def getPosition = Vector3.fromTileEntityCenter(owner) + override def getPosition = new Vector3(redstone.xPosition, redstone.yPosition, redstone.zPosition) @Optional.Method(modid = Mods.IDs.WirelessRedstoneCBE) - override def getDimension = owner.world.provider.dimensionId + override def getDimension = redstone.world.provider.dimensionId @Optional.Method(modid = Mods.IDs.WirelessRedstoneCBE) override def getFreq = wirelessFrequency From 3c62599d8d4c4b770086c7b47679dad5933291b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Thu, 15 Jan 2015 15:13:09 +0000 Subject: [PATCH 13/61] Added match check to term.read It can be ethier string or function. If it's string user can confirm only when entered text matches the string. If thes param is function, the function gets called when user clicks enter key, first parameter for it is entered text, it should return a value that decides if given text should is accepted(true), or not(false/nil) --- .../opencomputers/loot/OpenOS/lib/term.lua | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/main/resources/assets/opencomputers/loot/OpenOS/lib/term.lua b/src/main/resources/assets/opencomputers/loot/OpenOS/lib/term.lua index 03a53556e..07408ad51 100644 --- a/src/main/resources/assets/opencomputers/loot/OpenOS/lib/term.lua +++ b/src/main/resources/assets/opencomputers/loot/OpenOS/lib/term.lua @@ -108,10 +108,11 @@ function term.isAvailable() return component.isAvailable("gpu") and component.isAvailable("screen") end -function term.read(history, dobreak, hint, pwchar) +function term.read(history, dobreak, hint, pwchar, match) checkArg(1, history, "table", "nil") checkArg(3, hint, "function", "table", "nil") checkArg(4, pwchar, "string", "nil") + checkArg(5, match, "string", "function", "nil") history = history or {} table.insert(history, "") local offset = term.getCursor() - 1 @@ -327,12 +328,16 @@ function term.read(history, dobreak, hint, pwchar) elseif code == keyboard.keys.tab and hint then tab(keyboard.isShiftDown() and -1 or 1) elseif code == keyboard.keys.enter then - local cbx, cby = getCursor() - if cby ~= #history then -- bring entry to front - history[#history] = line() - table.remove(history, cby) + if not match or (type(match) == "string" and match:match(line() or "")) or (type(match) == "function" and match(line() or "")) then + local cbx, cby = getCursor() + if cby ~= #history then -- bring entry to front + history[#history] = line() + table.remove(history, cby) + end + return true, history[#history] .. "\n" + else + computer.beep(2000, 0.1) end - return true, history[#history] .. "\n" elseif keyboard.isControlDown() and code == keyboard.keys.d then if line() == "" then history[#history] = "" From f8277fefb5665d2dc3fc53a2c5fcbc64220b64a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Thu, 15 Jan 2015 16:37:28 +0100 Subject: [PATCH 14/61] Highlighting items in the NEI item panel matching the hovered slot now, too. Also fixed some derps in the process. --- .../scala/li/cil/oc/client/gui/Adapter.scala | 4 +- .../li/cil/oc/client/gui/Assembler.scala | 2 +- .../scala/li/cil/oc/client/gui/Case.scala | 6 +- .../scala/li/cil/oc/client/gui/Charger.scala | 4 +- .../scala/li/cil/oc/client/gui/Database.scala | 2 +- .../li/cil/oc/client/gui/Disassembler.scala | 2 +- .../li/cil/oc/client/gui/DiskDrive.scala | 4 +- .../scala/li/cil/oc/client/gui/Drone.scala | 2 +- .../oc/client/gui/DynamicGuiContainer.scala | 104 ++++++++++++------ .../scala/li/cil/oc/client/gui/Raid.scala | 4 +- .../scala/li/cil/oc/client/gui/Robot.scala | 2 +- .../scala/li/cil/oc/client/gui/Server.scala | 4 +- .../li/cil/oc/client/gui/ServerRack.scala | 4 +- .../scala/li/cil/oc/client/gui/Switch.scala | 4 +- .../oc/common/template/RobotTemplate.scala | 8 +- src/main/scala/li/cil/oc/util/ItemCosts.scala | 14 +-- .../li/cil/oc/util/ItemStackWrapper.scala | 30 +++++ 17 files changed, 130 insertions(+), 70 deletions(-) create mode 100644 src/main/scala/li/cil/oc/util/ItemStackWrapper.scala diff --git a/src/main/scala/li/cil/oc/client/gui/Adapter.scala b/src/main/scala/li/cil/oc/client/gui/Adapter.scala index 412b4dbfe..d389d6ee3 100644 --- a/src/main/scala/li/cil/oc/client/gui/Adapter.scala +++ b/src/main/scala/li/cil/oc/client/gui/Adapter.scala @@ -6,8 +6,8 @@ import li.cil.oc.common.tileentity import net.minecraft.entity.player.InventoryPlayer class Adapter(playerInventory: InventoryPlayer, val adapter: tileentity.Adapter) extends DynamicGuiContainer(new container.Adapter(playerInventory, adapter)) { - override def drawGuiContainerForegroundLayer(mouseX: Int, mouseY: Int) = { - super.drawGuiContainerForegroundLayer(mouseX, mouseY) + override def drawSecondaryForegroundLayer(mouseX: Int, mouseY: Int) = { + super.drawSecondaryForegroundLayer(mouseX, mouseY) fontRendererObj.drawString( Localization.localizeImmediately(adapter.getInventoryName), 8, 6, 0x404040) diff --git a/src/main/scala/li/cil/oc/client/gui/Assembler.scala b/src/main/scala/li/cil/oc/client/gui/Assembler.scala index c8f7731bc..5e280ef7c 100644 --- a/src/main/scala/li/cil/oc/client/gui/Assembler.scala +++ b/src/main/scala/li/cil/oc/client/gui/Assembler.scala @@ -60,7 +60,7 @@ class Assembler(playerInventory: InventoryPlayer, val assembler: tileentity.Asse add(buttonList, runButton) } - override def drawGuiContainerForegroundLayer(mouseX: Int, mouseY: Int) = { + override def drawSecondaryForegroundLayer(mouseX: Int, mouseY: Int) = { GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS) // Me lazy... prevents NEI render glitch. if (!assemblerContainer.isAssembling) { val message = diff --git a/src/main/scala/li/cil/oc/client/gui/Case.scala b/src/main/scala/li/cil/oc/client/gui/Case.scala index 9c19d64f1..a43f76577 100644 --- a/src/main/scala/li/cil/oc/client/gui/Case.scala +++ b/src/main/scala/li/cil/oc/client/gui/Case.scala @@ -33,9 +33,8 @@ class Case(playerInventory: InventoryPlayer, val computer: tileentity.Case) exte add(buttonList, powerButton) } - override def drawGuiContainerForegroundLayer(mouseX: Int, mouseY: Int) = { - super.drawGuiContainerForegroundLayer(mouseX, mouseY) - GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS) // Me lazy... prevents NEI render glitch. + override protected def drawSecondaryForegroundLayer(mouseX: Int, mouseY: Int) = { + super.drawSecondaryForegroundLayer(mouseX, mouseY) fontRendererObj.drawString( Localization.localizeImmediately(computer.getInventoryName), 8, 6, 0x404040) @@ -44,7 +43,6 @@ class Case(playerInventory: InventoryPlayer, val computer: tileentity.Case) exte tooltip.add(if (computer.isRunning) Localization.Computer.TurnOff else Localization.Computer.TurnOn) copiedDrawHoveringText(tooltip, mouseX - guiLeft, mouseY - guiTop, fontRendererObj) } - GL11.glPopAttrib() } override def drawSecondaryBackgroundLayer() { diff --git a/src/main/scala/li/cil/oc/client/gui/Charger.scala b/src/main/scala/li/cil/oc/client/gui/Charger.scala index 506f58b3c..cb4f2aeb3 100644 --- a/src/main/scala/li/cil/oc/client/gui/Charger.scala +++ b/src/main/scala/li/cil/oc/client/gui/Charger.scala @@ -6,8 +6,8 @@ import li.cil.oc.common.tileentity import net.minecraft.entity.player.InventoryPlayer class Charger(playerInventory: InventoryPlayer, val charger: tileentity.Charger) extends DynamicGuiContainer(new container.Charger(playerInventory, charger)) { - override def drawGuiContainerForegroundLayer(mouseX: Int, mouseY: Int) = { - super.drawGuiContainerForegroundLayer(mouseX, mouseY) + override def drawSecondaryForegroundLayer(mouseX: Int, mouseY: Int) = { + super.drawSecondaryForegroundLayer(mouseX, mouseY) fontRendererObj.drawString( Localization.localizeImmediately(charger.getInventoryName), 8, 6, 0x404040) diff --git a/src/main/scala/li/cil/oc/client/gui/Database.scala b/src/main/scala/li/cil/oc/client/gui/Database.scala index cc843dc78..58544a547 100644 --- a/src/main/scala/li/cil/oc/client/gui/Database.scala +++ b/src/main/scala/li/cil/oc/client/gui/Database.scala @@ -11,7 +11,7 @@ import org.lwjgl.opengl.GL11 class Database(playerInventory: InventoryPlayer, val databaseInventory: DatabaseInventory) extends DynamicGuiContainer(new container.Database(playerInventory, databaseInventory)) { ySize = 256 - override def drawGuiContainerForegroundLayer(mouseX: Int, mouseY: Int) {} + override def drawSecondaryForegroundLayer(mouseX: Int, mouseY: Int) {} override protected def drawGuiContainerBackgroundLayer(dt: Float, mouseX: Int, mouseY: Int) { GL11.glColor4f(1, 1, 1, 1) diff --git a/src/main/scala/li/cil/oc/client/gui/Disassembler.scala b/src/main/scala/li/cil/oc/client/gui/Disassembler.scala index bf671334b..7eb1fe59d 100644 --- a/src/main/scala/li/cil/oc/client/gui/Disassembler.scala +++ b/src/main/scala/li/cil/oc/client/gui/Disassembler.scala @@ -13,7 +13,7 @@ class Disassembler(playerInventory: InventoryPlayer, val disassembler: tileentit val progress = addWidget(new ProgressBar(18, 65)) - override def drawGuiContainerForegroundLayer(mouseX: Int, mouseY: Int) = { + override def drawSecondaryForegroundLayer(mouseX: Int, mouseY: Int) = { fontRendererObj.drawString( Localization.localizeImmediately(disassembler.getInventoryName), 8, 6, 0x404040) diff --git a/src/main/scala/li/cil/oc/client/gui/DiskDrive.scala b/src/main/scala/li/cil/oc/client/gui/DiskDrive.scala index 87afa86b4..29ab40a21 100644 --- a/src/main/scala/li/cil/oc/client/gui/DiskDrive.scala +++ b/src/main/scala/li/cil/oc/client/gui/DiskDrive.scala @@ -6,8 +6,8 @@ import li.cil.oc.common.tileentity import net.minecraft.entity.player.InventoryPlayer class DiskDrive(playerInventory: InventoryPlayer, val drive: tileentity.DiskDrive) extends DynamicGuiContainer(new container.DiskDrive(playerInventory, drive)) { - override def drawGuiContainerForegroundLayer(mouseX: Int, mouseY: Int) = { - super.drawGuiContainerForegroundLayer(mouseX, mouseY) + override def drawSecondaryForegroundLayer(mouseX: Int, mouseY: Int) = { + super.drawSecondaryForegroundLayer(mouseX, mouseY) fontRendererObj.drawString( Localization.localizeImmediately(drive.getInventoryName), 8, 6, 0x404040) diff --git a/src/main/scala/li/cil/oc/client/gui/Drone.scala b/src/main/scala/li/cil/oc/client/gui/Drone.scala index 63967af22..b57883314 100644 --- a/src/main/scala/li/cil/oc/client/gui/Drone.scala +++ b/src/main/scala/li/cil/oc/client/gui/Drone.scala @@ -87,7 +87,7 @@ class Drone(playerInventory: InventoryPlayer, val drone: entity.Drone) extends D override protected def changeSize(w: Double, h: Double, recompile: Boolean) = 2.0 - override protected def drawGuiContainerForegroundLayer(mouseX: Int, mouseY: Int) { + override protected def drawSecondaryForegroundLayer(mouseX: Int, mouseY: Int) { drawBufferLayer() GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS) // Me lazy... prevents NEI render glitch. if (func_146978_c(power.x, power.y, power.width, power.height, mouseX, mouseY)) { diff --git a/src/main/scala/li/cil/oc/client/gui/DynamicGuiContainer.scala b/src/main/scala/li/cil/oc/client/gui/DynamicGuiContainer.scala index 3328ce944..24ef6c657 100644 --- a/src/main/scala/li/cil/oc/client/gui/DynamicGuiContainer.scala +++ b/src/main/scala/li/cil/oc/client/gui/DynamicGuiContainer.scala @@ -1,10 +1,14 @@ package li.cil.oc.client.gui +import codechicken.nei.ItemPanel +import codechicken.nei.LayoutManager +import cpw.mods.fml.common.Optional import li.cil.oc.Localization import li.cil.oc.client.Textures import li.cil.oc.common import li.cil.oc.common.container.ComponentSlot import li.cil.oc.common.container.Player +import li.cil.oc.integration.Mods import li.cil.oc.integration.util.NEI import li.cil.oc.util.RenderState import net.minecraft.client.renderer.Tessellator @@ -22,12 +26,24 @@ abstract class DynamicGuiContainer(container: Container) extends CustomGuiContai protected var hoveredStackNEI: Option[ItemStack] = None - override protected def drawGuiContainerForegroundLayer(mouseX: Int, mouseY: Int) { + protected def drawSecondaryForegroundLayer(mouseX: Int, mouseY: Int) { fontRendererObj.drawString( Localization.localizeImmediately("container.inventory"), 8, ySize - 96 + 2, 0x404040) } + override protected def drawGuiContainerForegroundLayer(mouseX: Int, mouseY: Int) { + GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS) + + drawSecondaryForegroundLayer(mouseX, mouseY) + + for (slot <- 0 until inventorySlots.inventorySlots.size()) { + drawSlotHighlight(inventorySlots.inventorySlots.get(slot).asInstanceOf[Slot]) + } + + GL11.glPopAttrib() + } + protected def drawSecondaryBackgroundLayer() {} override protected def drawGuiContainerBackgroundLayer(dt: Float, mouseX: Int, mouseY: Int) { @@ -55,12 +71,11 @@ abstract class DynamicGuiContainer(container: Container) extends CustomGuiContai super.drawScreen(mouseX, mouseY, dt) - GL11.glPushMatrix() - GL11.glTranslatef(guiLeft, guiTop, 0) - for (slot <- 0 until inventorySlots.inventorySlots.size()) { - drawSlotHighlight(inventorySlots.inventorySlots.get(slot).asInstanceOf[Slot]) + if (Mods.NotEnoughItems.isAvailable) { + GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS) + drawNEIHighlights() + GL11.glPopAttrib() } - GL11.glPopMatrix() } protected def drawSlotInventory(slot: Slot) { @@ -70,45 +85,44 @@ abstract class DynamicGuiContainer(container: Container) extends CustomGuiContai drawDisabledSlot(component) } case _ => + zLevel += 1 if (!isInPlayerInventory(slot)) { drawSlotBackground(slot.xDisplayPosition - 1, slot.yDisplayPosition - 1) } if (!slot.getHasStack) slot match { case component: ComponentSlot if component.tierIcon != null => mc.getTextureManager.bindTexture(TextureMap.locationItemsTexture) - GL11.glDisable(GL11.GL_DEPTH_TEST) drawTexturedModelRectFromIcon(slot.xDisplayPosition, slot.yDisplayPosition, component.tierIcon, 16, 16) - GL11.glEnable(GL11.GL_DEPTH_TEST) case _ => } + zLevel -= 1 } } protected def drawSlotHighlight(slot: Slot) { - slot match { + if (mc.thePlayer.inventory.getItemStack == null) slot match { case component: ComponentSlot if component.slot == common.Slot.None || component.tier == common.Tier.None => // Ignore. case _ => - if (mc.thePlayer.inventory.getItemStack == null) { - val currentIsInPlayerInventory = isInPlayerInventory(slot) - val drawHighlight = hoveredSlot match { - case Some(hovered) => - val hoveredIsInPlayerInventory = isInPlayerInventory(hovered) - (currentIsInPlayerInventory != hoveredIsInPlayerInventory) && - ((currentIsInPlayerInventory && slot.getHasStack && isSelectiveSlot(hovered) && hovered.isItemValid(slot.getStack)) || - (hoveredIsInPlayerInventory && hovered.getHasStack && isSelectiveSlot(slot) && slot.isItemValid(hovered.getStack))) - case _ => hoveredStackNEI match { - case Some(stack) => !currentIsInPlayerInventory && isSelectiveSlot(slot) && slot.isItemValid(stack) - case _ => false - } - } - if (drawHighlight) { - GL11.glDisable(GL11.GL_DEPTH_TEST) - GL11.glDisable(GL11.GL_LIGHTING) - drawGradientRect(slot.xDisplayPosition, slot.yDisplayPosition, slot.xDisplayPosition + 16, slot.yDisplayPosition + 16, 0x80FFFFFF, 0x80FFFFFF) - GL11.glEnable(GL11.GL_LIGHTING) - GL11.glEnable(GL11.GL_DEPTH_TEST) + val currentIsInPlayerInventory = isInPlayerInventory(slot) + val drawHighlight = hoveredSlot match { + case Some(hovered) => + val hoveredIsInPlayerInventory = isInPlayerInventory(hovered) + (currentIsInPlayerInventory != hoveredIsInPlayerInventory) && + ((currentIsInPlayerInventory && slot.getHasStack && isSelectiveSlot(hovered) && hovered.isItemValid(slot.getStack)) || + (hoveredIsInPlayerInventory && hovered.getHasStack && isSelectiveSlot(slot) && slot.isItemValid(hovered.getStack))) + case _ => hoveredStackNEI match { + case Some(stack) => !currentIsInPlayerInventory && isSelectiveSlot(slot) && slot.isItemValid(stack) + case _ => false } } + if (drawHighlight) { + zLevel += 100 + drawGradientRect( + slot.xDisplayPosition, slot.yDisplayPosition, + slot.xDisplayPosition + 16, slot.yDisplayPosition + 16, + 0x80FFFFFF, 0x80FFFFFF) + zLevel -= 100 + } } } @@ -120,11 +134,7 @@ abstract class DynamicGuiContainer(container: Container) extends CustomGuiContai protected def drawDisabledSlot(slot: ComponentSlot) { GL11.glColor4f(1, 1, 1, 1) mc.getTextureManager.bindTexture(TextureMap.locationItemsTexture) - GL11.glDisable(GL11.GL_DEPTH_TEST) - GL11.glDisable(GL11.GL_LIGHTING) drawTexturedModelRectFromIcon(slot.xDisplayPosition, slot.yDisplayPosition, slot.tierIcon, 16, 16) - GL11.glEnable(GL11.GL_LIGHTING) - GL11.glEnable(GL11.GL_DEPTH_TEST) } protected def drawSlotBackground(x: Int, y: Int) { @@ -132,10 +142,10 @@ abstract class DynamicGuiContainer(container: Container) extends CustomGuiContai mc.getTextureManager.bindTexture(Textures.guiSlot) val t = Tessellator.instance t.startDrawingQuads() - t.addVertexWithUV(x, y + 18, zLevel + 1, 0, 1) - t.addVertexWithUV(x + 18, y + 18, zLevel + 1, 1, 1) - t.addVertexWithUV(x + 18, y, zLevel + 1, 1, 0) - t.addVertexWithUV(x, y, zLevel + 1, 0, 0) + t.addVertexWithUV(x, y + 18, zLevel, 0, 1) + t.addVertexWithUV(x + 18, y + 18, zLevel, 1, 1) + t.addVertexWithUV(x + 18, y, zLevel, 1, 0) + t.addVertexWithUV(x, y, zLevel, 0, 0) t.draw() } @@ -158,4 +168,26 @@ abstract class DynamicGuiContainer(container: Container) extends CustomGuiContai case player: Player => slot.inventory == player.playerInventory case _ => false } + + @Optional.Method(modid = Mods.IDs.NotEnoughItems) + private def drawNEIHighlights(): Unit = { + val panel = LayoutManager.itemPanel + if (panel == null) return + zLevel += 500 + for (index <- 0 until ItemPanel.items.size()) { + val rect = panel.getSlotRect(index) + val slot = panel.getSlotMouseOver(rect.x, rect.y) + if (slot != null) hoveredSlot match { + case Some(hovered) => + if (!isInPlayerInventory(hovered) && isSelectiveSlot(hovered) && hovered.isItemValid(slot.item)) { + drawGradientRect( + rect.x1 + 1, rect.y1 + 1, + rect.x2, rect.y2, + 0x40FFFFFF, 0x40FFFFFF) + } + case _ => + } + } + zLevel -= 500 + } } diff --git a/src/main/scala/li/cil/oc/client/gui/Raid.scala b/src/main/scala/li/cil/oc/client/gui/Raid.scala index 5d5fb2f56..03693687e 100644 --- a/src/main/scala/li/cil/oc/client/gui/Raid.scala +++ b/src/main/scala/li/cil/oc/client/gui/Raid.scala @@ -8,8 +8,8 @@ import net.minecraft.entity.player.InventoryPlayer import org.lwjgl.opengl.GL11 class Raid(playerInventory: InventoryPlayer, val raid: tileentity.Raid) extends DynamicGuiContainer(new container.Raid(playerInventory, raid)) { - override def drawGuiContainerForegroundLayer(mouseX: Int, mouseY: Int) = { - super.drawGuiContainerForegroundLayer(mouseX, mouseY) + override def drawSecondaryForegroundLayer(mouseX: Int, mouseY: Int) = { + super.drawSecondaryForegroundLayer(mouseX, mouseY) fontRendererObj.drawString( Localization.localizeImmediately(raid.getInventoryName), 8, 6, 0x404040) diff --git a/src/main/scala/li/cil/oc/client/gui/Robot.scala b/src/main/scala/li/cil/oc/client/gui/Robot.scala index e111465b2..227f61f13 100644 --- a/src/main/scala/li/cil/oc/client/gui/Robot.scala +++ b/src/main/scala/li/cil/oc/client/gui/Robot.scala @@ -128,7 +128,7 @@ class Robot(playerInventory: InventoryPlayer, val robot: tileentity.Robot) exten } } - override protected def drawGuiContainerForegroundLayer(mouseX: Int, mouseY: Int) { + override protected def drawSecondaryForegroundLayer(mouseX: Int, mouseY: Int) { drawBufferLayer() GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS) // Me lazy... prevents NEI render glitch. if (func_146978_c(power.x, power.y, power.width, power.height, mouseX, mouseY)) { diff --git a/src/main/scala/li/cil/oc/client/gui/Server.scala b/src/main/scala/li/cil/oc/client/gui/Server.scala index 0146a06b4..6540eddad 100644 --- a/src/main/scala/li/cil/oc/client/gui/Server.scala +++ b/src/main/scala/li/cil/oc/client/gui/Server.scala @@ -9,8 +9,8 @@ import net.minecraft.inventory.Slot import org.lwjgl.opengl.GL11 class Server(playerInventory: InventoryPlayer, serverInventory: ServerInventory) extends DynamicGuiContainer(new container.Server(playerInventory, serverInventory)) { - override def drawGuiContainerForegroundLayer(mouseX: Int, mouseY: Int) { - super.drawGuiContainerForegroundLayer(mouseX, mouseY) + override def drawSecondaryForegroundLayer(mouseX: Int, mouseY: Int) { + super.drawSecondaryForegroundLayer(mouseX, mouseY) fontRendererObj.drawString( Localization.localizeImmediately(serverInventory.getInventoryName), 8, 6, 0x404040) diff --git a/src/main/scala/li/cil/oc/client/gui/ServerRack.scala b/src/main/scala/li/cil/oc/client/gui/ServerRack.scala index f38694c99..9725d36d8 100644 --- a/src/main/scala/li/cil/oc/client/gui/ServerRack.scala +++ b/src/main/scala/li/cil/oc/client/gui/ServerRack.scala @@ -94,8 +94,8 @@ class ServerRack(playerInventory: InventoryPlayer, val rack: tileentity.ServerRa add(buttonList, switchButton) } - override def drawGuiContainerForegroundLayer(mouseX: Int, mouseY: Int) = { - super.drawGuiContainerForegroundLayer(mouseX, mouseY) + override def drawSecondaryForegroundLayer(mouseX: Int, mouseY: Int) = { + super.drawSecondaryForegroundLayer(mouseX, mouseY) GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS) // Prevents NEI render glitch. fontRendererObj.drawString( diff --git a/src/main/scala/li/cil/oc/client/gui/Switch.scala b/src/main/scala/li/cil/oc/client/gui/Switch.scala index c15b274a8..a60302136 100644 --- a/src/main/scala/li/cil/oc/client/gui/Switch.scala +++ b/src/main/scala/li/cil/oc/client/gui/Switch.scala @@ -11,8 +11,8 @@ class Switch(playerInventory: InventoryPlayer, val switch: tileentity.Switch) ex private val switchContainer = inventorySlots.asInstanceOf[container.Switch] private val format = new DecimalFormat("#.##hz") - override def drawGuiContainerForegroundLayer(mouseX: Int, mouseY: Int) = { - super.drawGuiContainerForegroundLayer(mouseX, mouseY) + override def drawSecondaryForegroundLayer(mouseX: Int, mouseY: Int) = { + super.drawSecondaryForegroundLayer(mouseX, mouseY) fontRendererObj.drawString( Localization.localizeImmediately(switch.getInventoryName), 8, 6, 0x404040) diff --git a/src/main/scala/li/cil/oc/common/template/RobotTemplate.scala b/src/main/scala/li/cil/oc/common/template/RobotTemplate.scala index 54257ce6c..852cf69d2 100644 --- a/src/main/scala/li/cil/oc/common/template/RobotTemplate.scala +++ b/src/main/scala/li/cil/oc/common/template/RobotTemplate.scala @@ -16,13 +16,13 @@ import net.minecraft.nbt.NBTTagList object RobotTemplate extends Template { override protected def hostClass = classOf[internal.Robot] - def selectTier1(stack: ItemStack) = ItemUtils.caseTier(stack) == Tier.One + def selectTier1(stack: ItemStack) = api.Items.get(stack) == api.Items.get("case1") - def selectTier2(stack: ItemStack) = ItemUtils.caseTier(stack) == Tier.Two + def selectTier2(stack: ItemStack) = api.Items.get(stack) == api.Items.get("case2") - def selectTier3(stack: ItemStack) = ItemUtils.caseTier(stack) == Tier.Three + def selectTier3(stack: ItemStack) = api.Items.get(stack) == api.Items.get("case3") - def selectCreative(stack: ItemStack) = ItemUtils.caseTier(stack) == Tier.Four + def selectCreative(stack: ItemStack) = api.Items.get(stack) == api.Items.get("caseCreative") def validate(inventory: IInventory): Array[AnyRef] = validateComputer(inventory) diff --git a/src/main/scala/li/cil/oc/util/ItemCosts.scala b/src/main/scala/li/cil/oc/util/ItemCosts.scala index 121f0ef80..c2663a1eb 100644 --- a/src/main/scala/li/cil/oc/util/ItemCosts.scala +++ b/src/main/scala/li/cil/oc/util/ItemCosts.scala @@ -19,13 +19,13 @@ import scala.collection.convert.WrapAsScala._ import scala.collection.mutable object ItemCosts { - protected val cache = mutable.Map.empty[ItemStack, Iterable[(ItemStack, Double)]] + protected val cache = mutable.Map.empty[ItemStackWrapper, Iterable[(ItemStack, Double)]] - cache += init.Items.ironNugget.createItemStack() -> Iterable((new ItemStack(Items.iron_ingot), 1.0 / 9.0)) + cache += new ItemStackWrapper(init.Items.ironNugget.createItemStack()) -> Iterable((new ItemStack(Items.iron_ingot), 1.0 / 9.0)) - def terminate(item: Item, meta: Int = 0) = cache += new ItemStack(item, 1, meta) -> mutable.Iterable((new ItemStack(item, 1, meta), 1)) + def terminate(item: Item, meta: Int = 0) = cache += new ItemStackWrapper(new ItemStack(item, 1, meta)) -> mutable.Iterable((new ItemStack(item, 1, meta), 1)) - def terminate(block: Block) = cache += new ItemStack(block) -> mutable.Iterable((new ItemStack(block), 1)) + def terminate(block: Block) = cache += new ItemStackWrapper(new ItemStack(block)) -> mutable.Iterable((new ItemStack(block), 1)) terminate(Blocks.clay) terminate(Blocks.cobblestone) @@ -83,7 +83,7 @@ object ItemCosts { def accumulate(input: Any, path: Seq[ItemStack] = Seq.empty): Iterable[(ItemStack, Double)] = input match { case stack: ItemStack => cache.find { - case (key, value) => fuzzyEquals(key, stack) + case (key, value) => fuzzyEquals(key.inner, stack) } match { case Some((_, value)) => value case _ => @@ -108,7 +108,7 @@ object ItemCosts { val scaled = deflate(ingredients.map { case (ingredient, count) => (ingredient.copy(), count / output) }).toArray.sortBy(_._1.getUnlocalizedName) - cache += stack.copy() -> scaled + cache += new ItemStackWrapper(stack.copy()) -> scaled scaled } } @@ -116,7 +116,7 @@ object ItemCosts { var result = Iterable.empty[(ItemStack, Double)] for (stack <- list if result.isEmpty) { cache.find { - case (key, value) => fuzzyEquals(key, stack) + case (key, value) => fuzzyEquals(key.inner, stack) } match { case Some((_, value)) => result = value case _ => diff --git a/src/main/scala/li/cil/oc/util/ItemStackWrapper.scala b/src/main/scala/li/cil/oc/util/ItemStackWrapper.scala new file mode 100644 index 000000000..69168c00c --- /dev/null +++ b/src/main/scala/li/cil/oc/util/ItemStackWrapper.scala @@ -0,0 +1,30 @@ +package li.cil.oc.util + +import java.util.Objects + +import net.minecraft.item.Item +import net.minecraft.item.ItemStack + +import scala.language.implicitConversions + +class ItemStackWrapper(val inner: ItemStack) extends Ordered[ItemStackWrapper] { + def id = if (inner.getItem != null) Item.getIdFromItem(inner.getItem) else 0 + + def damage = if (inner.getItem != null) inner.getItemDamage else 0 + + override def compare(that: ItemStackWrapper) = { + if (this.id == that.id) this.damage - that.damage + else this.id - that.id + } + + override def hashCode() = Objects.hash(int2Integer(id), int2Integer(damage)) + + override def equals(obj: scala.Any) = obj match { + case that: ItemStackWrapper => compare(that) == 0 + case _ => false + } + + override def clone() = new ItemStackWrapper(inner) + + override def toString = inner.toString +} From 0ad8c13176fa509503207bafd9fc62a1a87afc87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Thu, 15 Jan 2015 16:58:21 +0100 Subject: [PATCH 15/61] Minor refactoring to new term.read param to fit with other param handling and make it more homogenous to use. Also fixed flipped string pattern matching (was `pattern:match(line)` where it should be `line:match(pattern)`). --- .../assets/opencomputers/loot/OpenOS/lib/term.lua | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/main/resources/assets/opencomputers/loot/OpenOS/lib/term.lua b/src/main/resources/assets/opencomputers/loot/OpenOS/lib/term.lua index 07408ad51..617441312 100644 --- a/src/main/resources/assets/opencomputers/loot/OpenOS/lib/term.lua +++ b/src/main/resources/assets/opencomputers/loot/OpenOS/lib/term.lua @@ -108,11 +108,11 @@ function term.isAvailable() return component.isAvailable("gpu") and component.isAvailable("screen") end -function term.read(history, dobreak, hint, pwchar, match) +function term.read(history, dobreak, hint, pwchar, filter) checkArg(1, history, "table", "nil") checkArg(3, hint, "function", "table", "nil") checkArg(4, pwchar, "string", "nil") - checkArg(5, match, "string", "function", "nil") + checkArg(5, filter, "string", "function", "nil") history = history or {} table.insert(history, "") local offset = term.getCursor() - 1 @@ -131,6 +131,13 @@ function term.read(history, dobreak, hint, pwchar, match) pwchar = unicode.sub(pwchar, 1, 1) end + if type(filter) == "string" then + local pattern = filter + filter = function(line) + return line:match(pattern) + end + end + local function masktext(str) return pwchar and pwchar:rep(unicode.len(str)) or str end @@ -328,7 +335,7 @@ function term.read(history, dobreak, hint, pwchar, match) elseif code == keyboard.keys.tab and hint then tab(keyboard.isShiftDown() and -1 or 1) elseif code == keyboard.keys.enter then - if not match or (type(match) == "string" and match:match(line() or "")) or (type(match) == "function" and match(line() or "")) then + if not filter or filter(line() or "") then local cbx, cby = getCursor() if cby ~= #history then -- bring entry to front history[#history] = line() From 0db6028ecd047b897b6e472330f498a81ae51ad2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Thu, 15 Jan 2015 17:10:51 +0100 Subject: [PATCH 16/61] Prevent potential NPEs in client log-in event handler. --- .../scala/li/cil/oc/common/EventHandler.scala | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/main/scala/li/cil/oc/common/EventHandler.scala b/src/main/scala/li/cil/oc/common/EventHandler.scala index 2060b74f7..d7e32c70f 100644 --- a/src/main/scala/li/cil/oc/common/EventHandler.scala +++ b/src/main/scala/li/cil/oc/common/EventHandler.scala @@ -130,11 +130,18 @@ object EventHandler { @SubscribeEvent def clientLoggedIn(e: ClientConnectedToServerEvent) { - PetRenderer.hidden.clear() - if (Settings.get.hideOwnPet) { - PetRenderer.hidden += Minecraft.getMinecraft.thePlayer.getCommandSenderName + try { + PetRenderer.hidden.clear() + if (Settings.get.hideOwnPet) { + PetRenderer.hidden += Minecraft.getMinecraft.thePlayer.getCommandSenderName + } + ClientPacketSender.sendPetVisibility() + } + catch { + case _: Throwable => + // Reportedly, things can derp if this is called at inopportune moments, + // such as the server shutting down. } - ClientPacketSender.sendPetVisibility() } lazy val drone = api.Items.get("drone") @@ -194,8 +201,8 @@ object EventHandler { val dayOfMonth = now.get(Calendar.DAY_OF_MONTH) // On the 12th day of Christmas, my robot brought to me~ (month == Calendar.DECEMBER && dayOfMonth > 24) || (month == Calendar.JANUARY && dayOfMonth < 7) || - // OC's release-birthday! - (month == Calendar.DECEMBER && dayOfMonth == 14) + // OC's release-birthday! + (month == Calendar.DECEMBER && dayOfMonth == 14) } private def recraft(e: ItemCraftedEvent, item: ItemInfo, callback: ItemStack => Option[ItemStack]): Boolean = { From 42d5d997a342b5bdb717612b7ee66c08fcf30a06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Thu, 15 Jan 2015 19:16:22 +0100 Subject: [PATCH 17/61] Yet more redstone refactoring, also passing along old and new max signal values for convenience. --- .../oc/client/gui/DynamicGuiContainer.scala | 4 ++-- .../cil/oc/common/tileentity/Redstone.scala | 12 ++++++---- .../li/cil/oc/common/tileentity/Screen.scala | 4 ++-- .../cil/oc/common/tileentity/ServerRack.scala | 6 ++--- .../traits/BundledRedstoneAware.scala | 23 +++++++++++-------- .../common/tileentity/traits/Computer.scala | 6 ++--- .../tileentity/traits/RedstoneAware.scala | 6 ++--- .../server/component/RedstoneSignaller.scala | 12 ++++++++++ .../oc/server/component/RedstoneVanilla.scala | 7 +++--- .../server/component/RedstoneWireless.scala | 4 ++-- 10 files changed, 51 insertions(+), 33 deletions(-) create mode 100644 src/main/scala/li/cil/oc/server/component/RedstoneSignaller.scala diff --git a/src/main/scala/li/cil/oc/client/gui/DynamicGuiContainer.scala b/src/main/scala/li/cil/oc/client/gui/DynamicGuiContainer.scala index 24ef6c657..8e7c76a71 100644 --- a/src/main/scala/li/cil/oc/client/gui/DynamicGuiContainer.scala +++ b/src/main/scala/li/cil/oc/client/gui/DynamicGuiContainer.scala @@ -173,7 +173,7 @@ abstract class DynamicGuiContainer(container: Container) extends CustomGuiContai private def drawNEIHighlights(): Unit = { val panel = LayoutManager.itemPanel if (panel == null) return - zLevel += 500 + zLevel += 350 for (index <- 0 until ItemPanel.items.size()) { val rect = panel.getSlotRect(index) val slot = panel.getSlotMouseOver(rect.x, rect.y) @@ -188,6 +188,6 @@ abstract class DynamicGuiContainer(container: Container) extends CustomGuiContai case _ => } } - zLevel -= 500 + zLevel -= 350 } } diff --git a/src/main/scala/li/cil/oc/common/tileentity/Redstone.scala b/src/main/scala/li/cil/oc/common/tileentity/Redstone.scala index 9e48604ab..7810ca194 100644 --- a/src/main/scala/li/cil/oc/common/tileentity/Redstone.scala +++ b/src/main/scala/li/cil/oc/common/tileentity/Redstone.scala @@ -1,6 +1,7 @@ package li.cil.oc.common.tileentity import li.cil.oc.Settings +import li.cil.oc.api import li.cil.oc.api.network.Visibility import li.cil.oc.common.tileentity.traits.BundledRedstoneAware import li.cil.oc.common.tileentity.traits.Environment @@ -17,10 +18,12 @@ class Redstone extends Environment with BundledRedstoneAware { else new component.Redstone.Vanilla(this) val node = instance.node - if (node != null) { + val dummyNode = if (node != null) { node.setVisibility(Visibility.Network) _isOutputEnabled = true + api.Network.newNode(this, Visibility.None).create() } + else null override def canUpdate = isServer @@ -38,8 +41,9 @@ class Redstone extends Environment with BundledRedstoneAware { // ----------------------------------------------------------------------- // - override protected def onRedstoneInputChanged(side: ForgeDirection) { - super.onRedstoneInputChanged(side) - node.sendToReachable("computer.signal", "redstone_changed", Int.box(side.ordinal())) + override protected def onRedstoneInputChanged(side: ForgeDirection, oldMaxValue: Int, newMaxValue: Int) { + super.onRedstoneInputChanged(side, oldMaxValue, newMaxValue) + node.connect(dummyNode) + dummyNode.sendToNeighbors("redstone.changed", side, int2Integer(oldMaxValue), int2Integer(newMaxValue)) } } diff --git a/src/main/scala/li/cil/oc/common/tileentity/Screen.scala b/src/main/scala/li/cil/oc/common/tileentity/Screen.scala index 4812ceb8d..4c26a868f 100644 --- a/src/main/scala/li/cil/oc/common/tileentity/Screen.scala +++ b/src/main/scala/li/cil/oc/common/tileentity/Screen.scala @@ -314,8 +314,8 @@ class Screen(var tier: Int) extends traits.TextBuffer with SidedEnvironment with override def onAnalyze(player: EntityPlayer, side: Int, hitX: Float, hitY: Float, hitZ: Float) = Array(origin.node) - override protected def onRedstoneInputChanged(side: ForgeDirection) { - super.onRedstoneInputChanged(side) + override protected def onRedstoneInputChanged(side: ForgeDirection, oldMaxValue: Int, newMaxValue: Int) { + super.onRedstoneInputChanged(side, oldMaxValue, newMaxValue) val hasRedstoneInput = screens.map(_.maxInput).max > 0 if (hasRedstoneInput != hadRedstoneInput) { hadRedstoneInput = hasRedstoneInput diff --git a/src/main/scala/li/cil/oc/common/tileentity/ServerRack.scala b/src/main/scala/li/cil/oc/common/tileentity/ServerRack.scala index e2b988277..07efb74c1 100644 --- a/src/main/scala/li/cil/oc/common/tileentity/ServerRack.scala +++ b/src/main/scala/li/cil/oc/common/tileentity/ServerRack.scala @@ -506,10 +506,10 @@ class ServerRack extends traits.PowerAcceptor with traits.Hub with traits.PowerB checkRedstoneInputChanged() } - override protected def onRedstoneInputChanged(side: ForgeDirection) { - super.onRedstoneInputChanged(side) + override protected def onRedstoneInputChanged(side: ForgeDirection, oldMaxValue: Int, newMaxValue: Int) { + super.onRedstoneInputChanged(side, oldMaxValue, newMaxValue) servers collect { - case Some(server) => server.machine.node.sendToNeighbors("redstone.changed", toLocal(side)) + case Some(server) => server.machine.node.sendToNeighbors("redstone.changed", toLocal(side), int2Integer(oldMaxValue), int2Integer(newMaxValue)) } } diff --git a/src/main/scala/li/cil/oc/common/tileentity/traits/BundledRedstoneAware.scala b/src/main/scala/li/cil/oc/common/tileentity/traits/BundledRedstoneAware.scala index a0a3b16fb..3178f5769 100644 --- a/src/main/scala/li/cil/oc/common/tileentity/traits/BundledRedstoneAware.scala +++ b/src/main/scala/li/cil/oc/common/tileentity/traits/BundledRedstoneAware.scala @@ -48,13 +48,15 @@ trait BundledRedstoneAware extends RedstoneAware with IBundledEmitter with IBund def bundledInput(side: ForgeDirection, color: Int) = math.max(_bundledInput(side.ordinal())(color), _rednetInput(side.ordinal())(color)) - def rednetInput(side: ForgeDirection, color: Int, value: Int) = - if (_rednetInput(side.ordinal())(color) != value) { - if (_rednetInput(side.ordinal())(color) != -1) { - onRedstoneInputChanged(side) + def rednetInput(side: ForgeDirection, color: Int, value: Int): Unit = { + val oldValue = _rednetInput(side.ordinal())(color) + if (oldValue != value) { + if (oldValue != -1) { + onRedstoneInputChanged(side, oldValue, value) } _rednetInput(side.ordinal())(color) = value } + } def bundledOutput(side: ForgeDirection) = _bundledOutput(toLocal(side).ordinal()) @@ -78,19 +80,20 @@ trait BundledRedstoneAware extends RedstoneAware with IBundledEmitter with IBund override protected def updateRedstoneInput(side: ForgeDirection) { super.updateRedstoneInput(side) - val oldBundledInput = _bundledInput(side.ordinal()) + val ownBundledInput = _bundledInput(side.ordinal()) val newBundledInput = computeBundledInput(side) + val oldMaxValue = ownBundledInput.max var changed = false if (newBundledInput != null) for (color <- 0 until 16) { - changed = changed || (oldBundledInput(color) >= 0 && oldBundledInput(color) != newBundledInput(color)) - oldBundledInput(color) = newBundledInput(color) + changed = changed || (ownBundledInput(color) >= 0 && ownBundledInput(color) != newBundledInput(color)) + ownBundledInput(color) = newBundledInput(color) } else for (color <- 0 until 16) { - changed = changed || oldBundledInput(color) > 0 - oldBundledInput(color) = 0 + changed = changed || ownBundledInput(color) > 0 + ownBundledInput(color) = 0 } if (changed) { - onRedstoneInputChanged(side) + onRedstoneInputChanged(side, oldMaxValue, ownBundledInput.max) } } diff --git a/src/main/scala/li/cil/oc/common/tileentity/traits/Computer.scala b/src/main/scala/li/cil/oc/common/tileentity/traits/Computer.scala index 300f68b46..495f50f2b 100644 --- a/src/main/scala/li/cil/oc/common/tileentity/traits/Computer.scala +++ b/src/main/scala/li/cil/oc/common/tileentity/traits/Computer.scala @@ -204,9 +204,9 @@ trait Computer extends Environment with ComponentInventory with Rotatable with B checkRedstoneInputChanged() } - override protected def onRedstoneInputChanged(side: ForgeDirection) { - super.onRedstoneInputChanged(side) - machine.node.sendToNeighbors("redstone.changed", toLocal(side)) + override protected def onRedstoneInputChanged(side: ForgeDirection, oldMaxValue: Int, newMaxValue: Int) { + super.onRedstoneInputChanged(side, oldMaxValue, newMaxValue) + machine.node.sendToNeighbors("redstone.changed", toLocal(side), int2Integer(oldMaxValue), int2Integer(newMaxValue)) } // ----------------------------------------------------------------------- // diff --git a/src/main/scala/li/cil/oc/common/tileentity/traits/RedstoneAware.scala b/src/main/scala/li/cil/oc/common/tileentity/traits/RedstoneAware.scala index 8653b1b5e..e17cfaf0d 100644 --- a/src/main/scala/li/cil/oc/common/tileentity/traits/RedstoneAware.scala +++ b/src/main/scala/li/cil/oc/common/tileentity/traits/RedstoneAware.scala @@ -79,8 +79,8 @@ trait RedstoneAware extends RotationAware with IConnectable with IRedstoneEmitte val oldInput = _input(side.ordinal()) val newInput = computeInput(side) _input(side.ordinal()) = newInput - if (oldInput >= 0 && input(side) != oldInput) { - onRedstoneInputChanged(side) + if (oldInput >= 0 && newInput != oldInput) { + onRedstoneInputChanged(side, oldInput, newInput) } } @@ -140,7 +140,7 @@ trait RedstoneAware extends RotationAware with IConnectable with IRedstoneEmitte } } - protected def onRedstoneInputChanged(side: ForgeDirection) {} + protected def onRedstoneInputChanged(side: ForgeDirection, oldMaxValue: Int, newMaxValue: Int) {} protected def onRedstoneOutputEnabledChanged() { world.notifyBlocksOfNeighborChange(position, block) diff --git a/src/main/scala/li/cil/oc/server/component/RedstoneSignaller.scala b/src/main/scala/li/cil/oc/server/component/RedstoneSignaller.scala new file mode 100644 index 000000000..8ea7c31a4 --- /dev/null +++ b/src/main/scala/li/cil/oc/server/component/RedstoneSignaller.scala @@ -0,0 +1,12 @@ +package li.cil.oc.server.component + +import li.cil.oc.api.Persistable +import li.cil.oc.api.network.Node + +trait RedstoneSignaller extends Persistable { + def node: Node + + def onRedstoneChanged(side: AnyRef, oldMaxValue: AnyRef, newMaxValue: AnyRef): Unit = { + node.sendToReachable("computer.signal", "redstone_changed", side, oldMaxValue, newMaxValue) + } +} diff --git a/src/main/scala/li/cil/oc/server/component/RedstoneVanilla.scala b/src/main/scala/li/cil/oc/server/component/RedstoneVanilla.scala index aabcc2855..fd83cc951 100644 --- a/src/main/scala/li/cil/oc/server/component/RedstoneVanilla.scala +++ b/src/main/scala/li/cil/oc/server/component/RedstoneVanilla.scala @@ -7,12 +7,10 @@ import li.cil.oc.api.machine.Callback import li.cil.oc.api.machine.Context import li.cil.oc.api.network._ import li.cil.oc.api.prefab -import li.cil.oc.common.tileentity.traits.BundledRedstoneAware import li.cil.oc.common.tileentity.traits.RedstoneAware -import li.cil.oc.server.component import net.minecraftforge.common.util.ForgeDirection -trait RedstoneVanilla extends prefab.ManagedEnvironment { +trait RedstoneVanilla extends prefab.ManagedEnvironment with RedstoneSignaller { override val node = Network.newNode(this, Visibility.Network). withComponent("redstone", Visibility.Neighbors). create() @@ -47,7 +45,8 @@ trait RedstoneVanilla extends prefab.ManagedEnvironment { override def onMessage(message: Message): Unit = { super.onMessage(message) if (message.name == "redstone.changed") message.data match { - case Array(side: ForgeDirection) => node.sendToReachable("computer.signal", "redstone_changed", Int.box(side.ordinal())) + case Array(side: ForgeDirection, oldMaxValue: Number, newMaxValue: Number) => + onRedstoneChanged(int2Integer(side.ordinal()), oldMaxValue, newMaxValue) case _ => } } diff --git a/src/main/scala/li/cil/oc/server/component/RedstoneWireless.scala b/src/main/scala/li/cil/oc/server/component/RedstoneWireless.scala index 8b35769e9..dbcd54f2c 100644 --- a/src/main/scala/li/cil/oc/server/component/RedstoneWireless.scala +++ b/src/main/scala/li/cil/oc/server/component/RedstoneWireless.scala @@ -19,7 +19,7 @@ import net.minecraft.nbt.NBTTagCompound new Optional.Interface(iface = "codechicken.wirelessredstone.core.WirelessReceivingDevice", modid = Mods.IDs.WirelessRedstoneCBE), new Optional.Interface(iface = "codechicken.wirelessredstone.core.WirelessTransmittingDevice", modid = Mods.IDs.WirelessRedstoneCBE) )) -trait RedstoneWireless extends prefab.ManagedEnvironment with WirelessReceivingDevice with WirelessTransmittingDevice { +trait RedstoneWireless extends prefab.ManagedEnvironment with RedstoneSignaller with WirelessReceivingDevice with WirelessTransmittingDevice { def redstone: EnvironmentHost var wirelessFrequency = 0 @@ -77,7 +77,7 @@ trait RedstoneWireless extends prefab.ManagedEnvironment with WirelessReceivingD override def updateDevice(frequency: Int, on: Boolean) { if (frequency == wirelessFrequency && on != wirelessInput) { wirelessInput = on - node.sendToReachable("computer.signal", "redstone_changed", "wireless") + onRedstoneChanged("wireless", boolean2Boolean(!on), boolean2Boolean(on)) } } From f981a05c0f6bb7f803e8cc94cf4224ed2688a07f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Thu, 15 Jan 2015 19:39:43 +0100 Subject: [PATCH 18/61] Added `redstone.get/setWakeThreshold`, allows setting a redstone signal threshold that, when crossed from low to high causes connect computers to start. --- .../server/component/RedstoneSignaller.scala | 44 ++++++++++++++++--- .../oc/server/component/RedstoneVanilla.scala | 5 +-- .../server/component/RedstoneWireless.scala | 5 +-- .../li/cil/oc/server/machine/Machine.scala | 4 +- 4 files changed, 45 insertions(+), 13 deletions(-) diff --git a/src/main/scala/li/cil/oc/server/component/RedstoneSignaller.scala b/src/main/scala/li/cil/oc/server/component/RedstoneSignaller.scala index 8ea7c31a4..1b911599e 100644 --- a/src/main/scala/li/cil/oc/server/component/RedstoneSignaller.scala +++ b/src/main/scala/li/cil/oc/server/component/RedstoneSignaller.scala @@ -1,12 +1,44 @@ package li.cil.oc.server.component -import li.cil.oc.api.Persistable -import li.cil.oc.api.network.Node +import li.cil.oc.Settings +import li.cil.oc.api.machine.Arguments +import li.cil.oc.api.machine.Callback +import li.cil.oc.api.machine.Context +import li.cil.oc.api.prefab +import net.minecraft.nbt.NBTTagCompound -trait RedstoneSignaller extends Persistable { - def node: Node +trait RedstoneSignaller extends prefab.ManagedEnvironment { + var wakeThreshold = 0 - def onRedstoneChanged(side: AnyRef, oldMaxValue: AnyRef, newMaxValue: AnyRef): Unit = { - node.sendToReachable("computer.signal", "redstone_changed", side, oldMaxValue, newMaxValue) + // ----------------------------------------------------------------------- // + + @Callback(direct = true, doc = """function():number -- Get the current wake-up threshold.""") + def getWakeThreshold(context: Context, args: Arguments): Array[AnyRef] = result(wakeThreshold) + + @Callback(doc = """function(threshold:number) -- Set the wake-up threshold.""") + def setWakeThreshold(context: Context, args: Arguments): Array[AnyRef] = { + wakeThreshold = args.checkInteger(0) + null + } + + // ----------------------------------------------------------------------- // + + def onRedstoneChanged(side: AnyRef, oldMaxValue: Int, newMaxValue: Int): Unit = { + node.sendToReachable("computer.signal", "redstone_changed", side, int2Integer(oldMaxValue), int2Integer(newMaxValue)) + if (oldMaxValue < wakeThreshold && newMaxValue >= wakeThreshold) { + node.sendToNeighbors("computer.start") + } + } + + // ----------------------------------------------------------------------- // + + override def load(nbt: NBTTagCompound): Unit = { + super.load(nbt) + wakeThreshold = nbt.getInteger(Settings.namespace + "wakeThreshold") + } + + override def save(nbt: NBTTagCompound): Unit = { + super.save(nbt) + nbt.setInteger(Settings.namespace + "wakeThreshold", wakeThreshold) } } diff --git a/src/main/scala/li/cil/oc/server/component/RedstoneVanilla.scala b/src/main/scala/li/cil/oc/server/component/RedstoneVanilla.scala index fd83cc951..4196fa9f8 100644 --- a/src/main/scala/li/cil/oc/server/component/RedstoneVanilla.scala +++ b/src/main/scala/li/cil/oc/server/component/RedstoneVanilla.scala @@ -6,11 +6,10 @@ import li.cil.oc.api.machine.Arguments import li.cil.oc.api.machine.Callback import li.cil.oc.api.machine.Context import li.cil.oc.api.network._ -import li.cil.oc.api.prefab import li.cil.oc.common.tileentity.traits.RedstoneAware import net.minecraftforge.common.util.ForgeDirection -trait RedstoneVanilla extends prefab.ManagedEnvironment with RedstoneSignaller { +trait RedstoneVanilla extends RedstoneSignaller { override val node = Network.newNode(this, Visibility.Network). withComponent("redstone", Visibility.Neighbors). create() @@ -46,7 +45,7 @@ trait RedstoneVanilla extends prefab.ManagedEnvironment with RedstoneSignaller { super.onMessage(message) if (message.name == "redstone.changed") message.data match { case Array(side: ForgeDirection, oldMaxValue: Number, newMaxValue: Number) => - onRedstoneChanged(int2Integer(side.ordinal()), oldMaxValue, newMaxValue) + onRedstoneChanged(int2Integer(side.ordinal()), oldMaxValue.intValue(), newMaxValue.intValue()) case _ => } } diff --git a/src/main/scala/li/cil/oc/server/component/RedstoneWireless.scala b/src/main/scala/li/cil/oc/server/component/RedstoneWireless.scala index dbcd54f2c..37df26e97 100644 --- a/src/main/scala/li/cil/oc/server/component/RedstoneWireless.scala +++ b/src/main/scala/li/cil/oc/server/component/RedstoneWireless.scala @@ -9,7 +9,6 @@ import li.cil.oc.api.machine.Arguments import li.cil.oc.api.machine.Callback import li.cil.oc.api.machine.Context import li.cil.oc.api.network._ -import li.cil.oc.api.prefab import li.cil.oc.common.EventHandler import li.cil.oc.integration.Mods import li.cil.oc.integration.util @@ -19,7 +18,7 @@ import net.minecraft.nbt.NBTTagCompound new Optional.Interface(iface = "codechicken.wirelessredstone.core.WirelessReceivingDevice", modid = Mods.IDs.WirelessRedstoneCBE), new Optional.Interface(iface = "codechicken.wirelessredstone.core.WirelessTransmittingDevice", modid = Mods.IDs.WirelessRedstoneCBE) )) -trait RedstoneWireless extends prefab.ManagedEnvironment with RedstoneSignaller with WirelessReceivingDevice with WirelessTransmittingDevice { +trait RedstoneWireless extends RedstoneSignaller with WirelessReceivingDevice with WirelessTransmittingDevice { def redstone: EnvironmentHost var wirelessFrequency = 0 @@ -77,7 +76,7 @@ trait RedstoneWireless extends prefab.ManagedEnvironment with RedstoneSignaller override def updateDevice(frequency: Int, on: Boolean) { if (frequency == wirelessFrequency && on != wirelessInput) { wirelessInput = on - onRedstoneChanged("wireless", boolean2Boolean(!on), boolean2Boolean(on)) + onRedstoneChanged("wireless", if (on) 0 else 1, if (on) 1 else 0) } } diff --git a/src/main/scala/li/cil/oc/server/machine/Machine.scala b/src/main/scala/li/cil/oc/server/machine/Machine.scala index 565afbd5d..31fd20ce6 100644 --- a/src/main/scala/li/cil/oc/server/machine/Machine.scala +++ b/src/main/scala/li/cil/oc/server/machine/Machine.scala @@ -90,7 +90,7 @@ class Machine(val host: MachineHost) extends prefab.ManagedEnvironment with mach override def getBootAddress = bootAddress - override def setBootAddress(value: String) = bootAddress = Option(value).map(_.take(36)).getOrElse("") + override def setBootAddress(value: String) = bootAddress = Option(value).fold("")(_.take(36)) override def components = scala.collection.convert.WrapAsJava.mapAsJavaMap(_components) @@ -490,6 +490,8 @@ class Machine(val host: MachineHost) extends prefab.ManagedEnvironment with mach if (canInteract(player.getCommandSenderName)) signal(name, Seq(message.source.address) ++ args: _*) case _ => + if (message.name == "computer.start" && !isPaused) start() + else if (message.name == "computer.stop") stop() } } From 4e33221e9809bfb1d206ca5f080fb9294bad523f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Thu, 15 Jan 2015 20:03:04 +0100 Subject: [PATCH 19/61] Added `modem.get/setWakeMessage` for wake-on-lan. Closes #781, #700. --- .../cil/oc/server/component/NetworkCard.scala | 35 +++++++++++++++++-- .../server/component/RedstoneSignaller.scala | 10 +++--- 2 files changed, 38 insertions(+), 7 deletions(-) diff --git a/src/main/scala/li/cil/oc/server/component/NetworkCard.scala b/src/main/scala/li/cil/oc/server/component/NetworkCard.scala index 0992adc10..111e76ff2 100644 --- a/src/main/scala/li/cil/oc/server/component/NetworkCard.scala +++ b/src/main/scala/li/cil/oc/server/component/NetworkCard.scala @@ -1,5 +1,6 @@ package li.cil.oc.server.component +import com.google.common.base.Charsets import li.cil.oc.Settings import li.cil.oc.api import li.cil.oc.api.Network @@ -21,6 +22,8 @@ class NetworkCard(val host: EnvironmentHost) extends prefab.ManagedEnvironment { protected val openPorts = mutable.Set.empty[Int] + protected var wakeMessage: Option[String] = None + // ----------------------------------------------------------------------- // @Callback(doc = """function(port:number):boolean -- Opens the specified port. Returns true if the port was opened.""") @@ -75,6 +78,19 @@ class NetworkCard(val host: EnvironmentHost) extends prefab.ManagedEnvironment { @Callback(direct = true, doc = """function():number -- Gets the maximum packet size (config setting).""") def maxPacketSize(context: Context, args: Arguments): Array[AnyRef] = result(Settings.get.maxNetworkPacketSize) + @Callback(direct = true, doc = """function():string -- Get the current wake-up message.""") + def getWakeMessage(context: Context, args: Arguments): Array[AnyRef] = result(wakeMessage.orNull) + + @Callback(doc = """function(message:string):string -- Set the wake-up message.""") + def setWakeMessage(context: Context, args: Arguments): Array[AnyRef] = { + val oldMessage = wakeMessage + if (args.optAny(0, null) == null) + wakeMessage = None + else + wakeMessage = Option(args.checkString(0)) + result(oldMessage.orNull) + } + protected def doSend(packet: Packet) { node.sendToReachable("network.message", packet) } @@ -109,8 +125,19 @@ class NetworkCard(val host: EnvironmentHost) extends prefab.ManagedEnvironment { } protected def receivePacket(packet: Packet, distance: Double) { - if (packet.source != node.address && Option(packet.destination).forall(_ == node.address) && openPorts.contains(packet.port)) { - node.sendToReachable("computer.signal", Seq("modem_message", packet.source, Int.box(packet.port), Double.box(distance)) ++ packet.data: _*) + if (packet.source != node.address && Option(packet.destination).forall(_ == node.address)) { + if (openPorts.contains(packet.port)) { + node.sendToReachable("computer.signal", Seq("modem_message", packet.source, Int.box(packet.port), Double.box(distance)) ++ packet.data: _*) + } + // Accept wake-up messages regardless of port because we close all ports + // when our computer shuts down. + packet.data match { + case Array(message: Array[Byte]) if wakeMessage.contains(new String(message, Charsets.UTF_8)) => + node.sendToNeighbors("computer.start") + case Array(message: String) if wakeMessage.contains(message) => + node.sendToNeighbors("computer.start") + case _ => + } } } @@ -121,12 +148,16 @@ class NetworkCard(val host: EnvironmentHost) extends prefab.ManagedEnvironment { assert(openPorts.isEmpty) openPorts ++= nbt.getIntArray("openPorts") + if (nbt.hasKey("wakeMessage")) { + wakeMessage = Option(nbt.getString("wakeMessage")) + } } override def save(nbt: NBTTagCompound) { super.save(nbt) nbt.setIntArray("openPorts", openPorts.toArray) + wakeMessage.foreach(nbt.setString("wakeMessage", _)) } // ----------------------------------------------------------------------- // diff --git a/src/main/scala/li/cil/oc/server/component/RedstoneSignaller.scala b/src/main/scala/li/cil/oc/server/component/RedstoneSignaller.scala index 1b911599e..b43e293c0 100644 --- a/src/main/scala/li/cil/oc/server/component/RedstoneSignaller.scala +++ b/src/main/scala/li/cil/oc/server/component/RedstoneSignaller.scala @@ -1,6 +1,5 @@ package li.cil.oc.server.component -import li.cil.oc.Settings import li.cil.oc.api.machine.Arguments import li.cil.oc.api.machine.Callback import li.cil.oc.api.machine.Context @@ -15,10 +14,11 @@ trait RedstoneSignaller extends prefab.ManagedEnvironment { @Callback(direct = true, doc = """function():number -- Get the current wake-up threshold.""") def getWakeThreshold(context: Context, args: Arguments): Array[AnyRef] = result(wakeThreshold) - @Callback(doc = """function(threshold:number) -- Set the wake-up threshold.""") + @Callback(doc = """function(threshold:number):number -- Set the wake-up threshold.""") def setWakeThreshold(context: Context, args: Arguments): Array[AnyRef] = { + val oldThreshold = wakeThreshold wakeThreshold = args.checkInteger(0) - null + result(oldThreshold) } // ----------------------------------------------------------------------- // @@ -34,11 +34,11 @@ trait RedstoneSignaller extends prefab.ManagedEnvironment { override def load(nbt: NBTTagCompound): Unit = { super.load(nbt) - wakeThreshold = nbt.getInteger(Settings.namespace + "wakeThreshold") + wakeThreshold = nbt.getInteger("wakeThreshold") } override def save(nbt: NBTTagCompound): Unit = { super.save(nbt) - nbt.setInteger(Settings.namespace + "wakeThreshold", wakeThreshold) + nbt.setInteger("wakeThreshold", wakeThreshold) } } From f454a17c3375722302e391c511b5d93d3870857b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Thu, 15 Jan 2015 20:09:58 +0100 Subject: [PATCH 20/61] Version bump. --- build.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.properties b/build.properties index 1c71fd952..ee4f43ea2 100644 --- a/build.properties +++ b/build.properties @@ -1,7 +1,7 @@ minecraft.version=1.7.10 forge.version=10.13.2.1236 -oc.version=1.4.4a +oc.version=1.4.5 oc.subversion=dev ae2.version=rv1-stable-1 From bc51937f594f9c506cc3501184100a5f9932a1df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Thu, 15 Jan 2015 23:29:28 +0100 Subject: [PATCH 21/61] Updated year in license. --- LICENSE | 2 +- README.md | 2 +- src/main/resources/LICENSE | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/LICENSE b/LICENSE index e4a728039..730f0b8c4 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2013-2014 Florian "Sangar" Nücke +Copyright (c) 2013-2015 Florian "Sangar" Nücke Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 1daa8f8da..fb9f75438 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ A few useful links: You can find experimental builds [on the build server][jenkins]. Expect these to be generally more unstable than builds marked as releases. Use these **at your own risk**, but - when using the latest one - please *do* report bugs you encounter using them. Thanks! ## License / Use in Modpacks -This mod is [licensed under the **MIT license**](https://github.com/MightyPirates/OpenComputers/blob/master/LICENSE). All **assets are public domain**, unless otherwise stated; all are free to be distributed as long as the license / source credits are kept. This means you can use this mod in any mod pack **as you please**. I'd be happy to hear about you using it, though, just out of curiosity. +This mod is [licensed under the **MIT license**](https://github.com/MightyPirates/OpenComputers/blob/master-MC1.7.10/LICENSE). All **assets are public domain**, unless otherwise stated; all are free to be distributed as long as the license / source credits are kept. This means you can use this mod in any mod pack **as you please**. I'd be happy to hear about you using it, though, just out of curiosity. ## Contributing ###Assets and Localizations diff --git a/src/main/resources/LICENSE b/src/main/resources/LICENSE index 68dd6e055..8e9ad6ecb 100644 --- a/src/main/resources/LICENSE +++ b/src/main/resources/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2013-2014 Florian "Sangar" Nücke +Copyright (c) 2013-2015 Florian "Sangar" Nücke Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal From 9a49ca42444cab14a2699d9948226e03f9f45872 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Thu, 15 Jan 2015 23:48:01 +0100 Subject: [PATCH 22/61] Avoid premature re-initialization of primary component via component.isAvailable, fixes #818. --- .../assets/opencomputers/loot/OpenOS/boot/04_component.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/assets/opencomputers/loot/OpenOS/boot/04_component.lua b/src/main/resources/assets/opencomputers/loot/OpenOS/boot/04_component.lua index 287f27862..c58ca54c0 100644 --- a/src/main/resources/assets/opencomputers/loot/OpenOS/boot/04_component.lua +++ b/src/main/resources/assets/opencomputers/loot/OpenOS/boot/04_component.lua @@ -27,7 +27,7 @@ end function component.isAvailable(componentType) checkArg(1, componentType, "string") - if not primaries[componentType] then + if not primaries[componentType] and not adding[componentType] then -- This is mostly to avoid out of memory errors preventing proxy -- creation cause confusion by trying to create the proxy again, -- causing the oom error to be thrown again. From a7f2cc92295ad471c440feb4205997212909a808 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Fri, 16 Jan 2015 01:34:33 +0100 Subject: [PATCH 23/61] Added callback for T3 screens to allow entering precision mode, allowing sub-"pixel" precision in mouse events. Closes #816. --- src/main/java/li/cil/oc/api/API.java | 2 +- .../li/cil/oc/api/component/TextBuffer.java | 24 ++++- .../scala/li/cil/oc/client/PacketSender.scala | 18 ++-- .../scala/li/cil/oc/client/gui/Screen.scala | 36 +++---- .../cil/oc/common/component/TextBuffer.scala | 102 +++++++++++++----- .../li/cil/oc/common/tileentity/Screen.scala | 2 +- .../li/cil/oc/server/PacketHandler.scala | 23 ++-- 7 files changed, 143 insertions(+), 64 deletions(-) diff --git a/src/main/java/li/cil/oc/api/API.java b/src/main/java/li/cil/oc/api/API.java index eec93c4d0..4feef4c06 100644 --- a/src/main/java/li/cil/oc/api/API.java +++ b/src/main/java/li/cil/oc/api/API.java @@ -11,7 +11,7 @@ import li.cil.oc.api.detail.*; */ public class API { public static final String ID_OWNER = "OpenComputers|Core"; - public static final String VERSION = "4.2.1"; + public static final String VERSION = "4.2.2"; public static DriverAPI driver = null; public static FileSystemAPI fileSystem = null; diff --git a/src/main/java/li/cil/oc/api/component/TextBuffer.java b/src/main/java/li/cil/oc/api/component/TextBuffer.java index 167bc937f..ed0120c15 100644 --- a/src/main/java/li/cil/oc/api/component/TextBuffer.java +++ b/src/main/java/li/cil/oc/api/component/TextBuffer.java @@ -517,7 +517,7 @@ public interface TextBuffer extends ManagedEnvironment, Persistable { * @param button the button of the mouse that was pressed. * @param player the player that pressed the mouse button. Pass null on the client side. */ - void mouseDown(int x, int y, int button, EntityPlayer player); + void mouseDown(double x, double y, int button, EntityPlayer player); /** * Signals a mouse drag event for the buffer. @@ -530,7 +530,7 @@ public interface TextBuffer extends ManagedEnvironment, Persistable { * @param button the button of the mouse that is pressed. * @param player the player that moved the mouse. Pass null on the client side. */ - void mouseDrag(int x, int y, int button, EntityPlayer player); + void mouseDrag(double x, double y, int button, EntityPlayer player); /** * Signals a mouse button release event for the buffer. @@ -543,7 +543,7 @@ public interface TextBuffer extends ManagedEnvironment, Persistable { * @param button the button of the mouse that was released. * @param player the player that released the mouse button. Pass null on the client side. */ - void mouseUp(int x, int y, int button, EntityPlayer player); + void mouseUp(double x, double y, int button, EntityPlayer player); /** * Signals a mouse wheel scroll event for the buffer. @@ -556,6 +556,24 @@ public interface TextBuffer extends ManagedEnvironment, Persistable { * @param delta indicates the direction of the mouse scroll. * @param player the player that scrolled the mouse wheel. Pass null on the client side. */ + void mouseScroll(double x, double y, int delta, EntityPlayer player); + + // TODO Remove deprecated overloads in 1.5. + + /** @deprecated Use the floating-point variant instead. */ + @Deprecated + void mouseDown(int x, int y, int button, EntityPlayer player); + + /** @deprecated Use the floating-point variant instead. */ + @Deprecated + void mouseDrag(int x, int y, int button, EntityPlayer player); + + /** @deprecated Use the floating-point variant instead. */ + @Deprecated + void mouseUp(int x, int y, int button, EntityPlayer player); + + /** @deprecated Use the floating-point variant instead. */ + @Deprecated void mouseScroll(int x, int y, int delta, EntityPlayer player); // ----------------------------------------------------------------------- // diff --git a/src/main/scala/li/cil/oc/client/PacketSender.scala b/src/main/scala/li/cil/oc/client/PacketSender.scala index cd807ec2d..640aedd53 100644 --- a/src/main/scala/li/cil/oc/client/PacketSender.scala +++ b/src/main/scala/li/cil/oc/client/PacketSender.scala @@ -76,35 +76,35 @@ object PacketSender { } } - def sendMouseClick(address: String, x: Int, y: Int, drag: Boolean, button: Int) { + def sendMouseClick(address: String, x: Double, y: Double, drag: Boolean, button: Int) { val pb = new SimplePacketBuilder(PacketType.MouseClickOrDrag) pb.writeUTF(address) - pb.writeShort(x) - pb.writeShort(y) + pb.writeFloat(x.toFloat) + pb.writeFloat(y.toFloat) pb.writeBoolean(drag) pb.writeByte(button.toByte) pb.sendToServer() } - def sendMouseScroll(address: String, x: Int, y: Int, scroll: Int) { + def sendMouseScroll(address: String, x: Double, y: Double, scroll: Int) { val pb = new SimplePacketBuilder(PacketType.MouseScroll) pb.writeUTF(address) - pb.writeShort(x) - pb.writeShort(y) + pb.writeFloat(x.toFloat) + pb.writeFloat(y.toFloat) pb.writeByte(scroll) pb.sendToServer() } - def sendMouseUp(address: String, x: Int, y: Int, button: Int) { + def sendMouseUp(address: String, x: Double, y: Double, button: Int) { val pb = new SimplePacketBuilder(PacketType.MouseUp) pb.writeUTF(address) - pb.writeShort(x) - pb.writeShort(y) + pb.writeFloat(x.toFloat) + pb.writeFloat(y.toFloat) pb.writeByte(button.toByte) pb.sendToServer() diff --git a/src/main/scala/li/cil/oc/client/gui/Screen.scala b/src/main/scala/li/cil/oc/client/gui/Screen.scala index 3b69326ca..d6620f499 100644 --- a/src/main/scala/li/cil/oc/client/gui/Screen.scala +++ b/src/main/scala/li/cil/oc/client/gui/Screen.scala @@ -20,18 +20,18 @@ class Screen(val buffer: api.component.TextBuffer, val hasMouse: Boolean, val ha private var x, y = 0 - private var mx, my = 0 + private var mx, my = -1 override def handleMouseInput() { super.handleMouseInput() if (hasMouse && Mouse.hasWheel && Mouse.getEventDWheel != 0) { val mouseX = Mouse.getEventX * width / mc.displayWidth val mouseY = height - Mouse.getEventY * height / mc.displayHeight - 1 - val bx = (mouseX - x - bufferMargin) / TextBufferRenderCache.renderer.charRenderWidth + 1 - val by = (mouseY - y - bufferMargin) / TextBufferRenderCache.renderer.charRenderHeight + 1 + val bx = (mouseX - x - bufferMargin) / TextBufferRenderCache.renderer.charRenderWidth.toDouble + val by = (mouseY - y - bufferMargin) / TextBufferRenderCache.renderer.charRenderHeight.toDouble val bw = buffer.getWidth val bh = buffer.getHeight - if (bx > 0 && by > 0 && bx <= bw && by <= bh) { + if (bx >= 0 && by >= 0 && bx < bw && by < bh) { val scroll = math.signum(Mouse.getEventDWheel) buffer.mouseScroll(bx, by, scroll, null) } @@ -60,35 +60,35 @@ class Screen(val buffer: api.component.TextBuffer, val hasMouse: Boolean, val ha super.mouseMovedOrUp(mouseX, mouseY, button) if (hasMouse && button >= 0) { if (didDrag) { - val bx = ((mouseX - x - bufferMargin) / scale / TextBufferRenderCache.renderer.charRenderWidth).toInt + 1 - val by = ((mouseY - y - bufferMargin) / scale / TextBufferRenderCache.renderer.charRenderHeight).toInt + 1 + val bx = (mouseX - x - bufferMargin) / scale / TextBufferRenderCache.renderer.charRenderWidth + val by = (mouseY - y - bufferMargin) / scale / TextBufferRenderCache.renderer.charRenderHeight val bw = buffer.getWidth val bh = buffer.getHeight - if (bx > 0 && by > 0 && bx <= bw && by <= bh) { + if (bx >= 0 && by >= 0 && bx < bw && by < bh) { buffer.mouseUp(bx, by, button, null) } else { - buffer.mouseUp(-1, -1, button, null) + buffer.mouseUp(-1.0, -1.0, button, null) } } didDrag = false - mx = 0 - my = 0 + mx = -1 + my = -1 } } private def clickOrDrag(mouseX: Int, mouseY: Int, button: Int) { - val bx = ((mouseX - x - bufferMargin) / scale / TextBufferRenderCache.renderer.charRenderWidth).toInt + 1 - val by = ((mouseY - y - bufferMargin) / scale / TextBufferRenderCache.renderer.charRenderHeight).toInt + 1 + val bx = (mouseX - x - bufferMargin) / scale / TextBufferRenderCache.renderer.charRenderWidth + val by = (mouseY - y - bufferMargin) / scale / TextBufferRenderCache.renderer.charRenderHeight val bw = buffer.getWidth val bh = buffer.getHeight - if (bx > 0 && by > 0 && bx <= bw && by <= bh) { - if (bx != mx || by != my) { - if (mx > 0 && my > 0) buffer.mouseDrag(bx, by, button, null) + if (bx >= 0 && by >= 0 && bx < bw && by < bh) { + if (bx.toInt != mx || by.toInt != my) { + if (mx >= 0 && my >= 0) buffer.mouseDrag(bx, by, button, null) else buffer.mouseDown(bx, by, button, null) - didDrag = mx > 0 && my > 0 - mx = bx - my = by + didDrag = mx >= 0 && my >= 0 + mx = bx.toInt + my = by.toInt } } } diff --git a/src/main/scala/li/cil/oc/common/component/TextBuffer.scala b/src/main/scala/li/cil/oc/common/component/TextBuffer.scala index 3bb9186bb..be1654486 100644 --- a/src/main/scala/li/cil/oc/common/component/TextBuffer.scala +++ b/src/main/scala/li/cil/oc/common/component/TextBuffer.scala @@ -41,14 +41,16 @@ class TextBuffer(val host: EnvironmentHost) extends prefab.ManagedEnvironment wi withConnector(). create() - private var maxResolution = Settings.screenResolutionsByTier(0) + private var maxResolution = Settings.screenResolutionsByTier(Tier.One) - private var maxDepth = Settings.screenDepthsByTier(0) + private var maxDepth = Settings.screenDepthsByTier(Tier.One) private var aspectRatio = (1.0, 1.0) private var powerConsumptionPerTick = Settings.get.screenCost + private var precisionMode = false + // For client side only. private var isRendering = true @@ -162,6 +164,21 @@ class TextBuffer(val host: EnvironmentHost) extends prefab.ManagedEnvironment wi } } + @Callback(direct = true, doc = """function():boolean -- Returns whether the screen is in high precision mode (sub-pixel mouse event positions).""") + def isPrecise(computer: Context, args: Arguments): Array[AnyRef] = result(precisionMode) + + @Callback(doc = """function(enabled:boolean):boolean -- Set whether to use high precision mode (sub-pixel mouse event positions).""") + def setPrecise(computer: Context, args: Arguments): Array[AnyRef] = { + // Available for T3 screens only... easiest way to check for us is to + // base it off of the maximum color depth. + if (maxDepth == Settings.screenDepthsByTier(Tier.Three)) { + val oldValue = precisionMode + precisionMode = args.checkBoolean(0) + result(oldValue) + } + else result(Unit, "unsupported operation") + } + // ----------------------------------------------------------------------- // override def setEnergyCostPerTick(value: Double) { @@ -386,18 +403,32 @@ class TextBuffer(val host: EnvironmentHost) extends prefab.ManagedEnvironment wi override def clipboard(value: String, player: EntityPlayer) = proxy.clipboard(value, player) - override def mouseDown(x: Int, y: Int, button: Int, player: EntityPlayer) = + override def mouseDown(x: Double, y: Double, button: Int, player: EntityPlayer) = proxy.mouseDown(x, y, button, player) - override def mouseDrag(x: Int, y: Int, button: Int, player: EntityPlayer) = + override def mouseDrag(x: Double, y: Double, button: Int, player: EntityPlayer) = proxy.mouseDrag(x, y, button, player) - override def mouseUp(x: Int, y: Int, button: Int, player: EntityPlayer) = + override def mouseUp(x: Double, y: Double, button: Int, player: EntityPlayer) = proxy.mouseUp(x, y, button, player) - override def mouseScroll(x: Int, y: Int, delta: Int, player: EntityPlayer) = + override def mouseScroll(x: Double, y: Double, delta: Int, player: EntityPlayer) = proxy.mouseScroll(x, y, delta, player) + // TODO Remove in 1.5 + + override def mouseDown(x: Int, y: Int, button: Int, player: EntityPlayer) = + mouseDown(x, y, button, player) + + override def mouseDrag(x: Int, y: Int, button: Int, player: EntityPlayer) = + mouseDrag(x, y, button, player) + + override def mouseUp(x: Int, y: Int, button: Int, player: EntityPlayer) = + mouseUp(x, y, button, player) + + override def mouseScroll(x: Int, y: Int, delta: Int, player: EntityPlayer) = + mouseScroll(x, y, delta, player) + // ----------------------------------------------------------------------- // override def onConnect(node: Node) { @@ -443,6 +474,7 @@ class TextBuffer(val host: EnvironmentHost) extends prefab.ManagedEnvironment wi val maxHeight = nbt.getInteger(Settings.namespace + "maxHeight") maxResolution = (maxWidth, maxHeight) } + precisionMode = nbt.getBoolean(Settings.namespace + "precise") } // Null check for Waila (and other mods that may call this client side). @@ -470,6 +502,7 @@ class TextBuffer(val host: EnvironmentHost) extends prefab.ManagedEnvironment wi nbt.setBoolean(Settings.namespace + "hasPower", hasPower) nbt.setInteger(Settings.namespace + "maxWidth", maxResolution._1) nbt.setInteger(Settings.namespace + "maxHeight", maxResolution._2) + nbt.setBoolean(Settings.namespace + "precise", precisionMode) } } @@ -562,13 +595,13 @@ object TextBuffer { def clipboard(value: String, player: EntityPlayer): Unit - def mouseDown(x: Int, y: Int, button: Int, player: EntityPlayer): Unit + def mouseDown(x: Double, y: Double, button: Int, player: EntityPlayer): Unit - def mouseDrag(x: Int, y: Int, button: Int, player: EntityPlayer): Unit + def mouseDrag(x: Double, y: Double, button: Int, player: EntityPlayer): Unit - def mouseUp(x: Int, y: Int, button: Int, player: EntityPlayer): Unit + def mouseUp(x: Double, y: Double, button: Int, player: EntityPlayer): Unit - def mouseScroll(x: Int, y: Int, delta: Int, player: EntityPlayer): Unit + def mouseScroll(x: Double, y: Double, delta: Int, player: EntityPlayer): Unit } class ClientProxy(val owner: TextBuffer) extends Proxy { @@ -633,22 +666,22 @@ object TextBuffer { ClientPacketSender.sendClipboard(nodeAddress, value) } - override def mouseDown(x: Int, y: Int, button: Int, player: EntityPlayer) { + override def mouseDown(x: Double, y: Double, button: Int, player: EntityPlayer) { debug(s"{type = mouseDown, x = $x, y = $y, button = $button}") ClientPacketSender.sendMouseClick(nodeAddress, x, y, drag = false, button) } - override def mouseDrag(x: Int, y: Int, button: Int, player: EntityPlayer) { + override def mouseDrag(x: Double, y: Double, button: Int, player: EntityPlayer) { debug(s"{type = mouseDrag, x = $x, y = $y, button = $button}") ClientPacketSender.sendMouseClick(nodeAddress, x, y, drag = true, button) } - override def mouseUp(x: Int, y: Int, button: Int, player: EntityPlayer) { + override def mouseUp(x: Double, y: Double, button: Int, player: EntityPlayer) { debug(s"{type = mouseUp, x = $x, y = $y, button = $button}") ClientPacketSender.sendMouseUp(nodeAddress, x, y, button) } - override def mouseScroll(x: Int, y: Int, delta: Int, player: EntityPlayer) { + override def mouseScroll(x: Double, y: Double, delta: Int, player: EntityPlayer) { debug(s"{type = mouseScroll, x = $x, y = $y, delta = $delta}") ClientPacketSender.sendMouseScroll(nodeAddress, x, y, delta) } @@ -740,24 +773,41 @@ object TextBuffer { sendToKeyboards("keyboard.clipboard", player, value) } - override def mouseDown(x: Int, y: Int, button: Int, player: EntityPlayer) { - if (Settings.get.inputUsername) owner.node.sendToReachable("computer.checked_signal", player, "touch", Int.box(x), Int.box(y), Int.box(button), player.getCommandSenderName) - else owner.node.sendToReachable("computer.checked_signal", player, "touch", Int.box(x), Int.box(y), Int.box(button)) + override def mouseDown(x: Double, y: Double, button: Int, player: EntityPlayer) { + sendMouseEvent(player, "touch", x, y, button) } - override def mouseDrag(x: Int, y: Int, button: Int, player: EntityPlayer) { - if (Settings.get.inputUsername) owner.node.sendToReachable("computer.checked_signal", player, "drag", Int.box(x), Int.box(y), Int.box(button), player.getCommandSenderName) - else owner.node.sendToReachable("computer.checked_signal", player, "drag", Int.box(x), Int.box(y), Int.box(button)) + override def mouseDrag(x: Double, y: Double, button: Int, player: EntityPlayer) { + sendMouseEvent(player, "drag", x, y, button) } - override def mouseUp(x: Int, y: Int, button: Int, player: EntityPlayer) { - if (Settings.get.inputUsername) owner.node.sendToReachable("computer.checked_signal", player, "drop", Int.box(x), Int.box(y), Int.box(button), player.getCommandSenderName) - else owner.node.sendToReachable("computer.checked_signal", player, "drop", Int.box(x), Int.box(y), Int.box(button)) + override def mouseUp(x: Double, y: Double, button: Int, player: EntityPlayer) { + sendMouseEvent(player, "drop", x, y, button) } - override def mouseScroll(x: Int, y: Int, delta: Int, player: EntityPlayer) { - if (Settings.get.inputUsername) owner.node.sendToReachable("computer.checked_signal", player, "scroll", Int.box(x), Int.box(y), Int.box(delta), player.getCommandSenderName) - else owner.node.sendToReachable("computer.checked_signal", player, "scroll", Int.box(x), Int.box(y), Int.box(delta)) + override def mouseScroll(x: Double, y: Double, delta: Int, player: EntityPlayer) { + sendMouseEvent(player, "scroll", x, y, delta) + } + + private def sendMouseEvent(player: EntityPlayer, name: String, x: Double, y: Double, data: Int) = { + val args = mutable.ArrayBuffer.empty[AnyRef] + + args += player + args += name + if (owner.precisionMode) { + args += double2Double(x) + args += double2Double(y) + } + else { + args += int2Integer(x.toInt + 1) + args += int2Integer(y.toInt + 1) + } + args += int2Integer(data) + if (Settings.get.inputUsername) { + args += player.getCommandSenderName + } + + owner.node.sendToReachable("computer.checked_signal", args: _*) } private def sendToKeyboards(name: String, values: AnyRef*) { diff --git a/src/main/scala/li/cil/oc/common/tileentity/Screen.scala b/src/main/scala/li/cil/oc/common/tileentity/Screen.scala index 4c26a868f..ffac38a2e 100644 --- a/src/main/scala/li/cil/oc/common/tileentity/Screen.scala +++ b/src/main/scala/li/cil/oc/common/tileentity/Screen.scala @@ -137,7 +137,7 @@ class Screen(var tier: Int) extends traits.TextBuffer with SidedEnvironment with } // Convert to absolute coordinates and send the packet to the server. - origin.buffer.mouseDown((brx * bw).toInt + 1, (bry * bh).toInt + 1, 0, null) + origin.buffer.mouseDown(brx * bw, bry * bh, 0, null) true } diff --git a/src/main/scala/li/cil/oc/server/PacketHandler.scala b/src/main/scala/li/cil/oc/server/PacketHandler.scala index 99a8e89c1..1b6e92cd0 100644 --- a/src/main/scala/li/cil/oc/server/PacketHandler.scala +++ b/src/main/scala/li/cil/oc/server/PacketHandler.scala @@ -120,26 +120,37 @@ object PacketHandler extends CommonPacketHandler { def onMouseClick(p: PacketParser) { ComponentTracker.get(p.player.worldObj, p.readUTF()) match { case Some(buffer: api.component.TextBuffer) => - val x = p.readShort() - val y = p.readShort() + val x = p.readFloat() + val y = p.readFloat() val dragging = p.readBoolean() val button = p.readByte() - if (dragging) buffer.mouseDrag(x, y, button, p.player.asInstanceOf[EntityPlayer]) - else buffer.mouseDown(x, y, button, p.player.asInstanceOf[EntityPlayer]) + val player = p.player.asInstanceOf[EntityPlayer] + if (dragging) buffer.mouseDrag(x, y, button, player) + else buffer.mouseDown(x, y, button, player) case _ => // Invalid Packet } } def onMouseUp(p: PacketParser) { ComponentTracker.get(p.player.worldObj, p.readUTF()) match { - case Some(buffer: api.component.TextBuffer) => buffer.mouseUp(p.readShort(), p.readShort(), p.readByte(), p.player.asInstanceOf[EntityPlayer]) + case Some(buffer: api.component.TextBuffer) => + val x = p.readFloat() + val y = p.readFloat() + val button = p.readByte() + val player = p.player.asInstanceOf[EntityPlayer] + buffer.mouseUp(x, y, button, player) case _ => // Invalid Packet } } def onMouseScroll(p: PacketParser) { ComponentTracker.get(p.player.worldObj, p.readUTF()) match { - case Some(buffer: api.component.TextBuffer) => buffer.mouseScroll(p.readShort(), p.readShort(), p.readByte(), p.player.asInstanceOf[EntityPlayer]) + case Some(buffer: api.component.TextBuffer) => + val x = p.readFloat() + val y = p.readFloat() + val button = p.readByte() + val player = p.player.asInstanceOf[EntityPlayer] + buffer.mouseScroll(x, y, button, player) case _ => // Invalid Packet } } From e3526d3888d672ed4f3867287b965f83cc7e1b77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Fri, 16 Jan 2015 12:26:04 +0100 Subject: [PATCH 24/61] Corrected comment in config. --- src/main/resources/application.conf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/resources/application.conf b/src/main/resources/application.conf index c79466de2..6c067f3ca 100644 --- a/src/main/resources/application.conf +++ b/src/main/resources/application.conf @@ -675,11 +675,11 @@ opencomputers { # each point of complexity. tabletAssemblyComplexity: 5000 - # The base energy cost for assembling a microcontroller. + # The base energy cost for assembling a drone. droneAssemblyBase: 25000 # The additional amount of energy required to assemble a - # microcontroller for each point of complexity. + # drone for each point of complexity. droneAssemblyComplexity: 15000 # The amount of energy it takes to extract one ingredient from an From 4b52e39df59e43349e8e37667a2211942694669a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Fri, 16 Jan 2015 14:57:47 +0100 Subject: [PATCH 25/61] Made wireless redstone work in drones and tablets. --- .../li/cil/oc/server/component/RedstoneSignaller.scala | 6 ++++++ .../scala/li/cil/oc/server/component/RedstoneVanilla.scala | 5 ----- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/main/scala/li/cil/oc/server/component/RedstoneSignaller.scala b/src/main/scala/li/cil/oc/server/component/RedstoneSignaller.scala index b43e293c0..84b4d6016 100644 --- a/src/main/scala/li/cil/oc/server/component/RedstoneSignaller.scala +++ b/src/main/scala/li/cil/oc/server/component/RedstoneSignaller.scala @@ -1,12 +1,18 @@ package li.cil.oc.server.component +import li.cil.oc.api.Network import li.cil.oc.api.machine.Arguments import li.cil.oc.api.machine.Callback import li.cil.oc.api.machine.Context +import li.cil.oc.api.network.Visibility import li.cil.oc.api.prefab import net.minecraft.nbt.NBTTagCompound trait RedstoneSignaller extends prefab.ManagedEnvironment { + override val node = Network.newNode(this, Visibility.Network). + withComponent("redstone", Visibility.Neighbors). + create() + var wakeThreshold = 0 // ----------------------------------------------------------------------- // diff --git a/src/main/scala/li/cil/oc/server/component/RedstoneVanilla.scala b/src/main/scala/li/cil/oc/server/component/RedstoneVanilla.scala index 4196fa9f8..87b2b552d 100644 --- a/src/main/scala/li/cil/oc/server/component/RedstoneVanilla.scala +++ b/src/main/scala/li/cil/oc/server/component/RedstoneVanilla.scala @@ -1,6 +1,5 @@ package li.cil.oc.server.component -import li.cil.oc.api.Network import li.cil.oc.api.driver.EnvironmentHost import li.cil.oc.api.machine.Arguments import li.cil.oc.api.machine.Callback @@ -10,10 +9,6 @@ import li.cil.oc.common.tileentity.traits.RedstoneAware import net.minecraftforge.common.util.ForgeDirection trait RedstoneVanilla extends RedstoneSignaller { - override val node = Network.newNode(this, Visibility.Network). - withComponent("redstone", Visibility.Neighbors). - create() - def redstone: EnvironmentHost with RedstoneAware // ----------------------------------------------------------------------- // From 45fc2b8b6c5512bc9a56565aea494585b2c0f5c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Fri, 16 Jan 2015 15:40:47 +0100 Subject: [PATCH 26/61] Fix potential NPE in redstone block. --- src/main/scala/li/cil/oc/common/tileentity/Redstone.scala | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/scala/li/cil/oc/common/tileentity/Redstone.scala b/src/main/scala/li/cil/oc/common/tileentity/Redstone.scala index 7810ca194..c79d3c0c6 100644 --- a/src/main/scala/li/cil/oc/common/tileentity/Redstone.scala +++ b/src/main/scala/li/cil/oc/common/tileentity/Redstone.scala @@ -43,7 +43,9 @@ class Redstone extends Environment with BundledRedstoneAware { override protected def onRedstoneInputChanged(side: ForgeDirection, oldMaxValue: Int, newMaxValue: Int) { super.onRedstoneInputChanged(side, oldMaxValue, newMaxValue) - node.connect(dummyNode) - dummyNode.sendToNeighbors("redstone.changed", side, int2Integer(oldMaxValue), int2Integer(newMaxValue)) + if (node != null && node.network != null) { + node.connect(dummyNode) + dummyNode.sendToNeighbors("redstone.changed", side, int2Integer(oldMaxValue), int2Integer(newMaxValue)) + } } } From 3157eb4f364706caf85a460e7ddaf19c11143ab9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Sat, 17 Jan 2015 00:44:35 +0100 Subject: [PATCH 27/61] Fixed logic for handling nodes with duplicate addresses when merging networks. Closes #824. --- src/main/scala/li/cil/oc/server/network/Network.scala | 10 +++++----- src/main/scala/li/cil/oc/server/network/Node.scala | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/main/scala/li/cil/oc/server/network/Network.scala b/src/main/scala/li/cil/oc/server/network/Network.scala index 8e2f9355f..9727aa3f1 100644 --- a/src/main/scala/li/cil/oc/server/network/Network.scala +++ b/src/main/scala/li/cil/oc/server/network/Network.scala @@ -252,11 +252,11 @@ private class Network private(private val data: mutable.Map[String, Network.Vert // never happen in normal operation anyway. It *can* happen when NBT // editing stuff or using mods to clone blocks (e.g. WorldEdit). otherNetwork.data.filter(entry => data.contains(entry._1)).toArray.foreach { - case (address, node: MutableNode) => - val neighbors = node.neighbors.toArray // Copy to be on the safe side. - node.remove() - node.address = java.util.UUID.randomUUID().toString - neighbors.foreach(_.connect(node)) + case (address, node: Network.Vertex) => + val neighbors = node.data.neighbors.toArray // Copy to be on the safe side. + node.data.remove() + node.data.address = java.util.UUID.randomUUID().toString + neighbors.foreach(_.connect(node.data)) } if (addedNode.reachability == Visibility.Neighbors) diff --git a/src/main/scala/li/cil/oc/server/network/Node.scala b/src/main/scala/li/cil/oc/server/network/Node.scala index c18de90d0..bae0e6b08 100644 --- a/src/main/scala/li/cil/oc/server/network/Node.scala +++ b/src/main/scala/li/cil/oc/server/network/Node.scala @@ -11,8 +11,8 @@ import scala.collection.convert.WrapAsJava._ import scala.collection.convert.WrapAsScala._ trait Node extends ImmutableNode { - val host: Environment - val reachability: Visibility + def host: Environment + def reachability: Visibility final var address: String = null From 6f9f27fe021b0b48953bf32414d0391ef52099dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Sat, 17 Jan 2015 13:36:21 +0100 Subject: [PATCH 28/61] Fixed EEPROM with data (even if just an address) not being usable for crafting a Lua BIOS. Closes #828. --- src/main/scala/li/cil/oc/common/recipe/ExtendedRecipe.scala | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/scala/li/cil/oc/common/recipe/ExtendedRecipe.scala b/src/main/scala/li/cil/oc/common/recipe/ExtendedRecipe.scala index ead527217..d1568ffed 100644 --- a/src/main/scala/li/cil/oc/common/recipe/ExtendedRecipe.scala +++ b/src/main/scala/li/cil/oc/common/recipe/ExtendedRecipe.scala @@ -5,6 +5,7 @@ import java.util.UUID import li.cil.oc.Settings import li.cil.oc.api import li.cil.oc.api.detail.ItemInfo +import li.cil.oc.common.init.Items import li.cil.oc.integration.Mods import li.cil.oc.util.ExtendedNBT._ import li.cil.oc.util.ItemUtils @@ -20,6 +21,7 @@ import scala.util.control.Breaks._ object ExtendedRecipe { private lazy val drone = api.Items.get("drone") private lazy val eeprom = api.Items.get("eeprom") + private lazy val luaBios = Items.createLuaBios() private lazy val mcu = api.Items.get("microcontroller") private lazy val navigationUpgrade = api.Items.get("navigationUpgrade") private lazy val linkedCard = api.Items.get("linkedCard") @@ -71,7 +73,7 @@ object ExtendedRecipe { } } - if (api.Items.get(craftedStack) == eeprom) breakable { + if (api.Items.get(craftedStack) == eeprom && !ItemStack.areItemStackTagsEqual(craftedStack, luaBios)) breakable { for (slot <- 0 until inventory.getSizeInventory) { val stack = inventory.getStackInSlot(slot) if (stack != null && api.Items.get(stack) == eeprom && stack.hasTagCompound) { From d869ba4df94d9c9e00620bc07d421d028158c108 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Sat, 17 Jan 2015 14:54:53 +0100 Subject: [PATCH 29/61] Bumped default sample rate for generating computer speaker beeps to avoid artifacts and made it a setting. --- src/main/resources/application.conf | 7 +++++++ src/main/scala/li/cil/oc/Settings.scala | 1 + src/main/scala/li/cil/oc/util/Audio.scala | 3 ++- 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/main/resources/application.conf b/src/main/resources/application.conf index 6c067f3ca..446cd4b96 100644 --- a/src/main/resources/application.conf +++ b/src/main/resources/application.conf @@ -105,6 +105,13 @@ opencomputers { # importantly, can only render code page 437 (as opposed to... # a *lot* of unicode). fontRenderer: "unifont" + + # The sample rate used for generating beeps of computers' internal + # speakers. Use custom values at your own responsibility here; if it + # breaks OC you'll get no support. Some potentially reasonable + # lower values are 16000 or even 8000 (which was the old default, but + # leads to artifacting on certain frequencies). + beepSampleRate: 44100 } # Computer related settings, concerns server performance and security. diff --git a/src/main/scala/li/cil/oc/Settings.scala b/src/main/scala/li/cil/oc/Settings.scala index 56f5537e9..c0140ee1a 100644 --- a/src/main/scala/li/cil/oc/Settings.scala +++ b/src/main/scala/li/cil/oc/Settings.scala @@ -49,6 +49,7 @@ class Settings(val config: Config) { } val monochromeColor = Integer.decode(config.getString("client.monochromeColor")) val fontRenderer = config.getString("client.fontRenderer") + val beepSampleRate = config.getInt("client.beepSampleRate") // ----------------------------------------------------------------------- // // computer diff --git a/src/main/scala/li/cil/oc/util/Audio.scala b/src/main/scala/li/cil/oc/util/Audio.scala index 468dee7ec..ae8f9b515 100644 --- a/src/main/scala/li/cil/oc/util/Audio.scala +++ b/src/main/scala/li/cil/oc/util/Audio.scala @@ -6,6 +6,7 @@ import cpw.mods.fml.common.FMLCommonHandler import cpw.mods.fml.common.eventhandler.SubscribeEvent import cpw.mods.fml.common.gameevent.TickEvent.ClientTickEvent import li.cil.oc.OpenComputers +import li.cil.oc.Settings import net.minecraft.client.Minecraft import net.minecraft.client.audio.SoundCategory import org.lwjgl.BufferUtils @@ -23,7 +24,7 @@ import scala.collection.mutable * tick handler. */ object Audio { - private def sampleRate = 8000 + private def sampleRate = Settings.get.beepSampleRate private val sources = mutable.Set.empty[Source] From db05a22430610954344fadba286b628585c5e3ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Sun, 18 Jan 2015 04:15:45 +0100 Subject: [PATCH 30/61] Completely fitched the beep. MVP gamax92 ^ 0x80. --- src/main/resources/application.conf | 5 +++++ src/main/scala/li/cil/oc/Settings.scala | 1 + src/main/scala/li/cil/oc/util/Audio.scala | 12 ++++-------- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/main/resources/application.conf b/src/main/resources/application.conf index 446cd4b96..ec5211626 100644 --- a/src/main/resources/application.conf +++ b/src/main/resources/application.conf @@ -112,6 +112,11 @@ opencomputers { # lower values are 16000 or even 8000 (which was the old default, but # leads to artifacting on certain frequencies). beepSampleRate: 44100 + + # The base volume of beeps generated by computers. This may be in a + # range of [0, 127], where 0 means mute (the sound will not even be + # generated), and 127 means maximum amplitude / volume. + beepVolume: 32 } # Computer related settings, concerns server performance and security. diff --git a/src/main/scala/li/cil/oc/Settings.scala b/src/main/scala/li/cil/oc/Settings.scala index c0140ee1a..dac54c017 100644 --- a/src/main/scala/li/cil/oc/Settings.scala +++ b/src/main/scala/li/cil/oc/Settings.scala @@ -50,6 +50,7 @@ class Settings(val config: Config) { val monochromeColor = Integer.decode(config.getString("client.monochromeColor")) val fontRenderer = config.getString("client.fontRenderer") val beepSampleRate = config.getInt("client.beepSampleRate") + val beepAmplitude = config.getInt("client.beepVolume") max 0 min Byte.MaxValue // ----------------------------------------------------------------------- // // computer diff --git a/src/main/scala/li/cil/oc/util/Audio.scala b/src/main/scala/li/cil/oc/util/Audio.scala index ae8f9b515..c724821cb 100644 --- a/src/main/scala/li/cil/oc/util/Audio.scala +++ b/src/main/scala/li/cil/oc/util/Audio.scala @@ -26,6 +26,8 @@ import scala.collection.mutable object Audio { private def sampleRate = Settings.get.beepSampleRate + private def amplitude = Settings.get.beepAmplitude + private val sources = mutable.Set.empty[Source] private def volume = Minecraft.getMinecraft.gameSettings.getSoundLevel(SoundCategory.BLOCKS) @@ -40,7 +42,7 @@ object Audio { if (!disableAudio) { val distanceBasedGain = math.max(0, 1 - Minecraft.getMinecraft.thePlayer.getDistance(x, y, z) / 12).toFloat val gain = distanceBasedGain * volume - if (gain > 0 && AL.isCreated) { + if (gain > 0 && amplitude > 0 && AL.isCreated) { val sampleCounts = pattern.toCharArray. map(ch => if (ch == '.') durationInMilliseconds else 2 * durationInMilliseconds). map(_ * sampleRate / 1000) @@ -52,13 +54,7 @@ object Audio { for (sampleCount <- sampleCounts) { for (sample <- 0 until sampleCount) { val angle = 2 * math.Pi * offset - // We could sort of fake the square wave with a little less - // computational effort, but until somebody complains let's - // go with the fourier series! We leave out the 4 / Pi because - // it's just an approximation and we avoid clipping like this. - val value = (0 to 6).map(k => math.sin((1 + k * 2) * angle) / (1 + k * 2)).sum * Byte.MaxValue - // val tmp = math.sin(angle) * Byte.MaxValue - // val value = math.signum(tmp) * 0.99 + tmp * 0.01 + val value = (math.signum(math.sin(angle)) * amplitude).toByte ^ 0x80 offset += step if (offset > 1) offset -= 1 data.put(value.toByte) From 13a8dde8a6afb018ce96bcfb97929c006be97f50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Sun, 18 Jan 2015 14:27:23 +0100 Subject: [PATCH 31/61] Fixed highly unlikely, non-critical NPE in machine (could happen in the very rare case that an executor thread started while the machine was being removed from the network, leading it to run while the machine is unconnected - that's still possible, but non-critical; it'll just stop/silently error and stop now). --- src/main/scala/li/cil/oc/server/machine/Machine.scala | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/scala/li/cil/oc/server/machine/Machine.scala b/src/main/scala/li/cil/oc/server/machine/Machine.scala index 31fd20ce6..c895aeaee 100644 --- a/src/main/scala/li/cil/oc/server/machine/Machine.scala +++ b/src/main/scala/li/cil/oc/server/machine/Machine.scala @@ -255,7 +255,7 @@ class Machine(val host: MachineHost) extends prefab.ManagedEnvironment with mach }) override def invoke(address: String, method: String, args: Array[AnyRef]) = - Option(node.network.node(address)) match { + if (node != null && node.network != null) Option(node.network.node(address)) match { case Some(component: Component) if component.canBeSeenFrom(node) || component == node => val direct = component.annotation(method).direct if (direct && architecture.isInitialized) { @@ -264,6 +264,11 @@ class Machine(val host: MachineHost) extends prefab.ManagedEnvironment with mach component.invoke(method, this, args: _*) case _ => throw new IllegalArgumentException("no such component") } + else { + // Not really, but makes the VM stop, which is what we want in this case, + // because it means we've been disconnected / disposed already. + throw new LimitReachedException() + } override def invoke(value: Value, method: String, args: Array[AnyRef]): Array[AnyRef] = Callbacks(value).get(method) match { case Some(callback) => From da410fc13e2d2a7d5b4316344613d8b558e042d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Sun, 18 Jan 2015 14:28:04 +0100 Subject: [PATCH 32/61] Added timeout to item cost computation, just to be on the safe side. Had that lock up in dev mode a few times, pretty sure the synchronization should be enough, but hey. --- src/main/scala/li/cil/oc/util/ItemCosts.scala | 97 ++++++++++--------- 1 file changed, 53 insertions(+), 44 deletions(-) diff --git a/src/main/scala/li/cil/oc/util/ItemCosts.scala b/src/main/scala/li/cil/oc/util/ItemCosts.scala index c2663a1eb..bb436b667 100644 --- a/src/main/scala/li/cil/oc/util/ItemCosts.scala +++ b/src/main/scala/li/cil/oc/util/ItemCosts.scala @@ -19,7 +19,11 @@ import scala.collection.convert.WrapAsScala._ import scala.collection.mutable object ItemCosts { - protected val cache = mutable.Map.empty[ItemStackWrapper, Iterable[(ItemStack, Double)]] + private final val Timeout = 500 + + private val cache = mutable.Map.empty[ItemStackWrapper, Iterable[(ItemStack, Double)]] + + private var started = 0L cache += new ItemStackWrapper(init.Items.ironNugget.createItemStack()) -> Iterable((new ItemStack(Items.iron_ingot), 1.0 / 9.0)) @@ -67,7 +71,8 @@ object ItemCosts { } } - protected def computeIngredients(what: ItemStack): Iterable[(ItemStack, Double)] = { + protected def computeIngredients(what: ItemStack): Iterable[(ItemStack, Double)] = cache.synchronized { + started = System.currentTimeMillis() def deflate(list: Iterable[(ItemStack, Double)]): Iterable[(ItemStack, Double)] = { val counts = mutable.Map.empty[ItemStack, Double] for ((stack, count) <- list) { @@ -80,53 +85,57 @@ object ItemCosts { } counts } - def accumulate(input: Any, path: Seq[ItemStack] = Seq.empty): Iterable[(ItemStack, Double)] = input match { - case stack: ItemStack => - cache.find { - case (key, value) => fuzzyEquals(key.inner, stack) - } match { - case Some((_, value)) => value - case _ => - if (path.exists(value => fuzzyEquals(value, stack))) { - Iterable((stack, 1.0)) - } - else { - val recipes = CraftingManager.getInstance.getRecipeList.map(_.asInstanceOf[IRecipe]) - val recipe = recipes.find(recipe => recipe.getRecipeOutput != null && fuzzyEquals(stack, recipe.getRecipeOutput)) - val (ingredients, output) = recipe match { - case Some(recipe: ShapedRecipes) => (recipe.recipeItems.flatMap(accumulate(_, path :+ stack)).toIterable, recipe.getRecipeOutput.stackSize) - case Some(recipe: ShapelessRecipes) => (recipe.recipeItems.flatMap(accumulate(_, path :+ stack)).toIterable, recipe.getRecipeOutput.stackSize) - case Some(recipe: ShapedOreRecipe) => (recipe.getInput.flatMap(accumulate(_, path :+ stack)).toIterable, recipe.getRecipeOutput.stackSize) - case Some(recipe: ShapelessOreRecipe) => (recipe.getInput.flatMap(accumulate(_, path :+ stack)).toIterable, recipe.getRecipeOutput.stackSize) - case _ => FurnaceRecipes.smelting.getSmeltingList.asInstanceOf[util.Map[ItemStack, ItemStack]].find { - case (_, value) => fuzzyEquals(stack, value) - } match { - case Some((rein, raus)) => (accumulate(rein, path :+ stack), raus.stackSize) - case _ => (Iterable((stack, 1.0)), 1) - } - } - val scaled = deflate(ingredients.map { - case (ingredient, count) => (ingredient.copy(), count / output) - }).toArray.sortBy(_._1.getUnlocalizedName) - cache += new ItemStackWrapper(stack.copy()) -> scaled - scaled - } - } - case list: util.ArrayList[ItemStack]@unchecked if !list.isEmpty => - var result = Iterable.empty[(ItemStack, Double)] - for (stack <- list if result.isEmpty) { + def accumulate(input: Any, path: Seq[ItemStack] = Seq.empty): Iterable[(ItemStack, Double)] = { + val passed = System.currentTimeMillis() - started + if (passed > Timeout) Iterable.empty + else input match { + case stack: ItemStack => cache.find { case (key, value) => fuzzyEquals(key.inner, stack) } match { - case Some((_, value)) => result = value + case Some((_, value)) => value case _ => + if (path.exists(value => fuzzyEquals(value, stack))) { + Iterable((stack, 1.0)) + } + else { + val recipes = CraftingManager.getInstance.getRecipeList.map(_.asInstanceOf[IRecipe]) + val recipe = recipes.find(recipe => recipe.getRecipeOutput != null && fuzzyEquals(stack, recipe.getRecipeOutput)) + val (ingredients, output) = recipe match { + case Some(recipe: ShapedRecipes) => (recipe.recipeItems.flatMap(accumulate(_, path :+ stack)).toIterable, recipe.getRecipeOutput.stackSize) + case Some(recipe: ShapelessRecipes) => (recipe.recipeItems.flatMap(accumulate(_, path :+ stack)).toIterable, recipe.getRecipeOutput.stackSize) + case Some(recipe: ShapedOreRecipe) => (recipe.getInput.flatMap(accumulate(_, path :+ stack)).toIterable, recipe.getRecipeOutput.stackSize) + case Some(recipe: ShapelessOreRecipe) => (recipe.getInput.flatMap(accumulate(_, path :+ stack)).toIterable, recipe.getRecipeOutput.stackSize) + case _ => FurnaceRecipes.smelting.getSmeltingList.asInstanceOf[util.Map[ItemStack, ItemStack]].find { + case (_, value) => fuzzyEquals(stack, value) + } match { + case Some((rein, raus)) => (accumulate(rein, path :+ stack), raus.stackSize) + case _ => (Iterable((stack, 1.0)), 1) + } + } + val scaled = deflate(ingredients.map { + case (ingredient, count) => (ingredient.copy(), count / output) + }).toArray.sortBy(_._1.getUnlocalizedName) + cache += new ItemStackWrapper(stack.copy()) -> scaled + scaled + } } - } - if (result.isEmpty) { - result = accumulate(list.get(0), path) - } - result - case _ => Iterable.empty + case list: util.ArrayList[ItemStack]@unchecked if !list.isEmpty => + var result = Iterable.empty[(ItemStack, Double)] + for (stack <- list if result.isEmpty) { + cache.find { + case (key, value) => fuzzyEquals(key.inner, stack) + } match { + case Some((_, value)) => result = value + case _ => + } + } + if (result.isEmpty) { + result = accumulate(list.get(0), path) + } + result + case _ => Iterable.empty + } } accumulate(what) } From 83fdee38f338ea210c4a56d4e078e4e42bdd0055 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Sun, 18 Jan 2015 14:30:50 +0100 Subject: [PATCH 33/61] Added comparator override to capacitor, based on its (local!) buffer fill rate. Note that this updates its neighbor blocks only using block ticks, which are random (because I do not want capacitors to be ticking tile entities). So don't expect this to update *immediately*. --- .../li/cil/oc/common/block/Capacitor.scala | 18 ++++++++++++++++++ .../cil/oc/common/tileentity/Capacitor.scala | 4 ++-- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/main/scala/li/cil/oc/common/block/Capacitor.scala b/src/main/scala/li/cil/oc/common/block/Capacitor.scala index b554deaf9..136e5e798 100644 --- a/src/main/scala/li/cil/oc/common/block/Capacitor.scala +++ b/src/main/scala/li/cil/oc/common/block/Capacitor.scala @@ -1,11 +1,14 @@ package li.cil.oc.common.block +import java.util.Random + import li.cil.oc.common.tileentity import net.minecraft.block.Block import net.minecraft.world.World class Capacitor extends SimpleBlock { setLightLevel(0.34f) + setTickRandomly(true) override protected def customTextures = Array( None, @@ -24,6 +27,21 @@ class Capacitor extends SimpleBlock { // ----------------------------------------------------------------------- // + override def hasComparatorInputOverride = true + + override def getComparatorInputOverride(world: World, x: Int, y: Int, z: Int, side: Int) = + world.getTileEntity(x, y, z) match { + case capacitor: tileentity.Capacitor if !world.isRemote => + math.round(15 * capacitor.node.localBuffer / capacitor.node.localBufferSize).toInt + case _ => 0 + } + + override def updateTick(world: World, x: Int, y: Int, z: Int, rng: Random): Unit = { + world.notifyBlocksOfNeighborChange(x, y, z, this) + } + + override def tickRate(world : World) = 1 + override def onNeighborBlockChange(world: World, x: Int, y: Int, z: Int, block: Block) = world.getTileEntity(x, y, z) match { case capacitor: tileentity.Capacitor => capacitor.recomputeCapacity() diff --git a/src/main/scala/li/cil/oc/common/tileentity/Capacitor.scala b/src/main/scala/li/cil/oc/common/tileentity/Capacitor.scala index 89645ca4b..19b773931 100644 --- a/src/main/scala/li/cil/oc/common/tileentity/Capacitor.scala +++ b/src/main/scala/li/cil/oc/common/tileentity/Capacitor.scala @@ -1,9 +1,9 @@ package li.cil.oc.common.tileentity -import li.cil.oc.api.network.Node -import li.cil.oc.api.network.Visibility import li.cil.oc.Settings import li.cil.oc.api +import li.cil.oc.api.network.Node +import li.cil.oc.api.network.Visibility import net.minecraftforge.common.util.ForgeDirection class Capacitor extends traits.Environment { From 6079f0e0f515d5711e2aa0c91ab8e6c62356fd67 Mon Sep 17 00:00:00 2001 From: mpmxyz Date: Sun, 18 Jan 2015 18:55:56 +0100 Subject: [PATCH 34/61] Fixed filesystem.list returning a list with duplicate values The error was caused by increasing the index i after removing its value: The value after the removed one was ignored. To see an effect you need two directories being neighbors in the list. Both also have to have a symbolic link or a mounting point inside. -> That's a rare but possible combination. Here an example: bugdir/ a/ link1 -> link somewhere b/ link2 -> link somewhere #ls bugdir a b b (!) --- .../assets/opencomputers/loot/OpenOS/lib/filesystem.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/assets/opencomputers/loot/OpenOS/lib/filesystem.lua b/src/main/resources/assets/opencomputers/loot/OpenOS/lib/filesystem.lua index 0ab4e4e63..bb523ddc9 100644 --- a/src/main/resources/assets/opencomputers/loot/OpenOS/lib/filesystem.lua +++ b/src/main/resources/assets/opencomputers/loot/OpenOS/lib/filesystem.lua @@ -351,8 +351,8 @@ function filesystem.list(path) table.remove(result, i) else f = result[i] + i = i + 1 end - i = i + 1 end local i = 0 return function() From 25aab07368d637e505c73ae30643b0ac4fb386eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Sun, 18 Jan 2015 21:59:02 +0100 Subject: [PATCH 35/61] Fixed Mekanism energy acceptor method returning inverted value, leading to non-stop power acceptance. --- .../li/cil/oc/common/tileentity/traits/power/Mekanism.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/li/cil/oc/common/tileentity/traits/power/Mekanism.scala b/src/main/scala/li/cil/oc/common/tileentity/traits/power/Mekanism.scala index d6290a4cb..650344607 100644 --- a/src/main/scala/li/cil/oc/common/tileentity/traits/power/Mekanism.scala +++ b/src/main/scala/li/cil/oc/common/tileentity/traits/power/Mekanism.scala @@ -14,7 +14,7 @@ trait Mekanism extends Common { @Optional.Method(modid = Mods.IDs.Mekanism) def transferEnergyToAcceptor(side: ForgeDirection, amount: Double) = if (!Mods.Mekanism.isAvailable) 0 - else amount - tryChangeBuffer(side, amount * Settings.get.ratioMekanism) / Settings.get.ratioMekanism + else tryChangeBuffer(side, amount * Settings.get.ratioMekanism) / Settings.get.ratioMekanism @Optional.Method(modid = Mods.IDs.Mekanism) def getMaxEnergy = ForgeDirection.VALID_DIRECTIONS.map(globalBufferSize).max / Settings.get.ratioMekanism From 3561827cb378f797ea28906f8bd71db5927fc209 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Mon, 19 Jan 2015 18:52:53 +0100 Subject: [PATCH 36/61] Fixed bad override leading to incorrectly interpreted redstone output in some scenarios. Closes #836. --- build.properties | 4 ++-- src/main/scala/li/cil/oc/common/block/Assembler.scala | 2 ++ src/main/scala/li/cil/oc/common/block/Cable.scala | 2 ++ src/main/scala/li/cil/oc/common/block/Hologram.scala | 2 ++ src/main/scala/li/cil/oc/common/block/Keyboard.scala | 2 ++ src/main/scala/li/cil/oc/common/block/RedstoneAware.scala | 3 --- src/main/scala/li/cil/oc/common/block/RobotAfterimage.scala | 2 ++ src/main/scala/li/cil/oc/common/block/RobotProxy.scala | 2 ++ src/main/scala/li/cil/oc/common/block/Screen.scala | 2 ++ src/main/scala/li/cil/oc/common/block/ServerRack.scala | 4 +++- src/main/scala/li/cil/oc/common/block/SimpleBlock.scala | 4 +++- .../scala/li/cil/oc/common/block/traits/SpecialBlock.scala | 2 -- 12 files changed, 22 insertions(+), 9 deletions(-) diff --git a/build.properties b/build.properties index ee4f43ea2..1950bd709 100644 --- a/build.properties +++ b/build.properties @@ -11,8 +11,8 @@ bloodmagic.version=1.3.0a-1 cc.cf=2216/236 cc.version=1.65 ccl.version=1.1.1.104 -cofhlib.cf=2212/893 -cofhlib.version=[1.7.10]1.0.0B6-dev-26 +cofhlib.cf=2218/257 +cofhlib.version=[1.7.10]1.0.0B7-dev-29 eio.cf=2219/296 eio.version=1.7.10-2.2.1.276 es.version=1.4.5.24 diff --git a/src/main/scala/li/cil/oc/common/block/Assembler.scala b/src/main/scala/li/cil/oc/common/block/Assembler.scala index 577097d21..d5621d5d6 100644 --- a/src/main/scala/li/cil/oc/common/block/Assembler.scala +++ b/src/main/scala/li/cil/oc/common/block/Assembler.scala @@ -30,6 +30,8 @@ class Assembler extends SimpleBlock with traits.SpecialBlock with traits.PowerAc override def isBlockSolid(world: IBlockAccess, x: Int, y: Int, z: Int, side: ForgeDirection) = side == ForgeDirection.DOWN || side == ForgeDirection.UP + override def isSideSolid(world: IBlockAccess, x: Int, y: Int, z: Int, side: ForgeDirection) = side == ForgeDirection.DOWN || side == ForgeDirection.UP + // ----------------------------------------------------------------------- // override def energyThroughput = Settings.get.assemblerRate diff --git a/src/main/scala/li/cil/oc/common/block/Cable.scala b/src/main/scala/li/cil/oc/common/block/Cable.scala index e456b3230..27a884b97 100644 --- a/src/main/scala/li/cil/oc/common/block/Cable.scala +++ b/src/main/scala/li/cil/oc/common/block/Cable.scala @@ -52,6 +52,8 @@ class Cable extends SimpleBlock with traits.SpecialBlock { override def shouldSideBeRendered(world: IBlockAccess, x: Int, y: Int, z: Int, side: ForgeDirection) = true + override def isSideSolid(world: IBlockAccess, x: Int, y: Int, z: Int, side: ForgeDirection) = false + // ----------------------------------------------------------------------- // override def hasTileEntity(metadata: Int) = true diff --git a/src/main/scala/li/cil/oc/common/block/Hologram.scala b/src/main/scala/li/cil/oc/common/block/Hologram.scala index 9708d2817..06da52a63 100644 --- a/src/main/scala/li/cil/oc/common/block/Hologram.scala +++ b/src/main/scala/li/cil/oc/common/block/Hologram.scala @@ -35,6 +35,8 @@ class Hologram(val tier: Int) extends SimpleBlock with traits.SpecialBlock { super.shouldSideBeRendered(world, x, y, z, side) || side == ForgeDirection.UP } + override def isSideSolid(world: IBlockAccess, x: Int, y: Int, z: Int, side: ForgeDirection) = side == ForgeDirection.DOWN + // ----------------------------------------------------------------------- // override def rarity(stack: ItemStack) = Rarity.byTier(tier) diff --git a/src/main/scala/li/cil/oc/common/block/Keyboard.scala b/src/main/scala/li/cil/oc/common/block/Keyboard.scala index 81cd285c8..7c8d8fb2e 100644 --- a/src/main/scala/li/cil/oc/common/block/Keyboard.scala +++ b/src/main/scala/li/cil/oc/common/block/Keyboard.scala @@ -28,6 +28,8 @@ class Keyboard extends SimpleBlock with traits.SpecialBlock { Some("Keyboard") ) + override def isSideSolid(world: IBlockAccess, x: Int, y: Int, z: Int, side: ForgeDirection) = false + override def shouldSideBeRendered(world: IBlockAccess, x: Int, y: Int, z: Int, side: ForgeDirection) = true override def setBlockBoundsForItemRender(metadata: Int) = setBlockBounds(ForgeDirection.NORTH, ForgeDirection.WEST) diff --git a/src/main/scala/li/cil/oc/common/block/RedstoneAware.scala b/src/main/scala/li/cil/oc/common/block/RedstoneAware.scala index 3e4427ae9..e7f34c0fc 100644 --- a/src/main/scala/li/cil/oc/common/block/RedstoneAware.scala +++ b/src/main/scala/li/cil/oc/common/block/RedstoneAware.scala @@ -27,9 +27,6 @@ abstract class RedstoneAware extends SimpleBlock with IRedNetOmniNode { case _ => false } - override def isProvidingStrongPower(world: IBlockAccess, x: Int, y: Int, z: Int, side: ForgeDirection) = - isProvidingWeakPower(world, x, y, z, side) - override def isProvidingWeakPower(world: IBlockAccess, x: Int, y: Int, z: Int, side: ForgeDirection) = world.getTileEntity(x, y, z) match { case redstone: tileentity.traits.RedstoneAware => math.min(math.max(redstone.output(side), 0), 15) diff --git a/src/main/scala/li/cil/oc/common/block/RobotAfterimage.scala b/src/main/scala/li/cil/oc/common/block/RobotAfterimage.scala index 20a1b3bdd..0bc42e235 100644 --- a/src/main/scala/li/cil/oc/common/block/RobotAfterimage.scala +++ b/src/main/scala/li/cil/oc/common/block/RobotAfterimage.scala @@ -41,6 +41,8 @@ class RobotAfterimage extends SimpleBlock with traits.SpecialBlock { override def isBlockSolid(world: IBlockAccess, x: Int, y: Int, z: Int, side: ForgeDirection) = false + override def isSideSolid(world: IBlockAccess, x: Int, y: Int, z: Int, side: ForgeDirection) = false + override def getPickBlock(target: MovingObjectPosition, world: World, x: Int, y: Int, z: Int) = findMovingRobot(world, x, y, z) match { case Some(robot) => robot.info.createItemStack() diff --git a/src/main/scala/li/cil/oc/common/block/RobotProxy.scala b/src/main/scala/li/cil/oc/common/block/RobotProxy.scala index 80c7ad3e3..8d7042ab1 100644 --- a/src/main/scala/li/cil/oc/common/block/RobotProxy.scala +++ b/src/main/scala/li/cil/oc/common/block/RobotProxy.scala @@ -57,6 +57,8 @@ class RobotProxy extends RedstoneAware with traits.SpecialBlock with traits.Stat override def isBlockSolid(world: IBlockAccess, x: Int, y: Int, z: Int, side: ForgeDirection) = false + override def isSideSolid(world: IBlockAccess, x: Int, y: Int, z: Int, side: ForgeDirection) = false + override def getPickBlock(target: MovingObjectPosition, world: World, x: Int, y: Int, z: Int) = world.getTileEntity(x, y, z) match { case proxy: tileentity.RobotProxy => proxy.robot.info.copyItemStack() diff --git a/src/main/scala/li/cil/oc/common/block/Screen.scala b/src/main/scala/li/cil/oc/common/block/Screen.scala index daead40b5..fce0e3c5a 100644 --- a/src/main/scala/li/cil/oc/common/block/Screen.scala +++ b/src/main/scala/li/cil/oc/common/block/Screen.scala @@ -24,6 +24,8 @@ import net.minecraftforge.common.util.ForgeDirection class Screen(val tier: Int) extends RedstoneAware { setLightLevel(0.34f) + override def isSideSolid(world: IBlockAccess, x: Int, y: Int, z: Int, side: ForgeDirection) = toLocal(world, x, y, z, side) != ForgeDirection.SOUTH + @SideOnly(Side.CLIENT) override def getRenderColor(metadata: Int) = Color.byTier(tier) diff --git a/src/main/scala/li/cil/oc/common/block/ServerRack.scala b/src/main/scala/li/cil/oc/common/block/ServerRack.scala index 3178c851d..65a7357d7 100644 --- a/src/main/scala/li/cil/oc/common/block/ServerRack.scala +++ b/src/main/scala/li/cil/oc/common/block/ServerRack.scala @@ -39,7 +39,9 @@ class ServerRack extends RedstoneAware with traits.SpecialBlock with traits.Powe } } - override def isBlockSolid(world: IBlockAccess, x: Int, y: Int, z: Int, side: ForgeDirection) = side == ForgeDirection.SOUTH + override def isBlockSolid(world: IBlockAccess, x: Int, y: Int, z: Int, side: ForgeDirection) = side != ForgeDirection.SOUTH + + override def isSideSolid(world: IBlockAccess, x: Int, y: Int, z: Int, side: ForgeDirection) = toLocal(world, x, y, z, side) != ForgeDirection.SOUTH // ----------------------------------------------------------------------- // diff --git a/src/main/scala/li/cil/oc/common/block/SimpleBlock.scala b/src/main/scala/li/cil/oc/common/block/SimpleBlock.scala index 47fc3ff79..bae903a2b 100644 --- a/src/main/scala/li/cil/oc/common/block/SimpleBlock.scala +++ b/src/main/scala/li/cil/oc/common/block/SimpleBlock.scala @@ -148,7 +148,7 @@ class SimpleBlock(material: Material = Material.iron) extends Block(material) { // Block // ----------------------------------------------------------------------- // - override def isNormalCube(world: IBlockAccess, x: Int, y: Int, z: Int) = true + override def isSideSolid(world: IBlockAccess, x: Int, y: Int, z: Int, side: ForgeDirection) = true override def canHarvestBlock(player: EntityPlayer, meta: Int) = true @@ -247,6 +247,8 @@ class SimpleBlock(material: Material = Material.iron) extends Block(material) { def isProvidingWeakPower(world: IBlockAccess, x: Int, y: Int, z: Int, side: ForgeDirection) = 0 + override def shouldCheckWeakPower(world: IBlockAccess, x: Int, y: Int, z: Int, side: Int) = true + // ----------------------------------------------------------------------- // // NOTE: must not be final for immibis microblocks to work. diff --git a/src/main/scala/li/cil/oc/common/block/traits/SpecialBlock.scala b/src/main/scala/li/cil/oc/common/block/traits/SpecialBlock.scala index 242b5a037..90ae39232 100644 --- a/src/main/scala/li/cil/oc/common/block/traits/SpecialBlock.scala +++ b/src/main/scala/li/cil/oc/common/block/traits/SpecialBlock.scala @@ -5,8 +5,6 @@ import net.minecraft.world.IBlockAccess import net.minecraftforge.common.util.ForgeDirection trait SpecialBlock extends SimpleBlock { - override def isNormalCube(world: IBlockAccess, x: Int, y: Int, z: Int) = false - override def isOpaqueCube = false override def renderAsNormalBlock = false From cf8adae113d7361775a3854050fe8a9eadf199d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Mon, 19 Jan 2015 21:29:49 +0100 Subject: [PATCH 37/61] Corrected echo manpage to not assume besh. Closes #835. --- .../resources/assets/opencomputers/loot/OpenOS/usr/man/echo | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/resources/assets/opencomputers/loot/OpenOS/usr/man/echo b/src/main/resources/assets/opencomputers/loot/OpenOS/usr/man/echo index b6337a2b1..d867b58e6 100644 --- a/src/main/resources/assets/opencomputers/loot/OpenOS/usr/man/echo +++ b/src/main/resources/assets/opencomputers/loot/OpenOS/usr/man/echo @@ -9,7 +9,7 @@ DESCRIPTION EXAMPLES echo test - Print `test` to the terminal. + Print `test` to the standard output (which is usually the terminal). - echo "a b" > test - Writes the string `a b` to the standard output, which is redirected into file `test`. \ No newline at end of file + echo "a b" + Writes the string `a b`. \ No newline at end of file From d3918d39dc61c15abb85830e72bf9e334abeb865 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Mon, 19 Jan 2015 23:41:14 +0100 Subject: [PATCH 38/61] Let me herp you all about my derps. --- src/main/scala/li/cil/oc/common/block/SimpleBlock.scala | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/scala/li/cil/oc/common/block/SimpleBlock.scala b/src/main/scala/li/cil/oc/common/block/SimpleBlock.scala index bae903a2b..6d9ae64bc 100644 --- a/src/main/scala/li/cil/oc/common/block/SimpleBlock.scala +++ b/src/main/scala/li/cil/oc/common/block/SimpleBlock.scala @@ -247,8 +247,6 @@ class SimpleBlock(material: Material = Material.iron) extends Block(material) { def isProvidingWeakPower(world: IBlockAccess, x: Int, y: Int, z: Int, side: ForgeDirection) = 0 - override def shouldCheckWeakPower(world: IBlockAccess, x: Int, y: Int, z: Int, side: Int) = true - // ----------------------------------------------------------------------- // // NOTE: must not be final for immibis microblocks to work. From 19e39a2f1346df7a002791fe64a83928a02db1b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Mon, 19 Jan 2015 23:43:00 +0100 Subject: [PATCH 39/61] Extended implementation of switch CC peripheral to properly "fake" connected modems (all the remote stuffs). This means CC can now call methods on OC peripherals \o/ --- .../computercraft/SwitchPeripheral.scala | 143 ++++++++++++++---- 1 file changed, 116 insertions(+), 27 deletions(-) diff --git a/src/main/scala/li/cil/oc/integration/computercraft/SwitchPeripheral.scala b/src/main/scala/li/cil/oc/integration/computercraft/SwitchPeripheral.scala index a5ed79c98..c8d07ccd5 100644 --- a/src/main/scala/li/cil/oc/integration/computercraft/SwitchPeripheral.scala +++ b/src/main/scala/li/cil/oc/integration/computercraft/SwitchPeripheral.scala @@ -5,13 +5,90 @@ import dan200.computercraft.api.peripheral.IComputerAccess import dan200.computercraft.api.peripheral.IPeripheral import li.cil.oc.Settings import li.cil.oc.api +import li.cil.oc.api.machine.Context +import li.cil.oc.api.network.Component import li.cil.oc.common.tileentity.AccessPoint import li.cil.oc.common.tileentity.Switch import li.cil.oc.util.ResultWrapper._ +import net.minecraftforge.common.util.ForgeDirection +import scala.collection.convert.WrapAsJava._ +import scala.collection.convert.WrapAsScala._ import scala.collection.mutable class SwitchPeripheral(val switch: Switch) extends IPeripheral { + private val methods = Map[String, (IComputerAccess, ILuaContext, Array[AnyRef]) => Array[AnyRef]]( + // Generic modem methods. + "open" -> ((computer, context, arguments) => { + val port = checkPort(arguments, 0) + if (switch.openPorts(computer).size >= 128) + throw new IllegalArgumentException("too many open channels") + result(switch.openPorts(computer).add(port)) + }), + "isOpen" -> ((computer, context, arguments) => { + val port = checkPort(arguments, 0) + result(switch.openPorts(computer).contains(port)) + }), + "close" -> ((computer, context, arguments) => { + val port = checkPort(arguments, 0) + result(switch.openPorts(computer).remove(port)) + }), + "closeAll" -> ((computer, context, arguments) => { + switch.openPorts(computer).clear() + null + }), + "transmit" -> ((computer, context, arguments) => { + val sendPort = checkPort(arguments, 0) + val answerPort = checkPort(arguments, 1) + val data = Seq(Int.box(answerPort)) ++ arguments.drop(2) + val packet = api.Network.newPacket(s"cc${computer.getID}_${computer.getAttachmentName}", null, sendPort, data.toArray) + result(switch.tryEnqueuePacket(None, packet)) + }), + "isWireless" -> ((computer, context, arguments) => { + result(switch.isInstanceOf[AccessPoint]) + }), + + // Undocumented modem messages. + "callRemote" -> ((computer, context, arguments) => { + val address = checkString(arguments, 0) + visibleComponents.find(_.address == address) match { + case Some(component) => + val method = checkString(arguments, 1) + val fakeContext = new CCContext(computer, context) + component.invoke(method, fakeContext, arguments.drop(2): _*) + case _ => null + } + }), + "getMethodsRemote" -> ((computer, context, arguments) => { + val address = checkString(arguments, 0) + visibleComponents.find(_.address == address) match { + case Some(component) => result(mapAsJavaMap(component.methods.zipWithIndex.map(t => (t._2 + 1, t._1)).toMap)) + case _ => null + } + }), + "getNamesRemote" -> ((computer, context, arguments) => { + result(mapAsJavaMap(visibleComponents.map(_.address).zipWithIndex.map(t => (t._2 + 1, t._1)).toMap)) + }), + "getTypeRemote" -> ((computer, context, arguments) => { + val address = checkString(arguments, 0) + visibleComponents.find(_.address == address) match { + case Some(component) => result(component.name) + case _ => null + } + }), + "isPresentRemote" -> ((computer, context, arguments) => { + val address = checkString(arguments, 0) + result(visibleComponents.exists(_.address == address)) + }), + + // OC specific. + "maxPacketSize" -> ((computer, context, arguments) => { + result(Settings.get.maxNetworkPacketSize) + }) + ) + + private val methodNames = methods.keys.toArray.sorted + override def getType = "modem" override def attach(computer: IComputerAccess) { @@ -24,34 +101,9 @@ class SwitchPeripheral(val switch: Switch) extends IPeripheral { switch.openPorts -= computer } - override def getMethodNames = Array("open", "isOpen", "close", "closeAll", "maxPacketSize", "transmit", "isWireless") + override def getMethodNames = methodNames - override def callMethod(computer: IComputerAccess, context: ILuaContext, method: Int, arguments: Array[AnyRef]) = getMethodNames()(method) match { - case "open" => - val port = checkPort(arguments, 0) - if (switch.openPorts(computer).size >= 128) - throw new IllegalArgumentException("too many open channels") - result(switch.openPorts(computer).add(port)) - case "isOpen" => - val port = checkPort(arguments, 0) - result(switch.openPorts(computer).contains(port)) - case "close" => - val port = checkPort(arguments, 0) - result(switch.openPorts(computer).remove(port)) - case "closeAll" => - switch.openPorts(computer).clear() - null - case "maxPacketSize" => - result(Settings.get.maxNetworkPacketSize) - case "transmit" => - val sendPort = checkPort(arguments, 0) - val answerPort = checkPort(arguments, 1) - val data = Seq(Int.box(answerPort)) ++ arguments.drop(2) - val packet = api.Network.newPacket(s"cc${computer.getID}_${computer.getAttachmentName}", null, sendPort, data.toArray) - result(switch.tryEnqueuePacket(None, packet)) - case "isWireless" => result(switch.isInstanceOf[AccessPoint]) - case _ => null - } + override def callMethod(computer: IComputerAccess, context: ILuaContext, method: Int, arguments: Array[AnyRef]) = methods(methodNames(method))(computer, context, arguments) override def equals(other: IPeripheral) = other match { case peripheral: SwitchPeripheral => peripheral.switch == switch @@ -66,4 +118,41 @@ class SwitchPeripheral(val switch: Switch) extends IPeripheral { throw new IllegalArgumentException(s"bad argument #${index + 1} (number in [1, 65535] expected)") port } + + private def checkString(args: Array[AnyRef], index: Int) = { + if (args.length < index - 1 || !args(index).isInstanceOf[String]) + throw new IllegalArgumentException(s"bad argument #${index + 1} (string expected)") + args(index).asInstanceOf[String] + } + + private def visibleComponents = { + ForgeDirection.VALID_DIRECTIONS.flatMap(side => { + val node = switch.sidedNode(side) + node.reachableNodes.collect { + case component: Component if component.canBeSeenFrom(node) => component + } + }) + } + + class CCContext(val computer: IComputerAccess, val context: ILuaContext) extends Context { + override def node() = switch.node + + override def isPaused = false + + override def stop() = false + + override def canInteract(player: String) = true + + override def signal(name: String, args: AnyRef*) = { + computer.queueEvent(name, args.toArray) + true + } + + override def pause(seconds: Double) = false + + override def isRunning = true + + override def start() = false + } + } From 3a217d830d7a55b48cdfffd73d3b72f83fff53c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Tue, 20 Jan 2015 00:59:51 +0100 Subject: [PATCH 40/61] Test thinger for #834. --- src/main/scala/li/cil/oc/server/component/robot/Player.scala | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/scala/li/cil/oc/server/component/robot/Player.scala b/src/main/scala/li/cil/oc/server/component/robot/Player.scala index 01846be27..8efa4d8b9 100644 --- a/src/main/scala/li/cil/oc/server/component/robot/Player.scala +++ b/src/main/scala/li/cil/oc/server/component/robot/Player.scala @@ -304,6 +304,11 @@ class Player(val robot: tileentity.Robot) extends FakePlayer(robot.world.asInsta if (cobwebOverride) Settings.get.swingDelay else hardness * 1.5 / strength + // TODO Remove before release (how much that I'll forget about it?) + if (breakTime > 10) { + OpenComputers.log.info(s"Slow block break: block=${block.getUnlocalizedName}, meta=$metadata, hardness=$hardness, strength=$strength, time=$breakTime") + } + val preEvent = new RobotBreakBlockEvent.Pre(robot, world, x, y, z, breakTime * Settings.get.harvestRatio) MinecraftForge.EVENT_BUS.post(preEvent) if (preEvent.isCanceled) return 0 From 5679150b8067924a8dd941b77df0b1caca302943 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Tue, 20 Jan 2015 12:56:25 +0100 Subject: [PATCH 41/61] Make block breaking fail when we're too weak (strength is zero). Fixes #834. --- src/main/scala/li/cil/oc/server/component/robot/Player.scala | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/main/scala/li/cil/oc/server/component/robot/Player.scala b/src/main/scala/li/cil/oc/server/component/robot/Player.scala index 8efa4d8b9..bdb826e95 100644 --- a/src/main/scala/li/cil/oc/server/component/robot/Player.scala +++ b/src/main/scala/li/cil/oc/server/component/robot/Player.scala @@ -304,10 +304,7 @@ class Player(val robot: tileentity.Robot) extends FakePlayer(robot.world.asInsta if (cobwebOverride) Settings.get.swingDelay else hardness * 1.5 / strength - // TODO Remove before release (how much that I'll forget about it?) - if (breakTime > 10) { - OpenComputers.log.info(s"Slow block break: block=${block.getUnlocalizedName}, meta=$metadata, hardness=$hardness, strength=$strength, time=$breakTime") - } + if (breakTime.isInfinity) return 0 val preEvent = new RobotBreakBlockEvent.Pre(robot, world, x, y, z, breakTime * Settings.get.harvestRatio) MinecraftForge.EVENT_BUS.post(preEvent) From 49197c57b19f378fb49509e740a4c9963b19f4de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Wed, 21 Jan 2015 19:49:42 +0100 Subject: [PATCH 42/61] Fixed miniscule chance of items breaking in disassembler even when chance was set to zero (see #839). --- src/main/scala/li/cil/oc/common/tileentity/Disassembler.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/li/cil/oc/common/tileentity/Disassembler.scala b/src/main/scala/li/cil/oc/common/tileentity/Disassembler.scala index 7c888db78..ec73ce0d9 100644 --- a/src/main/scala/li/cil/oc/common/tileentity/Disassembler.scala +++ b/src/main/scala/li/cil/oc/common/tileentity/Disassembler.scala @@ -79,7 +79,7 @@ class Disassembler extends traits.Environment with traits.PowerAcceptor with tra if (buffer >= Settings.get.disassemblerItemCost) { buffer -= Settings.get.disassemblerItemCost val stack = queue.remove(0) - if (world.rand.nextDouble > Settings.get.disassemblerBreakChance) { + if (world.rand.nextDouble >= Settings.get.disassemblerBreakChance) { drop(stack) } } From 60c97140d9cb10f68f540ecfc8b29d0efd498404 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Wed, 21 Jan 2015 21:46:29 +0100 Subject: [PATCH 43/61] Make disassembler finish disassembly of added item immediately if added by a player in creative mode. Closes #839. --- .../oc/common/container/ComponentSlot.scala | 9 ++++++ .../oc/common/tileentity/Disassembler.scala | 29 ++++++++++++++++--- .../tileentity/traits/PlayerInputAware.scala | 14 +++++++++ 3 files changed, 48 insertions(+), 4 deletions(-) create mode 100644 src/main/scala/li/cil/oc/common/tileentity/traits/PlayerInputAware.scala diff --git a/src/main/scala/li/cil/oc/common/container/ComponentSlot.scala b/src/main/scala/li/cil/oc/common/container/ComponentSlot.scala index b7cde9ff1..29dd46492 100644 --- a/src/main/scala/li/cil/oc/common/container/ComponentSlot.scala +++ b/src/main/scala/li/cil/oc/common/container/ComponentSlot.scala @@ -36,6 +36,15 @@ trait ComponentSlot extends Slot { } } + override def putStack(stack: ItemStack): Unit = { + super.putStack(stack) + inventory match { + case playerAware: common.tileentity.traits.PlayerInputAware => + playerAware.onSetInventorySlotContents(container.playerInventory.player, getSlotIndex, stack) + case _ => + } + } + override def onSlotChanged() { super.onSlotChanged() for (slot <- container.inventorySlots) slot match { diff --git a/src/main/scala/li/cil/oc/common/tileentity/Disassembler.scala b/src/main/scala/li/cil/oc/common/tileentity/Disassembler.scala index ec73ce0d9..d7424db6b 100644 --- a/src/main/scala/li/cil/oc/common/tileentity/Disassembler.scala +++ b/src/main/scala/li/cil/oc/common/tileentity/Disassembler.scala @@ -13,6 +13,7 @@ import li.cil.oc.util.BlockPosition import li.cil.oc.util.ExtendedNBT._ import li.cil.oc.util.InventoryUtils import li.cil.oc.util.ItemUtils +import net.minecraft.entity.player.EntityPlayer import net.minecraft.item.ItemStack import net.minecraft.nbt.NBTTagCompound import net.minecraftforge.common.util.Constants.NBT @@ -20,7 +21,7 @@ import net.minecraftforge.common.util.ForgeDirection import scala.collection.mutable -class Disassembler extends traits.Environment with traits.PowerAcceptor with traits.Inventory with traits.StateAware { +class Disassembler extends traits.Environment with traits.PowerAcceptor with traits.Inventory with traits.StateAware with traits.PlayerInputAware { val node = api.Network.newNode(this, Visibility.None). withConnector(Settings.get.bufferConverter). create() @@ -33,6 +34,8 @@ class Disassembler extends traits.Environment with traits.PowerAcceptor with tra var buffer = 0.0 + var disassembleNextInstantly = false + def progress = if (queue.isEmpty) 0 else (1 - (queue.size * Settings.get.disassemblerItemCost - buffer) / totalRequiredEnergy) * 100 private def setActive(value: Boolean) = if (value != isActive) { @@ -64,7 +67,8 @@ class Disassembler extends traits.Environment with traits.PowerAcceptor with tra super.updateEntity() if (world.getTotalWorldTime % Settings.get.tickFrequency == 0) { if (queue.isEmpty) { - disassemble(decrStackSize(0, 1)) + val instant = disassembleNextInstantly // Is reset via decrStackSize + disassemble(decrStackSize(0, 1), instant) setActive(queue.nonEmpty) } else { @@ -76,7 +80,7 @@ class Disassembler extends traits.Environment with traits.PowerAcceptor with tra buffer += want } } - if (buffer >= Settings.get.disassemblerItemCost) { + while (buffer >= Settings.get.disassemblerItemCost && queue.nonEmpty) { buffer -= Settings.get.disassemblerItemCost val stack = queue.remove(0) if (world.rand.nextDouble >= Settings.get.disassemblerBreakChance) { @@ -87,7 +91,7 @@ class Disassembler extends traits.Environment with traits.PowerAcceptor with tra } } - def disassemble(stack: ItemStack) { + def disassemble(stack: ItemStack, instant: Boolean = false) { // Validate the item, never trust Minecraft / other Mods on anything! if (stack != null && isItemValidForSlot(0, stack)) { val ingredients = ItemUtils.getIngredients(stack) @@ -99,6 +103,10 @@ class Disassembler extends traits.Environment with traits.PowerAcceptor with tra case _ => queue ++= ingredients } totalRequiredEnergy = queue.size * Settings.get.disassemblerItemCost + if (instant) { + buffer = totalRequiredEnergy + disassembleNextInstantly = false // Just to be sure... + } } } @@ -152,4 +160,17 @@ class Disassembler extends traits.Environment with traits.PowerAcceptor with tra override def isItemValidForSlot(i: Int, stack: ItemStack) = ((Settings.get.disassembleAllTheThings || api.Items.get(stack) != null) && ItemUtils.getIngredients(stack).nonEmpty) || DisassemblerTemplates.select(stack) != None + + override def setInventorySlotContents(slot: Int, stack: ItemStack): Unit = { + super.setInventorySlotContents(slot, stack) + if (!world.isRemote) { + disassembleNextInstantly = false + } + } + + override def onSetInventorySlotContents(player: EntityPlayer, slot: Int, stack: ItemStack): Unit = { + if (!world.isRemote) { + disassembleNextInstantly = stack != null && slot == 0 && player.capabilities.isCreativeMode + } + } } diff --git a/src/main/scala/li/cil/oc/common/tileentity/traits/PlayerInputAware.scala b/src/main/scala/li/cil/oc/common/tileentity/traits/PlayerInputAware.scala new file mode 100644 index 000000000..7701b48b0 --- /dev/null +++ b/src/main/scala/li/cil/oc/common/tileentity/traits/PlayerInputAware.scala @@ -0,0 +1,14 @@ +package li.cil.oc.common.tileentity.traits + +import net.minecraft.entity.player.EntityPlayer +import net.minecraft.inventory.IInventory +import net.minecraft.item.ItemStack + +// Used to get notifications from containers when a player changes a slot in +// this inventory. Normally the player causing a setInventorySlotContents is +// unavailable. Using this we gain access to the causing player, allowing for +// some player-specific logic, such as the disassembler working instantaneously +// when used by a player in creative mode. +trait PlayerInputAware extends IInventory { + def onSetInventorySlotContents(player: EntityPlayer, slot: Int, stack: ItemStack): Unit +} From fe4f63dc23eaf95dc0cd26425daee0bf4901c784 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Thu, 22 Jan 2015 16:24:36 +0100 Subject: [PATCH 44/61] Fixed AE2 integration's getCraftables returning stored stacks; now properly returning recipe output stacks (mostly noticeable in the stack size of a craftable). Closes #841. --- .../cil/oc/integration/appeng/DriverController.scala | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/main/scala/li/cil/oc/integration/appeng/DriverController.scala b/src/main/scala/li/cil/oc/integration/appeng/DriverController.scala index abe2a6180..75037560f 100644 --- a/src/main/scala/li/cil/oc/integration/appeng/DriverController.scala +++ b/src/main/scala/li/cil/oc/integration/appeng/DriverController.scala @@ -63,9 +63,17 @@ object DriverController extends DriverTileEntity with EnvironmentAware { "busy" -> cpu.isBusy))) @Callback(doc = "function():table -- Get a list of known item recipes. These can be used to issue crafting requests.") - def getCraftables(context: Context, args: Arguments): Array[AnyRef] = + def getCraftables(context: Context, args: Arguments): Array[AnyRef] = { result(tileEntity.getProxy.getStorage.getItemInventory.getStorageList. - filter(_.isCraftable).map(new Craftable(tileEntity, _)).toArray) + filter(_.isCraftable).map(stack => { + val patterns = tileEntity.getProxy.getCrafting.getCraftingFor(stack, null, 0, tileEntity.getWorld) + val result = patterns.find(pattern => pattern.getOutputs.exists(_.isSameType(stack))) match { + case Some(pattern) => pattern.getOutputs.find(_.isSameType(stack)).get + case _ => stack.copy.setStackSize(0) // Should not be possible, but hey... + } + new Craftable(tileEntity, result) + }).toArray) + } @Callback(doc = "function():table -- Get a list of the stored items in the network.") def getItemsInNetwork(context: Context, args: Arguments): Array[AnyRef] = From dfa9633491946be7a4c449e28f107a4ada06a8a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Thu, 22 Jan 2015 21:02:46 +0100 Subject: [PATCH 45/61] Raid blocks will now keep their inventory when broken, allowing relocation without losing their data. --- .../scala/li/cil/oc/common/EventHandler.scala | 5 +- .../scala/li/cil/oc/common/block/Item.scala | 4 +- .../cil/oc/common/block/Microcontroller.scala | 43 +-- .../scala/li/cil/oc/common/block/Raid.scala | 47 ++- .../cil/oc/common/block/RobotAfterimage.scala | 4 +- .../li/cil/oc/common/block/RobotProxy.scala | 6 +- .../oc/common/block/traits/CustomDrops.scala | 46 +++ .../scala/li/cil/oc/common/entity/Drone.scala | 24 +- .../scala/li/cil/oc/common/init/Items.scala | 9 +- .../scala/li/cil/oc/common/item/Drone.scala | 6 +- .../scala/li/cil/oc/common/item/Tablet.scala | 11 +- .../li/cil/oc/common/item/data/ItemData.scala | 26 ++ .../item/data/MicrocontrollerData.scala | 49 ++++ .../item/data/NavigationUpgradeData.scala | 47 +++ .../li/cil/oc/common/item/data/RaidData.scala | 44 +++ .../cil/oc/common/item/data/RobotData.scala | 124 ++++++++ .../cil/oc/common/item/data/TabletData.scala | 58 ++++ .../cil/oc/common/recipe/ExtendedRecipe.scala | 4 +- .../oc/common/template/DroneTemplate.scala | 5 +- .../template/MicrocontrollerTemplate.scala | 5 +- .../template/NavigationUpgradeTemplate.scala | 4 +- .../oc/common/template/RobotTemplate.scala | 7 +- .../oc/common/template/TabletTemplate.scala | 6 +- .../li/cil/oc/common/tileentity/Charger.scala | 4 +- .../common/tileentity/Microcontroller.scala | 4 +- .../li/cil/oc/common/tileentity/Raid.scala | 2 +- .../li/cil/oc/common/tileentity/Robot.scala | 4 +- .../opencomputers/DriverTablet.scala | 6 +- .../server/component/UpgradeNavigation.scala | 2 +- src/main/scala/li/cil/oc/util/ItemUtils.scala | 272 ------------------ 30 files changed, 528 insertions(+), 350 deletions(-) create mode 100644 src/main/scala/li/cil/oc/common/block/traits/CustomDrops.scala create mode 100644 src/main/scala/li/cil/oc/common/item/data/ItemData.scala create mode 100644 src/main/scala/li/cil/oc/common/item/data/MicrocontrollerData.scala create mode 100644 src/main/scala/li/cil/oc/common/item/data/NavigationUpgradeData.scala create mode 100644 src/main/scala/li/cil/oc/common/item/data/RaidData.scala create mode 100644 src/main/scala/li/cil/oc/common/item/data/RobotData.scala create mode 100644 src/main/scala/li/cil/oc/common/item/data/TabletData.scala diff --git a/src/main/scala/li/cil/oc/common/EventHandler.scala b/src/main/scala/li/cil/oc/common/EventHandler.scala index d7e32c70f..f807c3ac3 100644 --- a/src/main/scala/li/cil/oc/common/EventHandler.scala +++ b/src/main/scala/li/cil/oc/common/EventHandler.scala @@ -13,6 +13,7 @@ import li.cil.oc.api.Network import li.cil.oc.api.detail.ItemInfo import li.cil.oc.client.renderer.PetRenderer import li.cil.oc.client.{PacketSender => ClientPacketSender} +import li.cil.oc.common.item.data.MicrocontrollerData import li.cil.oc.common.tileentity.traits.power import li.cil.oc.integration.Mods import li.cil.oc.integration.util @@ -163,12 +164,12 @@ object EventHandler { didRecraft = recraft(e, mcu, stack => { // Restore EEPROM currently used in microcontroller. - new ItemUtils.MicrocontrollerData(stack).components.find(api.Items.get(_) == eeprom) + new MicrocontrollerData(stack).components.find(api.Items.get(_) == eeprom) }) || didRecraft didRecraft = recraft(e, drone, stack => { // Restore EEPROM currently used in drone. - new ItemUtils.MicrocontrollerData(stack).components.find(api.Items.get(_) == eeprom) + new MicrocontrollerData(stack).components.find(api.Items.get(_) == eeprom) }) || didRecraft // Presents? diff --git a/src/main/scala/li/cil/oc/common/block/Item.scala b/src/main/scala/li/cil/oc/common/block/Item.scala index a83ba8417..66666d44c 100644 --- a/src/main/scala/li/cil/oc/common/block/Item.scala +++ b/src/main/scala/li/cil/oc/common/block/Item.scala @@ -5,9 +5,9 @@ import java.util import li.cil.oc.Settings import li.cil.oc.api import li.cil.oc.client.KeyBindings +import li.cil.oc.common.item.data.RobotData import li.cil.oc.common.tileentity import li.cil.oc.util.ItemCosts -import li.cil.oc.util.ItemUtils import net.minecraft.block.Block import net.minecraft.entity.player.EntityPlayer import net.minecraft.item.EnumRarity @@ -60,7 +60,7 @@ class Item(value: Block) extends ItemBlock(value) { // manually before it's placed to ensure different component addresses // in the different robots, to avoid interference of screens e.g. val needsCopying = player.capabilities.isCreativeMode && api.Items.get(stack) == api.Items.get("robot") - val stackToUse = if (needsCopying) new ItemUtils.RobotData(stack).copyItemStack() else stack + val stackToUse = if (needsCopying) new RobotData(stack).copyItemStack() else stack if (super.placeBlockAt(stackToUse, player, world, x, y, z, side, hitX, hitY, hitZ, metadata)) { // If it's a rotatable block try to make it face the player. world.getTileEntity(x, y, z) match { diff --git a/src/main/scala/li/cil/oc/common/block/Microcontroller.scala b/src/main/scala/li/cil/oc/common/block/Microcontroller.scala index 5228067f9..8b7631a1b 100644 --- a/src/main/scala/li/cil/oc/common/block/Microcontroller.scala +++ b/src/main/scala/li/cil/oc/common/block/Microcontroller.scala @@ -5,11 +5,11 @@ import java.util import li.cil.oc.Settings import li.cil.oc.client.KeyBindings import li.cil.oc.common.Tier +import li.cil.oc.common.item.data.MicrocontrollerData import li.cil.oc.common.tileentity import li.cil.oc.integration.util.NEI import li.cil.oc.integration.util.Wrench import li.cil.oc.util.BlockPosition -import li.cil.oc.util.ItemUtils import li.cil.oc.util.Rarity import net.minecraft.entity.EntityLivingBase import net.minecraft.entity.player.EntityPlayer @@ -18,7 +18,9 @@ import net.minecraft.util.MovingObjectPosition import net.minecraft.world.World import net.minecraftforge.common.util.ForgeDirection -class Microcontroller extends RedstoneAware with traits.PowerAcceptor with traits.StateAware { +import scala.reflect.ClassTag + +class Microcontroller(protected implicit val tileTag: ClassTag[tileentity.Microcontroller]) extends RedstoneAware with traits.PowerAcceptor with traits.StateAware with traits.CustomDrops[tileentity.Microcontroller] { setCreativeTab(null) NEI.hide(this) @@ -39,17 +41,12 @@ class Microcontroller extends RedstoneAware with traits.PowerAcceptor with trait case _ => null } - // Custom drop logic for NBT tagged item stack. - override def getDrops(world: World, x: Int, y: Int, z: Int, metadata: Int, fortune: Int) = new java.util.ArrayList[ItemStack]() - - override def onBlockPreDestroy(world: World, x: Int, y: Int, z: Int, metadata: Int) {} - // ----------------------------------------------------------------------- // override protected def tooltipTail(metadata: Int, stack: ItemStack, player: EntityPlayer, tooltip: util.List[String], advanced: Boolean) { super.tooltipTail(metadata, stack, player, tooltip, advanced) if (KeyBindings.showExtendedTooltips) { - val info = new ItemUtils.MicrocontrollerData(stack) + val info = new MicrocontrollerData(stack) for (component <- info.components) { tooltip.add("- " + component.getDisplayName) } @@ -57,7 +54,7 @@ class Microcontroller extends RedstoneAware with traits.PowerAcceptor with trait } override def rarity(stack: ItemStack) = { - val data = new ItemUtils.MicrocontrollerData(stack) + val data = new MicrocontrollerData(stack) Rarity.byTier(data.tier) } @@ -85,26 +82,16 @@ class Microcontroller extends RedstoneAware with traits.PowerAcceptor with trait else false } - override def onBlockPlacedBy(world: World, x: Int, y: Int, z: Int, entity: EntityLivingBase, stack: ItemStack) { - super.onBlockPlacedBy(world, x, y, z, entity, stack) - if (!world.isRemote) world.getTileEntity(x, y, z) match { - case mcu: tileentity.Microcontroller => - mcu.info.load(stack) - mcu.snooperNode.changeBuffer(mcu.info.storedEnergy - mcu.snooperNode.localBuffer) - case _ => - } + override protected def doCustomInit(tileEntity: tileentity.Microcontroller, player: EntityLivingBase, stack: ItemStack): Unit = { + super.doCustomInit(tileEntity, player, stack) + tileEntity.info.load(stack) + tileEntity.snooperNode.changeBuffer(tileEntity.info.storedEnergy - tileEntity.snooperNode.localBuffer) } - override def removedByPlayer(world: World, player: EntityPlayer, x: Int, y: Int, z: Int, willHarvest: Boolean): Boolean = { - if (!world.isRemote) { - world.getTileEntity(x, y, z) match { - case mcu: tileentity.Microcontroller => - mcu.saveComponents() - mcu.info.storedEnergy = mcu.snooperNode.localBuffer.toInt - dropBlockAsItem(world, x, y, z, mcu.info.createItemStack()) - case _ => - } - } - super.removedByPlayer(world, player, x, y, z, willHarvest) + override protected def doCustomDrops(tileEntity: tileentity.Microcontroller, player: EntityPlayer, willHarvest: Boolean): Unit = { + super.doCustomDrops(tileEntity, player, willHarvest) + tileEntity.saveComponents() + tileEntity.info.storedEnergy = tileEntity.snooperNode.localBuffer.toInt + dropBlockAsItem(tileEntity.world, tileEntity.x, tileEntity.y, tileEntity.z, tileEntity.info.createItemStack()) } } diff --git a/src/main/scala/li/cil/oc/common/block/Raid.scala b/src/main/scala/li/cil/oc/common/block/Raid.scala index 321958eaa..7c32128e3 100644 --- a/src/main/scala/li/cil/oc/common/block/Raid.scala +++ b/src/main/scala/li/cil/oc/common/block/Raid.scala @@ -1,10 +1,19 @@ package li.cil.oc.common.block +import java.util + +import li.cil.oc.client.KeyBindings import li.cil.oc.common.GuiType +import li.cil.oc.common.item.data.RaidData import li.cil.oc.common.tileentity +import net.minecraft.entity.EntityLivingBase +import net.minecraft.entity.player.EntityPlayer +import net.minecraft.item.ItemStack import net.minecraft.world.World -class Raid extends SimpleBlock with traits.GUI { +import scala.reflect.ClassTag + +class Raid(protected implicit val tileTag: ClassTag[tileentity.Raid]) extends SimpleBlock with traits.GUI with traits.CustomDrops[tileentity.Raid] { override protected def customTextures = Array( None, None, @@ -16,6 +25,18 @@ class Raid extends SimpleBlock with traits.GUI { // ----------------------------------------------------------------------- // + override protected def tooltipTail(metadata: Int, stack: ItemStack, player: EntityPlayer, tooltip: util.List[String], advanced: Boolean) { + super.tooltipTail(metadata, stack, player, tooltip, advanced) + if (KeyBindings.showExtendedTooltips) { + val data = new RaidData(stack) + for (disk <- data.disks) { + tooltip.add("- " + disk.getDisplayName) + } + } + } + + // ----------------------------------------------------------------------- // + override def guiType = GuiType.Raid override def hasTileEntity(metadata: Int) = true @@ -31,4 +52,28 @@ class Raid extends SimpleBlock with traits.GUI { case raid: tileentity.Raid if raid.presence.forall(ok => ok) => 15 case _ => 0 } + + override protected def doCustomInit(tileEntity: tileentity.Raid, player: EntityLivingBase, stack: ItemStack): Unit = { + super.doCustomInit(tileEntity, player, stack) + val data = new RaidData(stack) + for (i <- 0 until math.min(data.disks.length, tileEntity.getSizeInventory)) { + tileEntity.setInventorySlotContents(i, data.disks(i)) + } + data.label.foreach(tileEntity.label.setLabel) + if (!data.filesystem.hasNoTags) { + tileEntity.tryCreateRaid(data.filesystem.getCompoundTag("node").getString("address")) + tileEntity.filesystem.foreach(_.load(data.filesystem)) + } + } + + override protected def doCustomDrops(tileEntity: tileentity.Raid, player: EntityPlayer, willHarvest: Boolean): Unit = { + super.doCustomDrops(tileEntity, player, willHarvest) + val stack = createItemStack() + val data = new RaidData() + data.disks = tileEntity.items.map(_.orNull) + tileEntity.filesystem.foreach(_.save(data.filesystem)) + data.label = Option(tileEntity.label.getLabel) + data.save(stack) + dropBlockAsItem(tileEntity.world, tileEntity.x, tileEntity.y, tileEntity.z, stack) + } } diff --git a/src/main/scala/li/cil/oc/common/block/RobotAfterimage.scala b/src/main/scala/li/cil/oc/common/block/RobotAfterimage.scala index 0bc42e235..981199ffb 100644 --- a/src/main/scala/li/cil/oc/common/block/RobotAfterimage.scala +++ b/src/main/scala/li/cil/oc/common/block/RobotAfterimage.scala @@ -6,9 +6,9 @@ import cpw.mods.fml.relauncher.Side import cpw.mods.fml.relauncher.SideOnly import li.cil.oc.Settings import li.cil.oc.api +import li.cil.oc.common.item.data.RobotData import li.cil.oc.common.tileentity import li.cil.oc.integration.util.NEI -import li.cil.oc.util.ItemUtils import li.cil.oc.util.Rarity import net.minecraft.client.renderer.texture.IIconRegister import net.minecraft.entity.player.EntityPlayer @@ -52,7 +52,7 @@ class RobotAfterimage extends SimpleBlock with traits.SpecialBlock { // ----------------------------------------------------------------------- // override def rarity(stack: ItemStack) = { - val data = new ItemUtils.RobotData(stack) + val data = new RobotData(stack) Rarity.byTier(data.tier) } diff --git a/src/main/scala/li/cil/oc/common/block/RobotProxy.scala b/src/main/scala/li/cil/oc/common/block/RobotProxy.scala index 8d7042ab1..b825a14d7 100644 --- a/src/main/scala/li/cil/oc/common/block/RobotProxy.scala +++ b/src/main/scala/li/cil/oc/common/block/RobotProxy.scala @@ -9,11 +9,11 @@ import li.cil.oc.Settings import li.cil.oc.api import li.cil.oc.client.KeyBindings import li.cil.oc.common.GuiType +import li.cil.oc.common.item.data.RobotData import li.cil.oc.common.tileentity import li.cil.oc.integration.util.NEI import li.cil.oc.server.PacketSender import li.cil.oc.server.component.robot -import li.cil.oc.util.ItemUtils import li.cil.oc.util.Rarity import li.cil.oc.util.Tooltip import net.minecraft.client.renderer.texture.IIconRegister @@ -68,7 +68,7 @@ class RobotProxy extends RedstoneAware with traits.SpecialBlock with traits.Stat // ----------------------------------------------------------------------- // override def rarity(stack: ItemStack) = { - val data = new ItemUtils.RobotData(stack) + val data = new RobotData(stack) Rarity.byTier(data.tier) } @@ -84,7 +84,7 @@ class RobotProxy extends RedstoneAware with traits.SpecialBlock with traits.Stat override protected def tooltipTail(metadata: Int, stack: ItemStack, player: EntityPlayer, tooltip: util.List[String], advanced: Boolean) { super.tooltipTail(metadata, stack, player, tooltip, advanced) if (KeyBindings.showExtendedTooltips) { - val info = new ItemUtils.RobotData(stack) + val info = new RobotData(stack) val components = info.containers ++ info.components if (components.length > 0) { tooltip.addAll(Tooltip.get("Server.Components")) diff --git a/src/main/scala/li/cil/oc/common/block/traits/CustomDrops.scala b/src/main/scala/li/cil/oc/common/block/traits/CustomDrops.scala new file mode 100644 index 000000000..8a74a8897 --- /dev/null +++ b/src/main/scala/li/cil/oc/common/block/traits/CustomDrops.scala @@ -0,0 +1,46 @@ +package li.cil.oc.common.block.traits + +import java.util + +import li.cil.oc.common.block.SimpleBlock +import net.minecraft.entity.EntityLivingBase +import net.minecraft.entity.player.EntityPlayer +import net.minecraft.item.ItemStack +import net.minecraft.tileentity.TileEntity +import net.minecraft.world.World + +import scala.reflect.ClassTag + +trait CustomDrops[Tile <: TileEntity] extends SimpleBlock { + protected def tileTag: ClassTag[Tile] + + override def getDrops(world: World, x: Int, y: Int, z: Int, metadata: Int, fortune: Int): util.ArrayList[ItemStack] = new java.util.ArrayList[ItemStack]() + + override def onBlockPreDestroy(world: World, x: Int, y: Int, z: Int, metadata: Int): Unit = {} + + override def removedByPlayer(world: World, player: EntityPlayer, x: Int, y: Int, z: Int, willHarvest: Boolean): Boolean = { + if (!world.isRemote) { + val matcher = tileTag + world.getTileEntity(x, y, z) match { + case matcher(tileEntity) => doCustomDrops(tileEntity, player, willHarvest) + case _ => + } + } + super.removedByPlayer(world, player, x, y, z, willHarvest) + } + + override def onBlockPlacedBy(world: World, x: Int, y: Int, z: Int, player: EntityLivingBase, stack: ItemStack): Unit = { + super.onBlockPlacedBy(world, x, y, z, player, stack) + if (!world.isRemote) { + val matcher = tileTag + world.getTileEntity(x, y, z) match { + case matcher(tileEntity) => doCustomInit(tileEntity, player, stack) + case _ => + } + } + } + + protected def doCustomInit(tileEntity: Tile, player: EntityLivingBase, stack: ItemStack): Unit = {} + + protected def doCustomDrops(tileEntity: Tile, player: EntityPlayer, willHarvest: Boolean): Unit = {} +} diff --git a/src/main/scala/li/cil/oc/common/entity/Drone.scala b/src/main/scala/li/cil/oc/common/entity/Drone.scala index eb1925db3..a42ae9be4 100644 --- a/src/main/scala/li/cil/oc/common/entity/Drone.scala +++ b/src/main/scala/li/cil/oc/common/entity/Drone.scala @@ -20,12 +20,12 @@ import li.cil.oc.common.Slot import li.cil.oc.common.inventory.ComponentInventory import li.cil.oc.common.inventory.Inventory import li.cil.oc.common.inventory.MultiTank +import li.cil.oc.common.item.data.MicrocontrollerData import li.cil.oc.server.component import li.cil.oc.util.BlockPosition import li.cil.oc.util.ExtendedNBT._ import li.cil.oc.util.ExtendedWorld._ import li.cil.oc.util.InventoryUtils -import li.cil.oc.util.ItemUtils import net.minecraft.block.material.Material import net.minecraft.entity.Entity import net.minecraft.entity.item.EntityItem @@ -62,7 +62,7 @@ class Drone(val world: World) extends Entity(world) with MachineHost with intern var lastEnergyUpdate = 0 // Logic stuff, components, machine and such. - val info = new ItemUtils.MicrocontrollerData() + val info = new MicrocontrollerData() val machine = if (!world.isRemote) { val m = Machine.create(this) m.node.asInstanceOf[Connector].setLocalBufferSize(0) @@ -276,28 +276,48 @@ class Drone(val world: World) extends Entity(world) with MachineHost with intern } def isRunning = dataWatcher.getWatchableObjectByte(2) != 0 + def targetX = dataWatcher.getWatchableObjectFloat(3) + def targetY = dataWatcher.getWatchableObjectFloat(4) + def targetZ = dataWatcher.getWatchableObjectFloat(5) + def targetAcceleration = dataWatcher.getWatchableObjectFloat(6) + def selectedSlot = dataWatcher.getWatchableObjectByte(7) & 0xFF + def globalBuffer = dataWatcher.getWatchableObjectInt(8) + def globalBufferSize = dataWatcher.getWatchableObjectInt(9) + def statusText = dataWatcher.getWatchableObjectString(10) + def inventorySize = dataWatcher.getWatchableObjectByte(11) & 0xFF + def lightColor = dataWatcher.getWatchableObjectInt(12) def setRunning(value: Boolean) = dataWatcher.updateObject(2, byte2Byte(if (value) 1: Byte else 0: Byte)) + // Round target values to low accuracy to avoid floating point errors accumulating. def targetX_=(value: Float): Unit = dataWatcher.updateObject(3, float2Float(math.round(value * 4) / 4f)) + def targetY_=(value: Float): Unit = dataWatcher.updateObject(4, float2Float(math.round(value * 4) / 4f)) + def targetZ_=(value: Float): Unit = dataWatcher.updateObject(5, float2Float(math.round(value * 4) / 4f)) + def targetAcceleration_=(value: Float): Unit = dataWatcher.updateObject(6, float2Float(math.max(0, math.min(maxAcceleration, value)))) + def selectedSlot_=(value: Int) = dataWatcher.updateObject(7, byte2Byte(value.toByte)) + def globalBuffer_=(value: Int) = dataWatcher.updateObject(8, int2Integer(value)) + def globalBufferSize_=(value: Int) = dataWatcher.updateObject(9, int2Integer(value)) + def statusText_=(value: String) = dataWatcher.updateObject(10, Option(value).map(_.lines.map(_.take(10)).take(2).mkString("\n")).getOrElse("")) + def inventorySize_=(value: Int) = dataWatcher.updateObject(11, byte2Byte(value.toByte)) + def lightColor_=(value: Int) = dataWatcher.updateObject(12, int2Integer(value)) @SideOnly(Side.CLIENT) diff --git a/src/main/scala/li/cil/oc/common/init/Items.scala b/src/main/scala/li/cil/oc/common/init/Items.scala index df48e7b0e..65917615f 100644 --- a/src/main/scala/li/cil/oc/common/init/Items.scala +++ b/src/main/scala/li/cil/oc/common/init/Items.scala @@ -12,10 +12,11 @@ import li.cil.oc.common.block.SimpleBlock import li.cil.oc.common.item import li.cil.oc.common.item.SimpleItem import li.cil.oc.common.item.UpgradeLeash +import li.cil.oc.common.item.data.MicrocontrollerData +import li.cil.oc.common.item.data.RobotData import li.cil.oc.common.recipe.Recipes import li.cil.oc.integration.Mods import li.cil.oc.util.Color -import li.cil.oc.util.ItemUtils import net.minecraft.block.Block import net.minecraft.creativetab.CreativeTabs import net.minecraft.entity.player.EntityPlayer @@ -141,7 +142,7 @@ object Items extends ItemAPI { } def createConfiguredDrone() = { - val data = new ItemUtils.MicrocontrollerData() + val data = new MicrocontrollerData() data.tier = Tier.Four data.storedEnergy = Settings.get.bufferDrone.toInt @@ -167,7 +168,7 @@ object Items extends ItemAPI { } def createConfiguredMicrocontroller() = { - val data = new ItemUtils.MicrocontrollerData() + val data = new MicrocontrollerData() data.tier = Tier.Four data.storedEnergy = Settings.get.bufferMicrocontroller.toInt @@ -190,7 +191,7 @@ object Items extends ItemAPI { } def createConfiguredRobot() = { - val data = new ItemUtils.RobotData() + val data = new RobotData() data.name = "Creatix" data.tier = Tier.Four diff --git a/src/main/scala/li/cil/oc/common/item/Drone.scala b/src/main/scala/li/cil/oc/common/item/Drone.scala index 7e8df8a8f..3b95cf722 100644 --- a/src/main/scala/li/cil/oc/common/item/Drone.scala +++ b/src/main/scala/li/cil/oc/common/item/Drone.scala @@ -6,9 +6,9 @@ import cpw.mods.fml.relauncher.Side import cpw.mods.fml.relauncher.SideOnly import li.cil.oc.client.KeyBindings import li.cil.oc.common.entity +import li.cil.oc.common.item.data.MicrocontrollerData import li.cil.oc.integration.util.NEI import li.cil.oc.util.BlockPosition -import li.cil.oc.util.ItemUtils import li.cil.oc.util.Rarity import net.minecraft.entity.player.EntityPlayer import net.minecraft.item.ItemStack @@ -20,7 +20,7 @@ class Drone(val parent: Delegator) extends Delegate { override protected def tooltipExtended(stack: ItemStack, tooltip: util.List[String]): Unit = { if (KeyBindings.showExtendedTooltips) { - val info = new ItemUtils.MicrocontrollerData(stack) + val info = new MicrocontrollerData(stack) for (component <- info.components) { tooltip.add("- " + component.getDisplayName) } @@ -28,7 +28,7 @@ class Drone(val parent: Delegator) extends Delegate { } override def rarity(stack: ItemStack) = { - val data = new ItemUtils.MicrocontrollerData(stack) + val data = new MicrocontrollerData(stack) Rarity.byTier(data.tier) } diff --git a/src/main/scala/li/cil/oc/common/item/Tablet.scala b/src/main/scala/li/cil/oc/common/item/Tablet.scala index 414b3f9a5..b3e864005 100644 --- a/src/main/scala/li/cil/oc/common/item/Tablet.scala +++ b/src/main/scala/li/cil/oc/common/item/Tablet.scala @@ -29,10 +29,9 @@ import li.cil.oc.client.KeyBindings import li.cil.oc.common.GuiType import li.cil.oc.common.Slot import li.cil.oc.common.inventory.ComponentInventory +import li.cil.oc.common.item.data.TabletData import li.cil.oc.server.component import li.cil.oc.util.ExtendedNBT._ -import li.cil.oc.util.ItemUtils -import li.cil.oc.util.ItemUtils.TabletData import li.cil.oc.util.RotationHelper import li.cil.oc.util.Tooltip import net.minecraft.entity.Entity @@ -58,7 +57,7 @@ class Tablet(val parent: Delegator) extends Delegate { @SideOnly(Side.CLIENT) override def icon(stack: ItemStack, pass: Int) = { if (stack.hasTagCompound) { - val data = new ItemUtils.TabletData(stack) + val data = new TabletData(stack) if (data.isRunning) iconOn else iconOff } else super.icon(stack, pass) } @@ -74,7 +73,7 @@ class Tablet(val parent: Delegator) extends Delegate { override protected def tooltipExtended(stack: ItemStack, tooltip: util.List[String]): Unit = { if (KeyBindings.showExtendedTooltips) { - val info = new ItemUtils.TabletData(stack) + val info = new TabletData(stack) // Ignore/hide the screen. val components = info.items.drop(1) if (components.length > 1) { @@ -91,7 +90,7 @@ class Tablet(val parent: Delegator) extends Delegate { override def damage(stack: ItemStack) = { val nbt = stack.getTagCompound if (nbt != null) { - val data = new ItemUtils.TabletData() + val data = new TabletData() data.load(nbt) (data.maxEnergy - data.energy).toInt } @@ -101,7 +100,7 @@ class Tablet(val parent: Delegator) extends Delegate { override def maxDamage(stack: ItemStack) = { val nbt = stack.getTagCompound if (nbt != null) { - val data = new ItemUtils.TabletData() + val data = new TabletData() data.load(nbt) data.maxEnergy.toInt max 1 } diff --git a/src/main/scala/li/cil/oc/common/item/data/ItemData.scala b/src/main/scala/li/cil/oc/common/item/data/ItemData.scala new file mode 100644 index 000000000..1df64ade7 --- /dev/null +++ b/src/main/scala/li/cil/oc/common/item/data/ItemData.scala @@ -0,0 +1,26 @@ +package li.cil.oc.common.item.data + +import li.cil.oc.api.Persistable +import net.minecraft.item.ItemStack +import net.minecraft.nbt.NBTTagCompound + +object ItemData { + +} + +abstract class ItemData extends Persistable { + def load(stack: ItemStack) { + if (stack.hasTagCompound) { + // Because ItemStack's load function doesn't copy the compound tag, + // but keeps it as is, leading to oh so fun bugs! + load(stack.getTagCompound.copy().asInstanceOf[NBTTagCompound]) + } + } + + def save(stack: ItemStack) { + if (!stack.hasTagCompound) { + stack.setTagCompound(new NBTTagCompound()) + } + save(stack.getTagCompound) + } +} diff --git a/src/main/scala/li/cil/oc/common/item/data/MicrocontrollerData.scala b/src/main/scala/li/cil/oc/common/item/data/MicrocontrollerData.scala new file mode 100644 index 000000000..a8657920f --- /dev/null +++ b/src/main/scala/li/cil/oc/common/item/data/MicrocontrollerData.scala @@ -0,0 +1,49 @@ +package li.cil.oc.common.item.data + +import li.cil.oc.Settings +import li.cil.oc.api +import li.cil.oc.common.Tier +import li.cil.oc.util.ExtendedNBT._ +import li.cil.oc.util.ItemUtils +import net.minecraft.item.ItemStack +import net.minecraft.nbt.NBTTagCompound +import net.minecraftforge.common.util.Constants.NBT + +class MicrocontrollerData extends ItemData { + def this(stack: ItemStack) { + this() + load(stack) + } + + var tier = Tier.One + + var components = Array.empty[ItemStack] + + var storedEnergy = 0 + + override def load(nbt: NBTTagCompound) { + tier = nbt.getByte(Settings.namespace + "tier") + components = nbt.getTagList(Settings.namespace + "components", NBT.TAG_COMPOUND). + toArray[NBTTagCompound].map(ItemUtils.loadStack) + storedEnergy = nbt.getInteger(Settings.namespace + "storedEnergy") + } + + override def save(nbt: NBTTagCompound) { + nbt.setByte(Settings.namespace + "tier", tier.toByte) + nbt.setNewTagList(Settings.namespace + "components", components.toIterable) + nbt.setInteger(Settings.namespace + "storedEnergy", storedEnergy) + } + + def createItemStack() = { + val stack = api.Items.get("microcontroller").createItemStack(1) + save(stack) + stack + } + + def copyItemStack() = { + val stack = createItemStack() + val newInfo = new MicrocontrollerData(stack) + newInfo.save(stack) + stack + } +} diff --git a/src/main/scala/li/cil/oc/common/item/data/NavigationUpgradeData.scala b/src/main/scala/li/cil/oc/common/item/data/NavigationUpgradeData.scala new file mode 100644 index 000000000..0173c41de --- /dev/null +++ b/src/main/scala/li/cil/oc/common/item/data/NavigationUpgradeData.scala @@ -0,0 +1,47 @@ +package li.cil.oc.common.item.data + +import li.cil.oc.Settings +import li.cil.oc.util.ExtendedNBT._ +import li.cil.oc.util.ItemUtils +import net.minecraft.item.ItemMap +import net.minecraft.item.ItemStack +import net.minecraft.nbt.NBTTagCompound +import net.minecraft.world.World + +class NavigationUpgradeData extends ItemData { + def this(stack: ItemStack) { + this() + load(stack) + } + + var map = new ItemStack(net.minecraft.init.Items.filled_map) + + def mapData(world: World) = try map.getItem.asInstanceOf[ItemMap].getMapData(map, world) catch { + case _: Throwable => throw new Exception("invalid map") + } + + override def load(stack: ItemStack) { + if (stack.hasTagCompound) { + load(stack.getTagCompound.getCompoundTag(Settings.namespace + "data")) + } + } + + override def save(stack: ItemStack) { + if (!stack.hasTagCompound) { + stack.setTagCompound(new NBTTagCompound()) + } + save(stack.getCompoundTag(Settings.namespace + "data")) + } + + override def load(nbt: NBTTagCompound) { + if (nbt.hasKey(Settings.namespace + "map")) { + map = ItemUtils.loadStack(nbt.getCompoundTag(Settings.namespace + "map")) + } + } + + override def save(nbt: NBTTagCompound) { + if (map != null) { + nbt.setNewCompoundTag(Settings.namespace + "map", map.writeToNBT) + } + } +} diff --git a/src/main/scala/li/cil/oc/common/item/data/RaidData.scala b/src/main/scala/li/cil/oc/common/item/data/RaidData.scala new file mode 100644 index 000000000..b98f7b19d --- /dev/null +++ b/src/main/scala/li/cil/oc/common/item/data/RaidData.scala @@ -0,0 +1,44 @@ +package li.cil.oc.common.item.data + +import li.cil.oc.Settings +import li.cil.oc.api +import li.cil.oc.common.tileentity +import li.cil.oc.util.ExtendedNBT._ +import li.cil.oc.util.ItemUtils +import net.minecraft.item.ItemStack +import net.minecraft.nbt.NBTTagCompound +import net.minecraftforge.common.util.Constants.NBT + +class RaidData extends ItemData { + def this(stack: ItemStack) { + this() + load(stack) + } + + var disks = Array.empty[ItemStack] + + var filesystem = new NBTTagCompound() + + var label: Option[String] = None + + override def load(nbt: NBTTagCompound): Unit = { + disks = nbt.getTagList(Settings.namespace + "disks", NBT.TAG_COMPOUND). + toArray[NBTTagCompound].map(ItemUtils.loadStack) + filesystem = nbt.getCompoundTag(Settings.namespace + "filesystem") + if (nbt.hasKey(Settings.namespace + "label")) { + label = Option(nbt.getString(Settings.namespace + "label")) + } + } + + override def save(nbt: NBTTagCompound): Unit = { + nbt.setNewTagList(Settings.namespace + "disks", disks.toIterable) + nbt.setTag(Settings.namespace + "filesystem", filesystem) + label.foreach(nbt.setString(Settings.namespace + "label", _)) + } + + def createItemStack() = { + val stack = api.Items.get("raid").createItemStack(1) + save(stack) + stack + } +} diff --git a/src/main/scala/li/cil/oc/common/item/data/RobotData.scala b/src/main/scala/li/cil/oc/common/item/data/RobotData.scala new file mode 100644 index 000000000..8f3e29840 --- /dev/null +++ b/src/main/scala/li/cil/oc/common/item/data/RobotData.scala @@ -0,0 +1,124 @@ +package li.cil.oc.common.item.data + +import com.google.common.base.Charsets +import com.google.common.base.Strings +import li.cil.oc.OpenComputers +import li.cil.oc.Settings +import li.cil.oc.api +import li.cil.oc.common.init.Items +import li.cil.oc.integration.opencomputers.DriverScreen +import li.cil.oc.util.ExtendedNBT._ +import li.cil.oc.util.ItemUtils +import net.minecraft.item.ItemStack +import net.minecraft.nbt.NBTTagCompound +import net.minecraftforge.common.util.Constants.NBT + +import scala.io.Source + +object RobotData { + val names = try { + Source.fromInputStream(getClass.getResourceAsStream( + "/assets/" + Settings.resourceDomain + "/robot.names"))(Charsets.UTF_8). + getLines().map(_.takeWhile(_ != '#').trim()).filter(_ != "").toArray + } + catch { + case t: Throwable => + OpenComputers.log.warn("Failed loading robot name list.", t) + Array.empty[String] + } + + def randomName = if (names.length > 0) names((math.random * names.length).toInt) else "Robot" +} + +class RobotData extends ItemData { + def this(stack: ItemStack) { + this() + load(stack) + } + + var name = "" + + // Overall energy including components. + var totalEnergy = 0 + + // Energy purely stored in robot component - this is what we have to restore manually. + var robotEnergy = 0 + + var tier = 0 + + var components = Array.empty[ItemStack] + + var containers = Array.empty[ItemStack] + + var lightColor = 0xF23030 + + override def load(nbt: NBTTagCompound) { + if (nbt.hasKey("display") && nbt.getCompoundTag("display").hasKey("Name")) { + name = nbt.getCompoundTag("display").getString("Name") + } + if (Strings.isNullOrEmpty(name)) { + name = RobotData.randomName + } + totalEnergy = nbt.getInteger(Settings.namespace + "storedEnergy") + robotEnergy = nbt.getInteger(Settings.namespace + "robotEnergy") + tier = nbt.getInteger(Settings.namespace + "tier") + components = nbt.getTagList(Settings.namespace + "components", NBT.TAG_COMPOUND). + toArray[NBTTagCompound].map(ItemUtils.loadStack) + containers = nbt.getTagList(Settings.namespace + "containers", NBT.TAG_COMPOUND). + toArray[NBTTagCompound].map(ItemUtils.loadStack) + if (nbt.hasKey(Settings.namespace + "lightColor")) { + lightColor = nbt.getInteger(Settings.namespace + "lightColor") + } + + // Code for migrating from 1.4.1 -> 1.4.2, add EEPROM. + // TODO Remove in 1.5 + if (!nbt.hasKey(Settings.namespace + "biosFlag")) { + components :+= Items.createLuaBios() + } + } + + override def save(nbt: NBTTagCompound) { + if (!Strings.isNullOrEmpty(name)) { + if (!nbt.hasKey("display")) { + nbt.setTag("display", new NBTTagCompound()) + } + nbt.getCompoundTag("display").setString("Name", name) + } + nbt.setInteger(Settings.namespace + "storedEnergy", totalEnergy) + nbt.setInteger(Settings.namespace + "robotEnergy", robotEnergy) + nbt.setInteger(Settings.namespace + "tier", tier) + nbt.setNewTagList(Settings.namespace + "components", components.toIterable) + nbt.setNewTagList(Settings.namespace + "containers", containers.toIterable) + nbt.setInteger(Settings.namespace + "lightColor", lightColor) + + // TODO Remove in 1.5 + nbt.setBoolean(Settings.namespace + "biosFlag", true) + } + + def createItemStack() = { + val stack = api.Items.get("robot").createItemStack(1) + save(stack) + stack + } + + def copyItemStack() = { + val stack = createItemStack() + // Forget all node addresses and so on. This is used when 'picking' a + // robot in creative mode. + val newInfo = new RobotData(stack) + newInfo.components.foreach(cs => Option(api.Driver.driverFor(cs)) match { + case Some(driver) if driver == DriverScreen => + val nbt = driver.dataTag(cs) + for (tagName <- nbt.func_150296_c().toArray) { + nbt.removeTag(tagName.asInstanceOf[String]) + } + case _ => + }) + // Don't show energy info (because it's unreliable) but fill up the + // internal buffer. This is for creative use only, anyway. + newInfo.totalEnergy = 0 + newInfo.robotEnergy = 50000 + newInfo.save(stack) + stack + } +} diff --git a/src/main/scala/li/cil/oc/common/item/data/TabletData.scala b/src/main/scala/li/cil/oc/common/item/data/TabletData.scala new file mode 100644 index 000000000..fbada126b --- /dev/null +++ b/src/main/scala/li/cil/oc/common/item/data/TabletData.scala @@ -0,0 +1,58 @@ +package li.cil.oc.common.item.data + +import li.cil.oc.Settings +import li.cil.oc.common.init.Items +import li.cil.oc.util.ExtendedNBT._ +import li.cil.oc.util.ItemUtils +import net.minecraft.item.ItemStack +import net.minecraft.nbt.NBTTagCompound +import net.minecraftforge.common.util.Constants.NBT + +class TabletData extends ItemData { + def this(stack: ItemStack) { + this() + load(stack) + } + + var items = Array.fill[Option[ItemStack]](32)(None) + var isRunning = false + var energy = 0.0 + var maxEnergy = 0.0 + + override def load(nbt: NBTTagCompound) { + nbt.getTagList(Settings.namespace + "items", NBT.TAG_COMPOUND).foreach((slotNbt: NBTTagCompound) => { + val slot = slotNbt.getByte("slot") + if (slot >= 0 && slot < items.length) { + items(slot) = Option(ItemUtils.loadStack(slotNbt.getCompoundTag("item"))) + } + }) + isRunning = nbt.getBoolean(Settings.namespace + "isRunning") + energy = nbt.getDouble(Settings.namespace + "energy") + maxEnergy = nbt.getDouble(Settings.namespace + "maxEnergy") + + // Code for migrating from 1.4.1 -> 1.4.2, add EEPROM. + // TODO Remove in 1.5 + if (!nbt.hasKey(Settings.namespace + "biosFlag")) { + val firstEmpty = items.indexWhere(_.isEmpty) + items(firstEmpty) = Option(Items.createLuaBios()) + } + } + + override def save(nbt: NBTTagCompound) { + nbt.setNewTagList(Settings.namespace + "items", + items.zipWithIndex collect { + case (Some(stack), slot) => (stack, slot) + } map { + case (stack, slot) => + val slotNbt = new NBTTagCompound() + slotNbt.setByte("slot", slot.toByte) + slotNbt.setNewCompoundTag("item", stack.writeToNBT) + }) + nbt.setBoolean(Settings.namespace + "isRunning", isRunning) + nbt.setDouble(Settings.namespace + "energy", energy) + nbt.setDouble(Settings.namespace + "maxEnergy", maxEnergy) + + // TODO Remove in 1.5 + nbt.setBoolean(Settings.namespace + "biosFlag", true) + } +} diff --git a/src/main/scala/li/cil/oc/common/recipe/ExtendedRecipe.scala b/src/main/scala/li/cil/oc/common/recipe/ExtendedRecipe.scala index d1568ffed..e2a92a13d 100644 --- a/src/main/scala/li/cil/oc/common/recipe/ExtendedRecipe.scala +++ b/src/main/scala/li/cil/oc/common/recipe/ExtendedRecipe.scala @@ -6,9 +6,9 @@ import li.cil.oc.Settings import li.cil.oc.api import li.cil.oc.api.detail.ItemInfo import li.cil.oc.common.init.Items +import li.cil.oc.common.item.data.MicrocontrollerData import li.cil.oc.integration.Mods import li.cil.oc.util.ExtendedNBT._ -import li.cil.oc.util.ItemUtils import li.cil.oc.util.SideTracker import net.minecraft.init.Blocks import net.minecraft.inventory.InventoryCrafting @@ -97,7 +97,7 @@ object ExtendedRecipe { // Find old Microcontroller. (0 until inventory.getSizeInventory).map(inventory.getStackInSlot).find(api.Items.get(_) == descriptor) match { case Some(oldMcu) => - val data = new ItemUtils.MicrocontrollerData(oldMcu) + val data = new MicrocontrollerData(oldMcu) // Remove old EEPROM. val oldRom = data.components.filter(api.Items.get(_) == eeprom) diff --git a/src/main/scala/li/cil/oc/common/template/DroneTemplate.scala b/src/main/scala/li/cil/oc/common/template/DroneTemplate.scala index 64c9b9ef3..fada5345c 100644 --- a/src/main/scala/li/cil/oc/common/template/DroneTemplate.scala +++ b/src/main/scala/li/cil/oc/common/template/DroneTemplate.scala @@ -6,6 +6,7 @@ import li.cil.oc.api import li.cil.oc.api.internal import li.cil.oc.common.Slot import li.cil.oc.common.Tier +import li.cil.oc.common.item.data.MicrocontrollerData import li.cil.oc.util.ExtendedNBT._ import li.cil.oc.util.ItemUtils import net.minecraft.inventory.IInventory @@ -29,7 +30,7 @@ object DroneTemplate extends Template { def assemble(inventory: IInventory) = { val items = (0 until inventory.getSizeInventory).map(inventory.getStackInSlot) - val data = new ItemUtils.MicrocontrollerData() + val data = new MicrocontrollerData() data.tier = caseTier(inventory) data.components = items.drop(1).filter(_ != null).toArray data.storedEnergy = Settings.get.bufferDrone.toInt @@ -43,7 +44,7 @@ object DroneTemplate extends Template { def selectDisassembler(stack: ItemStack) = api.Items.get(stack) == api.Items.get("drone") def disassemble(stack: ItemStack, ingredients: Array[ItemStack]) = { - val info = new ItemUtils.MicrocontrollerData(stack) + val info = new MicrocontrollerData(stack) val itemName = ItemUtils.caseNameWithTierSuffix("droneCase", info.tier) Array(api.Items.get(itemName).createItemStack(1)) ++ info.components diff --git a/src/main/scala/li/cil/oc/common/template/MicrocontrollerTemplate.scala b/src/main/scala/li/cil/oc/common/template/MicrocontrollerTemplate.scala index ed8a7c6f2..4bbfe4080 100644 --- a/src/main/scala/li/cil/oc/common/template/MicrocontrollerTemplate.scala +++ b/src/main/scala/li/cil/oc/common/template/MicrocontrollerTemplate.scala @@ -6,6 +6,7 @@ import li.cil.oc.api import li.cil.oc.api.internal import li.cil.oc.common.Slot import li.cil.oc.common.Tier +import li.cil.oc.common.item.data.MicrocontrollerData import li.cil.oc.util.ExtendedNBT._ import li.cil.oc.util.ItemUtils import net.minecraft.inventory.IInventory @@ -29,7 +30,7 @@ object MicrocontrollerTemplate extends Template { def assemble(inventory: IInventory) = { val items = (0 until inventory.getSizeInventory).map(inventory.getStackInSlot) - val data = new ItemUtils.MicrocontrollerData() + val data = new MicrocontrollerData() data.tier = caseTier(inventory) data.components = items.drop(1).filter(_ != null).toArray data.storedEnergy = Settings.get.bufferMicrocontroller.toInt @@ -43,7 +44,7 @@ object MicrocontrollerTemplate extends Template { def selectDisassembler(stack: ItemStack) = api.Items.get(stack) == api.Items.get("microcontroller") def disassemble(stack: ItemStack, ingredients: Array[ItemStack]) = { - val info = new ItemUtils.MicrocontrollerData(stack) + val info = new MicrocontrollerData(stack) val itemName = ItemUtils.caseNameWithTierSuffix("microcontrollerCase", info.tier) Array(api.Items.get(itemName).createItemStack(1)) ++ info.components diff --git a/src/main/scala/li/cil/oc/common/template/NavigationUpgradeTemplate.scala b/src/main/scala/li/cil/oc/common/template/NavigationUpgradeTemplate.scala index 282eac6c1..a98635f02 100644 --- a/src/main/scala/li/cil/oc/common/template/NavigationUpgradeTemplate.scala +++ b/src/main/scala/li/cil/oc/common/template/NavigationUpgradeTemplate.scala @@ -2,7 +2,7 @@ package li.cil.oc.common.template import cpw.mods.fml.common.event.FMLInterModComms import li.cil.oc.api -import li.cil.oc.util.ItemUtils +import li.cil.oc.common.item.data.NavigationUpgradeData import net.minecraft.item.ItemStack import net.minecraft.nbt.NBTTagCompound @@ -12,7 +12,7 @@ object NavigationUpgradeTemplate { def selectDisassembler(stack: ItemStack) = api.Items.get(stack) == api.Items.get("navigationUpgrade") def disassemble(stack: ItemStack, ingredients: Array[ItemStack]) = { - val info = new ItemUtils.NavigationUpgradeData(stack) + val info = new NavigationUpgradeData(stack) ingredients.map { case part if part.getItem == net.minecraft.init.Items.filled_map => info.map case part => part diff --git a/src/main/scala/li/cil/oc/common/template/RobotTemplate.scala b/src/main/scala/li/cil/oc/common/template/RobotTemplate.scala index 852cf69d2..08890dc45 100644 --- a/src/main/scala/li/cil/oc/common/template/RobotTemplate.scala +++ b/src/main/scala/li/cil/oc/common/template/RobotTemplate.scala @@ -6,6 +6,7 @@ import li.cil.oc.api import li.cil.oc.api.internal import li.cil.oc.common.Slot import li.cil.oc.common.Tier +import li.cil.oc.common.item.data.RobotData import li.cil.oc.util.ExtendedNBT._ import li.cil.oc.util.ItemUtils import net.minecraft.inventory.IInventory @@ -28,9 +29,9 @@ object RobotTemplate extends Template { def assemble(inventory: IInventory) = { val items = (0 until inventory.getSizeInventory).map(inventory.getStackInSlot) - val data = new ItemUtils.RobotData() + val data = new RobotData() data.tier = ItemUtils.caseTier(inventory.getStackInSlot(0)) - data.name = ItemUtils.RobotData.randomName + data.name = RobotData.randomName data.robotEnergy = Settings.get.bufferRobot.toInt data.totalEnergy = data.robotEnergy data.containers = items.slice(1, 4).filter(_ != null).toArray @@ -45,7 +46,7 @@ object RobotTemplate extends Template { def selectDisassembler(stack: ItemStack) = api.Items.get(stack) == api.Items.get("robot") def disassemble(stack: ItemStack, ingredients: Array[ItemStack]) = { - val info = new ItemUtils.RobotData(stack) + val info = new RobotData(stack) val itemName = ItemUtils.caseNameWithTierSuffix("case", info.tier) Array(api.Items.get(itemName).createItemStack(1)) ++ info.containers ++ info.components diff --git a/src/main/scala/li/cil/oc/common/template/TabletTemplate.scala b/src/main/scala/li/cil/oc/common/template/TabletTemplate.scala index cc6581ed0..4f0a78c1a 100644 --- a/src/main/scala/li/cil/oc/common/template/TabletTemplate.scala +++ b/src/main/scala/li/cil/oc/common/template/TabletTemplate.scala @@ -6,8 +6,8 @@ import li.cil.oc.api import li.cil.oc.api.internal import li.cil.oc.common.Slot import li.cil.oc.common.Tier +import li.cil.oc.common.item.data.TabletData import li.cil.oc.util.ExtendedNBT._ -import li.cil.oc.util.ItemUtils import net.minecraft.inventory.IInventory import net.minecraft.item.ItemStack import net.minecraft.nbt.NBTTagCompound @@ -32,7 +32,7 @@ object TabletTemplate extends Template { val items = mutable.ArrayBuffer( Option(api.Items.get("screen1").createItemStack(1)) ) ++ (1 until inventory.getSizeInventory).map(slot => Option(inventory.getStackInSlot(slot))) - val data = new ItemUtils.TabletData() + val data = new TabletData() data.items = items.filter(_.isDefined).toArray data.energy = Settings.get.bufferTablet data.maxEnergy = data.energy @@ -46,7 +46,7 @@ object TabletTemplate extends Template { def selectDisassembler(stack: ItemStack) = api.Items.get(stack) == api.Items.get("tablet") def disassemble(stack: ItemStack, ingredients: Array[ItemStack]) = { - val info = new ItemUtils.TabletData(stack) + val info = new TabletData(stack) Array(api.Items.get("tabletCase").createItemStack(1)) ++ info.items.collect { case Some(item) => item }.drop(1) // Screen. diff --git a/src/main/scala/li/cil/oc/common/tileentity/Charger.scala b/src/main/scala/li/cil/oc/common/tileentity/Charger.scala index b26cb8f03..d4ccfa3f3 100644 --- a/src/main/scala/li/cil/oc/common/tileentity/Charger.scala +++ b/src/main/scala/li/cil/oc/common/tileentity/Charger.scala @@ -12,10 +12,10 @@ import li.cil.oc.api.network._ import li.cil.oc.common.Slot import li.cil.oc.common.entity.Drone import li.cil.oc.common.item.Tablet +import li.cil.oc.common.item.data.TabletData import li.cil.oc.server.{PacketSender => ServerPacketSender} import li.cil.oc.util.BlockPosition import li.cil.oc.util.ExtendedWorld._ -import li.cil.oc.util.ItemUtils import net.minecraft.entity.player.EntityPlayer import net.minecraft.item.ItemStack import net.minecraft.nbt.NBTTagCompound @@ -100,7 +100,7 @@ class Charger extends traits.Environment with traits.PowerAcceptor with traits.R handler(itemCharge) } } - val data = new ItemUtils.TabletData(stack) + val data = new TabletData(stack) tryCharge(data.energy, data.maxEnergy, (amount) => { data.energy = math.min(data.maxEnergy, data.energy + amount) data.save(stack) diff --git a/src/main/scala/li/cil/oc/common/tileentity/Microcontroller.scala b/src/main/scala/li/cil/oc/common/tileentity/Microcontroller.scala index 10de62d08..f3a85ecaa 100644 --- a/src/main/scala/li/cil/oc/common/tileentity/Microcontroller.scala +++ b/src/main/scala/li/cil/oc/common/tileentity/Microcontroller.scala @@ -14,15 +14,15 @@ import li.cil.oc.api.machine.Context import li.cil.oc.api.network._ import li.cil.oc.common.Slot import li.cil.oc.common.Tier +import li.cil.oc.common.item.data.MicrocontrollerData import li.cil.oc.util.ExtendedNBT._ -import li.cil.oc.util.ItemUtils import net.minecraft.item.ItemStack import net.minecraft.nbt.NBTTagCompound import net.minecraftforge.common.util.ForgeDirection // TODO Remove internal.Tiered in 1.5, only here for compatibility if someone ships an older 1.4 API. class Microcontroller extends traits.PowerAcceptor with traits.Computer with SidedEnvironment with internal.Microcontroller with internal.Tiered { - val info = new ItemUtils.MicrocontrollerData() + val info = new MicrocontrollerData() override val node = api.Network.newNode(this, Visibility.Network). withComponent("microcontroller"). diff --git a/src/main/scala/li/cil/oc/common/tileentity/Raid.scala b/src/main/scala/li/cil/oc/common/tileentity/Raid.scala index 8b2df850d..da162ccab 100644 --- a/src/main/scala/li/cil/oc/common/tileentity/Raid.scala +++ b/src/main/scala/li/cil/oc/common/tileentity/Raid.scala @@ -76,7 +76,7 @@ class Raid extends traits.Environment with traits.Inventory with traits.Rotatabl } } - private def tryCreateRaid(id: String) { + def tryCreateRaid(id: String) { if (items.count(_.isDefined) == items.length) { val fs = api.FileSystem.asManagedEnvironment( api.FileSystem.fromSaveDirectory(id, wipeDisksAndComputeSpace, Settings.get.bufferChanges), diff --git a/src/main/scala/li/cil/oc/common/tileentity/Robot.scala b/src/main/scala/li/cil/oc/common/tileentity/Robot.scala index 7e1e11c71..c0a5cd84b 100644 --- a/src/main/scala/li/cil/oc/common/tileentity/Robot.scala +++ b/src/main/scala/li/cil/oc/common/tileentity/Robot.scala @@ -20,6 +20,7 @@ import li.cil.oc.common.Tier import li.cil.oc.common.inventory.InventorySelection import li.cil.oc.common.inventory.MultiTank import li.cil.oc.common.inventory.TankSelection +import li.cil.oc.common.item.data.RobotData import li.cil.oc.integration.opencomputers.DriverKeyboard import li.cil.oc.integration.opencomputers.DriverRedstoneCard import li.cil.oc.integration.opencomputers.DriverScreen @@ -30,7 +31,6 @@ import li.cil.oc.util.BlockPosition import li.cil.oc.util.ExtendedNBT._ import li.cil.oc.util.ExtendedWorld._ import li.cil.oc.util.InventoryUtils -import li.cil.oc.util.ItemUtils import net.minecraft.block.Block import net.minecraft.block.BlockLiquid import net.minecraft.client.Minecraft @@ -54,7 +54,7 @@ import scala.collection.mutable class Robot extends traits.Computer with traits.PowerInformation with IFluidHandler with internal.Robot with internal.Tiered with MultiTank with InventorySelection with TankSelection { var proxy: RobotProxy = _ - val info = new ItemUtils.RobotData() + val info = new RobotData() val bot = if (isServer) new robot.Robot(this) else null diff --git a/src/main/scala/li/cil/oc/integration/opencomputers/DriverTablet.scala b/src/main/scala/li/cil/oc/integration/opencomputers/DriverTablet.scala index 9c28a2e73..e451197e3 100644 --- a/src/main/scala/li/cil/oc/integration/opencomputers/DriverTablet.scala +++ b/src/main/scala/li/cil/oc/integration/opencomputers/DriverTablet.scala @@ -4,7 +4,7 @@ import li.cil.oc.Settings import li.cil.oc.api import li.cil.oc.api.driver.EnvironmentHost import li.cil.oc.common.Slot -import li.cil.oc.util.ItemUtils +import li.cil.oc.common.item.data.TabletData import net.minecraft.item.ItemStack import net.minecraft.nbt.NBTTagCompound import net.minecraftforge.common.util.Constants.NBT @@ -14,7 +14,7 @@ object DriverTablet extends Item { isOneOf(stack, api.Items.get("tablet")) override def createEnvironment(stack: ItemStack, host: EnvironmentHost) = { - val data = new ItemUtils.TabletData(stack) + val data = new TabletData(stack) data.items.collect { case Some(fs) if DriverFileSystem.worksWith(fs) => fs }.headOption.map(DriverFileSystem.createEnvironment(_, host)).orNull @@ -23,7 +23,7 @@ object DriverTablet extends Item { override def slot(stack: ItemStack) = Slot.Tablet override def dataTag(stack: ItemStack) = { - val data = new ItemUtils.TabletData(stack) + val data = new TabletData(stack) val index = data.items.indexWhere { case Some(fs) => DriverFileSystem.worksWith(fs) case _ => false diff --git a/src/main/scala/li/cil/oc/server/component/UpgradeNavigation.scala b/src/main/scala/li/cil/oc/server/component/UpgradeNavigation.scala index 22f639368..aefdd926a 100644 --- a/src/main/scala/li/cil/oc/server/component/UpgradeNavigation.scala +++ b/src/main/scala/li/cil/oc/server/component/UpgradeNavigation.scala @@ -8,7 +8,7 @@ import li.cil.oc.api.machine.Callback import li.cil.oc.api.machine.Context import li.cil.oc.api.network._ import li.cil.oc.api.prefab -import li.cil.oc.util.ItemUtils.NavigationUpgradeData +import li.cil.oc.common.item.data.NavigationUpgradeData import net.minecraft.nbt.NBTTagCompound class UpgradeNavigation(val host: EnvironmentHost with Rotatable) extends prefab.ManagedEnvironment { diff --git a/src/main/scala/li/cil/oc/util/ItemUtils.scala b/src/main/scala/li/cil/oc/util/ItemUtils.scala index b7589040e..9c7468468 100644 --- a/src/main/scala/li/cil/oc/util/ItemUtils.scala +++ b/src/main/scala/li/cil/oc/util/ItemUtils.scala @@ -2,33 +2,22 @@ package li.cil.oc.util import java.util.Random -import com.google.common.base.Charsets -import com.google.common.base.Strings import li.cil.oc.OpenComputers -import li.cil.oc.Settings import li.cil.oc.api -import li.cil.oc.api.Persistable import li.cil.oc.common.Tier import li.cil.oc.common.block.DelegatorConverter -import li.cil.oc.common.init.Items -import li.cil.oc.integration.opencomputers.DriverScreen -import li.cil.oc.util.ExtendedNBT._ import net.minecraft.item.ItemBucket -import net.minecraft.item.ItemMap import net.minecraft.item.ItemStack import net.minecraft.item.crafting.CraftingManager import net.minecraft.item.crafting.IRecipe import net.minecraft.item.crafting.ShapedRecipes import net.minecraft.item.crafting.ShapelessRecipes import net.minecraft.nbt.NBTTagCompound -import net.minecraft.world.World -import net.minecraftforge.common.util.Constants.NBT import net.minecraftforge.oredict.ShapedOreRecipe import net.minecraftforge.oredict.ShapelessOreRecipe import scala.collection.convert.WrapAsScala._ import scala.collection.mutable -import scala.io.Source object ItemUtils { def caseTier(stack: ItemStack) = { @@ -106,265 +95,4 @@ object ItemUtils { case list: java.util.ArrayList[ItemStack]@unchecked if !list.isEmpty => list.get(rng.nextInt(list.size)) } - abstract class ItemData extends Persistable { - def load(stack: ItemStack) { - if (stack.hasTagCompound) { - // Because ItemStack's load function doesn't copy the compound tag, - // but keeps it as is, leading to oh so fun bugs! - load(stack.getTagCompound.copy().asInstanceOf[NBTTagCompound]) - } - } - - def save(stack: ItemStack) { - if (!stack.hasTagCompound) { - stack.setTagCompound(new NBTTagCompound()) - } - save(stack.getTagCompound) - } - } - - class MicrocontrollerData extends ItemData { - def this(stack: ItemStack) { - this() - load(stack) - } - - var tier = Tier.One - - var components = Array.empty[ItemStack] - - var storedEnergy = 0 - - override def load(nbt: NBTTagCompound) { - tier = nbt.getByte(Settings.namespace + "tier") - components = nbt.getTagList(Settings.namespace + "components", NBT.TAG_COMPOUND). - toArray[NBTTagCompound].map(loadStack) - storedEnergy = nbt.getInteger(Settings.namespace + "storedEnergy") - } - - override def save(nbt: NBTTagCompound) { - nbt.setByte(Settings.namespace + "tier", tier.toByte) - nbt.setNewTagList(Settings.namespace + "components", components.toIterable) - nbt.setInteger(Settings.namespace + "storedEnergy", storedEnergy) - } - - def createItemStack() = { - val stack = api.Items.get("microcontroller").createItemStack(1) - save(stack) - stack - } - - def copyItemStack() = { - val stack = createItemStack() - // Forget all node addresses and so on. This is used when 'picking' a - // microcontroller in creative mode. - val newInfo = new MicrocontrollerData(stack) - newInfo.components.foreach(cs => Option(api.Driver.driverFor(cs)) match { - case Some(driver) if driver == DriverScreen => - val nbt = driver.dataTag(cs) - for (tagName <- nbt.func_150296_c().toArray) { - nbt.removeTag(tagName.asInstanceOf[String]) - } - case _ => - }) - newInfo.save(stack) - stack - } - } - - class NavigationUpgradeData extends ItemData { - def this(stack: ItemStack) { - this() - load(stack) - } - - var map = new ItemStack(net.minecraft.init.Items.filled_map) - - def mapData(world: World) = try map.getItem.asInstanceOf[ItemMap].getMapData(map, world) catch { - case _: Throwable => throw new Exception("invalid map") - } - - override def load(stack: ItemStack) { - if (stack.hasTagCompound) { - load(stack.getTagCompound.getCompoundTag(Settings.namespace + "data")) - } - } - - override def save(stack: ItemStack) { - if (!stack.hasTagCompound) { - stack.setTagCompound(new NBTTagCompound()) - } - save(stack.getCompoundTag(Settings.namespace + "data")) - } - - override def load(nbt: NBTTagCompound) { - if (nbt.hasKey(Settings.namespace + "map")) { - map = loadStack(nbt.getCompoundTag(Settings.namespace + "map")) - } - } - - override def save(nbt: NBTTagCompound) { - if (map != null) { - nbt.setNewCompoundTag(Settings.namespace + "map", map.writeToNBT) - } - } - } - - class RobotData extends ItemData { - def this(stack: ItemStack) { - this() - load(stack) - } - - var name = "" - - // Overall energy including components. - var totalEnergy = 0 - - // Energy purely stored in robot component - this is what we have to restore manually. - var robotEnergy = 0 - - var tier = 0 - - var components = Array.empty[ItemStack] - - var containers = Array.empty[ItemStack] - - var lightColor = 0xF23030 - - override def load(nbt: NBTTagCompound) { - if (nbt.hasKey("display") && nbt.getCompoundTag("display").hasKey("Name")) { - name = nbt.getCompoundTag("display").getString("Name") - } - if (Strings.isNullOrEmpty(name)) { - name = RobotData.randomName - } - totalEnergy = nbt.getInteger(Settings.namespace + "storedEnergy") - robotEnergy = nbt.getInteger(Settings.namespace + "robotEnergy") - tier = nbt.getInteger(Settings.namespace + "tier") - components = nbt.getTagList(Settings.namespace + "components", NBT.TAG_COMPOUND). - toArray[NBTTagCompound].map(loadStack) - containers = nbt.getTagList(Settings.namespace + "containers", NBT.TAG_COMPOUND). - toArray[NBTTagCompound].map(loadStack) - if (nbt.hasKey(Settings.namespace + "lightColor")) { - lightColor = nbt.getInteger(Settings.namespace + "lightColor") - } - - // Code for migrating from 1.4.1 -> 1.4.2, add EEPROM. - // TODO Remove in 1.5 - if (!nbt.hasKey(Settings.namespace + "biosFlag")) { - components :+= Items.createLuaBios() - } - } - - override def save(nbt: NBTTagCompound) { - if (!Strings.isNullOrEmpty(name)) { - if (!nbt.hasKey("display")) { - nbt.setTag("display", new NBTTagCompound()) - } - nbt.getCompoundTag("display").setString("Name", name) - } - nbt.setInteger(Settings.namespace + "storedEnergy", totalEnergy) - nbt.setInteger(Settings.namespace + "robotEnergy", robotEnergy) - nbt.setInteger(Settings.namespace + "tier", tier) - nbt.setNewTagList(Settings.namespace + "components", components.toIterable) - nbt.setNewTagList(Settings.namespace + "containers", containers.toIterable) - nbt.setInteger(Settings.namespace + "lightColor", lightColor) - - // TODO Remove in 1.5 - nbt.setBoolean(Settings.namespace + "biosFlag", true) - } - - def createItemStack() = { - val stack = api.Items.get("robot").createItemStack(1) - save(stack) - stack - } - - def copyItemStack() = { - val stack = createItemStack() - // Forget all node addresses and so on. This is used when 'picking' a - // robot in creative mode. - val newInfo = new RobotData(stack) - newInfo.components.foreach(cs => Option(api.Driver.driverFor(cs)) match { - case Some(driver) if driver == DriverScreen => - val nbt = driver.dataTag(cs) - for (tagName <- nbt.func_150296_c().toArray) { - nbt.removeTag(tagName.asInstanceOf[String]) - } - case _ => - }) - // Don't show energy info (because it's unreliable) but fill up the - // internal buffer. This is for creative use only, anyway. - newInfo.totalEnergy = 0 - newInfo.robotEnergy = 50000 - newInfo.save(stack) - stack - } - } - - object RobotData { - val names = try { - Source.fromInputStream(getClass.getResourceAsStream( - "/assets/" + Settings.resourceDomain + "/robot.names"))(Charsets.UTF_8). - getLines().map(_.takeWhile(_ != '#').trim()).filter(_ != "").toArray - } - catch { - case t: Throwable => - OpenComputers.log.warn("Failed loading robot name list.", t) - Array.empty[String] - } - - def randomName = if (names.length > 0) names((math.random * names.length).toInt) else "Robot" - } - - class TabletData extends ItemData { - def this(stack: ItemStack) { - this() - load(stack) - } - - var items = Array.fill[Option[ItemStack]](32)(None) - var isRunning = false - var energy = 0.0 - var maxEnergy = 0.0 - - override def load(nbt: NBTTagCompound) { - nbt.getTagList(Settings.namespace + "items", NBT.TAG_COMPOUND).foreach((slotNbt: NBTTagCompound) => { - val slot = slotNbt.getByte("slot") - if (slot >= 0 && slot < items.length) { - items(slot) = Option(loadStack(slotNbt.getCompoundTag("item"))) - } - }) - isRunning = nbt.getBoolean(Settings.namespace + "isRunning") - energy = nbt.getDouble(Settings.namespace + "energy") - maxEnergy = nbt.getDouble(Settings.namespace + "maxEnergy") - - // Code for migrating from 1.4.1 -> 1.4.2, add EEPROM. - // TODO Remove in 1.5 - if (!nbt.hasKey(Settings.namespace + "biosFlag")) { - val firstEmpty = items.indexWhere(_.isEmpty) - items(firstEmpty) = Option(Items.createLuaBios()) - } - } - - override def save(nbt: NBTTagCompound) { - nbt.setNewTagList(Settings.namespace + "items", - items.zipWithIndex collect { - case (Some(stack), slot) => (stack, slot) - } map { - case (stack, slot) => - val slotNbt = new NBTTagCompound() - slotNbt.setByte("slot", slot.toByte) - slotNbt.setNewCompoundTag("item", stack.writeToNBT) - }) - nbt.setBoolean(Settings.namespace + "isRunning", isRunning) - nbt.setDouble(Settings.namespace + "energy", energy) - nbt.setDouble(Settings.namespace + "maxEnergy", maxEnergy) - - // TODO Remove in 1.5 - nbt.setBoolean(Settings.namespace + "biosFlag", true) - } - } - } From 068159cdf5a4686077dd1331b4c957943518346f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Thu, 22 Jan 2015 21:08:40 +0100 Subject: [PATCH 46/61] Added preconfigured Tablet to NEI, missed that when adding the other preconfigured stuff. --- .../scala/li/cil/oc/common/init/Items.scala | 35 ++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/src/main/scala/li/cil/oc/common/init/Items.scala b/src/main/scala/li/cil/oc/common/init/Items.scala index 65917615f..368cfda6a 100644 --- a/src/main/scala/li/cil/oc/common/init/Items.scala +++ b/src/main/scala/li/cil/oc/common/init/Items.scala @@ -14,6 +14,7 @@ import li.cil.oc.common.item.SimpleItem import li.cil.oc.common.item.UpgradeLeash import li.cil.oc.common.item.data.MicrocontrollerData import li.cil.oc.common.item.data.RobotData +import li.cil.oc.common.item.data.TabletData import li.cil.oc.common.recipe.Recipes import li.cil.oc.integration.Mods import li.cil.oc.util.Color @@ -234,6 +235,37 @@ object Items extends ItemAPI { stack } + def createConfiguredTablet() = { + val data = new TabletData() + + data.energy = Settings.get.bufferTablet + data.maxEnergy = data.energy + data.items = Array( + Option(get("screen1").createItemStack(1)), + Option(get("keyboard").createItemStack(1)), + + Option(get("signUpgrade").createItemStack(1)), + Option(get("pistonUpgrade").createItemStack(1)), + + Option(get("graphicsCard2").createItemStack(1)), + Option(get("redstoneCard2").createItemStack(1)), + Option(get("wlanCard").createItemStack(1)), + + Option(get("cpu3").createItemStack(1)), + Option(get("ram6").createItemStack(1)), + Option(get("ram6").createItemStack(1)), + + Option(createLuaBios()), + Option(createOpenOS()), + Option(get("hdd3").createItemStack(1)) + ) + + val stack = get("tablet").createItemStack(1) + data.save(stack) + + stack + } + // ----------------------------------------------------------------------- // var multi: item.Delegator = _ @@ -249,7 +281,8 @@ object Items extends ItemAPI { createLuaBios(), createConfiguredDrone(), createConfiguredMicrocontroller(), - createConfiguredRobot() + createConfiguredRobot(), + createConfiguredTablet() ) override def getSubItems(item: Item, tab: CreativeTabs, list: java.util.List[_]) { From 6156ccc1ef41578872e6c57ece6f7c6783a4c90d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Thu, 22 Jan 2015 21:52:29 +0100 Subject: [PATCH 47/61] Added interface to allow controlling on which sides `SimpleComponent`s can be connected. Closes #844. --- src/main/java/li/cil/oc/api/API.java | 2 +- .../cil/oc/api/network/ManagedPeripheral.java | 2 +- .../li/cil/oc/api/network/SidedComponent.java | 26 +++++++++++++++++++ .../scala/li/cil/oc/common/block/Cable.scala | 3 +++ .../li/cil/oc/server/network/Network.scala | 11 ++++---- 5 files changed, 36 insertions(+), 8 deletions(-) create mode 100644 src/main/java/li/cil/oc/api/network/SidedComponent.java diff --git a/src/main/java/li/cil/oc/api/API.java b/src/main/java/li/cil/oc/api/API.java index 4feef4c06..44dfd0b4a 100644 --- a/src/main/java/li/cil/oc/api/API.java +++ b/src/main/java/li/cil/oc/api/API.java @@ -11,7 +11,7 @@ import li.cil.oc.api.detail.*; */ public class API { public static final String ID_OWNER = "OpenComputers|Core"; - public static final String VERSION = "4.2.2"; + public static final String VERSION = "4.2.3"; public static DriverAPI driver = null; public static FileSystemAPI fileSystem = null; diff --git a/src/main/java/li/cil/oc/api/network/ManagedPeripheral.java b/src/main/java/li/cil/oc/api/network/ManagedPeripheral.java index b12c8ff9e..3e69def05 100644 --- a/src/main/java/li/cil/oc/api/network/ManagedPeripheral.java +++ b/src/main/java/li/cil/oc/api/network/ManagedPeripheral.java @@ -6,7 +6,7 @@ import li.cil.oc.api.machine.Context; /** * This interface can be used with an {@link li.cil.oc.api.network.Environment} * and is intended to be used for environments wrapping a ComputerCraft - * peripheral. Tt could be used for other purposes as well, though. It allows + * peripheral. It could be used for other purposes as well, though. It allows * providing method names in addition to those defined via the * {@link li.cil.oc.api.machine.Callback} annotation, and invoking said methods. */ diff --git a/src/main/java/li/cil/oc/api/network/SidedComponent.java b/src/main/java/li/cil/oc/api/network/SidedComponent.java new file mode 100644 index 000000000..68dd76866 --- /dev/null +++ b/src/main/java/li/cil/oc/api/network/SidedComponent.java @@ -0,0 +1,26 @@ +package li.cil.oc.api.network; + +import net.minecraftforge.common.util.ForgeDirection; + +/** + * This is an extended version of {@link li.cil.oc.api.network.SimpleComponent} + * which allows controlling connectivity on a side-by-side basis. + *

+ * Like the SimpleComponent interface, this is intended to be used + * with tile entities that should act as OC components. Please see the + * SimpleComponent interface for more information. + */ +public interface SidedComponent { + /** + * Whether this component can connect to a node on the specified side. + *

+ * The provided side is relative to the component, i.e. when the tile + * entity sits at (0, 0, 0) and is asked for its southern node (positive + * Z axis) it has to return the connectivity for the face between it and + * the block at (0, 0, 1). + * + * @param side the side to check for. + * @return whether the component may be connected to from the specified side. + */ + boolean canConnectNode(ForgeDirection side); +} diff --git a/src/main/scala/li/cil/oc/common/block/Cable.scala b/src/main/scala/li/cil/oc/common/block/Cable.scala index 27a884b97..f7a4038b8 100644 --- a/src/main/scala/li/cil/oc/common/block/Cable.scala +++ b/src/main/scala/li/cil/oc/common/block/Cable.scala @@ -9,6 +9,7 @@ import cpw.mods.fml.relauncher.Side import cpw.mods.fml.relauncher.SideOnly import li.cil.oc.Settings import li.cil.oc.api.network.Environment +import li.cil.oc.api.network.SidedComponent import li.cil.oc.api.network.SidedEnvironment import li.cil.oc.client.Textures import li.cil.oc.common.tileentity @@ -124,6 +125,8 @@ object Cable { case host: SidedEnvironment => if (host.getWorldObj.isRemote) host.canConnect(side) else host.sidedNode(side) != null + case host: Environment with SidedComponent => + host.canConnectNode(side) case host: Environment => true case host if Mods.ForgeMultipart.isAvailable => hasMultiPartNode(tileEntity) case _ => false diff --git a/src/main/scala/li/cil/oc/server/network/Network.scala b/src/main/scala/li/cil/oc/server/network/Network.scala index 9727aa3f1..fccfdd871 100644 --- a/src/main/scala/li/cil/oc/server/network/Network.scala +++ b/src/main/scala/li/cil/oc/server/network/Network.scala @@ -9,11 +9,7 @@ import li.cil.oc.OpenComputers import li.cil.oc.Settings import li.cil.oc.api import li.cil.oc.api.network -import li.cil.oc.api.network.Environment -import li.cil.oc.api.network.SidedEnvironment -import li.cil.oc.api.network.Visibility -import li.cil.oc.api.network.WirelessEndpoint -import li.cil.oc.api.network.{Node => ImmutableNode} +import li.cil.oc.api.network.{Node => ImmutableNode, _} import li.cil.oc.common.block.Cable import li.cil.oc.common.tileentity import li.cil.oc.integration.Mods @@ -439,7 +435,10 @@ object Network extends api.detail.NetworkAPI { private def getNetworkNode(tileEntity: TileEntity, side: ForgeDirection) = tileEntity match { case host: SidedEnvironment => Option(host.sidedNode(side)) - case host: Environment => Some(host.node) + case host: Environment with SidedComponent => + if (host.canConnectNode(side)) Option(host.node) + else None + case host: Environment => Option(host.node) case host if Mods.ForgeMultipart.isAvailable => getMultiPartNode(host) case _ => None } From 603f23a0fb3e77644625713f22df657cc0b67030 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Fri, 23 Jan 2015 20:42:13 +0100 Subject: [PATCH 48/61] May fix duplicates in dev jars on Jenkins. Or break everything. --- build.gradle | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/build.gradle b/build.gradle index 011f33e68..7adcd9391 100644 --- a/build.gradle +++ b/build.gradle @@ -17,6 +17,7 @@ buildscript { apply plugin: 'scala' apply plugin: 'forge' +apply plugin: 'idea' apply plugin: 'maven-publish' file "build.properties" withReader { @@ -211,7 +212,7 @@ processResources { jar { exclude "cofh/**" configurations.embedded.each { dep -> - from(project.zipTree(dep)){ + from(project.zipTree(dep)) { exclude 'META-INF', 'META-INF/**' } } @@ -231,7 +232,7 @@ task deobfJar(type: Jar) { from sourceSets.main.output exclude "cofh/**" configurations.embedded.each { dep -> - from(project.zipTree(dep)){ + from(project.zipTree(dep)) { exclude 'META-INF', 'META-INF/**' } } @@ -285,8 +286,8 @@ publishing { } // this is needed for IntelliJ so we don't have to copy over the assets manually every time -sourceSets { - main { - output.resourcesDir = output.classesDir +idea { + module { + outputDir = file('build/classes/main') } } From 40bbac10c64c0c993da3131c8e0c14b8d53dfd41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Sat, 24 Jan 2015 15:27:20 +0100 Subject: [PATCH 49/61] Preloading sounds, reduces lag on clientside when first starting a computer some. --- .../assets/opencomputers/sounds/preload.cfg | 16 ++++++++++ src/main/scala/li/cil/oc/client/Sound.scala | 32 ++++++++++++++++++- 2 files changed, 47 insertions(+), 1 deletion(-) create mode 100644 src/main/resources/assets/opencomputers/sounds/preload.cfg diff --git a/src/main/resources/assets/opencomputers/sounds/preload.cfg b/src/main/resources/assets/opencomputers/sounds/preload.cfg new file mode 100644 index 000000000..e7334d6c8 --- /dev/null +++ b/src/main/resources/assets/opencomputers/sounds/preload.cfg @@ -0,0 +1,16 @@ +assets/opencomputers/sounds/computer_running.ogg +assets/opencomputers/sounds/floppy_access1.ogg +assets/opencomputers/sounds/floppy_access2.ogg +assets/opencomputers/sounds/floppy_access3.ogg +assets/opencomputers/sounds/floppy_access4.ogg +assets/opencomputers/sounds/floppy_access5.ogg +assets/opencomputers/sounds/floppy_access6.ogg +assets/opencomputers/sounds/floppy_eject.ogg +assets/opencomputers/sounds/floppy_insert.ogg +assets/opencomputers/sounds/hdd_access1.ogg +assets/opencomputers/sounds/hdd_access2.ogg +assets/opencomputers/sounds/hdd_access3.ogg +assets/opencomputers/sounds/hdd_access4.ogg +assets/opencomputers/sounds/hdd_access5.ogg +assets/opencomputers/sounds/hdd_access6.ogg +assets/opencomputers/sounds/hdd_access7.ogg \ No newline at end of file diff --git a/src/main/scala/li/cil/oc/client/Sound.scala b/src/main/scala/li/cil/oc/client/Sound.scala index eb1de250b..1974b1e30 100644 --- a/src/main/scala/li/cil/oc/client/Sound.scala +++ b/src/main/scala/li/cil/oc/client/Sound.scala @@ -8,8 +8,10 @@ import java.util.Timer import java.util.TimerTask import java.util.UUID +import com.google.common.base.Charsets import cpw.mods.fml.client.FMLClientHandler import cpw.mods.fml.common.eventhandler.SubscribeEvent +import cpw.mods.fml.common.gameevent.TickEvent.ClientTickEvent import cpw.mods.fml.relauncher.ReflectionHelper import li.cil.oc.OpenComputers import li.cil.oc.Settings @@ -25,6 +27,7 @@ import paulscode.sound.SoundSystem import paulscode.sound.SoundSystemConfig import scala.collection.mutable +import scala.io.Source object Sound { private val sources = mutable.Map.empty[TileEntity, PseudoLoopingStream] @@ -101,6 +104,33 @@ object Sound { manager = event.manager } + private var hasPreloaded = Settings.get.soundVolume <= 0 + + @SubscribeEvent + def onTick(e: ClientTickEvent) { + if (!hasPreloaded && soundSystem != null) { + hasPreloaded = true + new Thread(new Runnable() { + override def run(): Unit = { + val preloadConfigLocation = new ResourceLocation(Settings.resourceDomain, "sounds/preload.cfg") + val preloadConfigResource = Minecraft.getMinecraft.getResourceManager.getResource(preloadConfigLocation) + for (location <- Source.fromInputStream(preloadConfigResource.getInputStream)(Charsets.UTF_8).getLines()) { + val url = getClass.getClassLoader.getResource(location) + if (url != null) try { + val sourceName = "preload_" + location + soundSystem.newSource(false, sourceName, url, location, true, 0, 0, 0, SoundSystemConfig.ATTENUATION_NONE, 16) + soundSystem.activate(sourceName) + soundSystem.removeSource(sourceName) + } catch { + case _: Throwable => // Meh. + } + else OpenComputers.log.warn(s"Couldn't preload sound $location!") + } + } + }) + } + } + @SubscribeEvent def onWorldUnload(event: WorldEvent.Unload) { commandQueue.synchronized(commandQueue.clear()) @@ -110,7 +140,7 @@ object Sound { } private abstract class Command(val when: Long, val tileEntity: TileEntity) extends Ordered[Command] { - def apply() + def apply(): Unit override def compare(that: Command) = (that.when - when).toInt } From 080c485c05fc79f0527564f92a12a2c0a4cc8998 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Sat, 24 Jan 2015 16:18:24 +0100 Subject: [PATCH 50/61] AE2 controller integration now works via interface block if channels are disabled (meaning controller block won't be available). Closes #791. --- .../integration/appeng/DriverController.scala | 25 +++++++++++++------ 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/src/main/scala/li/cil/oc/integration/appeng/DriverController.scala b/src/main/scala/li/cil/oc/integration/appeng/DriverController.scala index 75037560f..046abcd02 100644 --- a/src/main/scala/li/cil/oc/integration/appeng/DriverController.scala +++ b/src/main/scala/li/cil/oc/integration/appeng/DriverController.scala @@ -3,9 +3,12 @@ package li.cil.oc.integration.appeng import appeng.api.config.Actionable import appeng.api.networking.crafting.ICraftingLink import appeng.api.networking.crafting.ICraftingRequester +import appeng.api.networking.security.IActionHost import appeng.api.networking.security.MachineSource import appeng.api.storage.data.IAEItemStack import appeng.core.Api +import appeng.me.helpers.IGridProxyable +import appeng.tile.misc.TileInterface import appeng.tile.networking.TileController import appeng.util.item.AEItemStack import com.google.common.collect.ImmutableSet @@ -25,6 +28,7 @@ import li.cil.oc.util.ResultWrapper._ import net.minecraft.block.Block import net.minecraft.item.ItemStack import net.minecraft.nbt.NBTTagCompound +import net.minecraft.tileentity.TileEntity import net.minecraft.world.World import net.minecraftforge.common.DimensionManager import net.minecraftforge.common.util.Constants.NBT @@ -37,10 +41,17 @@ import scala.concurrent.ExecutionContext.Implicits.global import scala.concurrent.Future object DriverController extends DriverTileEntity with EnvironmentAware { - def getTileEntityClass = classOf[TileController] + private type AETile = TileEntity with IGridProxyable with IActionHost + + def getTileEntityClass = { + if (Api.instance.blocks.blockController != null && Api.instance.blocks.blockController.item != null) + classOf[TileController] + else + classOf[TileInterface] + } def createEnvironment(world: World, x: Int, y: Int, z: Int): ManagedEnvironment = - new Environment(world.getTileEntity(x, y, z).asInstanceOf[TileController]) + new Environment(world.getTileEntity(x, y, z).asInstanceOf[AETile]) override def providedEnvironment(stack: ItemStack) = if (stack != null && @@ -49,7 +60,7 @@ object DriverController extends DriverTileEntity with EnvironmentAware { Api.instance.blocks.blockController != null && Block.getBlockFromItem(stack.getItem) == Api.instance.blocks.blockController.block) classOf[Environment] else null - class Environment(tileEntity: TileController) extends ManagedTileEntityEnvironment[TileController](tileEntity, "me_controller") with NamedBlock { + class Environment(tileEntity: AETile) extends ManagedTileEntityEnvironment[AETile](tileEntity, "me_controller") with NamedBlock { override def preferredName = "me_controller" override def priority = 0 @@ -66,7 +77,7 @@ object DriverController extends DriverTileEntity with EnvironmentAware { def getCraftables(context: Context, args: Arguments): Array[AnyRef] = { result(tileEntity.getProxy.getStorage.getItemInventory.getStorageList. filter(_.isCraftable).map(stack => { - val patterns = tileEntity.getProxy.getCrafting.getCraftingFor(stack, null, 0, tileEntity.getWorld) + val patterns = tileEntity.getProxy.getCrafting.getCraftingFor(stack, null, 0, tileEntity.getWorldObj) val result = patterns.find(pattern => pattern.getOutputs.exists(_.isSameType(stack))) match { case Some(pattern) => pattern.getOutputs.find(_.isSameType(stack)).get case _ => stack.copy.setStackSize(0) // Should not be possible, but hey... @@ -104,7 +115,7 @@ object DriverController extends DriverTileEntity with EnvironmentAware { result(tileEntity.getProxy.getEnergy.getStoredPower) } - class Craftable(var controller: TileController, var stack: IAEItemStack) extends AbstractValue with ICraftingRequester { + class Craftable(var controller: AETile, var stack: IAEItemStack) extends AbstractValue with ICraftingRequester { def this() = this(null, null) private val links = mutable.Set.empty[ICraftingLink] @@ -188,8 +199,8 @@ object DriverController extends DriverTileEntity with EnvironmentAware { EventHandler.schedule(() => { val world = DimensionManager.getWorld(dimension) val tileEntity = world.getTileEntity(x, y, z) - if (tileEntity != null && tileEntity.isInstanceOf[TileController]) { - controller = tileEntity.asInstanceOf[TileController] + if (tileEntity != null && tileEntity.isInstanceOf[AETile]) { + controller = tileEntity.asInstanceOf[AETile] } }) } From f0af06144ed3befe52c0b8d50b81657868ae5c78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Sat, 24 Jan 2015 18:54:04 +0100 Subject: [PATCH 51/61] Allow binding debug card to a player to use the player's permissions for `runCommand` by shift-rightclicking it while holding it. Closes #843. --- .../assets/opencomputers/lang/en_US.lang | 2 +- .../li/cil/oc/common/item/DebugCard.scala | 26 +++++++++++++- .../oc/common/item/data/DebugCardData.scala | 34 +++++++++++++++++++ .../cil/oc/server/component/DebugCard.scala | 22 ++++++++++-- 4 files changed, 79 insertions(+), 5 deletions(-) create mode 100644 src/main/scala/li/cil/oc/common/item/data/DebugCardData.scala diff --git a/src/main/resources/assets/opencomputers/lang/en_US.lang b/src/main/resources/assets/opencomputers/lang/en_US.lang index 6356e7e98..9d4afc855 100644 --- a/src/main/resources/assets/opencomputers/lang/en_US.lang +++ b/src/main/resources/assets/opencomputers/lang/en_US.lang @@ -312,7 +312,7 @@ item.oc.AbstractBusCard.usage=This card allows computers, servers and robots to item.oc.Analyzer.usage=The §oAnalyzer§r is a handy tool for getting some information about OpenComputers-related blocks in the world. Simply (sneak-)activate a block to get some information printed to the chat. This ranges from basic things like the address of components, to power levels in the subnetwork the block is in, and information on the error lead to a computer to crash, for example.[nl][nl]Another useful functionality is that when using the using the analyzer on a block while holding down [Ctrl] the address of the block component will be copied to the clipboard. item.oc.ComponentBus.usage=A §oComponent Bus§r is a server-specific upgrade that allows the server to communicate with more components at the same time, without shutting down. Like with CPUs, higher tier buses provide higher component limits. item.oc.CPU.usage=The §oCentral Processing Unit§r is a core part for each computer. It defines the architecture of the computer, and the number of components that can be connected to the computer before it stops working. Higher tier CPUs also provide a higher per-tick direct call limit to the computer - in simpler terms: better CPUs run faster. -item.oc.DebugCard.usage=The §oDebug Card§r is a non-craftable item that was originally only intended to make debugging things easier, by automating some processes. It has since gotten a bunch more functionality, making it quite useful for custom map-making. +item.oc.DebugCard.usage=The §oDebug Card§r is a non-craftable item that was originally only intended to make debugging things easier, by automating some processes. It has since gotten a bunch more functionality, making it quite useful for custom map-making.[nl][nl]Note that you can use shift-rightclick while holding the card to bind it to you / unbind it, meaning §orunCommand§r will be performed using your permission levels instead of the default OpenComputers ones. item.oc.DroneCase.usage=The §oDrone Case§r is used to build Drones in the Assembler. Drones are light-weight, fast and very mobile machines with limited functionality. Unlike Robots they cannot use tools, and can interact with the world only in a relatively limited manner.[nl][nl]They make up for their limitations with speed and lower running energy costs. They are well suited for transport of small amounts of items, and ideal for reconnaissance. Pairing a Drone with a Robot can be quite powerful, with the Robot doing the "hard work", and the Drone providing information about the environment and transporting items to and from a central hub, for example.[nl][nl]Like microcontrollers, Drones can only be programmed using their EEPROM. Accordingly, the EEPROM can be changed by recrafting the Drone with another EEPROM. item.oc.eeprom.usage=The §oEEPROM§r is what contains the code used to initialize a computer when it is being booted. This data is stored as a plain byte array, and may mean different things to different CPU architectures. For example, for Lua it is usually a small script that searches for file systems with an init script, for other architectures it may be actual machine code. item.oc.FloppyDisk.usage=The §oFloppy Disk§r is the cheapest and smallest type of storage medium in OpenComputers. It is a handy early game way of storing data and transferring it between computers and robots. You may also find floppy disks with useful programs on them in dungeon chests.[nl][nl]Beware: shift-rightclicking while holding a floppy disk in your hand will wipe the floppy disk! diff --git a/src/main/scala/li/cil/oc/common/item/DebugCard.scala b/src/main/scala/li/cil/oc/common/item/DebugCard.scala index d52b29603..52609162c 100644 --- a/src/main/scala/li/cil/oc/common/item/DebugCard.scala +++ b/src/main/scala/li/cil/oc/common/item/DebugCard.scala @@ -1,3 +1,27 @@ package li.cil.oc.common.item -class DebugCard(val parent: Delegator) extends Delegate +import java.util + +import li.cil.oc.common.item.data.DebugCardData +import net.minecraft.entity.player.EntityPlayer +import net.minecraft.item.ItemStack +import net.minecraft.world.World + +class DebugCard(val parent: Delegator) extends Delegate { + override protected def tooltipExtended(stack: ItemStack, tooltip: util.List[String]): Unit = { + super.tooltipExtended(stack, tooltip) + val data = new DebugCardData(stack) + data.player.foreach(name => tooltip.add(s"§8$name§r")) + } + + override def onItemRightClick(stack: ItemStack, world: World, player: EntityPlayer): ItemStack = { + if (player.isSneaking) { + val data = new DebugCardData(stack) + if (data.player.contains(player.getCommandSenderName)) data.player = None + else data.player = Option(player.getCommandSenderName) + data.save(stack) + player.swingItem() + } + stack + } +} diff --git a/src/main/scala/li/cil/oc/common/item/data/DebugCardData.scala b/src/main/scala/li/cil/oc/common/item/data/DebugCardData.scala new file mode 100644 index 000000000..f22ac7a6b --- /dev/null +++ b/src/main/scala/li/cil/oc/common/item/data/DebugCardData.scala @@ -0,0 +1,34 @@ +package li.cil.oc.common.item.data + +import li.cil.oc.Settings +import net.minecraft.item.ItemStack +import net.minecraft.nbt.NBTTagCompound + +class DebugCardData extends ItemData { + def this(stack: ItemStack) { + this() + load(stack) + } + + var player: Option[String] = None + + override def load(nbt: NBTTagCompound) { + val tag = dataTag(nbt) + if (tag.hasKey(Settings.namespace + "player")) { + player = Option(tag.getString(Settings.namespace + "player")) + } + } + + override def save(nbt: NBTTagCompound) { + val tag = dataTag(nbt) + tag.removeTag(Settings.namespace + "player") + player.foreach(tag.setString(Settings.namespace + "player", _)) + } + + private def dataTag(nbt: NBTTagCompound) = { + if (!nbt.hasKey(Settings.namespace + "data")) { + nbt.setTag(Settings.namespace + "data", new NBTTagCompound()) + } + nbt.getCompoundTag(Settings.namespace + "data") + } +} diff --git a/src/main/scala/li/cil/oc/server/component/DebugCard.scala b/src/main/scala/li/cil/oc/server/component/DebugCard.scala index 7541263b8..4ff2f4ffe 100644 --- a/src/main/scala/li/cil/oc/server/component/DebugCard.scala +++ b/src/main/scala/li/cil/oc/server/component/DebugCard.scala @@ -45,6 +45,9 @@ class DebugCard(host: EnvironmentHost) extends prefab.ManagedEnvironment { // Used for delayed connecting to remote node again after loading. private var remoteNodePosition: Option[(Int, Int, Int)] = None + // Player this card is bound to (if any) to use for permissions. + var player: Option[String] = None + // ----------------------------------------------------------------------- // import li.cil.oc.server.component.DebugCard.checkEnabled @@ -89,7 +92,7 @@ class DebugCard(host: EnvironmentHost) extends prefab.ManagedEnvironment { def runCommand(context: Context, args: Arguments): Array[AnyRef] = { checkEnabled() val command = args.checkString(0) - val sender = new CommandSender(host) + val sender = new CommandSender(host, player) val value = MinecraftServer.getServer.getCommandManager.executeCommand(sender, command) result(value, sender.messages.orNull) } @@ -157,6 +160,9 @@ class DebugCard(host: EnvironmentHost) extends prefab.ManagedEnvironment { val z = nbt.getInteger(Settings.namespace + "remoteZ") remoteNodePosition = Some((x, y, z)) } + if (nbt.hasKey(Settings.namespace + "player")) { + player = Option(nbt.getString(Settings.namespace + "player")) + } } override def save(nbt: NBTTagCompound): Unit = { @@ -167,6 +173,7 @@ class DebugCard(host: EnvironmentHost) extends prefab.ManagedEnvironment { nbt.setInteger(Settings.namespace + "remoteY", y) nbt.setInteger(Settings.namespace + "remoteZ", z) } + player.foreach(nbt.setString(Settings.namespace + "player", _)) } } @@ -427,8 +434,17 @@ object DebugCard { } } - class CommandSender(val host: EnvironmentHost) extends ICommandSender { - val fakePlayer = FakePlayerFactory.get(host.world.asInstanceOf[WorldServer], Settings.get.fakePlayerProfile) + class CommandSender(val host: EnvironmentHost, val playerName: Option[String]) extends ICommandSender { + val fakePlayer = { + def defaultFakePlayer = FakePlayerFactory.get(host.world.asInstanceOf[WorldServer], Settings.get.fakePlayerProfile) + playerName match { + case Some(name) => Option(MinecraftServer.getServer.getConfigurationManager.func_152612_a(name)) match { + case Some(player) => player + case _ => defaultFakePlayer + } + case _ => defaultFakePlayer + } + } var messages: Option[String] = None From c6042b682d03aac25653148ad3ade9ebe8ab4078 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Sat, 24 Jan 2015 18:54:19 +0100 Subject: [PATCH 52/61] Version bump. --- build.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.properties b/build.properties index 1950bd709..42e5229ef 100644 --- a/build.properties +++ b/build.properties @@ -1,7 +1,7 @@ minecraft.version=1.7.10 forge.version=10.13.2.1236 -oc.version=1.4.5 +oc.version=1.4.6 oc.subversion=dev ae2.version=rv1-stable-1 From c5e114e0aeb962b878c0e97ae166ebc5ac9f94a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Sat, 24 Jan 2015 19:00:42 +0100 Subject: [PATCH 53/61] Added try-catch around Keyboard.* calls because they can apparently error if something is misconfigured somewhere. Closes #846. --- src/main/scala/li/cil/oc/client/KeyBindings.scala | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/main/scala/li/cil/oc/client/KeyBindings.scala b/src/main/scala/li/cil/oc/client/KeyBindings.scala index a19c6cc0c..2e4d8265b 100644 --- a/src/main/scala/li/cil/oc/client/KeyBindings.scala +++ b/src/main/scala/li/cil/oc/client/KeyBindings.scala @@ -5,9 +5,13 @@ import net.minecraft.client.settings.KeyBinding import org.lwjgl.input.Keyboard object KeyBindings { - def showExtendedTooltips = Keyboard.isCreated && Keyboard.isKeyDown(extendedTooltip.getKeyCode) + def showExtendedTooltips = Keyboard.isCreated && (try Keyboard.isKeyDown(extendedTooltip.getKeyCode) catch { + case _: Throwable => false // Don't ask me, sometimes things can apparently screw up LWJGL's keyboard handling. + }) - def showMaterialCosts = Keyboard.isCreated && Keyboard.isKeyDown(materialCosts.getKeyCode) + def showMaterialCosts = Keyboard.isCreated && (try Keyboard.isKeyDown(materialCosts.getKeyCode) catch { + case _: Throwable => false // Don't ask me, sometimes things can apparently screw up LWJGL's keyboard handling. + }) def extendedTooltip = FMLClientHandler.instance.getClient.gameSettings.keyBindSneak From dbf99cdf4ec7ec217b6d6174cf5db2b5e65a83c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Sat, 24 Jan 2015 20:35:29 +0100 Subject: [PATCH 54/61] Fixes error with AE2 rv2 caused by use of wrong API class. Closes #847. --- .../integration/appeng/DriverController.scala | 21 ++++++++++++------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/main/scala/li/cil/oc/integration/appeng/DriverController.scala b/src/main/scala/li/cil/oc/integration/appeng/DriverController.scala index 046abcd02..c7698aec7 100644 --- a/src/main/scala/li/cil/oc/integration/appeng/DriverController.scala +++ b/src/main/scala/li/cil/oc/integration/appeng/DriverController.scala @@ -1,5 +1,6 @@ package li.cil.oc.integration.appeng +import appeng.api.AEApi import appeng.api.config.Actionable import appeng.api.networking.crafting.ICraftingLink import appeng.api.networking.crafting.ICraftingRequester @@ -44,10 +45,13 @@ object DriverController extends DriverTileEntity with EnvironmentAware { private type AETile = TileEntity with IGridProxyable with IActionHost def getTileEntityClass = { - if (Api.instance.blocks.blockController != null && Api.instance.blocks.blockController.item != null) - classOf[TileController] - else - classOf[TileInterface] + if (AEApi.instance != null && AEApi.instance.blocks != null) { + if (AEApi.instance.blocks.blockController != null && AEApi.instance.blocks.blockController.item != null) + classOf[TileController] + else + classOf[TileInterface] + } + else null } def createEnvironment(world: World, x: Int, y: Int, z: Int): ManagedEnvironment = @@ -55,10 +59,11 @@ object DriverController extends DriverTileEntity with EnvironmentAware { override def providedEnvironment(stack: ItemStack) = if (stack != null && - Api.instance != null && - Api.instance.blocks != null && - Api.instance.blocks.blockController != null && - Block.getBlockFromItem(stack.getItem) == Api.instance.blocks.blockController.block) classOf[Environment] else null + AEApi.instance != null && + AEApi.instance.blocks != null && + AEApi.instance.blocks.blockController != null && + Block.getBlockFromItem(stack.getItem) == AEApi.instance.blocks.blockController.block) classOf[Environment] + else null class Environment(tileEntity: AETile) extends ManagedTileEntityEnvironment[AETile](tileEntity, "me_controller") with NamedBlock { override def preferredName = "me_controller" From 43193a59c6d5737314ff3f4deaa8fa14734d1d64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Sun, 25 Jan 2015 13:37:31 +0100 Subject: [PATCH 55/61] Avoid skipping physical removal in filesystem.remove when a virtual object had to be removed for deleting a directory. Closes #849. --- .../loot/OpenOS/lib/filesystem.lua | 33 ++++++++++++------- 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/src/main/resources/assets/opencomputers/loot/OpenOS/lib/filesystem.lua b/src/main/resources/assets/opencomputers/loot/OpenOS/lib/filesystem.lua index bb523ddc9..9904ed9d8 100644 --- a/src/main/resources/assets/opencomputers/loot/OpenOS/lib/filesystem.lua +++ b/src/main/resources/assets/opencomputers/loot/OpenOS/lib/filesystem.lua @@ -376,22 +376,31 @@ function filesystem.makeDirectory(path) end function filesystem.remove(path) - local node, rest, vnode, vrest = findNode(filesystem.path(path)) - local name = filesystem.name(path) - if vnode.children[name] then - vnode.children[name] = nil - removeEmptyNodes(vnode) - return true - elseif vnode.links[name] then - vnode.links[name] = nil - removeEmptyNodes(vnode) - return true - else + local function removeVirtual() + local node, rest, vnode, vrest = findNode(filesystem.path(path)) + local name = filesystem.name(path) + if vnode.children[name] then + vnode.children[name] = nil + removeEmptyNodes(vnode) + return true + elseif vnode.links[name] then + vnode.links[name] = nil + removeEmptyNodes(vnode) + return true + end + return false + end + local function removePhysical() node, rest = findNode(path) if node.fs and rest then return component.proxy(node.fs).remove(rest) end - return nil, "no such file or directory" + return false + end + local success = removeVirtual() + success = removePhysical() or success -- Always run. + if success then return true + else return nil, "no such file or directory" end end From 8b8ee1cb889caa043b4f241e3aa7eb72b7fcef88 Mon Sep 17 00:00:00 2001 From: Ivoah Date: Mon, 26 Jan 2015 08:30:13 -0500 Subject: [PATCH 56/61] Make port number optional in irc.lua --- .../resources/assets/opencomputers/loot/OpenIRC/irc.lua | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/resources/assets/opencomputers/loot/OpenIRC/irc.lua b/src/main/resources/assets/opencomputers/loot/OpenIRC/irc.lua index 9e0d7bee3..b0a87ea99 100644 --- a/src/main/resources/assets/opencomputers/loot/OpenIRC/irc.lua +++ b/src/main/resources/assets/opencomputers/loot/OpenIRC/irc.lua @@ -17,13 +17,17 @@ local text = require("text") local args, options = shell.parse(...) if #args < 1 then - print("Usage: irc [server:port]") + print("Usage: irc [server[:port]]") return end local nick = args[1] local host = args[2] or "irc.esper.net:6667" +if not host:find(":") then + host = host .. ":6667" +end + -- try to connect to server. local sock, reason = internet.open(host) if not sock then From b3cd8cb73472730e11467b5eb51e424c1cc56e13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Tue, 27 Jan 2015 02:09:31 +0100 Subject: [PATCH 57/61] Should fix #853. --- src/main/scala/li/cil/oc/common/item/Drone.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/li/cil/oc/common/item/Drone.scala b/src/main/scala/li/cil/oc/common/item/Drone.scala index 3b95cf722..13c5d907e 100644 --- a/src/main/scala/li/cil/oc/common/item/Drone.scala +++ b/src/main/scala/li/cil/oc/common/item/Drone.scala @@ -21,7 +21,7 @@ class Drone(val parent: Delegator) extends Delegate { override protected def tooltipExtended(stack: ItemStack, tooltip: util.List[String]): Unit = { if (KeyBindings.showExtendedTooltips) { val info = new MicrocontrollerData(stack) - for (component <- info.components) { + for (component <- info.components if component != null) { tooltip.add("- " + component.getDisplayName) } } From 8da121964b82264f547ac2a6f86c7b5cc5a5fdf5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Tue, 27 Jan 2015 13:47:45 +0100 Subject: [PATCH 58/61] Fixed `Connector.setLocalBufferSize` registering self before adjusting size, leading to manager not adding it to the connector list if its size was zero before. Fixes #859. --- .../li/cil/oc/server/network/Connector.scala | 18 +++++++++++------- .../li/cil/oc/server/network/Distributor.scala | 8 ++++---- .../li/cil/oc/server/network/Network.scala | 4 ++-- 3 files changed, 17 insertions(+), 13 deletions(-) diff --git a/src/main/scala/li/cil/oc/server/network/Connector.scala b/src/main/scala/li/cil/oc/server/network/Connector.scala index 244a55968..977cdc35f 100644 --- a/src/main/scala/li/cil/oc/server/network/Connector.scala +++ b/src/main/scala/li/cil/oc/server/network/Connector.scala @@ -6,7 +6,7 @@ import li.cil.oc.api.network.{Node => ImmutableNode} import net.minecraft.nbt.NBTTagCompound trait Connector extends network.Connector with Node { - var localBufferSize: Double + var localBufferSize = 0.0 var localBuffer = 0.0 @@ -85,20 +85,24 @@ trait Connector extends network.Connector with Node { } def setLocalBufferSize(size: Double) { + val clampedSize = math.max(size, 0) this.synchronized(distributor match { case Some(d) => d.synchronized { + val oldSize = localBufferSize + // Must apply new size before trying to register with distributor, else + // we get ignored if our size is zero. + localBufferSize = clampedSize if (network != null) { - if (localBufferSize <= 0 && size > 0) d.addConnector(this) - else if (localBufferSize > 0 && size == 0) d.removeConnector(this) - else d.globalBufferSize = math.max(d.globalBufferSize - localBufferSize + size, 0) + if (localBufferSize <= 0 && clampedSize > 0) d.addConnector(this) + else if (oldSize > 0 && clampedSize == 0) d.removeConnector(this) + else d.globalBufferSize = math.max(d.globalBufferSize - oldSize + clampedSize, 0) } - localBufferSize = math.max(size, 0) - val surplus = math.max(localBuffer - localBufferSize, 0) + val surplus = math.max(localBuffer - clampedSize, 0) changeBuffer(-surplus) d.changeBuffer(surplus) } case _ => - localBufferSize = math.max(size, 0) + localBufferSize = clampedSize localBuffer = math.min(localBuffer, localBufferSize) }) } diff --git a/src/main/scala/li/cil/oc/server/network/Distributor.scala b/src/main/scala/li/cil/oc/server/network/Distributor.scala index 5d88f36b8..a1d2acc1b 100644 --- a/src/main/scala/li/cil/oc/server/network/Distributor.scala +++ b/src/main/scala/li/cil/oc/server/network/Distributor.scala @@ -3,15 +3,15 @@ package li.cil.oc.server.network trait Distributor { def globalBuffer: Double - def globalBuffer_=(value: Double) + def globalBuffer_=(value: Double): Unit def globalBufferSize: Double - def globalBufferSize_=(value: Double) + def globalBufferSize_=(value: Double): Unit - def addConnector(connector: Connector) + def addConnector(connector: Connector): Unit - def removeConnector(connector: Connector) + def removeConnector(connector: Connector): Unit def changeBuffer(delta: Double): Double } diff --git a/src/main/scala/li/cil/oc/server/network/Network.scala b/src/main/scala/li/cil/oc/server/network/Network.scala index fccfdd871..b13579f8c 100644 --- a/src/main/scala/li/cil/oc/server/network/Network.scala +++ b/src/main/scala/li/cil/oc/server/network/Network.scala @@ -589,7 +589,7 @@ object Network extends api.detail.NetworkAPI { def create() = if (SideTracker.isServer) new Connector with NodeVarargPart { val host = _host val reachability = _reachability - var localBufferSize = _bufferSize + localBufferSize = _bufferSize } else null } @@ -599,7 +599,7 @@ object Network extends api.detail.NetworkAPI { val host = _host val reachability = _reachability val name = _name - var localBufferSize = _bufferSize + localBufferSize = _bufferSize setVisibility(_visibility) } else null From a0f11d36b52bdb642ad2ca83335a2fe9487da32d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Tue, 27 Jan 2015 13:57:33 +0100 Subject: [PATCH 59/61] Re-enabled `inventory_controller.getInventorySize(sides.back)` for backwards compatibility. Will be removed in 1.5, use `robot.inventorySize()`. Closes #860. --- .../oc/server/component/UpgradeInventoryController.scala | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/main/scala/li/cil/oc/server/component/UpgradeInventoryController.scala b/src/main/scala/li/cil/oc/server/component/UpgradeInventoryController.scala index 5e97814d9..516796292 100644 --- a/src/main/scala/li/cil/oc/server/component/UpgradeInventoryController.scala +++ b/src/main/scala/li/cil/oc/server/component/UpgradeInventoryController.scala @@ -76,6 +76,14 @@ object UpgradeInventoryController { else result(false) } + // TODO Remove in 1.5 + @Callback(doc = """function(side:number):number -- Get the number of slots in the inventory on the specified side of the robot.""") + override def getInventorySize(context: Context, args: Arguments): Array[AnyRef] = { + if (args.optInteger(0, -1) == ForgeDirection.NORTH.ordinal) // sides.back + getInventorySize(context, new ArgumentsImpl(args.toArray.drop(1))) // drop side, just pass slot + else super.getInventorySize(context, args) + } + // TODO Remove in 1.5 @Callback(doc = """function(side:number, slot:number):table -- Get a description of the stack in the the inventory on the specified side of the robot.""") override def getStackInSlot(context: Context, args: Arguments) = { From 1fe6b51e1c90503997946aa6f40326466a54c6cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Tue, 27 Jan 2015 14:21:38 +0100 Subject: [PATCH 60/61] Because OCD. --- src/main/resources/assets/opencomputers/loot/OpenIRC/irc.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/assets/opencomputers/loot/OpenIRC/irc.lua b/src/main/resources/assets/opencomputers/loot/OpenIRC/irc.lua index b0a87ea99..bd3018aa5 100644 --- a/src/main/resources/assets/opencomputers/loot/OpenIRC/irc.lua +++ b/src/main/resources/assets/opencomputers/loot/OpenIRC/irc.lua @@ -25,7 +25,7 @@ local nick = args[1] local host = args[2] or "irc.esper.net:6667" if not host:find(":") then - host = host .. ":6667" + host = host .. ":6667" end -- try to connect to server. From a218b27e3aee7708fa4980a4c661634615a89632 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Tue, 27 Jan 2015 14:22:32 +0100 Subject: [PATCH 61/61] Fixed a typo and made some docstrings more generic. --- .../component/traits/WorldInventoryAnalytics.scala | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/main/scala/li/cil/oc/server/component/traits/WorldInventoryAnalytics.scala b/src/main/scala/li/cil/oc/server/component/traits/WorldInventoryAnalytics.scala index 936b64830..f03e9ae2d 100644 --- a/src/main/scala/li/cil/oc/server/component/traits/WorldInventoryAnalytics.scala +++ b/src/main/scala/li/cil/oc/server/component/traits/WorldInventoryAnalytics.scala @@ -13,25 +13,25 @@ import net.minecraft.item.ItemStack import net.minecraftforge.common.util.ForgeDirection trait WorldInventoryAnalytics extends WorldAware with SideRestricted with NetworkAware { - @Callback(doc = """function(side:number):number -- Get the number of slots in the inventory on the specified side of the robot.""") + @Callback(doc = """function(side:number):number -- Get the number of slots in the inventory on the specified side of the device.""") def getInventorySize(context: Context, args: Arguments): Array[AnyRef] = { val facing = checkSideForAction(args, 0) withInventory(facing, inventory => result(inventory.getSizeInventory)) } - @Callback(doc = """function(side:number, slot:number):number -- Get number of items in the specified slot of the inventory on the specified side of the robot.""") + @Callback(doc = """function(side:number, slot:number):number -- Get number of items in the specified slot of the inventory on the specified side of the device.""") def getSlotStackSize(context: Context, args: Arguments): Array[AnyRef] = { val facing = checkSideForAction(args, 0) withInventory(facing, inventory => result(Option(inventory.getStackInSlot(args.checkSlot(inventory, 1))).fold(0)(_.stackSize))) } - @Callback(doc = """function(side:number, slot:number):number -- Get the maximum number of items in the specified slot of the inventory on the specified side of the robot.""") + @Callback(doc = """function(side:number, slot:number):number -- Get the maximum number of items in the specified slot of the inventory on the specified side of the device.""") def getSlotMaxStackSize(context: Context, args: Arguments): Array[AnyRef] = { val facing = checkSideForAction(args, 0) withInventory(facing, inventory => result(Option(inventory.getStackInSlot(args.checkSlot(inventory, 1))).fold(0)(_.getMaxStackSize))) } - @Callback(doc = """function(side:number, slotA:number, slotB:number):boolean -- Get whether the items in the two specified slots of the inventory on the specified side of the robot are of the same type.""") + @Callback(doc = """function(side:number, slotA:number, slotB:number):boolean -- Get whether the items in the two specified slots of the inventory on the specified side of the device are of the same type.""") def compareStacks(context: Context, args: Arguments): Array[AnyRef] = { val facing = checkSideForAction(args, 0) withInventory(facing, inventory => { @@ -44,12 +44,12 @@ trait WorldInventoryAnalytics extends WorldAware with SideRestricted with Networ }) } - @Callback(doc = """function(side:number, slot:number):table -- Get a description of the stack in the the inventory on the specified side of the robot.""") + @Callback(doc = """function(side:number, slot:number):table -- Get a description of the stack in the inventory on the specified side of the device.""") def getStackInSlot(context: Context, args: Arguments): Array[AnyRef] = if (Settings.get.allowItemStackInspection) { val facing = checkSideForAction(args, 0) withInventory(facing, inventory => result(inventory.getStackInSlot(args.checkSlot(inventory, 1)))) } - else result(Unit, "not enabled in config") + else result(null, "not enabled in config") @Callback(doc = """function(side:number, slot:number, dbAddress:string, dbSlot:number):boolean -- Store an item stack description in the specified slot of the database with the specified address.""") def store(context: Context, args: Arguments): Array[AnyRef] = { @@ -67,6 +67,6 @@ trait WorldInventoryAnalytics extends WorldAware with SideRestricted with Networ private def withInventory(side: ForgeDirection, f: IInventory => Array[AnyRef]) = InventoryUtils.inventoryAt(position.offset(side)) match { case Some(inventory) if inventory.isUseableByPlayer(fakePlayer) => f(inventory) - case _ => result(Unit, "no inventory") + case _ => result(null, "no inventory") } }