From 6c85fd8e108b285b2a95510775000c76bc1f72f2 Mon Sep 17 00:00:00 2001 From: cyber01 Date: Mon, 27 Apr 2015 19:01:39 +0300 Subject: [PATCH 01/13] Added waypoint. Corrected mistakes --- .../assets/opencomputers/doc/ru_RU/block/accessPoint.md | 2 +- .../assets/opencomputers/doc/ru_RU/block/waypoint.md | 9 +++++++++ .../opencomputers/doc/ru_RU/item/navigationUpgrade.md | 4 +++- src/main/resources/assets/opencomputers/lang/ru_RU.lang | 2 ++ 4 files changed, 15 insertions(+), 2 deletions(-) create mode 100644 src/main/resources/assets/opencomputers/doc/ru_RU/block/waypoint.md diff --git a/src/main/resources/assets/opencomputers/doc/ru_RU/block/accessPoint.md b/src/main/resources/assets/opencomputers/doc/ru_RU/block/accessPoint.md index 58779b515..744abec69 100644 --- a/src/main/resources/assets/opencomputers/doc/ru_RU/block/accessPoint.md +++ b/src/main/resources/assets/opencomputers/doc/ru_RU/block/accessPoint.md @@ -6,6 +6,6 @@ В дополнение к этому, точки доступа могут использоваться как повторители: они могут перенаправлять сообщения из проводной линии другим устройствам; или беспроводные сообщения как проводные, так и беспроводные. -Коммутаторы и [коммутаторы](switch.md) *не* отслеживают, какие пакеты и куда они передали, поэтому в сети могут образовываться петли или вы можете получать одно сообщение несколько раз. Из-за ограниченного буфера сообщений коммутатора, частое отправление сообщений приводит к их потере. Вы можете улучшить [коммутатор](switch.md) или точку доступа для увеличения скорости обработки сообщений, а также увеличения размера сообщений. +Точки доступа и [коммутаторы](switch.md) *не* отслеживают, какие пакеты и куда они передали, поэтому в сети могут образовываться петли или вы можете получать одно сообщение несколько раз. Из-за ограниченного буфера сообщений коммутатора, частое отправление сообщений приводит к их потере. Вы можете улучшить [коммутатор](switch.md) или точку доступа для увеличения скорости обработки сообщений, а также увеличения размера сообщений. Сообщения, могут перенаправлены всего несколько раз, поэтому цепочки с произвольным количеством коммутаторов или точек доступа невозможны. По умолчанию, сообщение может быть перенаправлено пять раз. diff --git a/src/main/resources/assets/opencomputers/doc/ru_RU/block/waypoint.md b/src/main/resources/assets/opencomputers/doc/ru_RU/block/waypoint.md new file mode 100644 index 000000000..4d0b29498 --- /dev/null +++ b/src/main/resources/assets/opencomputers/doc/ru_RU/block/waypoint.md @@ -0,0 +1,9 @@ +# Путевая точка + +!["В этом направлении!" - "Нет, в этом!"](oredict:oc:waypoint) + +Главное не что это такое, а как это использовать. [Навигационное улучшение](../item/navigationUpgrade.md) может обнаруживать путевые точки, что позволяет устройствам с этим улучшением ориентироваться в игровом мире. Это можно использовать для написания программ для [роботов](robot.md) и [дронов](../item/drone.md). + +Обратите внимание, что актуальным местоположением считается *блок перед путевой точкой* (выделен с помощью частиц), именно это местоположение будет передано, при запросе его навигационным улучшением. Это позволяет поместить путевую точку рядом или над сундуком и позволит обратиться к путевой точке "над сундуком", без необходимости вращения самой точки. + +Путевая точка имеет два параметра, которое могут быть использованы при ее опросе навигационным улучшением: уровень редстоун сигнала, который получает точка и изменяемое имя. Имя это строка, состоящая из 32 символов, оно может быть изменено через интерфейс или через API. Эти два параметра могут быть использованы устройством, для определения, что можно сделать с путевой точкой. Например, сортировочная программа может использовать блоки с высоким уровнем редстоун сигнала как входные, а с низким как выходные. \ No newline at end of file diff --git a/src/main/resources/assets/opencomputers/doc/ru_RU/item/navigationUpgrade.md b/src/main/resources/assets/opencomputers/doc/ru_RU/item/navigationUpgrade.md index 3d8036c4c..88fd718c8 100644 --- a/src/main/resources/assets/opencomputers/doc/ru_RU/item/navigationUpgrade.md +++ b/src/main/resources/assets/opencomputers/doc/ru_RU/item/navigationUpgrade.md @@ -4,4 +4,6 @@ Данное улучшение добавляет навигацию и ориентацию для устройств. Получаемые координаты начинаются от центра карты, где было собрано улучшение, радиус функционирования зависит от размера карты. -Карта внутри улучшения может быть обновлена, повторным крафтом улучшения с новой картой. Старая карта при этом будет возвращена игроку. \ No newline at end of file +Карта внутри улучшения может быть обновлена, повторным крафтом улучшения с новой картой. Старая карта при этом будет возвращена игроку. + +Наиболее эффективно это улучшение работает в паре с одной или несколькими [точками доступа](../block/waypoint.md). \ No newline at end of file diff --git a/src/main/resources/assets/opencomputers/lang/ru_RU.lang b/src/main/resources/assets/opencomputers/lang/ru_RU.lang index 00c7f09f4..4b66e4b7a 100644 --- a/src/main/resources/assets/opencomputers/lang/ru_RU.lang +++ b/src/main/resources/assets/opencomputers/lang/ru_RU.lang @@ -35,6 +35,7 @@ tile.oc.screen2.name=Монитор (2-ой уровень) tile.oc.screen3.name=Монитор (3-ий уровень) tile.oc.serverRack.name=Серверная стойка tile.oc.switch.name=Коммутатор +tile.oc.waypoint.name=Путевая точка # Items item.oc.AbstractBusCard.name=Карта абстрактной шины @@ -133,6 +134,7 @@ item.oc.UpgradeSolarGenerator.name=Улучшение "Солнечный ген item.oc.UpgradeTank.name=Улучшение "Бак для жидкостей" item.oc.UpgradeTankController.name=Улучшение "Контроллер бака" item.oc.UpgradeTractorBeam.name=Улучшение "Притягивающий луч" +oc:tooltip.Waypoint=Добавляет путевую точку для устройств с навигационным улучшением. item.oc.WirelessNetworkCard.name=Плата беспроводной сети item.oc.WorldSensorCard.name=Карта-мировой сенсор item.oc.wrench.name=Ключ From a30f2d12953fe2fc20828e95ad64d50c459f846b Mon Sep 17 00:00:00 2001 From: cyber01 Date: Mon, 27 Apr 2015 19:04:05 +0300 Subject: [PATCH 02/13] Corrected mistakes --- .../resources/assets/opencomputers/doc/ru_RU/block/waypoint.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/assets/opencomputers/doc/ru_RU/block/waypoint.md b/src/main/resources/assets/opencomputers/doc/ru_RU/block/waypoint.md index 4d0b29498..a8922004e 100644 --- a/src/main/resources/assets/opencomputers/doc/ru_RU/block/waypoint.md +++ b/src/main/resources/assets/opencomputers/doc/ru_RU/block/waypoint.md @@ -6,4 +6,4 @@ Обратите внимание, что актуальным местоположением считается *блок перед путевой точкой* (выделен с помощью частиц), именно это местоположение будет передано, при запросе его навигационным улучшением. Это позволяет поместить путевую точку рядом или над сундуком и позволит обратиться к путевой точке "над сундуком", без необходимости вращения самой точки. -Путевая точка имеет два параметра, которое могут быть использованы при ее опросе навигационным улучшением: уровень редстоун сигнала, который получает точка и изменяемое имя. Имя это строка, состоящая из 32 символов, оно может быть изменено через интерфейс или через API. Эти два параметра могут быть использованы устройством, для определения, что можно сделать с путевой точкой. Например, сортировочная программа может использовать блоки с высоким уровнем редстоун сигнала как входные, а с низким как выходные. \ No newline at end of file +Путевая точка имеет два параметра, которые могут быть использованы при ее опросе навигационным улучшением: уровень редстоун сигнала, который получает точка и изменяемое имя. Имя это строка, состоящая из 32 символов, оно может быть изменено через интерфейс или через API. Эти два параметра могут быть использованы устройством, для определения, что можно сделать с путевой точкой. Например, сортировочная программа может использовать блоки с высоким уровнем редстоун сигнала как входные, а с низким как выходные. \ No newline at end of file From 4956271d62192038407b3cb160343a63548c40bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Mon, 27 Apr 2015 20:34:47 +0200 Subject: [PATCH 03/13] Added support for BluePower's bundled redstone system. Closes #1103. --- build.gradle | 12 +++- build.properties | 3 + .../scala/li/cil/oc/common/item/Wrench.scala | 4 ++ .../traits/BundledRedstoneAware.scala | 66 ++++++++++++------- .../tileentity/traits/RedstoneAware.scala | 25 +++++-- .../scala/li/cil/oc/integration/Mods.scala | 3 + .../bluepower/BundledRedstoneDevice.scala | 38 +++++++++++ .../integration/bluepower/ModBluePower.scala | 12 ++++ .../bluepower/RedstoneDevice.scala | 33 ++++++++++ .../bluepower/RedstoneProvider.scala | 30 +++++++++ 10 files changed, 195 insertions(+), 31 deletions(-) create mode 100644 src/main/scala/li/cil/oc/integration/bluepower/BundledRedstoneDevice.scala create mode 100644 src/main/scala/li/cil/oc/integration/bluepower/ModBluePower.scala create mode 100644 src/main/scala/li/cil/oc/integration/bluepower/RedstoneDevice.scala create mode 100644 src/main/scala/li/cil/oc/integration/bluepower/RedstoneProvider.scala diff --git a/build.gradle b/build.gradle index b2c04c0b5..bd6bd6065 100644 --- a/build.gradle +++ b/build.gradle @@ -74,6 +74,10 @@ repositories { name = "bc" url = "http://mod-buildcraft.com/" } + maven { + name = "BluePower" + url = "http://maven.bluepowermod.com/" + } maven { name = "chickenbones" url = "http://chickenbones.net/maven/" @@ -82,6 +86,10 @@ repositories { name = "ic2, forestry" url = "http://maven.ic2.player.to/" } + maven { + name = "IGW" + url = "http://maven.k-4u.nl/" + } maven { name = "mobius" url = "http://mobiusstrip.eu/maven" @@ -156,12 +164,15 @@ dependencies { provided "codechicken:ForgeMultipart:${config.minecraft.version}-${config.fmp.version}:dev" provided "codechicken:NotEnoughItems:${config.minecraft.version}-${config.nei.version}:dev" provided "codechicken:WR-CBE:${config.minecraft.version}-${config.wrcbe.version}:dev" + provided "com.bluepowermod:BluePower:${config.bluepower.version}:deobf" provided "com.gregoriust.gregtech:gregtech_${config.minecraft.version}:${config.gt.version}:dev" provided "com.mod-buildcraft:buildcraft:${config.bc.version}:dev" provided "dev.calclavia.resonantengine:resonant-engine:${config.re.version}:dev" + provided "igwmod:IGW-Mod-1.7.10:${config.igwmod.version}:userdev" provided "mcp.mobius.waila:Waila:${config.waila.version}_${config.minecraft.version}:dev" provided "net.industrial-craft:industrialcraft-2:${config.ic2.version}:dev" provided "net.sengir.forestry:forestry_${config.minecraft.version}:${config.forestry.version}:dev" + provided "qmunity:QmunityLib:${config.qmunitylib.version}:deobf" provided "tmech:TMechworks:${config.minecraft.version}-${config.tmech.version}:deobf" provided name: 'GalacticraftCoreAll', version: config.gc.version, ext: 'jar' @@ -188,7 +199,6 @@ idea.module.scopes.PROVIDED.plus += [configurations.provided] minecraft { version = "${config.minecraft.version}-${config.forge.version}" - replaceIn "li/cil/oc/OpenComputers.scala" replace "@VERSION@", project.simpleVersion } diff --git a/build.properties b/build.properties index 8116216aa..275adcc4d 100644 --- a/build.properties +++ b/build.properties @@ -8,6 +8,7 @@ ae2.version=rv2-beta-26 bc.version=6.4.9 bloodmagic.cf=2223/203 bloodmagic.version=1.3.0a-1 +bluepower.version=0.2.928 cc.cf=2216/236 cc.version=1.65 ccl.version=1.1.1.104 @@ -22,12 +23,14 @@ gc.build=3 gc.version=3.0.7 gt.version=5.04.06 ic2.version=2.2.654-experimental +igwmod.version=1.1.3-18 mekanism.build=5 mekanism.version=7.1.2 mfr.cf=2229/626 mfr.version=[1.7.10]2.8.0RC8-86 nei.version=1.0.3.57 projred.version=4.5.8.59 +qmunitylib.version=0.1.105 rc.cf=2219/321 rc.version=1.7.10-9.4.0.0 redlogic.version=59.0.3 diff --git a/src/main/scala/li/cil/oc/common/item/Wrench.scala b/src/main/scala/li/cil/oc/common/item/Wrench.scala index 2fff19aa7..c27b5938c 100644 --- a/src/main/scala/li/cil/oc/common/item/Wrench.scala +++ b/src/main/scala/li/cil/oc/common/item/Wrench.scala @@ -15,6 +15,7 @@ import net.minecraftforge.common.util.ForgeDirection @Injectable.InterfaceList(Array( new Injectable.Interface(value = "appeng.api.implementations.items.IAEWrench", modid = Mods.IDs.AppliedEnergistics2), new Injectable.Interface(value = "buildcraft.api.tools.IToolWrench", modid = Mods.IDs.BuildCraftTools), + new Injectable.Interface(value = "com.bluepowermod.api.misc.IScrewdriver", modid = Mods.IDs.BluePower), new Injectable.Interface(value = "cofh.api.item.IToolHammer", modid = Mods.IDs.CoFHItem), new Injectable.Interface(value = "crazypants.enderio.tool.ITool", modid = Mods.IDs.EnderIO), new Injectable.Interface(value = "mekanism.api.IMekWrench", modid = Mods.IDs.Mekanism), @@ -48,6 +49,9 @@ class Wrench extends SimpleItem with api.internal.Wrench { def canWrench(stack: ItemStack, player: EntityPlayer, x: Int, y: Int, z: Int): Boolean = true + // BluePower + def damage(stack: ItemStack, damage: Int, player: EntityPlayer, simulated: Boolean): Boolean = damage == 0 + // BuildCraft def canWrench(player: EntityPlayer, x: Int, y: Int, z: Int): Boolean = true 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 8e70cafbb..7f451a55c 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 @@ -1,5 +1,7 @@ package li.cil.oc.common.tileentity.traits +import com.bluepowermod.api.BPApi +import com.bluepowermod.api.wire.redstone.IBundledDevice import cpw.mods.fml.common.Optional import li.cil.oc.Settings import li.cil.oc.integration.Mods @@ -48,6 +50,23 @@ trait BundledRedstoneAware extends RedstoneAware with IBundledEmitter with IBund def bundledInput(side: ForgeDirection) = (_bundledInput(side.ordinal()), _rednetInput(side.ordinal())).zipped.map(math.max) + def bundledInput(side: ForgeDirection, newBundledInput: Array[Int]): Unit = { + val ownBundledInput = _bundledInput(side.ordinal()) + val oldMaxValue = ownBundledInput.max + var changed = false + if (newBundledInput != null) for (color <- 0 until 16) { + changed = changed || (ownBundledInput(color) >= 0 && ownBundledInput(color) != newBundledInput(color)) + ownBundledInput(color) = newBundledInput(color) + } + else for (color <- 0 until 16) { + changed = changed || ownBundledInput(color) > 0 + ownBundledInput(color) = 0 + } + if (changed) { + onRedstoneInputChanged(side, oldMaxValue, ownBundledInput.max) + } + } + def bundledInput(side: ForgeDirection, color: Int) = math.max(_bundledInput(side.ordinal())(color), _rednetInput(side.ordinal())(color)) @@ -83,21 +102,7 @@ trait BundledRedstoneAware extends RedstoneAware with IBundledEmitter with IBund override def updateRedstoneInput(side: ForgeDirection) { super.updateRedstoneInput(side) - 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 || (ownBundledInput(color) >= 0 && ownBundledInput(color) != newBundledInput(color)) - ownBundledInput(color) = newBundledInput(color) - } - else for (color <- 0 until 16) { - changed = changed || ownBundledInput(color) > 0 - ownBundledInput(color) = 0 - } - if (changed) { - onRedstoneInputChanged(side, oldMaxValue, ownBundledInput.max) - } + bundledInput(side, computeBundledInput(side)) } override def readFromNBTForServer(nbt: NBTTagCompound) { @@ -144,9 +149,9 @@ trait BundledRedstoneAware extends RedstoneAware with IBundledEmitter with IBund if (world.blockExists(nx, ny, nz)) world.getTileEntity(nx, ny, nz) match { case wire: IInsulatedRedstoneWire => var strength: Array[Int] = null - for (face <- -1 to 5 if wire.wireConnectsInDirection(face, side.ordinal()) && strength == null) { - strength = Array.fill(16)(0) - strength(wire.getInsulatedWireColour) = wire.getEmittedSignalStrength(face, side.ordinal()) + for (face <- -1 to 5 if wire.wireConnectsInDirection(face, side.ordinal())) { + if (strength == null) strength = Array.fill(16)(0) + strength(wire.getInsulatedWireColour) = math.max(strength(wire.getInsulatedWireColour), wire.getEmittedSignalStrength(face, side.ordinal())) } strength case emitter: IBundledEmitter => @@ -164,12 +169,27 @@ trait BundledRedstoneAware extends RedstoneAware with IBundledEmitter with IBund Option(ProjectRedAPI.transmissionAPI.getBundledInput(world, x, y, z, side.ordinal)).fold(null: Array[Int])(_.map(_ & 0xFF)) } else null - (redLogic, projectRed) match { - case (a: Array[Int], b: Array[Int]) => (a, b).zipped.map((r1, r2) => math.max(r1, r2)) - case (a: Array[Int], _) => a - case (_, b: Array[Int]) => b - case _ => null + val bluePower = if (Mods.BluePower.isAvailable) { + var strength: Array[Int] = null + ForgeDirection.values.map(BPApi.getInstance.getRedstoneApi.getBundledDevice(world, x + side.offsetX, y + side.offsetY, z + side.offsetY, _, ForgeDirection.UNKNOWN)).collect { + case device: IBundledDevice => Option(device.getBundledOutput(side.getOpposite)).foreach(inputs => { + if (strength == null) strength = Array.fill(16)(0) + for (color <- 0 until strength.length) { + strength(color) = math.max(strength(color), inputs(color) & 0xFF) + } + }) + } + strength } + else null + var result: Array[Int] = null + for (inputs <- Iterable(redLogic, projectRed, bluePower) if inputs != null) { + if (result == null) result = Array.fill(16)(0) + for (color <- 0 until result.length) { + result(color) = math.max(result(color), inputs(color)) + } + } + result } override protected def onRedstoneOutputEnabledChanged() { 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 15e32493e..ac403a1f0 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 @@ -1,5 +1,7 @@ package li.cil.oc.common.tileentity.traits +import com.bluepowermod.api.BPApi +import com.bluepowermod.api.wire.redstone.IRedstoneDevice import cpw.mods.fml.common.Optional import cpw.mods.fml.relauncher.Side import cpw.mods.fml.relauncher.SideOnly @@ -47,6 +49,14 @@ trait RedstoneAware extends RotationAware with IConnectable with IRedstoneEmitte def input(side: ForgeDirection) = _input(side.ordinal()) max 0 + def input(side: ForgeDirection, newInput: Int): Unit = { + val oldInput = _input(side.ordinal()) + _input(side.ordinal()) = newInput + if (oldInput >= 0 && newInput != oldInput) { + onRedstoneInputChanged(side, oldInput, newInput) + } + } + def maxInput = ForgeDirection.VALID_DIRECTIONS.map(input).max def output(side: ForgeDirection) = _output(toLocal(side).ordinal()) @@ -76,12 +86,7 @@ trait RedstoneAware extends RotationAware with IConnectable with IRedstoneEmitte } def updateRedstoneInput(side: ForgeDirection) { - val oldInput = _input(side.ordinal()) - val newInput = computeInput(side) - _input(side.ordinal()) = newInput - if (oldInput >= 0 && newInput != oldInput) { - onRedstoneInputChanged(side, oldInput, newInput) - } + input(side, computeInput(side)) } // ----------------------------------------------------------------------- // @@ -136,7 +141,13 @@ trait RedstoneAware extends RotationAware with IConnectable with IRedstoneEmitte } } else 0 - math.max(vanilla, redLogic) + val bluePower = if (Mods.BluePower.isAvailable) { + ForgeDirection.values.map(BPApi.getInstance.getRedstoneApi.getRedstoneDevice(world, x + side.offsetX, y + side.offsetY, z + side.offsetY, _, ForgeDirection.UNKNOWN)).collect { + case device: IRedstoneDevice => device.getRedstonePower(side.getOpposite) & 0xFF + }.padTo(1, 0).max + } + else 0 + vanilla max redLogic max bluePower } } diff --git a/src/main/scala/li/cil/oc/integration/Mods.scala b/src/main/scala/li/cil/oc/integration/Mods.scala index 4c645a182..d6bb28040 100644 --- a/src/main/scala/li/cil/oc/integration/Mods.scala +++ b/src/main/scala/li/cil/oc/integration/Mods.scala @@ -22,6 +22,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 BluePower = new SimpleMod(IDs.BluePower) val BuildCraft = new SimpleMod(IDs.BuildCraft) val BuildCraftTiles = new SimpleMod(IDs.BuildCraftTiles) val BuildCraftTools = new SimpleMod(IDs.BuildCraftTools) @@ -78,6 +79,7 @@ object Mods { val Proxies = Array( integration.appeng.ModAppEng, integration.bloodmagic.ModBloodMagic, + integration.bluepower.ModBluePower, integration.buildcraft.tools.ModBuildCraftAPITools, integration.buildcraft.tiles.ModBuildCraftAPITiles, integration.buildcraft.transport.ModBuildCraftAPITransport, @@ -139,6 +141,7 @@ object Mods { final val AppliedEnergistics2 = "appliedenergistics2" final val BattleGear2 = "battlegear2" final val BloodMagic = "AWWayofTime" + final val BluePower = "bluepowerAPI" final val BuildCraft = "BuildCraft|Core" final val BuildCraftPower = "BuildCraftAPI|power" final val BuildCraftTiles = "BuildCraftAPI|tiles" diff --git a/src/main/scala/li/cil/oc/integration/bluepower/BundledRedstoneDevice.scala b/src/main/scala/li/cil/oc/integration/bluepower/BundledRedstoneDevice.scala new file mode 100644 index 000000000..2e20a0610 --- /dev/null +++ b/src/main/scala/li/cil/oc/integration/bluepower/BundledRedstoneDevice.scala @@ -0,0 +1,38 @@ +package li.cil.oc.integration.bluepower + +import com.bluepowermod.api.BPApi +import com.bluepowermod.api.connect.ConnectionType +import com.bluepowermod.api.connect.IConnectionCache +import com.bluepowermod.api.misc.MinecraftColor +import com.bluepowermod.api.wire.redstone.IBundledDevice +import li.cil.oc.common.tileentity.traits.BundledRedstoneAware +import net.minecraft.world.World +import net.minecraftforge.common.util.ForgeDirection + +class BundledRedstoneDevice(val tileEntity: BundledRedstoneAware) extends IBundledDevice { + lazy val cache = BPApi.getInstance.getRedstoneApi.createBundledConnectionCache(this) + + override def getX: Int = tileEntity.x + + override def getY: Int = tileEntity.y + + override def getZ: Int = tileEntity.z + + override def getWorld: World = tileEntity.world + + override def canConnect(side: ForgeDirection, dev: IBundledDevice, connectionType: ConnectionType): Boolean = tileEntity.isOutputEnabled + + override def isNormalFace(side: ForgeDirection): Boolean = true + + override def getBundledConnectionCache: IConnectionCache[_ <: IBundledDevice] = cache + + override def getBundledColor(side: ForgeDirection): MinecraftColor = MinecraftColor.ANY + + override def getBundledOutput(side: ForgeDirection): Array[Byte] = tileEntity.bundledOutput(side).map(_.toByte) + + override def getBundledPower(side: ForgeDirection): Array[Byte] = tileEntity.bundledInput(side).map(_.toByte) + + override def setBundledPower(side: ForgeDirection, power: Array[Byte]): Unit = tileEntity.bundledInput(side, power.map(_ & 0xFF)) + + override def onBundledUpdate(): Unit = tileEntity.checkRedstoneInputChanged() +} diff --git a/src/main/scala/li/cil/oc/integration/bluepower/ModBluePower.scala b/src/main/scala/li/cil/oc/integration/bluepower/ModBluePower.scala new file mode 100644 index 000000000..b24297d65 --- /dev/null +++ b/src/main/scala/li/cil/oc/integration/bluepower/ModBluePower.scala @@ -0,0 +1,12 @@ +package li.cil.oc.integration.bluepower + +import li.cil.oc.integration.ModProxy +import li.cil.oc.integration.Mods + +object ModBluePower extends ModProxy { + override def getMod = Mods.BluePower + + override def initialize(): Unit = { + RedstoneProvider.init() + } +} diff --git a/src/main/scala/li/cil/oc/integration/bluepower/RedstoneDevice.scala b/src/main/scala/li/cil/oc/integration/bluepower/RedstoneDevice.scala new file mode 100644 index 000000000..f97193757 --- /dev/null +++ b/src/main/scala/li/cil/oc/integration/bluepower/RedstoneDevice.scala @@ -0,0 +1,33 @@ +package li.cil.oc.integration.bluepower + +import com.bluepowermod.api.BPApi +import com.bluepowermod.api.connect.ConnectionType +import com.bluepowermod.api.connect.IConnectionCache +import com.bluepowermod.api.wire.redstone.IRedstoneDevice +import li.cil.oc.common.tileentity.traits.RedstoneAware +import net.minecraft.world.World +import net.minecraftforge.common.util.ForgeDirection + +class RedstoneDevice(val tileEntity: RedstoneAware) extends IRedstoneDevice { + lazy val cache = BPApi.getInstance.getRedstoneApi.createRedstoneConnectionCache(this) + + override def getX: Int = tileEntity.x + + override def getY: Int = tileEntity.y + + override def getZ: Int = tileEntity.z + + override def getWorld: World = tileEntity.world + + override def canConnect(side: ForgeDirection, dev: IRedstoneDevice, connectionType: ConnectionType): Boolean = tileEntity.isOutputEnabled + + override def isNormalFace(side: ForgeDirection): Boolean = true + + override def getRedstoneConnectionCache: IConnectionCache[_ <: IRedstoneDevice] = cache + + override def getRedstonePower(side: ForgeDirection): Byte = tileEntity.output(side).toByte + + override def setRedstonePower(side: ForgeDirection, power: Byte): Unit = tileEntity.input(side, power & 0xFF) + + override def onRedstoneUpdate(): Unit = tileEntity.checkRedstoneInputChanged() +} diff --git a/src/main/scala/li/cil/oc/integration/bluepower/RedstoneProvider.scala b/src/main/scala/li/cil/oc/integration/bluepower/RedstoneProvider.scala new file mode 100644 index 000000000..7297537ef --- /dev/null +++ b/src/main/scala/li/cil/oc/integration/bluepower/RedstoneProvider.scala @@ -0,0 +1,30 @@ +package li.cil.oc.integration.bluepower + +import com.bluepowermod.api.BPApi +import com.bluepowermod.api.wire.redstone.IBundledDevice +import com.bluepowermod.api.wire.redstone.IRedstoneDevice +import com.bluepowermod.api.wire.redstone.IRedstoneProvider +import li.cil.oc.common.tileentity.traits.BundledRedstoneAware +import li.cil.oc.common.tileentity.traits.RedstoneAware +import net.minecraft.world.World +import net.minecraftforge.common.util.ForgeDirection + +object RedstoneProvider extends IRedstoneProvider { + def init(): Unit = { + BPApi.getInstance.getRedstoneApi.registerRedstoneProvider(this) + } + + override def getRedstoneDeviceAt(world: World, x: Int, y: Int, z: Int, side: ForgeDirection, face: ForgeDirection): IRedstoneDevice = { + world.getTileEntity(x, y, z) match { + case tileEntity: RedstoneAware => new RedstoneDevice(tileEntity) + case _ => null + } + } + + override def getBundledDeviceAt(world: World, x: Int, y: Int, z: Int, side: ForgeDirection, face: ForgeDirection): IBundledDevice = { + world.getTileEntity(x, y, z) match { + case tileEntity: BundledRedstoneAware => new BundledRedstoneDevice(tileEntity) + case _ => null + } + } +} From 2886fdcd4dee60ffdb79a115a1db48e9e6a985bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Mon, 27 Apr 2015 21:16:41 +0200 Subject: [PATCH 04/13] Reworked redstone logic to make it more modular. --- .../traits/BundledRedstoneAware.scala | 56 +------------------ .../tileentity/traits/RedstoneAware.scala | 36 +----------- .../common/tileentity/traits/TileEntity.scala | 2 +- .../scala/li/cil/oc/integration/Mods.scala | 2 + .../integration/bluepower/ModBluePower.scala | 29 +++++++++- .../projectred/ModProjectRed.scala | 24 ++++++++ .../oc/integration/redlogic/ModRedLogic.scala | 53 ++++++++++++++++++ .../oc/integration/util/BundledRedstone.scala | 35 +++++++++++- .../oc/integration/vanilla/ModVanilla.scala | 19 ++++++- 9 files changed, 162 insertions(+), 94 deletions(-) create mode 100644 src/main/scala/li/cil/oc/integration/projectred/ModProjectRed.scala create mode 100644 src/main/scala/li/cil/oc/integration/redlogic/ModRedLogic.scala 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 7f451a55c..d8c7f030f 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 @@ -1,18 +1,15 @@ package li.cil.oc.common.tileentity.traits -import com.bluepowermod.api.BPApi -import com.bluepowermod.api.wire.redstone.IBundledDevice import cpw.mods.fml.common.Optional import li.cil.oc.Settings import li.cil.oc.integration.Mods +import li.cil.oc.integration.util.BundledRedstone import li.cil.oc.util.BlockPosition import li.cil.oc.util.ExtendedNBT._ import li.cil.oc.util.ExtendedWorld._ import mods.immibis.redlogic.api.wiring.IBundledEmitter import mods.immibis.redlogic.api.wiring.IBundledUpdatable -import mods.immibis.redlogic.api.wiring.IInsulatedRedstoneWire import mrtjp.projectred.api.IBundledTile -import mrtjp.projectred.api.ProjectRedAPI import net.minecraft.nbt.NBTTagCompound import net.minecraft.nbt.NBTTagIntArray import net.minecraftforge.common.util.Constants.NBT @@ -102,7 +99,7 @@ trait BundledRedstoneAware extends RedstoneAware with IBundledEmitter with IBund override def updateRedstoneInput(side: ForgeDirection) { super.updateRedstoneInput(side) - bundledInput(side, computeBundledInput(side)) + bundledInput(side, BundledRedstone.computeBundledInput(position, side)) } override def readFromNBTForServer(nbt: NBTTagCompound) { @@ -143,55 +140,6 @@ trait BundledRedstoneAware extends RedstoneAware with IBundledEmitter with IBund // ----------------------------------------------------------------------- // - protected def computeBundledInput(side: ForgeDirection): Array[Int] = { - val redLogic = if (Mods.RedLogic.isAvailable) { - val (nx, ny, nz) = (x + side.offsetX, y + side.offsetY, z + side.offsetZ) - if (world.blockExists(nx, ny, nz)) world.getTileEntity(nx, ny, nz) match { - case wire: IInsulatedRedstoneWire => - var strength: Array[Int] = null - for (face <- -1 to 5 if wire.wireConnectsInDirection(face, side.ordinal())) { - if (strength == null) strength = Array.fill(16)(0) - strength(wire.getInsulatedWireColour) = math.max(strength(wire.getInsulatedWireColour), wire.getEmittedSignalStrength(face, side.ordinal())) - } - strength - case emitter: IBundledEmitter => - var strength: Array[Int] = null - for (i <- -1 to 5 if strength == null) { - strength = Option(emitter.getBundledCableStrength(i, side.getOpposite.ordinal())).fold(null: Array[Int])(_.map(_ & 0xFF)) - } - strength - case _ => null - } - else null - } - else null - val projectRed = if (Mods.ProjectRedTransmission.isAvailable) { - Option(ProjectRedAPI.transmissionAPI.getBundledInput(world, x, y, z, side.ordinal)).fold(null: Array[Int])(_.map(_ & 0xFF)) - } - else null - val bluePower = if (Mods.BluePower.isAvailable) { - var strength: Array[Int] = null - ForgeDirection.values.map(BPApi.getInstance.getRedstoneApi.getBundledDevice(world, x + side.offsetX, y + side.offsetY, z + side.offsetY, _, ForgeDirection.UNKNOWN)).collect { - case device: IBundledDevice => Option(device.getBundledOutput(side.getOpposite)).foreach(inputs => { - if (strength == null) strength = Array.fill(16)(0) - for (color <- 0 until strength.length) { - strength(color) = math.max(strength(color), inputs(color) & 0xFF) - } - }) - } - strength - } - else null - var result: Array[Int] = null - for (inputs <- Iterable(redLogic, projectRed, bluePower) if inputs != null) { - if (result == null) result = Array.fill(16)(0) - for (color <- 0 until result.length) { - result(color) = math.max(result(color), inputs(color)) - } - } - result - } - override protected def onRedstoneOutputEnabledChanged() { if (Mods.MineFactoryReloaded.isAvailable) { for (side <- ForgeDirection.VALID_DIRECTIONS) { 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 ac403a1f0..3ba0f4cd5 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 @@ -1,20 +1,17 @@ package li.cil.oc.common.tileentity.traits -import com.bluepowermod.api.BPApi -import com.bluepowermod.api.wire.redstone.IRedstoneDevice import cpw.mods.fml.common.Optional import cpw.mods.fml.relauncher.Side import cpw.mods.fml.relauncher.SideOnly import li.cil.oc.Settings import li.cil.oc.integration.Mods +import li.cil.oc.integration.util.BundledRedstone import li.cil.oc.server.{PacketSender => ServerPacketSender} -import li.cil.oc.util.BlockPosition import li.cil.oc.util.ExtendedWorld._ import mods.immibis.redlogic.api.wiring.IConnectable import mods.immibis.redlogic.api.wiring.IRedstoneEmitter import mods.immibis.redlogic.api.wiring.IRedstoneUpdatable import mods.immibis.redlogic.api.wiring.IWire -import net.minecraft.init.Blocks import net.minecraft.nbt.NBTTagCompound import net.minecraftforge.common.util.ForgeDirection @@ -86,7 +83,7 @@ trait RedstoneAware extends RotationAware with IConnectable with IRedstoneEmitte } def updateRedstoneInput(side: ForgeDirection) { - input(side, computeInput(side)) + input(side, BundledRedstone.computeInput(position, side)) } // ----------------------------------------------------------------------- // @@ -122,35 +119,6 @@ trait RedstoneAware extends RotationAware with IConnectable with IRedstoneEmitte // ----------------------------------------------------------------------- // - protected def computeInput(side: ForgeDirection) = { - val blockPos = BlockPosition(x, y, z).offset(side) - if (!world.blockExists(blockPos)) 0 - else { - // See BlockRedstoneLogic.getInputStrength() for reference. - val vanilla = math.max(world.getIndirectPowerLevelTo(blockPos, side), - if (world.getBlock(blockPos) == Blocks.redstone_wire) world.getBlockMetadata(blockPos) else 0) - val redLogic = if (Mods.RedLogic.isAvailable) { - world.getTileEntity(blockPos) match { - case emitter: IRedstoneEmitter => - var strength = 0 - for (i <- -1 to 5) { - strength = math.max(strength, emitter.getEmittedSignalStrength(i, side.getOpposite.ordinal())) - } - strength - case _ => 0 - } - } - else 0 - val bluePower = if (Mods.BluePower.isAvailable) { - ForgeDirection.values.map(BPApi.getInstance.getRedstoneApi.getRedstoneDevice(world, x + side.offsetX, y + side.offsetY, z + side.offsetY, _, ForgeDirection.UNKNOWN)).collect { - case device: IRedstoneDevice => device.getRedstonePower(side.getOpposite) & 0xFF - }.padTo(1, 0).max - } - else 0 - vanilla max redLogic max bluePower - } - } - protected def onRedstoneInputChanged(side: ForgeDirection, oldMaxValue: Int, newMaxValue: Int) {} protected def onRedstoneOutputEnabledChanged() { diff --git a/src/main/scala/li/cil/oc/common/tileentity/traits/TileEntity.scala b/src/main/scala/li/cil/oc/common/tileentity/traits/TileEntity.scala index e01b6d788..9b6dfd2fc 100644 --- a/src/main/scala/li/cil/oc/common/tileentity/traits/TileEntity.scala +++ b/src/main/scala/li/cil/oc/common/tileentity/traits/TileEntity.scala @@ -20,7 +20,7 @@ trait TileEntity extends net.minecraft.tileentity.TileEntity { def z = zCoord - def position = BlockPosition(x, y, z) + def position = BlockPosition(x, y, z, world) def block = getBlockType diff --git a/src/main/scala/li/cil/oc/integration/Mods.scala b/src/main/scala/li/cil/oc/integration/Mods.scala index d6bb28040..9b50bf26f 100644 --- a/src/main/scala/li/cil/oc/integration/Mods.scala +++ b/src/main/scala/li/cil/oc/integration/Mods.scala @@ -96,7 +96,9 @@ object Mods { integration.ic2.ModIndustrialCraft2, integration.mfr.ModMineFactoryReloaded, integration.mystcraft.ModMystcraft, + integration.projectred.ModProjectRed, integration.railcraft.ModRailcraft, + integration.redlogic.ModRedLogic, integration.stargatetech2.ModStargateTech2, integration.thaumcraft.ModThaumcraft, integration.thermalexpansion.ModThermalExpansion, diff --git a/src/main/scala/li/cil/oc/integration/bluepower/ModBluePower.scala b/src/main/scala/li/cil/oc/integration/bluepower/ModBluePower.scala index b24297d65..c97251e24 100644 --- a/src/main/scala/li/cil/oc/integration/bluepower/ModBluePower.scala +++ b/src/main/scala/li/cil/oc/integration/bluepower/ModBluePower.scala @@ -1,12 +1,39 @@ package li.cil.oc.integration.bluepower +import com.bluepowermod.api.BPApi +import com.bluepowermod.api.wire.redstone.IBundledDevice +import com.bluepowermod.api.wire.redstone.IRedstoneDevice import li.cil.oc.integration.ModProxy import li.cil.oc.integration.Mods +import li.cil.oc.integration.util.BundledRedstone +import li.cil.oc.integration.util.BundledRedstone.RedstoneProvider +import li.cil.oc.util.BlockPosition +import net.minecraftforge.common.util.ForgeDirection -object ModBluePower extends ModProxy { +object ModBluePower extends ModProxy with RedstoneProvider { override def getMod = Mods.BluePower override def initialize(): Unit = { RedstoneProvider.init() + + BundledRedstone.addProvider(this) + } + + override def computeInput(pos: BlockPosition, side: ForgeDirection): Int = { + val world = pos.world.get + val (nx, ny, nz) = (pos.x + side.offsetX, pos.y + side.offsetY, pos.z + side.offsetZ) + ForgeDirection.values.map(BPApi.getInstance.getRedstoneApi.getRedstoneDevice(world, nx, ny, nz, _, ForgeDirection.UNKNOWN)).collect { + case device: IRedstoneDevice => device.getRedstonePower(side.getOpposite) & 0xFF + }.padTo(1, 0).max + } + + def computeBundledInput(pos: BlockPosition, side: ForgeDirection): Array[Int] = { + val world = pos.world.get + val (nx, ny, nz) = (pos.x + side.offsetX, pos.y + side.offsetY, pos.z + side.offsetZ) + val inputs = ForgeDirection.values.map(BPApi.getInstance.getRedstoneApi.getBundledDevice(world, nx, ny, nz, _, ForgeDirection.UNKNOWN)).collect { + case device: IBundledDevice => Option(device.getBundledOutput(side.getOpposite)).fold(null: Array[Int])(_.map(_ & 0xFF)) + }.filter(_ != null) + if (inputs.isEmpty) null + else inputs.reduce((a, b) => (a, b).zipped.map((l, r) => math.max(l, r))) } } diff --git a/src/main/scala/li/cil/oc/integration/projectred/ModProjectRed.scala b/src/main/scala/li/cil/oc/integration/projectred/ModProjectRed.scala new file mode 100644 index 000000000..b2982427a --- /dev/null +++ b/src/main/scala/li/cil/oc/integration/projectred/ModProjectRed.scala @@ -0,0 +1,24 @@ +package li.cil.oc.integration.projectred + +import li.cil.oc.integration.ModProxy +import li.cil.oc.integration.Mods +import li.cil.oc.integration.util.BundledRedstone +import li.cil.oc.integration.util.BundledRedstone.RedstoneProvider +import li.cil.oc.util.BlockPosition +import mrtjp.projectred.api.ProjectRedAPI +import net.minecraftforge.common.util.ForgeDirection + +object ModProjectRed extends ModProxy with RedstoneProvider { + override def getMod = Mods.ProjectRedTransmission + + override def initialize(): Unit = { + BundledRedstone.addProvider(this) + } + + override def computeInput(pos: BlockPosition, side: ForgeDirection): Int = 0 + + def computeBundledInput(pos: BlockPosition, side: ForgeDirection): Array[Int] = { + Option(ProjectRedAPI.transmissionAPI.getBundledInput(pos.world.get, pos.x, pos.y, pos.z, side.ordinal)). + fold(null: Array[Int])(_.map(_ & 0xFF)) + } +} diff --git a/src/main/scala/li/cil/oc/integration/redlogic/ModRedLogic.scala b/src/main/scala/li/cil/oc/integration/redlogic/ModRedLogic.scala new file mode 100644 index 000000000..a762a2f5b --- /dev/null +++ b/src/main/scala/li/cil/oc/integration/redlogic/ModRedLogic.scala @@ -0,0 +1,53 @@ +package li.cil.oc.integration.redlogic + +import li.cil.oc.integration.ModProxy +import li.cil.oc.integration.Mods +import li.cil.oc.integration.util.BundledRedstone +import li.cil.oc.integration.util.BundledRedstone.RedstoneProvider +import li.cil.oc.util.BlockPosition +import li.cil.oc.util.ExtendedWorld._ +import mods.immibis.redlogic.api.wiring.IBundledEmitter +import mods.immibis.redlogic.api.wiring.IInsulatedRedstoneWire +import mods.immibis.redlogic.api.wiring.IRedstoneEmitter +import net.minecraftforge.common.util.ForgeDirection + +object ModRedLogic extends ModProxy with RedstoneProvider { + override def getMod = Mods.RedLogic + + override def initialize(): Unit = { + BundledRedstone.addProvider(this) + } + + override def computeInput(pos: BlockPosition, side: ForgeDirection): Int = { + pos.world.get.getTileEntity(pos) match { + case emitter: IRedstoneEmitter => + var strength = 0 + for (i <- -1 to 5) { + strength = math.max(strength, emitter.getEmittedSignalStrength(i, side.getOpposite.ordinal())) + } + strength + case _ => 0 + } + } + + def computeBundledInput(pos: BlockPosition, side: ForgeDirection): Array[Int] = { + val world = pos.world.get + val npos = pos.offset(side) + world.getTileEntity(npos) match { + case wire: IInsulatedRedstoneWire => + var strength: Array[Int] = null + for (face <- -1 to 5 if wire.wireConnectsInDirection(face, side.ordinal())) { + if (strength == null) strength = Array.fill(16)(0) + strength(wire.getInsulatedWireColour) = math.max(strength(wire.getInsulatedWireColour), wire.getEmittedSignalStrength(face, side.ordinal())) + } + strength + case emitter: IBundledEmitter => + var strength: Array[Int] = null + for (i <- -1 to 5 if strength == null) { + strength = Option(emitter.getBundledCableStrength(i, side.getOpposite.ordinal())).fold(null: Array[Int])(_.map(_ & 0xFF)) + } + strength + case _ => null + } + } +} diff --git a/src/main/scala/li/cil/oc/integration/util/BundledRedstone.scala b/src/main/scala/li/cil/oc/integration/util/BundledRedstone.scala index 2502881dc..de3983539 100644 --- a/src/main/scala/li/cil/oc/integration/util/BundledRedstone.scala +++ b/src/main/scala/li/cil/oc/integration/util/BundledRedstone.scala @@ -1,9 +1,38 @@ package li.cil.oc.integration.util import li.cil.oc.integration.Mods +import li.cil.oc.util.BlockPosition +import li.cil.oc.util.ExtendedWorld._ +import net.minecraftforge.common.util.ForgeDirection + +import scala.collection.mutable object BundledRedstone { - def isAvailable = Mods.RedLogic.isAvailable || - Mods.MineFactoryReloaded.isAvailable || - Mods.ProjectRedTransmission.isAvailable + val providers = mutable.Buffer.empty[RedstoneProvider] + + def addProvider(provider: RedstoneProvider): Unit = providers += provider + + def isAvailable = Mods.MineFactoryReloaded.isAvailable || providers.length > 0 + + def computeInput(pos: BlockPosition, side: ForgeDirection): Int = { + if (pos.world.get.blockExists(pos.offset(side))) + providers.map(_.computeInput(pos, side)).padTo(1, 0).max + else 0 + } + + def computeBundledInput(pos: BlockPosition, side: ForgeDirection): Array[Int] = { + if (pos.world.get.blockExists(pos.offset(side))) { + val inputs = providers.map(_.computeBundledInput(pos, side)).filter(_ != null) + if (inputs.isEmpty) null + else inputs.reduce((a, b) => (a, b).zipped.map((l, r) => math.max(l, r))) + } + else null + } + + trait RedstoneProvider { + def computeInput(pos: BlockPosition, side: ForgeDirection): Int + + def computeBundledInput(pos: BlockPosition, side: ForgeDirection): Array[Int] + } + } diff --git a/src/main/scala/li/cil/oc/integration/vanilla/ModVanilla.scala b/src/main/scala/li/cil/oc/integration/vanilla/ModVanilla.scala index a1916d1be..93dddf5a8 100644 --- a/src/main/scala/li/cil/oc/integration/vanilla/ModVanilla.scala +++ b/src/main/scala/li/cil/oc/integration/vanilla/ModVanilla.scala @@ -4,8 +4,14 @@ import li.cil.oc.Settings import li.cil.oc.api.Driver import li.cil.oc.integration.ModProxy import li.cil.oc.integration.Mods +import li.cil.oc.integration.util.BundledRedstone +import li.cil.oc.integration.util.BundledRedstone.RedstoneProvider +import li.cil.oc.util.BlockPosition +import li.cil.oc.util.ExtendedWorld._ +import net.minecraft.init.Blocks +import net.minecraftforge.common.util.ForgeDirection -object ModVanilla extends ModProxy { +object ModVanilla extends ModProxy with RedstoneProvider { def getMod = Mods.Minecraft def initialize() { @@ -36,5 +42,16 @@ object ModVanilla extends ModProxy { Driver.add(ConverterWorldProvider) RecipeHandler.init() + + BundledRedstone.addProvider(this) } + + override def computeInput(pos: BlockPosition, side: ForgeDirection): Int = { + val world = pos.world.get + // See BlockRedstoneLogic.getInputStrength() for reference. + math.max(world.getIndirectPowerLevelTo(pos, side), + if (world.getBlock(pos) == Blocks.redstone_wire) world.getBlockMetadata(pos) else 0) + } + + override def computeBundledInput(pos: BlockPosition, side: ForgeDirection): Array[Int] = null } From 15cc9a7146cf3b0fa9ccac31703abb4587e1d284 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Wed, 29 Apr 2015 16:18:21 +0200 Subject: [PATCH 05/13] Caching redstone devices for bluepower. --- .../oc/integration/bluepower/RedstoneProvider.scala | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/main/scala/li/cil/oc/integration/bluepower/RedstoneProvider.scala b/src/main/scala/li/cil/oc/integration/bluepower/RedstoneProvider.scala index 7297537ef..489ff09d1 100644 --- a/src/main/scala/li/cil/oc/integration/bluepower/RedstoneProvider.scala +++ b/src/main/scala/li/cil/oc/integration/bluepower/RedstoneProvider.scala @@ -9,21 +9,27 @@ import li.cil.oc.common.tileentity.traits.RedstoneAware import net.minecraft.world.World import net.minecraftforge.common.util.ForgeDirection +import scala.collection.mutable + object RedstoneProvider extends IRedstoneProvider { + val redstoneDevices = mutable.WeakHashMap.empty[RedstoneAware, RedstoneDevice] + + val bundledRedstoneDevices = mutable.WeakHashMap.empty[BundledRedstoneAware, BundledRedstoneDevice] + def init(): Unit = { BPApi.getInstance.getRedstoneApi.registerRedstoneProvider(this) } override def getRedstoneDeviceAt(world: World, x: Int, y: Int, z: Int, side: ForgeDirection, face: ForgeDirection): IRedstoneDevice = { world.getTileEntity(x, y, z) match { - case tileEntity: RedstoneAware => new RedstoneDevice(tileEntity) + case tileEntity: RedstoneAware => redstoneDevices.getOrElseUpdate(tileEntity, new RedstoneDevice(tileEntity)) case _ => null } } override def getBundledDeviceAt(world: World, x: Int, y: Int, z: Int, side: ForgeDirection, face: ForgeDirection): IBundledDevice = { world.getTileEntity(x, y, z) match { - case tileEntity: BundledRedstoneAware => new BundledRedstoneDevice(tileEntity) + case tileEntity: BundledRedstoneAware => bundledRedstoneDevices.getOrElseUpdate(tileEntity, new BundledRedstoneDevice(tileEntity)) case _ => null } } From cb704dab33b408d00cf63b7702dc5e7816b95c91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Wed, 29 Apr 2015 16:19:08 +0200 Subject: [PATCH 06/13] Basic integration for IGWMod, providing manual pages for blocks and items. --- .../opencomputers/doc/en_US/block/print.md | 2 +- .../renderer/markdown/MarkupFormat.scala | 5 ++ .../markdown/segment/BasicTextSegment.scala | 3 + .../markdown/segment/BoldSegment.scala | 6 +- .../markdown/segment/CodeSegment.scala | 6 +- .../markdown/segment/HeaderSegment.scala | 6 +- .../markdown/segment/ItalicSegment.scala | 6 +- .../markdown/segment/LinkSegment.scala | 9 ++- .../markdown/segment/RenderSegment.scala | 6 +- .../renderer/markdown/segment/Segment.scala | 21 +++++++ .../segment/StrikethroughSegment.scala | 6 +- .../markdown/segment/TextSegment.scala | 2 - .../scala/li/cil/oc/common/init/Items.scala | 4 +- .../scala/li/cil/oc/integration/Mods.scala | 10 +++- .../oc/integration/igw/ModIngameWiki.scala | 14 +++++ .../oc/integration/igw/WikiEventHandler.scala | 57 +++++++++++++++++++ 16 files changed, 149 insertions(+), 14 deletions(-) create mode 100644 src/main/scala/li/cil/oc/client/renderer/markdown/MarkupFormat.scala create mode 100644 src/main/scala/li/cil/oc/integration/igw/ModIngameWiki.scala create mode 100644 src/main/scala/li/cil/oc/integration/igw/WikiEventHandler.scala diff --git a/src/main/resources/assets/opencomputers/doc/en_US/block/print.md b/src/main/resources/assets/opencomputers/doc/en_US/block/print.md index 8fea03113..e1775103e 100644 --- a/src/main/resources/assets/opencomputers/doc/en_US/block/print.md +++ b/src/main/resources/assets/opencomputers/doc/en_US/block/print.md @@ -6,6 +6,6 @@ 3D prints can be recycled by putting them as input into a [3D printer](printer.md). This will re-use some of the [chamelium](../item/chamelium.md) that was used to print them. Color that was used to print the model will not be recycled. -Holding the key for OpenComputers' extended tooltips (default is [Shift]), a print's active state will be shown, if any. +Holding the key for OpenComputers' extended tooltips (default is `Shift`), a print's active state will be shown, if any. Printed blocks are also Forge MultiPart compatible. If present, multiple prints can be placed into a single block-space, unless they do not collide, and the total number of shapes in the block-space does not exceed the limit for a single model. Due to the nature of Forge MultiPart, prints can therefore also be placed into the same block-space as any other Forge MultiPart compatible block, such as torches, levers, cables or red alloy wires from Project Red, for example. diff --git a/src/main/scala/li/cil/oc/client/renderer/markdown/MarkupFormat.scala b/src/main/scala/li/cil/oc/client/renderer/markdown/MarkupFormat.scala new file mode 100644 index 000000000..72a5c3118 --- /dev/null +++ b/src/main/scala/li/cil/oc/client/renderer/markdown/MarkupFormat.scala @@ -0,0 +1,5 @@ +package li.cil.oc.client.renderer.markdown + +object MarkupFormat extends Enumeration { + val Markdown, IGWMod = Value +} diff --git a/src/main/scala/li/cil/oc/client/renderer/markdown/segment/BasicTextSegment.scala b/src/main/scala/li/cil/oc/client/renderer/markdown/segment/BasicTextSegment.scala index 7fd3e328f..d19a4d21e 100644 --- a/src/main/scala/li/cil/oc/client/renderer/markdown/segment/BasicTextSegment.scala +++ b/src/main/scala/li/cil/oc/client/renderer/markdown/segment/BasicTextSegment.scala @@ -1,6 +1,7 @@ package li.cil.oc.client.renderer.markdown.segment import li.cil.oc.client.renderer.markdown.Document +import li.cil.oc.client.renderer.markdown.MarkupFormat import net.minecraft.client.gui.FontRenderer trait BasicTextSegment extends Segment { @@ -38,6 +39,8 @@ trait BasicTextSegment extends Segment { lines * lineHeight(renderer) } + override def toString(format: MarkupFormat.Value): String = text + // ----------------------------------------------------------------------- // protected def text: String diff --git a/src/main/scala/li/cil/oc/client/renderer/markdown/segment/BoldSegment.scala b/src/main/scala/li/cil/oc/client/renderer/markdown/segment/BoldSegment.scala index 820d423b2..908bf155f 100644 --- a/src/main/scala/li/cil/oc/client/renderer/markdown/segment/BoldSegment.scala +++ b/src/main/scala/li/cil/oc/client/renderer/markdown/segment/BoldSegment.scala @@ -1,9 +1,13 @@ package li.cil.oc.client.renderer.markdown.segment +import li.cil.oc.client.renderer.markdown.MarkupFormat import net.minecraft.util.EnumChatFormatting private[markdown] class BoldSegment(parent: Segment, text: String) extends TextSegment(parent, text) { override protected def format = EnumChatFormatting.BOLD.toString - override def toString: String = s"{BoldSegment: text = $text}" + override def toString(format: MarkupFormat.Value): String = format match { + case MarkupFormat.Markdown => s"**$text**" + case MarkupFormat.IGWMod => s"[prefix{l}]$text [prefix{}]" + } } diff --git a/src/main/scala/li/cil/oc/client/renderer/markdown/segment/CodeSegment.scala b/src/main/scala/li/cil/oc/client/renderer/markdown/segment/CodeSegment.scala index 46f36f4aa..5356e55e4 100644 --- a/src/main/scala/li/cil/oc/client/renderer/markdown/segment/CodeSegment.scala +++ b/src/main/scala/li/cil/oc/client/renderer/markdown/segment/CodeSegment.scala @@ -1,6 +1,7 @@ package li.cil.oc.client.renderer.markdown.segment import li.cil.oc.client.renderer.TextBufferRenderCache +import li.cil.oc.client.renderer.markdown.MarkupFormat import net.minecraft.client.gui.FontRenderer import org.lwjgl.opengl.GL11 @@ -30,5 +31,8 @@ private[markdown] class CodeSegment(val parent: Segment, val text: String) exten override protected def stringWidth(s: String, renderer: FontRenderer): Int = s.length * TextBufferRenderCache.renderer.charRenderWidth - override def toString: String = s"{CodeSegment: text = $text}" + override def toString(format: MarkupFormat.Value): String = format match { + case MarkupFormat.Markdown => s"`$text`" + case MarkupFormat.IGWMod => s"[prefix{1}]$text [prefix{}]" + } } diff --git a/src/main/scala/li/cil/oc/client/renderer/markdown/segment/HeaderSegment.scala b/src/main/scala/li/cil/oc/client/renderer/markdown/segment/HeaderSegment.scala index 18657a757..1baf4e06a 100644 --- a/src/main/scala/li/cil/oc/client/renderer/markdown/segment/HeaderSegment.scala +++ b/src/main/scala/li/cil/oc/client/renderer/markdown/segment/HeaderSegment.scala @@ -1,5 +1,6 @@ package li.cil.oc.client.renderer.markdown.segment +import li.cil.oc.client.renderer.markdown.MarkupFormat import net.minecraft.util.EnumChatFormatting private[markdown] class HeaderSegment(parent: Segment, text: String, val level: Int) extends TextSegment(parent, text) { @@ -9,5 +10,8 @@ private[markdown] class HeaderSegment(parent: Segment, text: String, val level: override protected def format = EnumChatFormatting.UNDERLINE.toString - override def toString: String = s"{HeaderSegment: text = $text, level = $level}" + override def toString(format: MarkupFormat.Value): String = format match { + case MarkupFormat.Markdown => s"${"#" * level} $text" + case MarkupFormat.IGWMod => s"[prefix{l}]$text [prefix{}]" + } } diff --git a/src/main/scala/li/cil/oc/client/renderer/markdown/segment/ItalicSegment.scala b/src/main/scala/li/cil/oc/client/renderer/markdown/segment/ItalicSegment.scala index ee6bd34d8..e8afb72e9 100644 --- a/src/main/scala/li/cil/oc/client/renderer/markdown/segment/ItalicSegment.scala +++ b/src/main/scala/li/cil/oc/client/renderer/markdown/segment/ItalicSegment.scala @@ -1,9 +1,13 @@ package li.cil.oc.client.renderer.markdown.segment +import li.cil.oc.client.renderer.markdown.MarkupFormat import net.minecraft.util.EnumChatFormatting private[markdown] class ItalicSegment(parent: Segment, text: String) extends TextSegment(parent, text) { override protected def format = EnumChatFormatting.ITALIC.toString - override def toString: String = s"{ItalicSegment: text = $text}" + override def toString(format: MarkupFormat.Value): String = format match { + case MarkupFormat.Markdown => s"*$text*" + case MarkupFormat.IGWMod => s"[prefix{o}]$text [prefix{}]" + } } diff --git a/src/main/scala/li/cil/oc/client/renderer/markdown/segment/LinkSegment.scala b/src/main/scala/li/cil/oc/client/renderer/markdown/segment/LinkSegment.scala index 15fc30289..213cf4443 100644 --- a/src/main/scala/li/cil/oc/client/renderer/markdown/segment/LinkSegment.scala +++ b/src/main/scala/li/cil/oc/client/renderer/markdown/segment/LinkSegment.scala @@ -3,8 +3,10 @@ package li.cil.oc.client.renderer.markdown.segment import java.net.URI import li.cil.oc.Localization +import li.cil.oc.OpenComputers import li.cil.oc.api import li.cil.oc.client.Manual +import li.cil.oc.client.renderer.markdown.MarkupFormat import net.minecraft.client.Minecraft private[markdown] class LinkSegment(parent: Segment, text: String, val url: String) extends TextSegment(parent, text) with InteractiveSegment { @@ -54,5 +56,10 @@ private[markdown] class LinkSegment(parent: Segment, text: String, val url: Stri } } - override def toString: String = s"{LinkSegment: text = $text, url = $url}" + override def toString(format: MarkupFormat.Value): String = format match { + case MarkupFormat.Markdown => s"[$text]($url)" + case MarkupFormat.IGWMod => + if (url.startsWith("http://") || url.startsWith("https://")) text + else s"[link{${OpenComputers.ID}:$url}]$text [link{}]" + } } diff --git a/src/main/scala/li/cil/oc/client/renderer/markdown/segment/RenderSegment.scala b/src/main/scala/li/cil/oc/client/renderer/markdown/segment/RenderSegment.scala index d1183338c..d635e98d5 100644 --- a/src/main/scala/li/cil/oc/client/renderer/markdown/segment/RenderSegment.scala +++ b/src/main/scala/li/cil/oc/client/renderer/markdown/segment/RenderSegment.scala @@ -3,6 +3,7 @@ package li.cil.oc.client.renderer.markdown.segment import li.cil.oc.api.manual.ImageRenderer import li.cil.oc.api.manual.InteractiveImageRenderer import li.cil.oc.client.renderer.markdown.Document +import li.cil.oc.client.renderer.markdown.MarkupFormat import net.minecraft.client.gui.FontRenderer import org.lwjgl.opengl.GL11 @@ -74,5 +75,8 @@ private[markdown] class RenderSegment(val parent: Segment, val title: String, va hovered } - override def toString: String = s"{RendererSegment: title = $title, imageRenderer = $imageRenderer}" + override def toString(format: MarkupFormat.Value): String = format match { + case MarkupFormat.Markdown => s"![$title]($imageRenderer)" + case MarkupFormat.IGWMod => "(Sorry, images only work in the OpenComputers manual for now.)" // TODO + } } diff --git a/src/main/scala/li/cil/oc/client/renderer/markdown/segment/Segment.scala b/src/main/scala/li/cil/oc/client/renderer/markdown/segment/Segment.scala index 7e6ca0527..645dd1a90 100644 --- a/src/main/scala/li/cil/oc/client/renderer/markdown/segment/Segment.scala +++ b/src/main/scala/li/cil/oc/client/renderer/markdown/segment/Segment.scala @@ -1,8 +1,10 @@ package li.cil.oc.client.renderer.markdown.segment +import li.cil.oc.client.renderer.markdown.MarkupFormat import net.minecraft.client.gui.FontRenderer import scala.annotation.tailrec +import scala.collection.mutable import scala.util.matching.Regex trait Segment { @@ -46,6 +48,25 @@ trait Segment { */ def render(x: Int, y: Int, indent: Int, maxWidth: Int, renderer: FontRenderer, mouseX: Int, mouseY: Int): Option[InteractiveSegment] = None + def renderAsText(format: MarkupFormat.Value): Iterable[String] = { + var segment = this + val result = mutable.Buffer.empty[String] + val builder = mutable.StringBuilder.newBuilder + while (segment != null) { + builder.append(segment.toString(format)) + if (segment.isLast) { + result += builder.toString() + builder.clear() + } + segment = segment.next + } + result.toIterable + } + + def toString(format: MarkupFormat.Value): String + + override def toString: String = toString(MarkupFormat.Markdown) + // ----------------------------------------------------------------------- // // Used during construction, checks a segment for inner segments. diff --git a/src/main/scala/li/cil/oc/client/renderer/markdown/segment/StrikethroughSegment.scala b/src/main/scala/li/cil/oc/client/renderer/markdown/segment/StrikethroughSegment.scala index 3b2056c79..e3b544e22 100644 --- a/src/main/scala/li/cil/oc/client/renderer/markdown/segment/StrikethroughSegment.scala +++ b/src/main/scala/li/cil/oc/client/renderer/markdown/segment/StrikethroughSegment.scala @@ -1,9 +1,13 @@ package li.cil.oc.client.renderer.markdown.segment +import li.cil.oc.client.renderer.markdown.MarkupFormat import net.minecraft.util.EnumChatFormatting private[markdown] class StrikethroughSegment(parent: Segment, text: String) extends TextSegment(parent, text) { override protected def format = EnumChatFormatting.STRIKETHROUGH.toString - override def toString: String = s"{StrikethroughSegment: text = $text}" + override def toString(format: MarkupFormat.Value): String = format match { + case MarkupFormat.Markdown => s"~~$text~~" + case MarkupFormat.IGWMod => s"[prefix{m}]$text [prefix{}]" + } } diff --git a/src/main/scala/li/cil/oc/client/renderer/markdown/segment/TextSegment.scala b/src/main/scala/li/cil/oc/client/renderer/markdown/segment/TextSegment.scala index 9c0bc8383..491c6faad 100644 --- a/src/main/scala/li/cil/oc/client/renderer/markdown/segment/TextSegment.scala +++ b/src/main/scala/li/cil/oc/client/renderer/markdown/segment/TextSegment.scala @@ -96,6 +96,4 @@ private[markdown] class TextSegment(val parent: Segment, val text: String) exten case _ => None } } - - override def toString: String = s"{TextSegment: text = $text}" } 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 d09a0e920..4b30ae26d 100644 --- a/src/main/scala/li/cil/oc/common/init/Items.scala +++ b/src/main/scala/li/cil/oc/common/init/Items.scala @@ -32,9 +32,9 @@ import net.minecraft.world.World import scala.collection.mutable object Items extends ItemAPI { - private val descriptors = mutable.Map.empty[String, ItemInfo] + val descriptors = mutable.Map.empty[String, ItemInfo] - private val names = mutable.Map.empty[Any, String] + val names = mutable.Map.empty[Any, String] override def get(name: String): ItemInfo = descriptors.get(name).orNull diff --git a/src/main/scala/li/cil/oc/integration/Mods.scala b/src/main/scala/li/cil/oc/integration/Mods.scala index 9b50bf26f..715db2a1f 100644 --- a/src/main/scala/li/cil/oc/integration/Mods.scala +++ b/src/main/scala/li/cil/oc/integration/Mods.scala @@ -44,6 +44,7 @@ object Mods { val GregTech = new ClassBasedMod(IDs.GregTech, "gregtech.api.GregTech_API")() val IndustrialCraft2 = new SimpleMod(IDs.IndustrialCraft2, providesPower = true) val IndustrialCraft2Classic = new SimpleMod(IDs.IndustrialCraft2Classic, providesPower = true) + val IngameWiki = new SimpleMod(IDs.IngameWiki, version = "@[1.1.3,)") val Mekanism = new SimpleMod(IDs.Mekanism, providesPower = true) val Minecraft = new SimpleMod(IDs.Minecraft) val MineFactoryReloaded = new SimpleMod(IDs.MineFactoryReloaded) @@ -114,9 +115,13 @@ object Mods { // being used rather than other more concrete implementations. integration.computercraft.ModComputerCraft, - // We go last to ensure all other mod integration is done, e.g. to + // We go late to ensure all other mod integration is done, e.g. to // allow properly checking if wireless redstone is present. - integration.opencomputers.ModOpenComputers + integration.opencomputers.ModOpenComputers, + + // Run IGW registration after OC registration because we use the manual + // in there to know which pages to register. + integration.igw.ModIngameWiki ) def init(): Unit = { @@ -166,6 +171,7 @@ object Mods { final val GregTech = "gregtech" final val IndustrialCraft2 = "IC2" final val IndustrialCraft2Classic = "IC2-Classic" + final val IngameWiki = "IGWMod" final val Mekanism = "Mekanism" final val Minecraft = "Minecraft" final val MineFactoryReloaded = "MineFactoryReloaded" diff --git a/src/main/scala/li/cil/oc/integration/igw/ModIngameWiki.scala b/src/main/scala/li/cil/oc/integration/igw/ModIngameWiki.scala new file mode 100644 index 000000000..2e85980ca --- /dev/null +++ b/src/main/scala/li/cil/oc/integration/igw/ModIngameWiki.scala @@ -0,0 +1,14 @@ +package li.cil.oc.integration.igw + +import li.cil.oc.api.Driver +import li.cil.oc.integration.ModProxy +import li.cil.oc.integration.Mods +import net.minecraftforge.common.MinecraftForge + +object ModIngameWiki extends ModProxy { + override def getMod = Mods.IngameWiki + + override def initialize(): Unit = { + WikiEventHandler.init() + } +} diff --git a/src/main/scala/li/cil/oc/integration/igw/WikiEventHandler.scala b/src/main/scala/li/cil/oc/integration/igw/WikiEventHandler.scala new file mode 100644 index 000000000..c8b8dfe1d --- /dev/null +++ b/src/main/scala/li/cil/oc/integration/igw/WikiEventHandler.scala @@ -0,0 +1,57 @@ +package li.cil.oc.integration.igw + +import java.util + +import cpw.mods.fml.common.eventhandler.SubscribeEvent +import igwmod.api.PageChangeEvent +import igwmod.api.WikiRegistry +import li.cil.oc.OpenComputers +import li.cil.oc.api +import li.cil.oc.client.Manual +import li.cil.oc.client.renderer.markdown +import li.cil.oc.client.renderer.markdown.MarkupFormat +import li.cil.oc.common.init.Items +import net.minecraftforge.common.MinecraftForge + +import scala.collection.convert.WrapAsJava._ +import scala.collection.convert.WrapAsScala._ + +object WikiEventHandler { + var lastPath = "" + + def init(): Unit = { + MinecraftForge.EVENT_BUS.register(this) + + for ((name, info) <- Items.descriptors) { + val stack = info.createItemStack(1) + val path = api.Manual.pathFor(stack) + if (path != null && api.Manual.contentFor(path) != null) { + WikiRegistry.registerBlockAndItemPageEntry(stack) + } + } + } + + @SubscribeEvent + def onPageChangeEvent(e: PageChangeEvent): Unit = { + val path = + if (e.associatedStack != null) + "/" + api.Manual.pathFor(e.associatedStack) + else if (e.currentFile.startsWith(OpenComputers.ID + ":")) + e.currentFile.stripPrefix(OpenComputers.ID + ":") + else null + + val base = lastPath + lastPath = "" + if (path != null) { + val resolvedPath = Manual.makeRelative(path, base) + val content = api.Manual.contentFor(resolvedPath) + if (content != null) { + val document = markdown.Document.parse(content) + val processed = document.renderAsText(MarkupFormat.IGWMod) + e.pageText = new util.ArrayList[String](asJavaCollection(processed)) + e.currentFile = resolvedPath + lastPath = resolvedPath + } + } + } +} From 4a036f89e390239dca08fece77027a92e913d5a1 Mon Sep 17 00:00:00 2001 From: Kubuxu Date: Wed, 29 Apr 2015 18:18:06 +0200 Subject: [PATCH 07/13] Implement event.pullMultiple and event.pullFiltered --- .../opencomputers/loot/OpenOS/lib/event.lua | 110 ++++++++++++++---- 1 file changed, 85 insertions(+), 25 deletions(-) diff --git a/src/main/resources/assets/opencomputers/loot/OpenOS/lib/event.lua b/src/main/resources/assets/opencomputers/loot/OpenOS/lib/event.lua index 76020d1e3..fa9cbfaaa 100644 --- a/src/main/resources/assets/opencomputers/loot/OpenOS/lib/event.lua +++ b/src/main/resources/assets/opencomputers/loot/OpenOS/lib/event.lua @@ -4,19 +4,6 @@ local keyboard = require("keyboard") local event, listeners, timers = {}, {}, {} local lastInterrupt = -math.huge -local function matches(signal, name, filter) - if name and not (type(signal[1]) == "string" and signal[1]:match(name)) - then - return false - end - for i = 1, filter.n do - if filter[i] ~= nil and filter[i] ~= signal[i + 1] then - return false - end - end - return true -end - local function call(callback, ...) local result, message = pcall(callback, ...) if not result and type(event.onError) == "function" then @@ -64,6 +51,45 @@ local function tick() end end +local function createPlainFilter(name, ...) + local filter = table.pack(...) + if name == nil and filter.n == 0 then + return nil + end + + return function(...) + local signal = table.pack(...) + if name and not (type(signal[1]) == "string" and signal[1]:match(name)) then + return false + end + for i = 1, filter.n do + if filter[i] ~= nil and filter[i] ~= signal[i + 1] then + return false + end + end + return true + end +end + +local function createMultipleFilter(...) + local filter = table.pack(...) + if filter.n == 0 then + return nil + end + + return function(...) + local signal = table.pack(...) + if type(signal[1]) ~= "string" then + return false + end + for i = 1, filter.n do + if filter[i] ~= nil and signal[1]:match(filter[i]) then + return true + end + end + return false + end +end ------------------------------------------------------------------------------- function event.cancel(timerId) @@ -118,28 +144,50 @@ end function event.pull(...) local args = table.pack(...) - local seconds, name, filter if type(args[1]) == "string" then - name = args[1] - filter = table.pack(table.unpack(args, 2, args.n)) + return event.pullFiltered(createPlainFilter(...)) else checkArg(1, args[1], "number", "nil") checkArg(2, args[2], "string", "nil") - seconds = args[1] - name = args[2] - filter = table.pack(table.unpack(args, 3, args.n)) + return event.pullFiltered(args[1], createPlainFilter(select(2, ...))) end +end - local hasFilter = name ~= nil - if not hasFilter then - for i = 1, filter.n do - hasFilter = hasFilter or filter[i] ~= nil +function event.pullMultiple(...) + local seconds + local args + if type(...) == "number" then + seconds = ... + args = table.pack(select(2,...)) + for i=1,args.n do + checkArg(i+1, args[i], "string", "nil") end + else + args = table.pack(...) + for i=1,args.n do + checkArg(i, args[i], "string", "nil") + end + end + return event.pullFiltered(seconds, createMultipleFilter(table.unpack(args, 1, args.n))) + +end + +function event.pullFiltered(...) + local args = table.pack(...) + local seconds, filter + + if type(args[1]) == "function" then + filter = args[1] + else + checkArg(1, args[1], "number", "nil") + checkArg(2, args[2], "function", "nil") + seconds = args[1] + filter = args[2] end local deadline = seconds and (computer.uptime() + seconds) or - (hasFilter and math.huge or 0) + (filter and math.huge or 0) repeat local closest = seconds and deadline or math.huge for _, timer in pairs(timers) do @@ -154,9 +202,15 @@ function event.pull(...) lastInterrupt = computer.uptime() error("interrupted", 0) end - if not (seconds or hasFilter) or matches(signal, name, filter) then + if event.shouldSoftInterrupt() and (filter == nil or filter("interrupted", computer.uptime() - lastInterrupt)) then + local awaited = computer.uptime() - lastInterrupt + lastInterrupt = computer.uptime() + return "interrupted", awaited + end + if not (seconds or filter) or filter == nil or filter(table.unpack(signal, 1, signal.n)) then return table.unpack(signal, 1, signal.n) end + until computer.uptime() >= deadline end @@ -167,6 +221,12 @@ function event.shouldInterrupt() keyboard.isKeyDown(keyboard.keys.c) end +function event.shouldSoftInterrupt() + return computer.uptime() - lastInterrupt > 1 and + keyboard.isControlDown() and + keyboard.isKeyDown(keyboard.keys.c) +end + function event.timer(interval, callback, times) checkArg(1, interval, "number") checkArg(2, callback, "function") From f78d5a427776720a27bbac1956eab143ee96887b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Wed, 29 Apr 2015 18:24:42 +0200 Subject: [PATCH 08/13] Fixed potential log spam in disassembler. Closes #1107. --- src/main/scala/li/cil/oc/common/Loot.scala | 2 +- src/main/scala/li/cil/oc/server/component/EEPROM.scala | 4 ++-- src/main/scala/li/cil/oc/util/ItemUtils.scala | 8 ++++---- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/main/scala/li/cil/oc/common/Loot.scala b/src/main/scala/li/cil/oc/common/Loot.scala index 96f48fec1..641769c5d 100644 --- a/src/main/scala/li/cil/oc/common/Loot.scala +++ b/src/main/scala/li/cil/oc/common/Loot.scala @@ -117,5 +117,5 @@ object Loot extends WeightedRandomChestContent(new ItemStack(null: Item), 1, 1, if (disks.length > 0) ChestGenHooks.generateStacks(random, disks(random.nextInt(disks.length)), theMinimumChanceToGenerateItem, theMaximumChanceToGenerateItem) - else Array.empty + else Array.empty[ItemStack] } diff --git a/src/main/scala/li/cil/oc/server/component/EEPROM.scala b/src/main/scala/li/cil/oc/server/component/EEPROM.scala index 372415c44..5594d386b 100644 --- a/src/main/scala/li/cil/oc/server/component/EEPROM.scala +++ b/src/main/scala/li/cil/oc/server/component/EEPROM.scala @@ -39,7 +39,7 @@ class EEPROM extends prefab.ManagedEnvironment { if (!node.tryChangeBuffer(-Settings.get.eepromWriteCost)) { return result(Unit, "not enough energy") } - val newData = args.optByteArray(0, Array.empty) + val newData = args.optByteArray(0, Array.empty[Byte]) if (newData.length > Settings.get.eepromSize) throw new IllegalArgumentException("not enough space") codeData = newData context.pause(2) // deliberately slow to discourage use as normal storage medium @@ -85,7 +85,7 @@ class EEPROM extends prefab.ManagedEnvironment { if (!node.tryChangeBuffer(-Settings.get.eepromWriteCost)) { return result(Unit, "not enough energy") } - val newData = args.optByteArray(0, Array.empty) + val newData = args.optByteArray(0, Array.empty[Byte]) if (newData.length > Settings.get.eepromDataSize) throw new IllegalArgumentException("not enough space") volatileData = newData context.pause(1) // deliberately slow to discourage use as normal storage medium diff --git a/src/main/scala/li/cil/oc/util/ItemUtils.scala b/src/main/scala/li/cil/oc/util/ItemUtils.scala index b4534c543..309e8480a 100644 --- a/src/main/scala/li/cil/oc/util/ItemUtils.scala +++ b/src/main/scala/li/cil/oc/util/ItemUtils.scala @@ -55,7 +55,7 @@ object ItemUtils { // we have no way of returning the fluid only (and I can't be arsed // to make it output fluids into fluiducts or such, sorry). !input.getItem.isInstanceOf[ItemBucket]).toArray - def getOutputSize(recipe: IRecipe) = + def getOutputSize(recipe: IRecipe): Double = if (recipe != null && recipe.getRecipeOutput != null) recipe.getRecipeOutput.stackSize else @@ -69,11 +69,11 @@ object ItemUtils { case Some(recipe: ShapelessRecipes) => getFilteredInputs(recipe.recipeItems.map(_.asInstanceOf[ItemStack]), getOutputSize(recipe)) case Some(recipe: ShapedOreRecipe) => getFilteredInputs(resolveOreDictEntries(recipe.getInput), getOutputSize(recipe)) case Some(recipe: ShapelessOreRecipe) => getFilteredInputs(resolveOreDictEntries(recipe.getInput), getOutputSize(recipe)) - case _ => Array.empty + case _ => Array.empty[ItemStack] } // Avoid positive feedback loops. if (ingredients.exists(ingredient => ingredient.isItemEqual(stack))) { - return Array.empty + return Array.empty[ItemStack] } // Merge equal items for size division by output size. val merged = mutable.ArrayBuffer.empty[ItemStack] @@ -98,7 +98,7 @@ object ItemUtils { catch { case t: Throwable => OpenComputers.log.warn("Whoops, something went wrong when trying to figure out an item's parts.", t) - Array.empty + Array.empty[ItemStack] } private lazy val rng = new Random() From 4c4051540ba6e5cc27369365b30979a9c50e8cf2 Mon Sep 17 00:00:00 2001 From: Kubuxu Date: Wed, 29 Apr 2015 18:18:56 +0200 Subject: [PATCH 09/13] Make dmesg use new event capabilities. --- .../assets/opencomputers/loot/OpenOS/bin/dmesg.lua | 12 +++++++++--- .../assets/opencomputers/loot/OpenOS/usr/man/dmesg | 9 ++++++++- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/main/resources/assets/opencomputers/loot/OpenOS/bin/dmesg.lua b/src/main/resources/assets/opencomputers/loot/OpenOS/bin/dmesg.lua index ab3bb4a0e..077352930 100644 --- a/src/main/resources/assets/opencomputers/loot/OpenOS/bin/dmesg.lua +++ b/src/main/resources/assets/opencomputers/loot/OpenOS/bin/dmesg.lua @@ -2,15 +2,21 @@ local event = require "event" local component = require "component" local keyboard = require "keyboard" +local args = {...} + local interactive = io.output() == io.stdout local color, isPal, evt if interactive then color, isPal = component.gpu.getForeground() end -io.write("Press 'q' to exit\n") +io.write("Press 'Ctrl-C' to exit\n") pcall(function() repeat - evt = table.pack(event.pull()) + if #args > 0 then + evt = table.pack(event.pullMultiple("interrupted", table.unpack(args))) + else + evt = table.pack(event.pull()) + end if interactive then component.gpu.setForeground(0xCC2200) end io.write("[" .. os.date("%T") .. "] ") if interactive then component.gpu.setForeground(0x44CC00) end @@ -25,7 +31,7 @@ pcall(function() end io.write("\n") - until evt[1] == "key_down" and evt[4] == keyboard.keys.q + until evt[1] == "interrupted" end) if interactive then component.gpu.setForeground(color, isPal) diff --git a/src/main/resources/assets/opencomputers/loot/OpenOS/usr/man/dmesg b/src/main/resources/assets/opencomputers/loot/OpenOS/usr/man/dmesg index 89f1f7e10..ee8f0d0bf 100644 --- a/src/main/resources/assets/opencomputers/loot/OpenOS/usr/man/dmesg +++ b/src/main/resources/assets/opencomputers/loot/OpenOS/usr/man/dmesg @@ -2,5 +2,12 @@ NAME dmesg - display messages(events) SYNOPIS - dmesg + dmesg [EVENT]... + +EXAMPLES + dmesg + Shows all events. + + dmesg touch + Shows only "touch" events. From 495f3411815b9264e9ea7a3ad18b9cd31a5ead62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Thu, 30 Apr 2015 11:18:19 +0200 Subject: [PATCH 10/13] Make safe subset of `debug.getinfo` available in sandbox. Closes #1110. --- .../assets/opencomputers/lua/machine.lua | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/main/resources/assets/opencomputers/lua/machine.lua b/src/main/resources/assets/opencomputers/lua/machine.lua index e72d36f1f..27b90e6d8 100644 --- a/src/main/resources/assets/opencomputers/lua/machine.lua +++ b/src/main/resources/assets/opencomputers/lua/machine.lua @@ -888,6 +888,26 @@ sandbox = { }, debug = { + getinfo = function(...) + local result = debug.getinfo(...) + if result then + -- Only make primitive information available in the sandbox. + return { + source = result.source, + short_src = result.short_src, + linedefined = result.linedefined, + lastlinedefined = result.lastlinedefined, + what = result.what, + currentline = result.currentline, + nups = result.nups, + nparams = result.nparams, + isvararg = result.isvararg, + name = result.name, + namewhat = result.namewhat, + istailcall = result.istailcall + } + end + end, traceback = debug.traceback }, From d5f1280fc9c9f463c45eff76119cfc513d8c3fd5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Thu, 30 Apr 2015 11:33:13 +0200 Subject: [PATCH 11/13] Added `beep(short, short)` and `beep(String)` to the Machine interface. Closes #1112. Allows architectures (and components or anything else for that matter) to play custom tones and beep patterns. --- src/main/java/li/cil/oc/api/API.java | 2 +- .../java/li/cil/oc/api/machine/Machine.java | 47 +++++++++++++++++++ .../li/cil/oc/server/machine/Machine.scala | 12 +++-- 3 files changed, 56 insertions(+), 5 deletions(-) diff --git a/src/main/java/li/cil/oc/api/API.java b/src/main/java/li/cil/oc/api/API.java index eb7f7c73f..50189f915 100644 --- a/src/main/java/li/cil/oc/api/API.java +++ b/src/main/java/li/cil/oc/api/API.java @@ -16,7 +16,7 @@ import li.cil.oc.api.detail.NetworkAPI; */ public class API { public static final String ID_OWNER = "OpenComputers|Core"; - public static final String VERSION = "5.2.2"; + public static final String VERSION = "5.2.3"; public static DriverAPI driver = null; public static FileSystemAPI fileSystem = null; diff --git a/src/main/java/li/cil/oc/api/machine/Machine.java b/src/main/java/li/cil/oc/api/machine/Machine.java index 4b83405da..b7270f76c 100644 --- a/src/main/java/li/cil/oc/api/machine/Machine.java +++ b/src/main/java/li/cil/oc/api/machine/Machine.java @@ -141,6 +141,51 @@ public interface Machine extends ManagedEnvironment, Context { */ double cpuTime(); + // ----------------------------------------------------------------------- // + + /** + * Play a sound using the machine's built-in speaker. + *

+ * This is what's used to emit beep codes when an error occurs while trying + * to start the computer, for example, and what's used for playing sounds + * when computer.beep is called. + *

+ * Be responsible in how you limit calls to this, as each call will cause + * a packet to be sent to all nearby clients, and will cause the receiving + * clients to generate the required sound sample on-the-fly. It is + * therefore recommended to not call this too frequently, and to limit the + * length of the sound to something relatively short (not longer than a few + * seconds at most). + *

+ * The audio will be played at the machine's host's location. + * + * @param frequency the frequency of the tone to generate. + * @param duration the duration of the tone to generate, in milliseconds. + */ + void beep(short frequency, short duration); + + /** + * Utility method for playing beep codes. + *

+ * The underlying functionality is similar to that of {@link #beep(short, short)}, + * except that this will play tones at a fixed frequency, and two different + * durations - in a pattern as defined in the passed string. + *

+ * This is useful for generating beep codes, such as for boot errors. It + * has the advantage of only generating a single network packet, and + * generating a single, longer sound sample for the full pattern. As such + * the same considerations should be made as for {@link #beep(short, short)}, + * i.e. prefer not to use overly long patterns. + *

+ * The passed pattern must consist of dots (.) and dashes (-), + * where a dot is short tone, and a dash is a long tone. + *

+ * The audio will be played at the machine's host's location. + * + * @param pattern the beep pattern to play. + */ + void beep(String pattern); + /** * Crashes the computer. *

@@ -221,6 +266,8 @@ public interface Machine extends ManagedEnvironment, Context { */ Object[] invoke(Value value, String method, Object[] args) throws Exception; + // ----------------------------------------------------------------------- // + /** * The list of users registered on this machine. *

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 65c829fa5..2a2ecaec9 100644 --- a/src/main/scala/li/cil/oc/server/machine/Machine.scala +++ b/src/main/scala/li/cil/oc/server/machine/Machine.scala @@ -235,10 +235,6 @@ class Machine(val host: MachineHost) extends prefab.ManagedEnvironment with mach false }) - private def beep(pattern: String) { - PacketSender.sendSound(host.world, host.xPosition, host.yPosition, host.zPosition, pattern) - } - override def pause(seconds: Double): Boolean = { val ticksToPause = math.max((seconds * 20).toInt, 0) def shouldPause(state: Machine.State.Value) = state match { @@ -270,6 +266,14 @@ class Machine(val host: MachineHost) extends prefab.ManagedEnvironment with mach true }) + override def beep(frequency: Short, duration: Short): Unit = { + PacketSender.sendSound(host.world, host.xPosition, host.yPosition, host.zPosition, frequency, duration) + } + + override def beep(pattern: String) { + PacketSender.sendSound(host.world, host.xPosition, host.yPosition, host.zPosition, pattern) + } + override def crash(message: String) = { this.message = Option(message) state.synchronized { From 7d69f996cb612f8c206c12f50578b3a85b5d82e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Thu, 30 Apr 2015 11:44:47 +0200 Subject: [PATCH 12/13] Added handling for OOM errors when allocating hologram rendering data. Closes #1105. --- .../tileentity/HologramRenderer.scala | 27 ++++++++++++++++--- .../tileentity/HologramRendererFallback.scala | 2 +- 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/src/main/scala/li/cil/oc/client/renderer/tileentity/HologramRenderer.scala b/src/main/scala/li/cil/oc/client/renderer/tileentity/HologramRenderer.scala index 4c59ed9d3..670e00492 100644 --- a/src/main/scala/li/cil/oc/client/renderer/tileentity/HologramRenderer.scala +++ b/src/main/scala/li/cil/oc/client/renderer/tileentity/HologramRenderer.scala @@ -57,7 +57,18 @@ object HologramRenderer extends TileEntitySpecialRenderer with Callable[Int] wit /** Used to pass the current screen along to call(). */ private var hologram: Hologram = null + /** + * Whether initialization failed (e.g. due to an out of memory error) and we + * should render using the fallback renderer instead. + */ + private var failed = false + override def renderTileEntityAt(te: TileEntity, x: Double, y: Double, z: Double, f: Float) { + if (failed) { + HologramRendererFallback.renderTileEntityAt(te, x, y, z, f) + return + } + RenderState.checkError(getClass.getName + ".renderTileEntityAt: entering (aka: wasntme)") hologram = te.asInstanceOf[Hologram] @@ -142,12 +153,13 @@ object HologramRenderer extends TileEntitySpecialRenderer with Callable[Int] wit } def draw(glBuffer: Int) { - initialize() - validate(glBuffer) - publish(glBuffer) + if (initialize()) { + validate(glBuffer) + publish(glBuffer) + } } - private def initialize() { + private def initialize(): Boolean = !failed && (try { // First run only, create structure information. if (commonBuffer == 0) { dataBuffer = BufferUtils.createIntBuffer(hologram.width * hologram.width * hologram.height * 6 * 4 * 2) @@ -222,7 +234,14 @@ object HologramRenderer extends TileEntitySpecialRenderer with Callable[Int] wit GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, commonBuffer) GL15.glBufferData(GL15.GL_ARRAY_BUFFER, data, GL15.GL_STATIC_DRAW) } + true } + catch { + case oom: OutOfMemoryError => + HologramRendererFallback.text = "Not enough memory" + failed = true + false + }) private def validate(glBuffer: Int) { // Refresh indexes when the hologram's data changed. diff --git a/src/main/scala/li/cil/oc/client/renderer/tileentity/HologramRendererFallback.scala b/src/main/scala/li/cil/oc/client/renderer/tileentity/HologramRendererFallback.scala index 794ea08ca..ecae894dd 100644 --- a/src/main/scala/li/cil/oc/client/renderer/tileentity/HologramRendererFallback.scala +++ b/src/main/scala/li/cil/oc/client/renderer/tileentity/HologramRendererFallback.scala @@ -7,7 +7,7 @@ import net.minecraft.tileentity.TileEntity import org.lwjgl.opengl.GL11 object HologramRendererFallback extends TileEntitySpecialRenderer { - val text = "Requires OpenGL 1.5" + var text = "Requires OpenGL 1.5" override def renderTileEntityAt(te: TileEntity, x: Double, y: Double, z: Double, f: Float) { RenderState.checkError(getClass.getName + ".renderTileEntityAt: entering (aka: wasntme)") From 1e642a0a24ffba9a182d16feabb9a4461c140be7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Thu, 30 Apr 2015 12:23:04 +0200 Subject: [PATCH 13/13] Added fallback beeping when failing to generate tones, using MC note sound. Closes #1023. May not work, and some nuance is lost (beep length), but it's still better than nothing. --- src/main/scala/li/cil/oc/util/Audio.scala | 29 +++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/src/main/scala/li/cil/oc/util/Audio.scala b/src/main/scala/li/cil/oc/util/Audio.scala index c724821cb..517be611e 100644 --- a/src/main/scala/li/cil/oc/util/Audio.scala +++ b/src/main/scala/li/cil/oc/util/Audio.scala @@ -8,7 +8,9 @@ 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.PositionedSoundRecord import net.minecraft.client.audio.SoundCategory +import net.minecraft.util.ResourceLocation import org.lwjgl.BufferUtils import org.lwjgl.openal.AL import org.lwjgl.openal.AL10 @@ -39,10 +41,29 @@ object Audio { } def play(x: Float, y: Float, z: Float, pattern: String, frequencyInHz: Int = 1000, durationInMilliseconds: Int = 200): Unit = { - if (!disableAudio) { - val distanceBasedGain = math.max(0, 1 - Minecraft.getMinecraft.thePlayer.getDistance(x, y, z) / 12).toFloat - val gain = distanceBasedGain * volume - if (gain > 0 && amplitude > 0 && AL.isCreated) { + val mc = Minecraft.getMinecraft + val distanceBasedGain = math.max(0, 1 - mc.thePlayer.getDistance(x, y, z) / 12).toFloat + val gain = distanceBasedGain * volume + if (gain <= 0 || amplitude <= 0) return + + if (disableAudio) { + // Fallback audio generation, using built-in Minecraft sound. This can be + // necessary on certain systems with audio cards that do not have enough + // memory. May still fail, but at least we can say we tried! + // Valid range is 20-2000Hz, clamp it to that and get a relative value. + // MC's pitch system supports a minimum pitch of 0.5, however, so up it + // by that. + val clampedFrequency = ((frequencyInHz - 20) max 0 min 1980) / 1980f + 0.5f + var delay = 0 + for (ch <- pattern) { + val record = new PositionedSoundRecord(new ResourceLocation("note.harp"), gain, clampedFrequency, x, y, z) + if (delay == 0) mc.getSoundHandler.playSound(record) + else mc.getSoundHandler.playDelayedSound(record, delay) + delay += ((if (ch == '.') durationInMilliseconds else 2 * durationInMilliseconds) * 20 / 1000) max 1 + } + } + else { + if (AL.isCreated) { val sampleCounts = pattern.toCharArray. map(ch => if (ch == '.') durationInMilliseconds else 2 * durationInMilliseconds). map(_ * sampleRate / 1000)