From cd3b6119b3abb2dfc47ef2f09f61ca201939b2fc Mon Sep 17 00:00:00 2001 From: Johannes Lohrer Date: Tue, 9 Jun 2015 16:45:32 +0200 Subject: [PATCH 01/30] new branch --- build.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.properties b/build.properties index 2aab16d6a..2d8637818 100644 --- a/build.properties +++ b/build.properties @@ -1,5 +1,5 @@ minecraft.version=1.7.10 -forge.version=10.13.3.1395-1710ls +forge.version=10.13.3.1428-1.7.10 oc.version=1.5.13 oc.subversion=dev From f4044db8a08033ed4ca731b7788ec5aaa2e48a71 Mon Sep 17 00:00:00 2001 From: Johannes Lohrer Date: Sun, 21 Jun 2015 13:41:10 +0200 Subject: [PATCH 02/30] agri craft not 100% working --- build.gradle | 5 ++ build.properties | 2 + src/main/scala/li/cil/oc/Constants.scala | 1 + .../scala/li/cil/oc/common/init/Items.scala | 7 +- .../cil/oc/common/item/UpgradeFarming.scala | 5 ++ .../scala/li/cil/oc/integration/Mods.scala | 6 +- .../integration/agricraft/ModAgriCraft.scala | 38 +++++++++++ .../opencomputers/DriverUpgradeFarming.scala | 26 ++++++++ .../opencomputers/ModOpenComputers.scala | 1 + .../li/cil/oc/integration/util/Crop.scala | 26 ++++++++ .../oc/integration/vanilla/ModVanilla.scala | 64 ++++++++++++++++++- .../oc/server/component/UpgradeFarming.scala | 33 ++++++++++ 12 files changed, 208 insertions(+), 6 deletions(-) create mode 100644 src/main/scala/li/cil/oc/common/item/UpgradeFarming.scala create mode 100644 src/main/scala/li/cil/oc/integration/agricraft/ModAgriCraft.scala create mode 100644 src/main/scala/li/cil/oc/integration/opencomputers/DriverUpgradeFarming.scala create mode 100644 src/main/scala/li/cil/oc/integration/util/Crop.scala create mode 100644 src/main/scala/li/cil/oc/server/component/UpgradeFarming.scala diff --git a/build.gradle b/build.gradle index b091cbdb5..e7d9eac85 100644 --- a/build.gradle +++ b/build.gradle @@ -152,6 +152,10 @@ repositories { name 'BloodMagic' artifactPattern "http://addons-origin.cursecdn.com/files/${config.bloodmagic.cf}/[module]-${config.minecraft.version}-[revision].[ext]" } + ivy { + name 'AgriCraft' + artifactPattern "http://addons-origin.cursecdn.com/files/${config.agricraft.cf}/[module]-${config.minecraft.version}-[revision].[ext]" + } } configurations { @@ -191,6 +195,7 @@ dependencies { 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' + provided name: 'AgriCraft', version: config.agricraft.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 2d8637818..7e525ce5e 100644 --- a/build.properties +++ b/build.properties @@ -5,6 +5,8 @@ oc.version=1.5.13 oc.subversion=dev ae2.version=rv2-beta-26 +agricraft.cf=2229/714 +agricraft.version=1.3.1 bc.version=7.0.8 bloodmagic.cf=2223/203 bloodmagic.version=1.3.0a-1 diff --git a/src/main/scala/li/cil/oc/Constants.scala b/src/main/scala/li/cil/oc/Constants.scala index be261a68d..0fa0aadf1 100644 --- a/src/main/scala/li/cil/oc/Constants.scala +++ b/src/main/scala/li/cil/oc/Constants.scala @@ -146,6 +146,7 @@ object Constants { final val TexturePicker = "texturePicker" final val TractorBeamUpgrade = "tractorBeamUpgrade" final val Transistor = "transistor" + final val FarmingUpgrade = "farmingUpgrade" final val UpgradeContainerTier1 = "upgradeContainer1" final val UpgradeContainerTier2 = "upgradeContainer2" final val UpgradeContainerTier3 = "upgradeContainer3" 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 3fd66423c..fd6f67e4c 100644 --- a/src/main/scala/li/cil/oc/common/init/Items.scala +++ b/src/main/scala/li/cil/oc/common/init/Items.scala @@ -14,8 +14,7 @@ import li.cil.oc.common.Loot import li.cil.oc.common.Tier import li.cil.oc.common.block.SimpleBlock import li.cil.oc.common.item -import li.cil.oc.common.item.Delegator -import li.cil.oc.common.item.UpgradeLeash +import li.cil.oc.common.item.{UpgradeFarming, Delegator, UpgradeLeash} import li.cil.oc.common.item.data.DroneData import li.cil.oc.common.item.data.HoverBootsData import li.cil.oc.common.item.data.MicrocontrollerData @@ -538,5 +537,9 @@ object Items extends ItemAPI { // 1.5.12 registerItem(new item.APU(multi, Tier.Three), Constants.ItemName.APUCreative) + + //??? + registerItem(new UpgradeFarming(multi),Constants.ItemName.FarmingUpgrade) + } } diff --git a/src/main/scala/li/cil/oc/common/item/UpgradeFarming.scala b/src/main/scala/li/cil/oc/common/item/UpgradeFarming.scala new file mode 100644 index 000000000..bbb076041 --- /dev/null +++ b/src/main/scala/li/cil/oc/common/item/UpgradeFarming.scala @@ -0,0 +1,5 @@ +package li.cil.oc.common.item + +class UpgradeFarming (val parent: Delegator) extends traits.Delegate with traits.ItemTier{ + +} diff --git a/src/main/scala/li/cil/oc/integration/Mods.scala b/src/main/scala/li/cil/oc/integration/Mods.scala index 9e3c1bcdc..fb253870a 100644 --- a/src/main/scala/li/cil/oc/integration/Mods.scala +++ b/src/main/scala/li/cil/oc/integration/Mods.scala @@ -19,6 +19,7 @@ object Mods { def All = knownMods.clone() + val AgriCraft = new SimpleMod(IDs.AgriCraft) val AppliedEnergistics2 = new SimpleMod(IDs.AppliedEnergistics2, version = "@[rv1,)", providesPower = true) val BattleGear2 = new SimpleMod(IDs.BattleGear2) val BloodMagic = new SimpleMod(IDs.BloodMagic) @@ -79,6 +80,7 @@ object Mods { // ----------------------------------------------------------------------- // val Proxies = Array( + integration.agricraft.ModAgriCraft, integration.appeng.ModAppEng, integration.bloodmagic.ModBloodMagic, integration.bluepower.ModBluePower, @@ -147,6 +149,7 @@ object Mods { // ----------------------------------------------------------------------- // object IDs { + final val AgriCraft = "AgriCraft" final val AppliedEnergistics2 = "appliedenergistics2" final val BattleGear2 = "battlegear2" final val BloodMagic = "AWWayofTime" @@ -168,7 +171,8 @@ object Mods { final val Factorization = "factorization" final val Forestry = "Forestry" final val ForgeMultipart = "ForgeMultipart" - final val DeepStorageUnit = "MineFactoryReloaded|DeepStorageUnit" // Doesn't really exist. + final val DeepStorageUnit = "MineFactoryReloaded|DeepStorageUnit" + // Doesn't really exist. final val Galacticraft = "Galacticraft API" final val GregTech = "gregtech" final val IndustrialCraft2 = "IC2" diff --git a/src/main/scala/li/cil/oc/integration/agricraft/ModAgriCraft.scala b/src/main/scala/li/cil/oc/integration/agricraft/ModAgriCraft.scala new file mode 100644 index 000000000..c4c82eee0 --- /dev/null +++ b/src/main/scala/li/cil/oc/integration/agricraft/ModAgriCraft.scala @@ -0,0 +1,38 @@ +package li.cil.oc.integration.agricraft + +import com.InfinityRaider.AgriCraft.blocks.BlockCrop +import li.cil.oc.integration.util.Crop +import li.cil.oc.integration.util.Crop.CropProvider +import li.cil.oc.integration.{Mods, Mod, ModProxy} +import li.cil.oc.server.component._ +import li.cil.oc.util.BlockPosition +import net.minecraft.block.Block +import net.minecraft.item.Item + +object ModAgriCraft extends ModProxy with CropProvider { + override def getMod: Mod = Mods.AgriCraft + + override def initialize(): Unit = { + Crop.addProvider(this) + } + + override def getInformation(pos: BlockPosition): Array[AnyRef] = { + val world = pos.world.get + val target = world.getBlock(pos.x,pos.y,pos.z) + target match { + case crop:BlockCrop=>{ + val meta = world.getBlockMetadata(pos.x, pos.y, pos.z) + val value = meta * 100 / 2 + result(Item.itemRegistry.getNameForObject(crop.getSeed)) + } + case _=>result(Unit,"not a thing") + } + } + + override def isValidFor(block: Block): Boolean = { + block match { + case _: BlockCrop => true + case _ => false + } + } +} diff --git a/src/main/scala/li/cil/oc/integration/opencomputers/DriverUpgradeFarming.scala b/src/main/scala/li/cil/oc/integration/opencomputers/DriverUpgradeFarming.scala new file mode 100644 index 000000000..305393e3e --- /dev/null +++ b/src/main/scala/li/cil/oc/integration/opencomputers/DriverUpgradeFarming.scala @@ -0,0 +1,26 @@ +package li.cil.oc.integration.opencomputers + +import li.cil.oc.api.driver.item.HostAware +import li.cil.oc.api.driver.{EnvironmentAware, EnvironmentHost} +import li.cil.oc.api.internal.Robot +import li.cil.oc.common.{Slot, Tier} +import li.cil.oc.server.component +import li.cil.oc.{Constants, api} +import net.minecraft.item.ItemStack + +object DriverUpgradeFarming extends Item with HostAware with EnvironmentAware { + override def worksWith(stack: ItemStack) = isOneOf(stack, + api.Items.get(Constants.ItemName.FarmingUpgrade)) + + override def createEnvironment(stack: ItemStack, host: EnvironmentHost) = + host match { + case robot: EnvironmentHost with Robot => new component.UpgradeFarming(robot) + case _ => null + } + + override def slot(stack: ItemStack) = Slot.Upgrade + + override def tier(stack: ItemStack) = Tier.One + + override def providedEnvironment(stack: ItemStack) = classOf[component.UpgradeFarming] +} 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 423cd12d6..c71b883a1 100644 --- a/src/main/scala/li/cil/oc/integration/opencomputers/ModOpenComputers.scala +++ b/src/main/scala/li/cil/oc/integration/opencomputers/ModOpenComputers.scala @@ -119,6 +119,7 @@ object ModOpenComputers extends ModProxy { api.Driver.add(DriverUpgradeCrafting) api.Driver.add(DriverUpgradeDatabase) api.Driver.add(DriverUpgradeExperience) + api.Driver.add(DriverUpgradeFarming) api.Driver.add(DriverUpgradeGenerator) api.Driver.add(DriverUpgradeHover) api.Driver.add(DriverUpgradeInventory) diff --git a/src/main/scala/li/cil/oc/integration/util/Crop.scala b/src/main/scala/li/cil/oc/integration/util/Crop.scala new file mode 100644 index 000000000..b90b5ff1f --- /dev/null +++ b/src/main/scala/li/cil/oc/integration/util/Crop.scala @@ -0,0 +1,26 @@ +package li.cil.oc.integration.util + +import li.cil.oc.util.BlockPosition +import net.minecraft.block.Block + +import scala.collection.mutable + +object Crop { + + + val providers = mutable.Buffer.empty[CropProvider] + + def addProvider(provider: CropProvider): Unit = providers += provider + + def getProviderForBlock(block: Block): Option[CropProvider] = { + providers.find(_.isValidFor(block)) + } + + trait CropProvider { + def getInformation(pos: BlockPosition): Array[AnyRef] + + def isValidFor(block: Block): Boolean + } + + +} 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 c87d797af..1f3f1a8fd 100644 --- a/src/main/scala/li/cil/oc/integration/vanilla/ModVanilla.scala +++ b/src/main/scala/li/cil/oc/integration/vanilla/ModVanilla.scala @@ -4,14 +4,18 @@ 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.{Crop, BundledRedstone} import li.cil.oc.integration.util.BundledRedstone.RedstoneProvider +import li.cil.oc.integration.util.Crop.CropProvider +import li.cil.oc.server.component._ import li.cil.oc.util.BlockPosition import li.cil.oc.util.ExtendedWorld._ -import net.minecraft.init.Blocks +import net.minecraft.block._ +import net.minecraft.init.{Items, Blocks} +import net.minecraft.item.Item import net.minecraftforge.common.util.ForgeDirection -object ModVanilla extends ModProxy with RedstoneProvider { +object ModVanilla extends ModProxy with RedstoneProvider with CropProvider { def getMod = Mods.Minecraft def initialize() { @@ -44,6 +48,7 @@ object ModVanilla extends ModProxy with RedstoneProvider { RecipeHandler.init() BundledRedstone.addProvider(this) + Crop.addProvider(this) } override def computeInput(pos: BlockPosition, side: ForgeDirection): Int = { @@ -53,4 +58,57 @@ object ModVanilla extends ModProxy with RedstoneProvider { } override def computeBundledInput(pos: BlockPosition, side: ForgeDirection): Array[Int] = null + + override def getInformation(pos: BlockPosition): Array[AnyRef] = { + val world = pos.world.get + val target = world.getBlock(pos.x, pos.y, pos.z) + target match { + case crop: BlockBush => { + val meta = world.getBlockMetadata(pos.x, pos.y, pos.z) + var name = crop.getLocalizedName + var modifier = 7 + crop match { + + case Blocks.wheat => { + name = Item.itemRegistry.getNameForObject(Items.wheat) + } + case Blocks.melon_stem => { + //Localize this? + name = "Melon stem" + } + case Blocks.pumpkin_stem => { + name = "Pumpkin stem" + } + case Blocks.nether_wart => { + modifier = 3 + } + case _ => + } + result(name, meta * 100 / modifier) + } + case cocoa: BlockCocoa => { + val meta = world.getBlockMetadata(pos.x, pos.y, pos.z) + val value = meta * 100 / 2 + + result(cocoa.getLocalizedName, Math.min(value, 100)) + } + case _: BlockMelon | _: BlockPumpkin => { + result(target.getLocalizedName, 100) + } + case _: BlockCactus | _: BlockReed => { + val meta = world.getBlockMetadata(pos.x, pos.y, pos.z) + result(target.getLocalizedName, meta) + } + case _ => result(Unit, "Not a crop") + } + } + + override def isValidFor(block: Block): Boolean = { + block match { + //has to be specified for crops otherwise overriding blocks of other mods might not get their own Provider + case _: BlockStem | Blocks.wheat | Blocks.carrots | Blocks.potatoes | _: BlockCocoa | _: BlockMelon | _: BlockPumpkin | _: BlockCactus | _: BlockReed => true + case _ => false + } + + } } diff --git a/src/main/scala/li/cil/oc/server/component/UpgradeFarming.scala b/src/main/scala/li/cil/oc/server/component/UpgradeFarming.scala new file mode 100644 index 000000000..7224528ef --- /dev/null +++ b/src/main/scala/li/cil/oc/server/component/UpgradeFarming.scala @@ -0,0 +1,33 @@ +package li.cil.oc.server.component + +import li.cil.oc.api.driver.EnvironmentHost +import li.cil.oc.api.machine.{Callback, Arguments, Context} +import li.cil.oc.api.network.Visibility +import li.cil.oc.api.{Network, prefab, internal} +import li.cil.oc.integration.util.Crop +import li.cil.oc.integration.util.Crop.CropProvider +import li.cil.oc.util.BlockPosition +import net.minecraft.block._ +import net.minecraft.init.{Items, Blocks} +import net.minecraft.item.Item +import net.minecraftforge.common.IPlantable +import net.minecraftforge.common.util.ForgeDirection + +class UpgradeFarming(val host: EnvironmentHost with internal.Robot) extends prefab.ManagedEnvironment { + override val node = Network.newNode(this, Visibility.Network). + withComponent("farming"). + create() + + @Callback(doc = """function([count:number]):boolean -- checks the ripeness of the seed.""") + def check(context: Context, args: Arguments): Array[AnyRef] = { + val hostPos = BlockPosition(host) + val targetPos = hostPos.offset(ForgeDirection.DOWN) + val target = host.world.getBlock(targetPos.x, targetPos.y, targetPos.z) + Crop.getProviderForBlock(target) match { + case Some(provider) => provider.getInformation(BlockPosition(targetPos.x, targetPos.y, targetPos.z, host.world)) + case _ => result(Unit, "Not a crop") + } + + } + +} From 07dbc24080099533b7dd71a63d3028f2cae04ee1 Mon Sep 17 00:00:00 2001 From: Izaya Date: Thu, 6 Aug 2015 21:25:42 +1000 Subject: [PATCH 03/30] Change some config option names. Should fix #1353, just provides some clairity for the difference. --- 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 054de7e09..c35bc1bf2 100644 --- a/src/main/resources/application.conf +++ b/src/main/resources/application.conf @@ -126,10 +126,10 @@ opencomputers { # happen. startupDelay: 0.25 - # The maximum size of the byte array that can be stored on EEPROMs. + # The maximum size of the byte array that can be stored on EEPROMs as executable data.. eepromSize: 4096 - # The maximum size of the byte array that can be stored on EEPROMs. + # The maximum size of the byte array that can be stored on EEPROMs as configuration data. eepromDataSize: 256 # The number of components the different CPU tiers support. This list From 752af734adfa9e734a48a9b85f9fb88f753386a0 Mon Sep 17 00:00:00 2001 From: Maxim Karpov Date: Sun, 9 Aug 2015 16:34:52 +0300 Subject: [PATCH 04/30] Add parameter to disable resolution reset ... because sometimes it isnt necessary and causes noticeable flickering --- .../oc/server/component/GraphicsCard.scala | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/main/scala/li/cil/oc/server/component/GraphicsCard.scala b/src/main/scala/li/cil/oc/server/component/GraphicsCard.scala index 4ad804a3b..968ab8a15 100644 --- a/src/main/scala/li/cil/oc/server/component/GraphicsCard.scala +++ b/src/main/scala/li/cil/oc/server/component/GraphicsCard.scala @@ -55,22 +55,25 @@ abstract class GraphicsCard extends prefab.ManagedEnvironment { } } - @Callback(doc = """function(address:string):boolean -- Binds the GPU to the screen with the specified address.""") + @Callback(doc = """function(address:string[,reset:boolean=true]):boolean -- Binds the GPU to the screen with the specified address and resets screen settings if `reset` is true.""") def bind(context: Context, args: Arguments): Array[AnyRef] = { val address = args.checkString(0) + val reset = args.optBoolean(1, true) node.network.node(address) match { case null => result(Unit, "invalid address") case node: Node if node.host.isInstanceOf[TextBuffer] => screenAddress = Option(address) screenInstance = Some(node.host.asInstanceOf[TextBuffer]) screen(s => { - val (gmw, gmh) = maxResolution - val smw = s.getMaximumWidth - val smh = s.getMaximumHeight - s.setResolution(math.min(gmw, smw), math.min(gmh, smh)) - s.setColorDepth(ColorDepth.values.apply(math.min(maxDepth.ordinal, s.getMaximumColorDepth.ordinal))) - s.setForegroundColor(0xFFFFFF) - s.setBackgroundColor(0x000000) + if (reset) { + val (gmw, gmh) = maxResolution + val smw = s.getMaximumWidth + val smh = s.getMaximumHeight + s.setResolution(math.min(gmw, smw), math.min(gmh, smh)) + s.setColorDepth(ColorDepth.values.apply(math.min(maxDepth.ordinal, s.getMaximumColorDepth.ordinal))) + s.setForegroundColor(0xFFFFFF) + s.setBackgroundColor(0x000000) + } result(true) }) case _ => result(Unit, "not a screen") From 8e3eccdbed602462985a0c2bb733f45ba07de150 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Wed, 12 Aug 2015 14:49:41 -0700 Subject: [PATCH 05/30] Add small delay when rebinding while keeping screen contents to discourage driving multiple screens with frequent changes using one GPU. --- src/main/scala/li/cil/oc/server/component/GraphicsCard.scala | 3 ++- src/main/scala/li/cil/oc/server/component/Server.scala | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/scala/li/cil/oc/server/component/GraphicsCard.scala b/src/main/scala/li/cil/oc/server/component/GraphicsCard.scala index 968ab8a15..e90de08bb 100644 --- a/src/main/scala/li/cil/oc/server/component/GraphicsCard.scala +++ b/src/main/scala/li/cil/oc/server/component/GraphicsCard.scala @@ -55,7 +55,7 @@ abstract class GraphicsCard extends prefab.ManagedEnvironment { } } - @Callback(doc = """function(address:string[,reset:boolean=true]):boolean -- Binds the GPU to the screen with the specified address and resets screen settings if `reset` is true.""") + @Callback(doc = """function(address:string[, reset:boolean=true]):boolean -- Binds the GPU to the screen with the specified address and resets screen settings if `reset` is true.""") def bind(context: Context, args: Arguments): Array[AnyRef] = { val address = args.checkString(0) val reset = args.optBoolean(1, true) @@ -74,6 +74,7 @@ abstract class GraphicsCard extends prefab.ManagedEnvironment { s.setForegroundColor(0xFFFFFF) s.setBackgroundColor(0x000000) } + else context.pause(0.2) // To discourage outputting "in realtime" to multiple screens using one GPU. result(true) }) case _ => result(Unit, "not a screen") diff --git a/src/main/scala/li/cil/oc/server/component/Server.scala b/src/main/scala/li/cil/oc/server/component/Server.scala index 01f8b0905..c0506e805 100644 --- a/src/main/scala/li/cil/oc/server/component/Server.scala +++ b/src/main/scala/li/cil/oc/server/component/Server.scala @@ -66,7 +66,7 @@ class Server(val rack: tileentity.ServerRack, val slot: Int) extends Environment // Ensure the message originated in our local network, to avoid infinite // recursion if two unconnected servers are in one server rack. if (rack.internalSwitch && message.name == "network.message" && - rack.sides(this.slot) == None && // Only if we're in internal mode. + rack.sides(this.slot).isEmpty && // Only if we're in internal mode. message.source != machine.node && // In this case it was relayed from another internal machine. node.network.node(message.source.address) != null) { for (slot <- rack.servers.indices) { From 6037f7a651163c47a15d663ee29e7211c7b1635d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Wed, 12 Aug 2015 15:07:04 -0700 Subject: [PATCH 06/30] Allow passing side to piston upgrade's push() function. Down won't work in tablets held by players because they're holding it too high, but I honestly don't care. Refactored and extended ExtendedArguments a bit to be more in line with normal Arguments' methods. --- .../oc/server/component/UpgradePiston.scala | 8 +-- .../component/traits/InventoryControl.scala | 2 +- .../traits/InventoryWorldControl.scala | 4 +- .../traits/InventoryWorldControlMk2.scala | 4 +- .../server/component/traits/TankControl.scala | 2 +- .../traits/TankInventoryControl.scala | 4 +- .../component/traits/TankWorldControl.scala | 4 +- .../li/cil/oc/util/ExtendedArguments.scala | 53 ++++++++++++------- 8 files changed, 50 insertions(+), 31 deletions(-) diff --git a/src/main/scala/li/cil/oc/server/component/UpgradePiston.scala b/src/main/scala/li/cil/oc/server/component/UpgradePiston.scala index 4512d4414..800fc4b52 100644 --- a/src/main/scala/li/cil/oc/server/component/UpgradePiston.scala +++ b/src/main/scala/li/cil/oc/server/component/UpgradePiston.scala @@ -11,6 +11,7 @@ import li.cil.oc.api.network.Visibility import li.cil.oc.api.prefab import li.cil.oc.util.BlockPosition import li.cil.oc.util.ExtendedWorld._ +import li.cil.oc.util.ExtendedArguments._ import net.minecraft.init.Blocks class UpgradePiston(val host: Rotatable with EnvironmentHost) extends prefab.ManagedEnvironment { @@ -19,11 +20,12 @@ class UpgradePiston(val host: Rotatable with EnvironmentHost) extends prefab.Man withConnector(). create() - @Callback(doc = """function():boolean -- Tries to push the block in front of the container of the upgrade.""") + @Callback(doc = """function([side:number]):boolean -- Tries to push the block on the specified side of the container of the upgrade. Defaults to front.""") def push(context: Context, args: Arguments): Array[AnyRef] = { val hostPos = BlockPosition(host) - val blockPos = hostPos.offset(host.facing) - if (!host.world.isAirBlock(blockPos) && node.tryChangeBuffer(-Settings.get.pistonCost) && Blocks.piston.tryExtend(host.world, hostPos.x, hostPos.y, hostPos.z, host.facing.ordinal)) { + val facing = args.optSideForAction(0, host.facing) + val blockPos = hostPos.offset(facing) + if (!host.world.isAirBlock(blockPos) && node.tryChangeBuffer(-Settings.get.pistonCost) && Blocks.piston.tryExtend(host.world, hostPos.x, hostPos.y, hostPos.z, facing.ordinal)) { host.world.setBlockToAir(blockPos) host.world.playSoundEffect(host.xPosition, host.yPosition, host.zPosition, "tile.piston.out", 0.5f, host.world.rand.nextFloat() * 0.25f + 0.6f) context.pause(0.5) diff --git a/src/main/scala/li/cil/oc/server/component/traits/InventoryControl.scala b/src/main/scala/li/cil/oc/server/component/traits/InventoryControl.scala index d8273c60e..b4001edec 100644 --- a/src/main/scala/li/cil/oc/server/component/traits/InventoryControl.scala +++ b/src/main/scala/li/cil/oc/server/component/traits/InventoryControl.scala @@ -50,7 +50,7 @@ trait InventoryControl extends InventoryAware { @Callback(doc = "function(toSlot:number[, amount:number]):boolean -- Move up to the specified amount of items from the selected slot into the specified slot.") def transferTo(context: Context, args: Arguments): Array[AnyRef] = { val slot = args.checkSlot(inventory, 0) - val count = args.optionalItemCount(1) + val count = args.optItemCount(1) if (slot == selectedSlot || count == 0) { result(true) } diff --git a/src/main/scala/li/cil/oc/server/component/traits/InventoryWorldControl.scala b/src/main/scala/li/cil/oc/server/component/traits/InventoryWorldControl.scala index 93367771b..643979f5b 100644 --- a/src/main/scala/li/cil/oc/server/component/traits/InventoryWorldControl.scala +++ b/src/main/scala/li/cil/oc/server/component/traits/InventoryWorldControl.scala @@ -33,7 +33,7 @@ trait InventoryWorldControl extends InventoryAware with WorldAware with SideRest @Callback(doc = "function(side:number[, count:number=64]):boolean -- Drops items from the selected slot towards the specified side.") def drop(context: Context, args: Arguments): Array[AnyRef] = { val facing = checkSideForAction(args, 0) - val count = args.optionalItemCount(1) + val count = args.optItemCount(1) val stack = inventory.getStackInSlot(selectedSlot) if (stack != null && stack.stackSize > 0) { val blockPos = position.offset(facing) @@ -69,7 +69,7 @@ trait InventoryWorldControl extends InventoryAware with WorldAware with SideRest @Callback(doc = "function(side:number[, count:number=64]):boolean -- Suck up items from the specified side.") def suck(context: Context, args: Arguments): Array[AnyRef] = { val facing = checkSideForAction(args, 0) - val count = args.optionalItemCount(1) + val count = args.optItemCount(1) val blockPos = position.offset(facing) if (InventoryUtils.inventoryAt(blockPos).exists(inventory => { diff --git a/src/main/scala/li/cil/oc/server/component/traits/InventoryWorldControlMk2.scala b/src/main/scala/li/cil/oc/server/component/traits/InventoryWorldControlMk2.scala index 814ed4706..ad5d40185 100644 --- a/src/main/scala/li/cil/oc/server/component/traits/InventoryWorldControlMk2.scala +++ b/src/main/scala/li/cil/oc/server/component/traits/InventoryWorldControlMk2.scala @@ -14,7 +14,7 @@ trait InventoryWorldControlMk2 extends InventoryAware with WorldAware with SideR @Callback(doc = """function(facing:number, slot:number[, count:number]):boolean -- Drops the selected item stack into the specified slot of an inventory.""") def dropIntoSlot(context: Context, args: Arguments): Array[AnyRef] = { val facing = checkSideForAction(args, 0) - val count = args.optionalItemCount(2) + val count = args.optItemCount(2) val stack = inventory.getStackInSlot(selectedSlot) if (stack != null && stack.stackSize > 0) { withInventory(facing, inventory => { @@ -43,7 +43,7 @@ trait InventoryWorldControlMk2 extends InventoryAware with WorldAware with SideR @Callback(doc = """function(facing:number, slot:number[, count:number]):boolean -- Sucks items from the specified slot of an inventory.""") def suckFromSlot(context: Context, args: Arguments): Array[AnyRef] = { val facing = checkSideForAction(args, 0) - val count = args.optionalItemCount(2) + val count = args.optItemCount(2) withInventory(facing, inventory => { val slot = args.checkSlot(inventory, 1) if (InventoryUtils.extractFromInventorySlot(InventoryUtils.insertIntoInventory(_, this.inventory, slots = Option(insertionSlots)), inventory, facing.getOpposite, slot, count)) { diff --git a/src/main/scala/li/cil/oc/server/component/traits/TankControl.scala b/src/main/scala/li/cil/oc/server/component/traits/TankControl.scala index a57293d32..33815f2e9 100644 --- a/src/main/scala/li/cil/oc/server/component/traits/TankControl.scala +++ b/src/main/scala/li/cil/oc/server/component/traits/TankControl.scala @@ -53,7 +53,7 @@ trait TankControl extends TankAware { @Callback(doc = "function(index:number[, count:number=1000]):boolean -- Move the specified amount of fluid from the selected tank into the specified tank.") def transferFluidTo(context: Context, args: Arguments): Array[AnyRef] = { val index = args.checkTank(tank, 0) - val count = args.optionalFluidCount(1) + val count = args.optFluidCount(1) if (index == selectedTank || count == 0) { result(true) } diff --git a/src/main/scala/li/cil/oc/server/component/traits/TankInventoryControl.scala b/src/main/scala/li/cil/oc/server/component/traits/TankInventoryControl.scala index 993243f9a..8553bd053 100644 --- a/src/main/scala/li/cil/oc/server/component/traits/TankInventoryControl.scala +++ b/src/main/scala/li/cil/oc/server/component/traits/TankInventoryControl.scala @@ -35,7 +35,7 @@ trait TankInventoryControl extends WorldAware with InventoryAware with TankAware @Callback(doc = """function([amount:number]):boolean -- Transfers fluid from a tank in the selected inventory slot to the selected tank.""") def drain(context: Context, args: Arguments): Array[AnyRef] = { - val amount = args.optionalFluidCount(0) + val amount = args.optFluidCount(0) Option(tank.getFluidTank(selectedTank)) match { case Some(into) => inventory.getStackInSlot(selectedSlot) match { case stack: ItemStack => @@ -77,7 +77,7 @@ trait TankInventoryControl extends WorldAware with InventoryAware with TankAware @Callback(doc = """function([amount:number]):boolean -- Transfers fluid from the selected tank to a tank in the selected inventory slot.""") def fill(context: Context, args: Arguments): Array[AnyRef] = { - val amount = args.optionalFluidCount(0) + val amount = args.optFluidCount(0) Option(tank.getFluidTank(selectedTank)) match { case Some(from) => inventory.getStackInSlot(selectedSlot) match { case stack: ItemStack => 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 282b33036..91a08b8fd 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 @@ -36,7 +36,7 @@ trait TankWorldControl extends TankAware with WorldAware with SideRestricted { @Callback(doc = "function(side:boolean[, amount:number=1000]):boolean, number or string -- Drains the specified amount of fluid from the specified side. Returns the amount drained, or an error message.") def drain(context: Context, args: Arguments): Array[AnyRef] = { val facing = checkSideForAction(args, 0) - val count = args.optionalFluidCount(1) + val count = args.optFluidCount(1) getTank(selectedTank) match { case Some(tank) => val space = tank.getCapacity - tank.getFluidAmount @@ -97,7 +97,7 @@ trait TankWorldControl extends TankAware with WorldAware with SideRestricted { @Callback(doc = "function(side:number[, amount:number=1000]):boolean, number of string -- Eject the specified amount of fluid to the specified side. Returns the amount ejected or an error message.") def fill(context: Context, args: Arguments): Array[AnyRef] = { val facing = checkSideForAction(args, 0) - val count = args.optionalFluidCount(1) + val count = args.optFluidCount(1) getTank(selectedTank) match { case Some(tank) => val amount = math.min(count, tank.getFluidAmount) diff --git a/src/main/scala/li/cil/oc/util/ExtendedArguments.scala b/src/main/scala/li/cil/oc/util/ExtendedArguments.scala index a6b682f6d..d6dcc1dbf 100644 --- a/src/main/scala/li/cil/oc/util/ExtendedArguments.scala +++ b/src/main/scala/li/cil/oc/util/ExtendedArguments.scala @@ -12,17 +12,13 @@ object ExtendedArguments { implicit def extendedArguments(args: Arguments): ExtendedArguments = new ExtendedArguments(args) class ExtendedArguments(val args: Arguments) { - def optionalItemCount(n: Int) = - if (args.count > n && args.checkAny(n) != null) { - math.max(0, math.min(64, args.checkInteger(n))) - } - else 64 + def optItemCount(index: Int, default: Int = 64) = + if (!isDefined(index) || !hasValue(index)) default + else math.max(0, math.min(64, args.checkInteger(index))) - def optionalFluidCount(n: Int) = - if (args.count > n && args.checkAny(n) != null) { - math.max(0, args.checkInteger(n)) - } - else 1000 + def optFluidCount(index: Int, default: Int = 1000) = + if (!isDefined(index) || !hasValue(index)) default + else math.max(0, args.checkInteger(index)) def checkSlot(inventory: IInventory, n: Int) = { val slot = args.checkInteger(n) - 1 @@ -32,9 +28,9 @@ object ExtendedArguments { slot } - def optSlot(inventory: IInventory, n: Int, default: Int) = { - if (n >= 0 && n < args.count()) checkSlot(inventory, n) - else default + def optSlot(inventory: IInventory, index: Int, default: Int) = { + if (!isDefined(index)) default + else checkSlot(inventory, index) } def checkTank(multi: MultiTank, n: Int) = { @@ -45,14 +41,26 @@ object ExtendedArguments { tank } - def checkSideForAction(n: Int) = checkSide(n, ForgeDirection.SOUTH, ForgeDirection.UP, ForgeDirection.DOWN) + def checkSideForAction(index: Int) = checkSide(index, ForgeDirection.SOUTH, ForgeDirection.UP, ForgeDirection.DOWN) - def checkSideForMovement(n: Int) = checkSide(n, ForgeDirection.SOUTH, ForgeDirection.NORTH, ForgeDirection.UP, ForgeDirection.DOWN) + def optSideForAction(index: Int, default: ForgeDirection) = + if (!isDefined(index)) default + else checkSideForAction(index) - def checkSideForFace(n: Int, facing: ForgeDirection) = checkSide(n, ForgeDirection.VALID_DIRECTIONS.filter(_ != facing.getOpposite): _*) + def checkSideForMovement(index: Int) = checkSide(index, ForgeDirection.SOUTH, ForgeDirection.NORTH, ForgeDirection.UP, ForgeDirection.DOWN) - def checkSide(n: Int, allowed: ForgeDirection*) = { - val side = args.checkInteger(n) + def optSideForMovement(index: Int, default: ForgeDirection) = + if (!isDefined(index)) default + else checkSideForMovement(index) + + def checkSideForFace(index: Int, facing: ForgeDirection) = checkSide(index, ForgeDirection.VALID_DIRECTIONS.filter(_ != facing.getOpposite): _*) + + def optSideForFace(index: Int, default: ForgeDirection) = + if (!isDefined(index)) default + else checkSideForAction(index) + + def checkSide(index: Int, allowed: ForgeDirection*) = { + val side = args.checkInteger(index) if (side < 0 || side > 5) { throw new IllegalArgumentException("invalid side") } @@ -60,6 +68,15 @@ object ExtendedArguments { if (allowed.isEmpty || (allowed contains direction)) direction else throw new IllegalArgumentException("unsupported side") } + + def optSide(index: Int, default: ForgeDirection, allowed: ForgeDirection*) = { + if (!isDefined(index)) default + else checkSide(index, allowed: _*) + } + + private def isDefined(index: Int) = index >= 0 && index < args.count() + + private def hasValue(index: Int) = args.checkAny(index) != null } } From e99e9732285d5f7a5d976f9b84e6d9fab4bf5611 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Wed, 12 Aug 2015 15:07:30 -0700 Subject: [PATCH 07/30] Version bump. --- build.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.properties b/build.properties index 11be8b19c..4f5fc4aad 100644 --- a/build.properties +++ b/build.properties @@ -1,7 +1,7 @@ minecraft.version=1.7.10 forge.version=10.13.4.1448-1.7.10 -oc.version=1.5.15 +oc.version=1.5.16 oc.subversion=dev ae2.version=rv2-beta-26 From 638cc08026cc92294755a279850a6c0239ff0683 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Wed, 12 Aug 2015 18:08:31 -0700 Subject: [PATCH 08/30] Added special cases for piston upgrade to make them work for all directions in drones, and also work down for tablets. Moved rotation translation logic and caches to RotationHelper (should even save some memory due to central caching). --- .../scala/li/cil/oc/common/item/Tablet.scala | 6 +- .../common/tileentity/traits/Rotatable.scala | 76 ++---------------- .../opencomputers/DriverUpgradePiston.scala | 6 +- .../oc/server/component/UpgradePiston.scala | 37 +++++++-- .../scala/li/cil/oc/util/RotationHelper.scala | 80 +++++++++++++++++++ 5 files changed, 125 insertions(+), 80 deletions(-) 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 77ec032d8..5525b412a 100644 --- a/src/main/scala/li/cil/oc/common/item/Tablet.scala +++ b/src/main/scala/li/cil/oc/common/item/Tablet.scala @@ -243,9 +243,11 @@ class TabletWrapper(var stack: ItemStack, var player: EntityPlayer) extends Comp override def facing = RotationHelper.fromYaw(player.rotationYaw) - override def toLocal(value: ForgeDirection) = value // -T-O-D-O- do we care? no we don't + override def toLocal(value: ForgeDirection) = + RotationHelper.toLocal(ForgeDirection.NORTH, facing, value) - override def toGlobal(value: ForgeDirection) = value // -T-O-D-O- do we care? no we don't + override def toGlobal(value: ForgeDirection) = + RotationHelper.toGlobal(ForgeDirection.NORTH, facing, value) def readFromNBT() { if (stack.hasTagCompound) { diff --git a/src/main/scala/li/cil/oc/common/tileentity/traits/Rotatable.scala b/src/main/scala/li/cil/oc/common/tileentity/traits/Rotatable.scala index ecef8e282..88888efb3 100644 --- a/src/main/scala/li/cil/oc/common/tileentity/traits/Rotatable.scala +++ b/src/main/scala/li/cil/oc/common/tileentity/traits/Rotatable.scala @@ -6,6 +6,7 @@ import li.cil.oc.Settings import li.cil.oc.api.internal import li.cil.oc.server.{PacketSender => ServerPacketSender} import li.cil.oc.util.ExtendedWorld._ +import li.cil.oc.util.RotationHelper import net.minecraft.entity.Entity import net.minecraft.nbt.NBTTagCompound import net.minecraftforge.common.util.ForgeDirection @@ -16,58 +17,9 @@ trait Rotatable extends RotationAware with internal.Rotatable { // Lookup tables // ----------------------------------------------------------------------- // - /** - * Translates forge directions based on the block's pitch and yaw. The base - * forward direction is facing south with no pitch. The outer array is for - * the three different pitch states, the inner for the four different yaw - * states. - */ - private val translations = Array( - // Pitch = Down - Array( - // Yaw = North - Array(D.south, D.north, D.up, D.down, D.east, D.west, D.unknown), - // Yaw = South - Array(D.south, D.north, D.down, D.up, D.west, D.east, D.unknown), - // Yaw = West - Array(D.south, D.north, D.west, D.east, D.up, D.down, D.unknown), - // Yaw = East - Array(D.south, D.north, D.east, D.west, D.down, D.up, D.unknown)), - // Pitch = Up - Array( - // Yaw = North - Array(D.north, D.south, D.down, D.up, D.east, D.west, D.unknown), - // Yaw = South - Array(D.north, D.south, D.up, D.down, D.west, D.east, D.unknown), - // Yaw = West - Array(D.north, D.south, D.west, D.east, D.down, D.up, D.unknown), - // Yaw = East - Array(D.north, D.south, D.east, D.west, D.up, D.down, D.unknown)), - // Pitch = Forward (North|East|South|West) - Array( - // Yaw = North - Array(D.down, D.up, D.south, D.north, D.east, D.west, D.unknown), - // Yaw = South - Array(D.down, D.up, D.north, D.south, D.west, D.east, D.unknown), - // Yaw = West - Array(D.down, D.up, D.west, D.east, D.south, D.north, D.unknown), - // Yaw = East - Array(D.down, D.up, D.east, D.west, D.north, D.south, D.unknown))) + private val pitch2Direction = Array(ForgeDirection.UP, ForgeDirection.NORTH, ForgeDirection.DOWN) - private val pitch2Direction = Array(D.up, D.north, D.down) - - private val yaw2Direction = Array(D.south, D.west, D.north, D.east) - - /** Shortcuts for forge directions to make the above more readable. */ - private object D { - val down = ForgeDirection.DOWN - val up = ForgeDirection.UP - val north = ForgeDirection.NORTH - val south = ForgeDirection.SOUTH - val west = ForgeDirection.WEST - val east = ForgeDirection.EAST - val unknown = ForgeDirection.UNKNOWN - } + private val yaw2Direction = Array(ForgeDirection.SOUTH, ForgeDirection.WEST, ForgeDirection.NORTH, ForgeDirection.EAST) // ----------------------------------------------------------------------- // // State @@ -79,12 +31,6 @@ trait Rotatable extends RotationAware with internal.Rotatable { /** One of the four cardinal directions. */ private var _yaw = ForgeDirection.SOUTH - /** Translation for facings based on current pitch and yaw. */ - private var cachedTranslation = translations(_pitch.ordinal)(_yaw.ordinal - 2) - - /** Translation from local to global coordinates. */ - private var cachedInverseTranslation = invert(cachedTranslation) - // ----------------------------------------------------------------------- // // Accessors // ----------------------------------------------------------------------- // @@ -147,9 +93,9 @@ trait Rotatable extends RotationAware with internal.Rotatable { else false } - override def toLocal(value: ForgeDirection) = cachedTranslation(value.ordinal) + override def toLocal(value: ForgeDirection) = RotationHelper.toLocal(_pitch, _yaw, value) - override def toGlobal(value: ForgeDirection) = cachedInverseTranslation(value.ordinal) + override def toGlobal(value: ForgeDirection) = RotationHelper.toGlobal(_pitch, _yaw, value) def validFacings = Array(ForgeDirection.NORTH, ForgeDirection.SOUTH, ForgeDirection.WEST, ForgeDirection.EAST) @@ -213,13 +159,8 @@ trait Rotatable extends RotationAware with internal.Rotatable { /** Updates cached translation array and sends notification to clients. */ private def updateTranslation() = { - val newTranslation = translations(_pitch.ordinal)(_yaw.ordinal - 2) - if (cachedTranslation != newTranslation) { - cachedTranslation = newTranslation - cachedInverseTranslation = invert(cachedTranslation) - if (world != null) { - onRotationChanged() - } + if (world != null) { + onRotationChanged() } } @@ -239,7 +180,4 @@ trait Rotatable extends RotationAware with internal.Rotatable { } changed } - - private def invert(t: Array[ForgeDirection]) = - t.indices.map(i => ForgeDirection.getOrientation(t.indexOf(ForgeDirection.getOrientation(i)))) } diff --git a/src/main/scala/li/cil/oc/integration/opencomputers/DriverUpgradePiston.scala b/src/main/scala/li/cil/oc/integration/opencomputers/DriverUpgradePiston.scala index 3ffb00733..b58201993 100644 --- a/src/main/scala/li/cil/oc/integration/opencomputers/DriverUpgradePiston.scala +++ b/src/main/scala/li/cil/oc/integration/opencomputers/DriverUpgradePiston.scala @@ -5,7 +5,7 @@ import li.cil.oc.api import li.cil.oc.api.driver.EnvironmentAware import li.cil.oc.api.driver.EnvironmentHost import li.cil.oc.api.driver.item.HostAware -import li.cil.oc.api.internal.Rotatable +import li.cil.oc.api.internal import li.cil.oc.common.Slot import li.cil.oc.server.component import net.minecraft.item.ItemStack @@ -15,7 +15,9 @@ object DriverUpgradePiston extends Item with HostAware with EnvironmentAware { api.Items.get(Constants.ItemName.PistonUpgrade)) override def createEnvironment(stack: ItemStack, host: EnvironmentHost) = host match { - case rotatable: Rotatable with EnvironmentHost => new component.UpgradePiston(rotatable) + case host: internal.Drone => new component.UpgradePiston.Drone(host) + case host: internal.Tablet => new component.UpgradePiston.Tablet(host) + case host: internal.Rotatable with EnvironmentHost => new component.UpgradePiston.Rotatable(host) case _ => null } diff --git a/src/main/scala/li/cil/oc/server/component/UpgradePiston.scala b/src/main/scala/li/cil/oc/server/component/UpgradePiston.scala index 800fc4b52..bfe12cb8f 100644 --- a/src/main/scala/li/cil/oc/server/component/UpgradePiston.scala +++ b/src/main/scala/li/cil/oc/server/component/UpgradePiston.scala @@ -3,29 +3,34 @@ package li.cil.oc.server.component import li.cil.oc.Settings import li.cil.oc.api.Network import li.cil.oc.api.driver.EnvironmentHost -import li.cil.oc.api.internal.Rotatable +import li.cil.oc.api.internal 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 li.cil.oc.util.BlockPosition -import li.cil.oc.util.ExtendedWorld._ import li.cil.oc.util.ExtendedArguments._ +import li.cil.oc.util.ExtendedWorld._ import net.minecraft.init.Blocks +import net.minecraftforge.common.util.ForgeDirection -class UpgradePiston(val host: Rotatable with EnvironmentHost) extends prefab.ManagedEnvironment { +abstract class UpgradePiston(val host: EnvironmentHost) extends prefab.ManagedEnvironment { override val node = Network.newNode(this, Visibility.Network). withComponent("piston"). withConnector(). create() + def pushDirection(args: Arguments, index: Int): ForgeDirection + + def pushOrigin(side: ForgeDirection) = BlockPosition(host) + @Callback(doc = """function([side:number]):boolean -- Tries to push the block on the specified side of the container of the upgrade. Defaults to front.""") def push(context: Context, args: Arguments): Array[AnyRef] = { - val hostPos = BlockPosition(host) - val facing = args.optSideForAction(0, host.facing) - val blockPos = hostPos.offset(facing) - if (!host.world.isAirBlock(blockPos) && node.tryChangeBuffer(-Settings.get.pistonCost) && Blocks.piston.tryExtend(host.world, hostPos.x, hostPos.y, hostPos.z, facing.ordinal)) { + val side = pushDirection(args, 0) + val hostPos = pushOrigin(side) + val blockPos = hostPos.offset(side) + if (!host.world.isAirBlock(blockPos) && node.tryChangeBuffer(-Settings.get.pistonCost) && Blocks.piston.tryExtend(host.world, hostPos.x, hostPos.y, hostPos.z, side.ordinal)) { host.world.setBlockToAir(blockPos) host.world.playSoundEffect(host.xPosition, host.yPosition, host.zPosition, "tile.piston.out", 0.5f, host.world.rand.nextFloat() * 0.25f + 0.6f) context.pause(0.5) @@ -34,3 +39,21 @@ class UpgradePiston(val host: Rotatable with EnvironmentHost) extends prefab.Man else result(false) } } + +object UpgradePiston { + + class Drone(drone: internal.Drone) extends UpgradePiston(drone) { + override def pushDirection(args: Arguments, index: Int) = args.optSide(index, ForgeDirection.SOUTH, ForgeDirection.VALID_DIRECTIONS: _*) + } + + class Tablet(tablet: internal.Tablet) extends Rotatable(tablet) { + override def pushOrigin(side: ForgeDirection) = + if (side == ForgeDirection.DOWN && tablet.player.getEyeHeight > 1) super.pushOrigin(side).offset(ForgeDirection.DOWN) + else super.pushOrigin(side) + } + + class Rotatable(val rotatable: internal.Rotatable with EnvironmentHost) extends UpgradePiston(rotatable) { + override def pushDirection(args: Arguments, index: Int) = rotatable.toGlobal(args.optSideForAction(index, ForgeDirection.SOUTH)) + } + +} \ No newline at end of file diff --git a/src/main/scala/li/cil/oc/util/RotationHelper.scala b/src/main/scala/li/cil/oc/util/RotationHelper.scala index ec7821671..d55528182 100644 --- a/src/main/scala/li/cil/oc/util/RotationHelper.scala +++ b/src/main/scala/li/cil/oc/util/RotationHelper.scala @@ -2,6 +2,8 @@ package li.cil.oc.util import net.minecraftforge.common.util.ForgeDirection +import scala.collection.mutable + object RotationHelper { def fromYaw(yaw: Float) = { (yaw / 360 * 4).round & 3 match { @@ -11,4 +13,82 @@ object RotationHelper { case 3 => ForgeDirection.EAST } } + + def toLocal(pitch: ForgeDirection, yaw: ForgeDirection, value: ForgeDirection) = + translationFor(pitch, yaw)(value.ordinal) + + def toGlobal(pitch: ForgeDirection, yaw: ForgeDirection, value: ForgeDirection) = + inverseTranslationFor(pitch, yaw)(value.ordinal) + + def translationFor(pitch: ForgeDirection, yaw: ForgeDirection) = + translationCache. + getOrElseUpdate(pitch, mutable.Map.empty). + getOrElseUpdate(yaw, translations(pitch.ordinal)(yaw.ordinal - 2)) + + def inverseTranslationFor(pitch: ForgeDirection, yaw: ForgeDirection) = + inverseTranslationCache. + getOrElseUpdate(pitch, mutable.Map.empty). + getOrElseUpdate(yaw, { + val t = translationFor(pitch, yaw) + t.indices. + map(ForgeDirection.getOrientation). + map(t.indexOf). + map(ForgeDirection.getOrientation). + toArray + }) + + // ----------------------------------------------------------------------- // + + private val translationCache = mutable.Map.empty[ForgeDirection, mutable.Map[ForgeDirection, Array[ForgeDirection]]] + private val inverseTranslationCache = mutable.Map.empty[ForgeDirection, mutable.Map[ForgeDirection, Array[ForgeDirection]]] + + /** + * Translates forge directions based on the block's pitch and yaw. The base + * forward direction is facing south with no pitch. The outer array is for + * the three different pitch states, the inner for the four different yaw + * states. + */ + private val translations = Array( + // Pitch = Down + Array( + // Yaw = North + Array(D.south, D.north, D.up, D.down, D.east, D.west, D.unknown), + // Yaw = South + Array(D.south, D.north, D.down, D.up, D.west, D.east, D.unknown), + // Yaw = West + Array(D.south, D.north, D.west, D.east, D.up, D.down, D.unknown), + // Yaw = East + Array(D.south, D.north, D.east, D.west, D.down, D.up, D.unknown)), + // Pitch = Up + Array( + // Yaw = North + Array(D.north, D.south, D.down, D.up, D.east, D.west, D.unknown), + // Yaw = South + Array(D.north, D.south, D.up, D.down, D.west, D.east, D.unknown), + // Yaw = West + Array(D.north, D.south, D.west, D.east, D.down, D.up, D.unknown), + // Yaw = East + Array(D.north, D.south, D.east, D.west, D.up, D.down, D.unknown)), + // Pitch = Forward (North|East|South|West) + Array( + // Yaw = North + Array(D.down, D.up, D.south, D.north, D.east, D.west, D.unknown), + // Yaw = South + Array(D.down, D.up, D.north, D.south, D.west, D.east, D.unknown), + // Yaw = West + Array(D.down, D.up, D.west, D.east, D.south, D.north, D.unknown), + // Yaw = East + Array(D.down, D.up, D.east, D.west, D.north, D.south, D.unknown))) + + /** Shortcuts for forge directions to make the above more readable. */ + private object D { + val down = ForgeDirection.DOWN + val up = ForgeDirection.UP + val north = ForgeDirection.NORTH + val south = ForgeDirection.SOUTH + val west = ForgeDirection.WEST + val east = ForgeDirection.EAST + val unknown = ForgeDirection.UNKNOWN + } + } From 8e914587e89a646c5b7a732d0972a0b49ef50ad3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Wed, 12 Aug 2015 18:46:37 -0700 Subject: [PATCH 09/30] Added Better Records integration (item stack converters for records, multi-records and frequency crystals). Closes #1364. --- .../scala/li/cil/oc/integration/Mods.scala | 3 ++ .../betterrecords/ConverterRecord.scala | 40 +++++++++++++++++++ .../betterrecords/ModBetterRecords.scala | 13 ++++++ 3 files changed, 56 insertions(+) create mode 100644 src/main/scala/li/cil/oc/integration/betterrecords/ConverterRecord.scala create mode 100644 src/main/scala/li/cil/oc/integration/betterrecords/ModBetterRecords.scala diff --git a/src/main/scala/li/cil/oc/integration/Mods.scala b/src/main/scala/li/cil/oc/integration/Mods.scala index 4a508be9d..d05106b32 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 BetterRecords = new SimpleMod(IDs.BetterRecords) val BloodMagic = new SimpleMod(IDs.BloodMagic) val BluePower = new SimpleMod(IDs.BluePower, version = "@[0.2.928,)") val BuildCraft = new SimpleMod(IDs.BuildCraft) @@ -84,6 +85,7 @@ object Mods { val Proxies = Array( integration.appeng.ModAppEng, + integration.betterrecords.ModBetterRecords, integration.bloodmagic.ModBloodMagic, integration.bluepower.ModBluePower, integration.buildcraft.library.ModBuildCraftAPILibrary, @@ -156,6 +158,7 @@ object Mods { object IDs { final val AppliedEnergistics2 = "appliedenergistics2" final val BattleGear2 = "battlegear2" + final val BetterRecords = "betterrecords" final val BloodMagic = "AWWayofTime" final val BluePower = "bluepowerAPI" final val BuildCraft = "BuildCraft|Core" diff --git a/src/main/scala/li/cil/oc/integration/betterrecords/ConverterRecord.scala b/src/main/scala/li/cil/oc/integration/betterrecords/ConverterRecord.scala new file mode 100644 index 000000000..ad145e330 --- /dev/null +++ b/src/main/scala/li/cil/oc/integration/betterrecords/ConverterRecord.scala @@ -0,0 +1,40 @@ +package li.cil.oc.integration.betterrecords + +import java.util + +import li.cil.oc.api.driver.Converter +import li.cil.oc.util.ExtendedNBT._ +import net.minecraft.item.ItemStack +import net.minecraft.nbt.NBTTagCompound +import net.minecraftforge.common.util.Constants.NBT + +import scala.collection.convert.WrapAsScala._ + +object ConverterRecord extends Converter { + final val UrlRecordClassName = "com.codingforcookies.betterrecords.src.items.ItemURLRecord" + final val UrlMultiRecordClassName = "com.codingforcookies.betterrecords.src.items.ItemURLMultiRecord" + final val FreqCrystalClassName = "com.codingforcookies.betterrecords.src.items.ItemFreqCrystal" + + override def convert(value: scala.Any, output: util.Map[AnyRef, AnyRef]): Unit = value match { + case stack: ItemStack if stack.getItem != null && stack.getItem.getClass.getName == UrlRecordClassName && stack.hasTagCompound => + convertRecord(stack.getTagCompound, output) + case stack: ItemStack if stack.getItem != null && stack.getItem.getClass.getName == UrlMultiRecordClassName && stack.hasTagCompound => + output += "songs" -> stack.getTagCompound.getTagList("songs", NBT.TAG_COMPOUND).map((nbt: NBTTagCompound) => convertRecord(nbt, new util.HashMap[AnyRef, AnyRef]())) + case stack: ItemStack if stack.getItem != null && stack.getItem.getClass.getName == FreqCrystalClassName && stack.hasTagCompound => + convertRecord(stack.getTagCompound, output) + case _ => + } + + private def convertRecord(nbt: NBTTagCompound, output: util.Map[AnyRef, AnyRef]) = { + if (nbt.hasKey("url", NBT.TAG_STRING)) + output += "url" -> nbt.getString("url") + if (nbt.hasKey("name", NBT.TAG_STRING)) + output += "filename" -> nbt.getString("name") + if (nbt.hasKey("author", NBT.TAG_STRING)) + output += "author" -> nbt.getString("author") + if (nbt.hasKey("local", NBT.TAG_STRING)) + output += "title" -> nbt.getString("local") + + output + } +} diff --git a/src/main/scala/li/cil/oc/integration/betterrecords/ModBetterRecords.scala b/src/main/scala/li/cil/oc/integration/betterrecords/ModBetterRecords.scala new file mode 100644 index 000000000..258b557af --- /dev/null +++ b/src/main/scala/li/cil/oc/integration/betterrecords/ModBetterRecords.scala @@ -0,0 +1,13 @@ +package li.cil.oc.integration.betterrecords + +import li.cil.oc.api.Driver +import li.cil.oc.integration.ModProxy +import li.cil.oc.integration.Mods + +object ModBetterRecords extends ModProxy { + override def getMod = Mods.BetterRecords + + override def initialize() { + Driver.add(ConverterRecord) + } +} From 4c567e54c31548cbb556f61c95798fedcb2cf4ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Wed, 12 Aug 2015 19:11:04 -0700 Subject: [PATCH 10/30] Synchronize cache access, to be on the safe side. --- src/main/scala/li/cil/oc/util/RotationHelper.scala | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/scala/li/cil/oc/util/RotationHelper.scala b/src/main/scala/li/cil/oc/util/RotationHelper.scala index d55528182..0561b6867 100644 --- a/src/main/scala/li/cil/oc/util/RotationHelper.scala +++ b/src/main/scala/li/cil/oc/util/RotationHelper.scala @@ -21,12 +21,12 @@ object RotationHelper { inverseTranslationFor(pitch, yaw)(value.ordinal) def translationFor(pitch: ForgeDirection, yaw: ForgeDirection) = - translationCache. + translationCache.synchronized(translationCache. getOrElseUpdate(pitch, mutable.Map.empty). - getOrElseUpdate(yaw, translations(pitch.ordinal)(yaw.ordinal - 2)) + getOrElseUpdate(yaw, translations(pitch.ordinal)(yaw.ordinal - 2))) def inverseTranslationFor(pitch: ForgeDirection, yaw: ForgeDirection) = - inverseTranslationCache. + inverseTranslationCache.synchronized(inverseTranslationCache. getOrElseUpdate(pitch, mutable.Map.empty). getOrElseUpdate(yaw, { val t = translationFor(pitch, yaw) @@ -35,7 +35,7 @@ object RotationHelper { map(t.indexOf). map(ForgeDirection.getOrientation). toArray - }) + })) // ----------------------------------------------------------------------- // From 0285d4bfda942471496faac96833322d6b6d5760 Mon Sep 17 00:00:00 2001 From: Jakub Sztandera Date: Fri, 14 Aug 2015 14:36:18 +0200 Subject: [PATCH 11/30] Change usage of gitref in versioning As git ref hash can't be used to order versions it should be only used to denote differences between them. By using plus sign instead of hyphen many version compression scripts and similar will stop confusing custom build versions. It is also then compatible with SemVer version 2 ordering rules as for point 10 and 11. It also was moved at the end so it is more obvious that it a metadata. http://semver.org --- build.gradle | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 534615fb7..e688714dd 100644 --- a/build.gradle +++ b/build.gradle @@ -45,12 +45,13 @@ def getGitRef() { if (System.getenv("BUILD_NUMBER") != null) version += ".${System.getenv("BUILD_NUMBER")}" -else - version += "-" + getGitRef() if (config.oc.subversion != null && config.oc.subversion != "") version += "-${config.oc.subversion}" +if (System.getenv("BUILD_NUMBER") == null) + version += "+" + getGitRef() + ext.simpleVersion = version version = "MC${config.minecraft.version}-${project.version}" From 54b7019a1174eecd86d025a045a19cdc17b778fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Sun, 23 Aug 2015 21:43:30 +0200 Subject: [PATCH 12/30] Added relay block to replace switch and access point; has slot for wlan card or linked card to upgrade accordingly. Closes #1334. --- .../doc/en_US/block/accessPoint.md | 2 + .../opencomputers/doc/en_US/block/index.md | 3 +- .../doc/en_US/block/netSplitter.md | 2 +- .../opencomputers/doc/en_US/block/relay.md | 13 + .../doc/en_US/block/serverRack.md | 2 +- .../opencomputers/doc/en_US/block/switch.md | 2 + .../opencomputers/doc/en_US/item/lanCard.md | 2 +- .../assets/opencomputers/lang/en_US.lang | 7 +- .../opencomputers/recipes/default.recipes | 9 +- .../opencomputers/recipes/gregtech.recipes | 4 +- .../opencomputers/recipes/hardmode.recipes | 4 +- .../textures/gui/upgrade_tab.png | Bin 0 -> 185 bytes src/main/scala/li/cil/oc/Constants.scala | 1 + .../scala/li/cil/oc/client/GuiHandler.scala | 10 +- .../li/cil/oc/client/PacketHandler.scala | 2 +- src/main/scala/li/cil/oc/client/Proxy.scala | 1 + .../scala/li/cil/oc/client/Textures.scala | 1 + .../scala/li/cil/oc/client/gui/Relay.scala | 122 ++++++++ .../scala/li/cil/oc/client/gui/Switch.scala | 1 + .../renderer/tileentity/SwitchRenderer.scala | 2 +- .../scala/li/cil/oc/common/GuiHandler.scala | 2 + src/main/scala/li/cil/oc/common/GuiType.scala | 1 + .../li/cil/oc/common/InventorySlots.scala | 7 + .../li/cil/oc/common/block/AccessPoint.scala | 1 + .../scala/li/cil/oc/common/block/Relay.scala | 34 +++ .../scala/li/cil/oc/common/block/Switch.scala | 1 + .../li/cil/oc/common/container/Relay.scala | 33 ++ .../li/cil/oc/common/container/Switch.scala | 1 + .../scala/li/cil/oc/common/init/Blocks.scala | 6 +- .../li/cil/oc/common/recipe/Recipes.scala | 6 + .../oc/common/tileentity/AccessPoint.scala | 5 +- .../li/cil/oc/common/tileentity/Relay.scala | 282 ++++++++++++++++++ .../li/cil/oc/common/tileentity/Switch.scala | 45 +-- .../common/tileentity/traits/SwitchLike.scala | 27 ++ .../computercraft/PeripheralProvider.scala | 4 +- .../computercraft/SwitchPeripheral.scala | 10 +- .../scala/li/cil/oc/server/PacketSender.scala | 2 +- .../cil/oc/server/component/LinkedCard.scala | 6 +- .../oc/server/network/QuantumNetwork.scala | 17 +- 39 files changed, 608 insertions(+), 72 deletions(-) create mode 100644 src/main/resources/assets/opencomputers/doc/en_US/block/relay.md create mode 100644 src/main/resources/assets/opencomputers/textures/gui/upgrade_tab.png create mode 100644 src/main/scala/li/cil/oc/client/gui/Relay.scala create mode 100644 src/main/scala/li/cil/oc/common/block/Relay.scala create mode 100644 src/main/scala/li/cil/oc/common/container/Relay.scala create mode 100644 src/main/scala/li/cil/oc/common/tileentity/Relay.scala create mode 100644 src/main/scala/li/cil/oc/common/tileentity/traits/SwitchLike.scala diff --git a/src/main/resources/assets/opencomputers/doc/en_US/block/accessPoint.md b/src/main/resources/assets/opencomputers/doc/en_US/block/accessPoint.md index 5dde0da28..78bacc26c 100644 --- a/src/main/resources/assets/opencomputers/doc/en_US/block/accessPoint.md +++ b/src/main/resources/assets/opencomputers/doc/en_US/block/accessPoint.md @@ -2,6 +2,8 @@ ![AAA](oredict:oc:accessPoint) +*This block is deprecated and will be removed in a future version.* Craft it into a [relay](relay.md) to avoid losing it. + The access point is the wireless version of the [switch](switch.md). It can be used to separate subnetworks so that machines in them will not see [components](../general/computer.md) in other networks, while still allowing to send network messages to the machines in other networks. In addition to that, this block can act as a repeater: it can re-send wired messages as wired messages to other devices; or wireless messages as wired or wireless messages. diff --git a/src/main/resources/assets/opencomputers/doc/en_US/block/index.md b/src/main/resources/assets/opencomputers/doc/en_US/block/index.md index a33f40557..26a47e734 100644 --- a/src/main/resources/assets/opencomputers/doc/en_US/block/index.md +++ b/src/main/resources/assets/opencomputers/doc/en_US/block/index.md @@ -36,10 +36,9 @@ Keep in mind that some of these may not be available, depending on the recipe se * [Disassembler](disassembler.md) ## Networking -* [Access Point](accessPoint.md) * [Cable](cable.md) * [Net Splitter](netSplitter.md) -* [Switch](switch.md) +* [Relay](relay.md) ## Power management * [Capacitor](capacitor.md) diff --git a/src/main/resources/assets/opencomputers/doc/en_US/block/netSplitter.md b/src/main/resources/assets/opencomputers/doc/en_US/block/netSplitter.md index 230e4484f..f6c02a752 100644 --- a/src/main/resources/assets/opencomputers/doc/en_US/block/netSplitter.md +++ b/src/main/resources/assets/opencomputers/doc/en_US/block/netSplitter.md @@ -2,6 +2,6 @@ ![*.net *.split](oredict:oc:netSplitter) -The net splitter is a device that allows controlling connectivity between subnetworks. Unlike the [switch](switch.md) or [power converter](powerConverter.md) it directly connects adjacent subnetworks, i.e. components can be accessed. Each side's connectivity can be toggled using a wrench (e.g. the [scrench](../item/wrench.md)). When a redstone signal is applied to the net splitter, all sides' connectivity is inverted. +The net splitter is a device that allows controlling connectivity between subnetworks. Unlike the [relay](relay.md) or [power converter](powerConverter.md) it directly connects adjacent subnetworks, i.e. components can be accessed. Each side's connectivity can be toggled using a wrench (e.g. the [scrench](../item/wrench.md)). When a redstone signal is applied to the net splitter, all sides' connectivity is inverted. This block can therefore be used to toggle connectivity to certain parts of a component network. Use a [redstone I/O block](redstone.md) or [redstone cards](../item/redstoneCard1.md) to automate the net splitter. diff --git a/src/main/resources/assets/opencomputers/doc/en_US/block/relay.md b/src/main/resources/assets/opencomputers/doc/en_US/block/relay.md new file mode 100644 index 000000000..212369838 --- /dev/null +++ b/src/main/resources/assets/opencomputers/doc/en_US/block/relay.md @@ -0,0 +1,13 @@ +# Relay + +![Building bridges.](oredict:oc:relay) + +The relay can be used to allow different subnetworks to send network messages to each other, without exposing components to [computers](../general/computer.md) in other networks. Keeping components local is usually a good idea, to avoid [computers](../general/computer.md) using the wrong [screen](screen1.md) or to avoid component overflows to happen (causing [computers](../general/computer.md) to crash and refuse to boot up). + +The relay can be upgraded by inserting a [wireless network card](../item/wlanCard.md) to also relay messages wirelessly. Wireless messages can be received and relayed by other relays with a wireless network card, or by [computers](../general/computer.md) with a wireless network card. + +Alternatively the relay can be upgraded using [linked cards](../item/linkedCard.md). In this case it will forward messages through the tunnel provided by the linked card, too; at the usual cost, so make sure the relay is sufficiently powered. + +Relays do *not* keep track of which packets they forwarded recently, so avoid cycles in your network or you may receive the same packet multiple times. Due to the limited buffer size of relays, sending messages too frequently will result in packet loss. You can upgrade your relays to increase the speed with which they relay messages, as well as their internal message queue size. + +Packets are only re-sent a certain number of times, so chaining an arbitrary number of relays is not possible. By default, a packet will be re-sent up to five times. diff --git a/src/main/resources/assets/opencomputers/doc/en_US/block/serverRack.md b/src/main/resources/assets/opencomputers/doc/en_US/block/serverRack.md index 49f1df835..5630023b4 100644 --- a/src/main/resources/assets/opencomputers/doc/en_US/block/serverRack.md +++ b/src/main/resources/assets/opencomputers/doc/en_US/block/serverRack.md @@ -6,4 +6,4 @@ A server rack houses up to four [servers](../item/server1.md). A [server](../ite Each [server](../item/server1.md) in a server rack can only communicate with one "face" of the server rack at a time - or none at all. Which side each [server](../item/server1.md) is connected to can be configured in the server rack's GUI. Beware that the sides are from the point of view of the server rack, i.e. if you are looking at the front of the server rack, `sides.right` will be to your left and vice versa. -Server racks act as [switch](switch.md) and [power distributor](powerDistributor.md) in one. The switch mode of the server rack can be configured in its GUI, with the two options being internal and external. In external mode the server rack will behave like a normal [switch](switch.md). In internal mode, messages are only passed to the [servers](../item/server1.md) in the rack, and will not be automatically relayed to the other faces of the rack. [Servers](../item/server1.md) will still be able to send messages to each other. This allows using server racks as advanced [switches](switch.md) that can perform filter and mapping operations, for example. +Server racks act as [relay](relay.md) and [power distributor](powerDistributor.md) in one. The switch mode of the server rack can be configured in its GUI, with the two options being internal and external. In external mode the server rack will behave like a normal [relay](relay.md). In internal mode, messages are only passed to the [servers](../item/server1.md) in the rack, and will not be automatically relayed to the other faces of the rack. [Servers](../item/server1.md) will still be able to send messages to each other. This allows using server racks as advanced [relays](relay.md) that can perform filter and mapping operations, for example. diff --git a/src/main/resources/assets/opencomputers/doc/en_US/block/switch.md b/src/main/resources/assets/opencomputers/doc/en_US/block/switch.md index a607e0cfd..35ad59fd4 100644 --- a/src/main/resources/assets/opencomputers/doc/en_US/block/switch.md +++ b/src/main/resources/assets/opencomputers/doc/en_US/block/switch.md @@ -2,6 +2,8 @@ ![Building bridges.](oredict:oc:switch) +*This block is deprecated and will be removed in a future version.* Craft it into a [relay](relay.md) to avoid losing it. + The switch can be used to allow different subnetworks to send network messages to each other, without exposing components to [computers](../general/computer.md) in other networks. Keeping components local is usually a good idea, to avoid [computers](../general/computer.md) using the wrong [screen](screen1.md) or to avoid component overflows to happen (causing [computers](../general/computer.md) to crash and refuse to boot up). There is also a wireless variation of this block, called the [access point](accessPoint.md), which will also relay messages wirelessly. Wireless messages can be received and relayed by other [access points](accessPoint.md), or by [computers](../general/computer.md) with a [wireless network card](../item/wlanCard.md). diff --git a/src/main/resources/assets/opencomputers/doc/en_US/item/lanCard.md b/src/main/resources/assets/opencomputers/doc/en_US/item/lanCard.md index 3fbd8a6c4..fc730e035 100644 --- a/src/main/resources/assets/opencomputers/doc/en_US/item/lanCard.md +++ b/src/main/resources/assets/opencomputers/doc/en_US/item/lanCard.md @@ -2,4 +2,4 @@ ![Enter the network.](oredict:oc:lanCard) -The network card allows [computers](../general/computer.md) to send and receive network messages. Messages (or packets) can be broadcasted to all receiving nodes in a subnetwork, or sent to a specific node with a specified address. [Switches](../block/switch.md) and [access points](../block/accessPoint.md) can be used to bridge multiple subnetworks by relaying messages between the subnetworks they are connected to. It is also possible to send a targeted message if the receiver is in another subnetwork, if the networks are connected via one or more [switches](../block/switch.md). +The network card allows [computers](../general/computer.md) to send and receive network messages. Messages (or packets) can be broadcasted to all receiving nodes in a subnetwork, or sent to a specific node with a specified address. [Relays](../block/relay.md) can be used to bridge multiple subnetworks by relaying messages between the subnetworks they are connected to. It is also possible to send a targeted message if the receiver is in another subnetwork, if the networks are connected via one or more [relays](../block/relay.md). diff --git a/src/main/resources/assets/opencomputers/lang/en_US.lang b/src/main/resources/assets/opencomputers/lang/en_US.lang index 6d8d2cdb6..12020008f 100644 --- a/src/main/resources/assets/opencomputers/lang/en_US.lang +++ b/src/main/resources/assets/opencomputers/lang/en_US.lang @@ -3,7 +3,7 @@ # Use [nl] to for a line break. # Blocks -tile.oc.accessPoint.name=Access Point +tile.oc.accessPoint.name=§cAccess Point§7 tile.oc.adapter.name=Adapter tile.oc.assembler.name=Electronics Assembler tile.oc.cable.name=Cable @@ -29,13 +29,14 @@ tile.oc.print.name=3D Print tile.oc.printer.name=3D Printer tile.oc.raid.name=Raid tile.oc.redstone.name=Redstone I/O +tile.oc.relay.name=Relay tile.oc.robot.name=Robot tile.oc.robotAfterimage.name=Robot tile.oc.screen1.name=Screen (Tier 1) tile.oc.screen2.name=Screen (Tier 2) tile.oc.screen3.name=Screen (Tier 3) tile.oc.serverRack.name=Server Rack -tile.oc.switch.name=Switch +tile.oc.switch.name=§cSwitch§7 tile.oc.netSplitter.name=Net Splitter tile.oc.waypoint.name=Waypoint @@ -235,6 +236,7 @@ oc:container.Disassembler=Disassembler oc:container.DiskDrive=Disk Drive oc:container.Printer=Printer oc:container.Raid=Raid +oc:container.Relay=Relay oc:container.Server=Server oc:container.ServerRack=Server Rack oc:container.Switch=Switch @@ -328,6 +330,7 @@ oc:tooltip.RedstoneCard.RedNet=§fRedNet§7 is §asupported§7. oc:tooltip.RedstoneCard.WirelessCBE=§fWireless Redstone (ChickenBones)§7 is §asupported§7. oc:tooltip.RedstoneCard.WirelessSV=§fWireless Redstone (SlimeVoid)§7 is §asupported§7. oc:tooltip.RedstoneCard=Allows reading and emitting redstone signals around the computer or robot. +oc:tooltip.Relay=Allows connecting different networks to each other. Only network messages will be passed along, components will not be visible through this. Use this to separate networks while still allowing communication using Network Cards, for example. oc:tooltip.Robot=Unlike computers, robots can move around and interact with the world much like a player can.[nl] §cCan not connect to external components.§7 # The underscore makes sure this isn't hidden with the rest of the tooltip. oc:tooltip.Robot_Level=§fLevel§7: §a%s§7 diff --git a/src/main/resources/assets/opencomputers/recipes/default.recipes b/src/main/resources/assets/opencomputers/recipes/default.recipes index e44ddf5bc..2350ace4a 100644 --- a/src/main/resources/assets/opencomputers/recipes/default.recipes +++ b/src/main/resources/assets/opencomputers/recipes/default.recipes @@ -504,11 +504,6 @@ interweb { [string, string, string]] } -accessPoint { - input: [[ingotIron, "oc:wlanCard", ingotIron] - ["oc:cable", "oc:lanCard", "oc:cable"] - [ingotIron, "oc:materialCircuitBoardPrinted", ingotIron]] -} adapter { input: [[ingotIron, "oc:cable", ingotIron] ["oc:cable", "oc:circuitChip1", "oc:cable"] @@ -607,7 +602,7 @@ powerDistributor { serverRack { input: [["oc:circuitChip2", "oc:wlanCard", "oc:circuitChip2"] [fenceIron, chest, fenceIron] - ["oc:switch", "oc:materialCircuitBoardPrinted", "oc:powerDistributor"]] + ["oc:relay", "oc:materialCircuitBoardPrinted", "oc:powerDistributor"]] } raid { input: [[nuggetIron, "oc:cpu3", nuggetIron] @@ -619,7 +614,7 @@ redstone { [blockRedstone, "oc:redstoneCard1", blockRedstone] [ingotIron, "oc:materialCircuitBoardPrinted", ingotIron]] } -switch { +relay { input: [[ingotIron, "oc:cable", ingotIron] ["oc:cable", "oc:lanCard", "oc:cable"] [ingotIron, "oc:materialCircuitBoardPrinted", ingotIron]] diff --git a/src/main/resources/assets/opencomputers/recipes/gregtech.recipes b/src/main/resources/assets/opencomputers/recipes/gregtech.recipes index 4c95c8eb8..f2b3768c7 100644 --- a/src/main/resources/assets/opencomputers/recipes/gregtech.recipes +++ b/src/main/resources/assets/opencomputers/recipes/gregtech.recipes @@ -318,7 +318,7 @@ powerDistributor { serverRack { input: [[craftingToolScrewdriver, "oc:wlanCard", craftingToolWrench] ["ic2.reactorVentDiamond", chest, "ic2.reactorVentDiamond"] - ["oc:switch", "oc:materialCircuitBoardPrinted","oc:powerDistributor"]] + ["oc:relay", "oc:materialCircuitBoardPrinted","oc:powerDistributor"]] } redstone { # 32731 = Activity Detector @@ -326,7 +326,7 @@ redstone { [{item="gt.metaitem.01", subID=32731}, {block="gt.blockcasings", subID=2}, "oc:redstoneCard1"] ["oc:circuitChip2", "oc:materialCircuitBoardPrinted", "oc:circuitChip2"]] } -switch { +relay { input: [["", "oc:lanCard", ""] ["oc:cable", {block="gt.blockcasings", subID=2}, "oc:cable"] ["oc:materialCircuitBoardPrinted", craftingToolWrench, "oc:materialCircuitBoardPrinted"]] diff --git a/src/main/resources/assets/opencomputers/recipes/hardmode.recipes b/src/main/resources/assets/opencomputers/recipes/hardmode.recipes index ed930d4f3..fe0614746 100644 --- a/src/main/resources/assets/opencomputers/recipes/hardmode.recipes +++ b/src/main/resources/assets/opencomputers/recipes/hardmode.recipes @@ -363,14 +363,14 @@ powerDistributor { serverRack { input: [["oc:circuitChip3", "oc:wlanCard", "oc:circuitChip3"] [fenceIron, chest, fenceIron] - ["oc:switch", "oc:materialCircuitBoardPrinted","oc:powerDistributor"]] + ["oc:relay", "oc:materialCircuitBoardPrinted","oc:powerDistributor"]] } redstone { input: [[ingotIron, "oc:circuitChip3", ingotIron] [blockRedstone, "oc:redstoneCard1", blockRedstone] [ingotIron, "oc:materialCircuitBoardPrinted", ingotIron]] } -switch { +relay { input: [[ingotIron, "oc:cable", ingotIron] ["oc:cable", "oc:lanCard", "oc:cable"] [ingotIron, "oc:materialCircuitBoardPrinted", ingotIron]] diff --git a/src/main/resources/assets/opencomputers/textures/gui/upgrade_tab.png b/src/main/resources/assets/opencomputers/textures/gui/upgrade_tab.png new file mode 100644 index 0000000000000000000000000000000000000000..2ca3b14c7ac35ec4c60bc29b73c7c404fff85c51 GIT binary patch literal 185 zcmeAS@N?(olHy`uVBq!ia0vp^;y^6L!3-p`v&?;flw^r(L`iUdT1k0gQ7VIDN`6wR zf@f}GdTLN=VoGJ<$y6JlBK`oM5ZBPq(EtDc19``e9Ro6|Snj0*Ijki?e!)QQe}>=N z_=14~`kpS1Ar-fh5)QFNL`X<%WK?_e=nRh!&zT5@!z+Gl5IoM+@RD)20XOrvl%q@n a2@Ll?ur`bTUn~sN%HZkh=d#Wzp$PyQ9zNOt literal 0 HcmV?d00001 diff --git a/src/main/scala/li/cil/oc/Constants.scala b/src/main/scala/li/cil/oc/Constants.scala index 10646c14d..78b5ac786 100644 --- a/src/main/scala/li/cil/oc/Constants.scala +++ b/src/main/scala/li/cil/oc/Constants.scala @@ -31,6 +31,7 @@ object Constants { final val Printer = "printer" final val Raid = "raid" final val Redstone = "redstone" + final val Relay = "relay" final val Robot = "robot" final val RobotAfterimage = "robotAfterimage" final val ScreenTier1 = "screen1" diff --git a/src/main/scala/li/cil/oc/client/GuiHandler.scala b/src/main/scala/li/cil/oc/client/GuiHandler.scala index 44190606b..08882733e 100644 --- a/src/main/scala/li/cil/oc/client/GuiHandler.scala +++ b/src/main/scala/li/cil/oc/client/GuiHandler.scala @@ -34,12 +34,14 @@ object GuiHandler extends CommonGuiHandler { new gui.DiskDrive(player.inventory, t) case t: tileentity.Printer if id == GuiType.Printer.id => new gui.Printer(player.inventory, t) - case t: tileentity.Raid if id == GuiType.Raid.id => - new gui.Raid(player.inventory, t) - case t: tileentity.RobotProxy if id == GuiType.Robot.id => - new gui.Robot(player.inventory, t.robot) case t: tileentity.ServerRack if id == GuiType.Rack.id => new gui.ServerRack(player.inventory, t) + case t: tileentity.Raid if id == GuiType.Raid.id => + new gui.Raid(player.inventory, t) + case t: tileentity.Relay if id == GuiType.Relay.id => + new gui.Relay(player.inventory, t) + case t: tileentity.RobotProxy if id == GuiType.Robot.id => + new gui.Robot(player.inventory, t.robot) case t: tileentity.Screen if id == GuiType.Screen.id => new gui.Screen(t.origin.buffer, t.tier > 0, () => t.origin.hasKeyboard, () => t.origin.buffer.isRenderingEnabled) case t: tileentity.Switch if id == GuiType.Switch.id => diff --git a/src/main/scala/li/cil/oc/client/PacketHandler.scala b/src/main/scala/li/cil/oc/client/PacketHandler.scala index 9cf57901b..e05f3c4d9 100644 --- a/src/main/scala/li/cil/oc/client/PacketHandler.scala +++ b/src/main/scala/li/cil/oc/client/PacketHandler.scala @@ -423,7 +423,7 @@ object PacketHandler extends CommonPacketHandler { } def onSwitchActivity(p: PacketParser) = - p.readTileEntity[Switch]() match { + p.readTileEntity[traits.SwitchLike]() match { case Some(t) => t.lastMessage = System.currentTimeMillis() case _ => // Invalid packet. } diff --git a/src/main/scala/li/cil/oc/client/Proxy.scala b/src/main/scala/li/cil/oc/client/Proxy.scala index aa96dcb65..45930095c 100644 --- a/src/main/scala/li/cil/oc/client/Proxy.scala +++ b/src/main/scala/li/cil/oc/client/Proxy.scala @@ -67,6 +67,7 @@ private[oc] class Proxy extends CommonProxy { ClientRegistry.bindTileEntitySpecialRenderer(classOf[tileentity.ServerRack], ServerRackRenderer) ClientRegistry.bindTileEntitySpecialRenderer(classOf[tileentity.Switch], SwitchRenderer) ClientRegistry.bindTileEntitySpecialRenderer(classOf[tileentity.AccessPoint], SwitchRenderer) + ClientRegistry.bindTileEntitySpecialRenderer(classOf[tileentity.Relay], SwitchRenderer) ClientRegistry.bindTileEntitySpecialRenderer(classOf[tileentity.RobotProxy], RobotRenderer) ClientRegistry.bindTileEntitySpecialRenderer(classOf[tileentity.Screen], ScreenRenderer) ClientRegistry.bindTileEntitySpecialRenderer(classOf[tileentity.NetSplitter], NetSplitterRenderer) diff --git a/src/main/scala/li/cil/oc/client/Textures.scala b/src/main/scala/li/cil/oc/client/Textures.scala index 78b84868e..195f400da 100644 --- a/src/main/scala/li/cil/oc/client/Textures.scala +++ b/src/main/scala/li/cil/oc/client/Textures.scala @@ -43,6 +43,7 @@ object Textures { val guiRobotSelection = new ResourceLocation(Settings.resourceDomain, "textures/gui/robot_selection.png") val guiServer = new ResourceLocation(Settings.resourceDomain, "textures/gui/server.png") val guiSlot = new ResourceLocation(Settings.resourceDomain, "textures/gui/slot.png") + val guiUpgradeTab = new ResourceLocation(Settings.resourceDomain, "textures/gui/upgrade_tab.png") val guiWaypoint = new ResourceLocation(Settings.resourceDomain, "textures/gui/waypoint.png") val blockCaseFrontOn = new ResourceLocation(Settings.resourceDomain, "textures/blocks/CaseFrontOn.png") diff --git a/src/main/scala/li/cil/oc/client/gui/Relay.scala b/src/main/scala/li/cil/oc/client/gui/Relay.scala new file mode 100644 index 000000000..c6f578e67 --- /dev/null +++ b/src/main/scala/li/cil/oc/client/gui/Relay.scala @@ -0,0 +1,122 @@ +package li.cil.oc.client.gui + +import java.lang.Iterable +import java.text.DecimalFormat +import java.util + +import codechicken.nei.VisiblityData +import codechicken.nei.api.INEIGuiHandler +import codechicken.nei.api.TaggedInventoryArea +import cpw.mods.fml.common.Optional +import li.cil.oc.Localization +import li.cil.oc.client.Textures +import li.cil.oc.common.container +import li.cil.oc.common.tileentity +import li.cil.oc.integration.Mods +import net.minecraft.client.Minecraft +import net.minecraft.client.gui.inventory.GuiContainer +import net.minecraft.client.renderer.Tessellator +import net.minecraft.entity.player.InventoryPlayer +import net.minecraft.item.ItemStack +import org.lwjgl.opengl.GL11 +import org.lwjgl.util.Rectangle + +@Optional.Interface(iface = "codechicken.nei.api.INEIGuiHandler", modid = Mods.IDs.NotEnoughItems) +class Relay(playerInventory: InventoryPlayer, val relay: tileentity.Relay) extends DynamicGuiContainer(new container.Relay(playerInventory, relay)) with INEIGuiHandler { + private val format = new DecimalFormat("#.##hz") + + private val tabPosition = new Rectangle(xSize, 10, 23, 26) + + override protected def drawSecondaryBackgroundLayer(): Unit = { + super.drawSecondaryBackgroundLayer() + + // Tab background. + GL11.glColor4f(1, 1, 1, 1) + Minecraft.getMinecraft.getTextureManager.bindTexture(Textures.guiUpgradeTab) + val x = windowX + tabPosition.getX + val y = windowY + tabPosition.getY + val w = tabPosition.getWidth + val h = tabPosition.getHeight + val t = Tessellator.instance + t.startDrawingQuads() + t.addVertexWithUV(x, y + h, zLevel, 0, 1) + t.addVertexWithUV(x + w, y + h, zLevel, 1, 1) + t.addVertexWithUV(x + w, y, zLevel, 1, 0) + t.addVertexWithUV(x, y, zLevel, 0, 0) + t.draw() + } + + override def mouseClicked(mouseX: Int, mouseY: Int, button: Int): Unit = { + // So MC doesn't throw away the item in the upgrade slot when we're trying to pick it up... + val originalWidth = xSize + try { + xSize += tabPosition.getWidth + super.mouseClicked(mouseX, mouseY, button) + } + finally { + xSize = originalWidth + } + } + + override def mouseMovedOrUp(mouseX: Int, mouseY: Int, button: Int): Unit = { + // So MC doesn't throw away the item in the upgrade slot when we're trying to pick it up... + val originalWidth = xSize + try { + xSize += tabPosition.getWidth + super.mouseMovedOrUp(mouseX, mouseY, button) + } + finally { + xSize = originalWidth + } + } + + override def drawSecondaryForegroundLayer(mouseX: Int, mouseY: Int) = { + super.drawSecondaryForegroundLayer(mouseX, mouseY) + fontRendererObj.drawString( + Localization.localizeImmediately(relay.getInventoryName), + 8, 6, 0x404040) + + fontRendererObj.drawString( + Localization.Switch.TransferRate, + 14, 20, 0x404040) + fontRendererObj.drawString( + Localization.Switch.PacketsPerCycle, + 14, 39, 0x404040) + fontRendererObj.drawString( + Localization.Switch.QueueSize, + 14, 58, 0x404040) + + fontRendererObj.drawString( + format.format(20f / inventoryContainer.relayDelay), + 108, 20, 0x404040) + fontRendererObj.drawString( + inventoryContainer.packetsPerCycleAvg + " / " + inventoryContainer.relayAmount, + 108, 39, thresholdBasedColor(inventoryContainer.packetsPerCycleAvg, math.ceil(inventoryContainer.relayAmount / 2f).toInt, inventoryContainer.relayAmount)) + fontRendererObj.drawString( + inventoryContainer.queueSize + " / " + inventoryContainer.maxQueueSize, + 108, 58, thresholdBasedColor(inventoryContainer.queueSize, inventoryContainer.maxQueueSize / 2, inventoryContainer.maxQueueSize)) + } + + private def thresholdBasedColor(value: Int, yellow: Int, red: Int) = { + if (value < yellow) 0x009900 + else if (value < red) 0x999900 + else 0x990000 + } + + @Optional.Method(modid = Mods.IDs.NotEnoughItems) + override def modifyVisiblity(gui: GuiContainer, currentVisibility: VisiblityData): VisiblityData = null + + @Optional.Method(modid = Mods.IDs.NotEnoughItems) + override def getItemSpawnSlots(gui: GuiContainer, stack: ItemStack): Iterable[Integer] = null + + @Optional.Method(modid = Mods.IDs.NotEnoughItems) + override def getInventoryAreas(gui: GuiContainer): util.List[TaggedInventoryArea] = null + + @Optional.Method(modid = Mods.IDs.NotEnoughItems) + override def handleDragNDrop(gui: GuiContainer, mouseX: Int, mouseY: Int, stack: ItemStack, button: Int): Boolean = false + + @Optional.Method(modid = Mods.IDs.NotEnoughItems) + override def hideItemPanelSlot(gui: GuiContainer, x: Int, y: Int, w: Int, h: Int): Boolean = { + new Rectangle(x - windowX, y - windowY, w, h).intersects(tabPosition) + } +} 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 ea2dc471f..e58511a44 100644 --- a/src/main/scala/li/cil/oc/client/gui/Switch.scala +++ b/src/main/scala/li/cil/oc/client/gui/Switch.scala @@ -7,6 +7,7 @@ import li.cil.oc.common.container import li.cil.oc.common.tileentity import net.minecraft.entity.player.InventoryPlayer +// TODO Remove in 1.7 class Switch(playerInventory: InventoryPlayer, val switch: tileentity.Switch) extends DynamicGuiContainer(new container.Switch(playerInventory, switch)) { private val format = new DecimalFormat("#.##hz") diff --git a/src/main/scala/li/cil/oc/client/renderer/tileentity/SwitchRenderer.scala b/src/main/scala/li/cil/oc/client/renderer/tileentity/SwitchRenderer.scala index 4491c9c85..b2fbe27b4 100644 --- a/src/main/scala/li/cil/oc/client/renderer/tileentity/SwitchRenderer.scala +++ b/src/main/scala/li/cil/oc/client/renderer/tileentity/SwitchRenderer.scala @@ -13,7 +13,7 @@ object SwitchRenderer extends TileEntitySpecialRenderer { override def renderTileEntityAt(tileEntity: TileEntity, x: Double, y: Double, z: Double, f: Float) { RenderState.checkError(getClass.getName + ".renderTileEntityAt: entering (aka: wasntme)") - val switch = tileEntity.asInstanceOf[tileentity.Switch] + val switch = tileEntity.asInstanceOf[tileentity.traits.SwitchLike] val activity = math.max(0, 1 - (System.currentTimeMillis() - switch.lastMessage) / 1000.0) if (activity > 0) { GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS) diff --git a/src/main/scala/li/cil/oc/common/GuiHandler.scala b/src/main/scala/li/cil/oc/common/GuiHandler.scala index ff56edec2..6ce0419bd 100644 --- a/src/main/scala/li/cil/oc/common/GuiHandler.scala +++ b/src/main/scala/li/cil/oc/common/GuiHandler.scala @@ -28,6 +28,8 @@ abstract class GuiHandler extends IGuiHandler { new container.Printer(player.inventory, t) case t: tileentity.Raid if id == GuiType.Raid.id => new container.Raid(player.inventory, t) + case t: tileentity.Relay if id == GuiType.Relay.id => + new container.Relay(player.inventory, t) case t: tileentity.RobotProxy if id == GuiType.Robot.id => new container.Robot(player.inventory, t.robot) case t: tileentity.ServerRack if id == GuiType.Rack.id => diff --git a/src/main/scala/li/cil/oc/common/GuiType.scala b/src/main/scala/li/cil/oc/common/GuiType.scala index 864bdbf39..5eda4b249 100644 --- a/src/main/scala/li/cil/oc/common/GuiType.scala +++ b/src/main/scala/li/cil/oc/common/GuiType.scala @@ -26,6 +26,7 @@ object GuiType extends ScalaEnum { val Printer = new EnumVal { def name = "Printer"; def subType = GuiType.Category.Block } val Rack = new EnumVal { def name = "Rack"; def subType = GuiType.Category.Block } val Raid = new EnumVal { def name = "Raid"; def subType = GuiType.Category.Block } + val Relay = new EnumVal { def name = "Relay"; def subType = GuiType.Category.Block } val Robot = new EnumVal { def name = "Robot"; def subType = GuiType.Category.Block } val Screen = new EnumVal { def name = "Screen"; def subType = GuiType.Category.Block } val Server = new EnumVal { def name = "Server"; def subType = GuiType.Category.Item } diff --git a/src/main/scala/li/cil/oc/common/InventorySlots.scala b/src/main/scala/li/cil/oc/common/InventorySlots.scala index 6961b5bd4..1ac7ef962 100644 --- a/src/main/scala/li/cil/oc/common/InventorySlots.scala +++ b/src/main/scala/li/cil/oc/common/InventorySlots.scala @@ -120,6 +120,13 @@ object InventorySlots { ) ) + val relay = Array( + InventorySlot(Slot.CPU, Tier.Three), + InventorySlot(Slot.Memory, Tier.Three), + InventorySlot(Slot.HDD, Tier.Three), + InventorySlot(Slot.Card, Tier.Three) + ) + val switch = Array( InventorySlot(Slot.CPU, Tier.Three), InventorySlot(Slot.Memory, Tier.Three), diff --git a/src/main/scala/li/cil/oc/common/block/AccessPoint.scala b/src/main/scala/li/cil/oc/common/block/AccessPoint.scala index f181c86ef..2ae339da7 100644 --- a/src/main/scala/li/cil/oc/common/block/AccessPoint.scala +++ b/src/main/scala/li/cil/oc/common/block/AccessPoint.scala @@ -4,6 +4,7 @@ import li.cil.oc.Settings import li.cil.oc.common.tileentity import net.minecraft.world.World +// TODO Remove in 1.7 class AccessPoint extends Switch with traits.PowerAcceptor { override protected def customTextures = Array( None, diff --git a/src/main/scala/li/cil/oc/common/block/Relay.scala b/src/main/scala/li/cil/oc/common/block/Relay.scala new file mode 100644 index 000000000..1a420de04 --- /dev/null +++ b/src/main/scala/li/cil/oc/common/block/Relay.scala @@ -0,0 +1,34 @@ +package li.cil.oc.common.block + +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.world.World + +class Relay extends SimpleBlock with traits.GUI with traits.PowerAcceptor { + override protected def customTextures = Array( + None, + Some("SwitchTop"), + Some("SwitchSide"), + Some("SwitchSide"), + Some("SwitchSide"), + Some("SwitchSide") + ) + + override def registerBlockIcons(iconRegister: IIconRegister) = { + super.registerBlockIcons(iconRegister) + Textures.Switch.iconSideActivity = iconRegister.registerIcon(Settings.resourceDomain + ":SwitchSideOn") + } + + // ----------------------------------------------------------------------- // + + override def guiType = GuiType.Relay + + override def energyThroughput = Settings.get.accessPointRate + + override def hasTileEntity(metadata: Int) = true + + override def createTileEntity(world: World, metadata: Int) = new tileentity.Relay() +} 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 fb4d4514b..29335e0fb 100644 --- a/src/main/scala/li/cil/oc/common/block/Switch.scala +++ b/src/main/scala/li/cil/oc/common/block/Switch.scala @@ -7,6 +7,7 @@ import li.cil.oc.common.tileentity import net.minecraft.client.renderer.texture.IIconRegister import net.minecraft.world.World +// TODO Remove in 1.7 class Switch extends SimpleBlock with traits.GUI { override protected def customTextures = Array( None, diff --git a/src/main/scala/li/cil/oc/common/container/Relay.scala b/src/main/scala/li/cil/oc/common/container/Relay.scala new file mode 100644 index 000000000..d9ee4a54f --- /dev/null +++ b/src/main/scala/li/cil/oc/common/container/Relay.scala @@ -0,0 +1,33 @@ +package li.cil.oc.common.container + +import li.cil.oc.common.Slot +import li.cil.oc.common.tileentity +import net.minecraft.entity.player.InventoryPlayer +import net.minecraft.nbt.NBTTagCompound + +class Relay(playerInventory: InventoryPlayer, relay: tileentity.Relay) extends Player(playerInventory, relay) { + addSlotToContainer(151, 15, Slot.CPU) + addSlotToContainer(151, 34, Slot.Memory) + addSlotToContainer(151, 53, Slot.HDD) + addSlotToContainer(178, 15, Slot.Card) + addPlayerInventorySlots(8, 84) + + def relayDelay = synchronizedData.getInteger("relayDelay") + + def relayAmount = synchronizedData.getInteger("relayAmount") + + def maxQueueSize = synchronizedData.getInteger("maxQueueSize") + + def packetsPerCycleAvg = synchronizedData.getInteger("packetsPerCycleAvg") + + def queueSize = synchronizedData.getInteger("queueSize") + + override protected def detectCustomDataChanges(nbt: NBTTagCompound): Unit = { + synchronizedData.setInteger("relayDelay", relay.relayDelay) + synchronizedData.setInteger("relayAmount", relay.relayAmount) + synchronizedData.setInteger("maxQueueSize", relay.maxQueueSize) + synchronizedData.setInteger("packetsPerCycleAvg", relay.packetsPerCycleAvg()) + synchronizedData.setInteger("queueSize", relay.queue.size) + super.detectCustomDataChanges(nbt) + } +} diff --git a/src/main/scala/li/cil/oc/common/container/Switch.scala b/src/main/scala/li/cil/oc/common/container/Switch.scala index ae6c16254..78d884368 100644 --- a/src/main/scala/li/cil/oc/common/container/Switch.scala +++ b/src/main/scala/li/cil/oc/common/container/Switch.scala @@ -5,6 +5,7 @@ import li.cil.oc.common.tileentity import net.minecraft.entity.player.InventoryPlayer import net.minecraft.nbt.NBTTagCompound +// TODO Remove in 1.7 class Switch(playerInventory: InventoryPlayer, switch: tileentity.Switch) extends Player(playerInventory, switch) { addSlotToContainer(151, 15, Slot.CPU) addSlotToContainer(151, 34, Slot.Memory) diff --git a/src/main/scala/li/cil/oc/common/init/Blocks.scala b/src/main/scala/li/cil/oc/common/init/Blocks.scala index 7acf21d27..73ea7bea2 100644 --- a/src/main/scala/li/cil/oc/common/init/Blocks.scala +++ b/src/main/scala/li/cil/oc/common/init/Blocks.scala @@ -30,6 +30,7 @@ object Blocks { GameRegistry.registerTileEntity(classOf[tileentity.Printer], Settings.namespace + "printer") GameRegistry.registerTileEntity(classOf[tileentity.Raid], Settings.namespace + "raid") GameRegistry.registerTileEntity(classOf[tileentity.Redstone], Settings.namespace + "redstone") + GameRegistry.registerTileEntity(classOf[tileentity.Relay], Settings.namespace + "relay") GameRegistry.registerTileEntity(classOf[tileentity.RobotProxy], Settings.namespace + "robot") GameRegistry.registerTileEntity(classOf[tileentity.Switch], Settings.namespace + "switch") GameRegistry.registerTileEntity(classOf[tileentity.Screen], Settings.namespace + "screen") @@ -37,7 +38,7 @@ object Blocks { GameRegistry.registerTileEntity(classOf[tileentity.NetSplitter], Settings.namespace + "netSplitter") GameRegistry.registerTileEntity(classOf[tileentity.Waypoint], Settings.namespace + "waypoint") - Recipes.addBlock(new AccessPoint(), Constants.BlockName.AccessPoint, "oc:accessPoint") + Items.registerBlock(new AccessPoint(), Constants.BlockName.AccessPoint) Recipes.addBlock(new Adapter(), Constants.BlockName.Adapter, "oc:adapter") Recipes.addBlock(new Assembler(), Constants.BlockName.Assembler, "oc:assembler") Recipes.addBlock(new Cable(), Constants.BlockName.Cable, "oc:cable") @@ -57,11 +58,12 @@ object Blocks { Recipes.addBlock(new PowerDistributor(), Constants.BlockName.PowerDistributor, "oc:powerDistributor") Recipes.addBlock(new Raid(), Constants.BlockName.Raid, "oc:raid") Recipes.addBlock(new Redstone(), Constants.BlockName.Redstone, "oc:redstone") + Recipes.addBlock(new Relay(), Constants.BlockName.Relay, "oc:relay") Recipes.addBlock(new Screen(Tier.One), Constants.BlockName.ScreenTier1, "oc:screen1") Recipes.addBlock(new Screen(Tier.Three), Constants.BlockName.ScreenTier3, "oc:screen3") Recipes.addBlock(new Screen(Tier.Two), Constants.BlockName.ScreenTier2, "oc:screen2") Recipes.addBlock(new ServerRack(), Constants.BlockName.ServerRack, "oc:serverRack") - Recipes.addBlock(new Switch(), Constants.BlockName.Switch, "oc:switch") + Items.registerBlock(new Switch(), Constants.BlockName.Switch) Items.registerBlock(new Case(Tier.Four), Constants.BlockName.CaseCreative) Items.registerBlock(new Microcontroller(), Constants.BlockName.Microcontroller) diff --git a/src/main/scala/li/cil/oc/common/recipe/Recipes.scala b/src/main/scala/li/cil/oc/common/recipe/Recipes.scala index 6bab1aba8..9e1aa47e8 100644 --- a/src/main/scala/li/cil/oc/common/recipe/Recipes.scala +++ b/src/main/scala/li/cil/oc/common/recipe/Recipes.scala @@ -316,6 +316,12 @@ object Recipes { GameRegistry.addRecipe(new ExtendedShapelessOreRecipe( lightPrint, print.createItemStack(1), new ItemStack(net.minecraft.init.Blocks.glowstone))) + + // Switch/AccessPoint -> Relay conversion + GameRegistry.addShapelessRecipe(api.Items.get(Constants.BlockName.Relay).createItemStack(1), + api.Items.get(Constants.BlockName.AccessPoint).createItemStack(1)) + GameRegistry.addShapelessRecipe(api.Items.get(Constants.BlockName.Relay).createItemStack(1), + api.Items.get(Constants.BlockName.Switch).createItemStack(1)) } catch { case e: Throwable => OpenComputers.log.error("Error parsing recipes, you may not be able to craft any items from this mod!", e) diff --git a/src/main/scala/li/cil/oc/common/tileentity/AccessPoint.scala b/src/main/scala/li/cil/oc/common/tileentity/AccessPoint.scala index 8cc3586e4..0c40bc06c 100644 --- a/src/main/scala/li/cil/oc/common/tileentity/AccessPoint.scala +++ b/src/main/scala/li/cil/oc/common/tileentity/AccessPoint.scala @@ -16,6 +16,7 @@ import net.minecraft.nbt.NBTTagCompound import net.minecraftforge.common.util.Constants.NBT import net.minecraftforge.common.util.ForgeDirection +// TODO Remove in 1.7 class AccessPoint extends Switch with WirelessEndpoint with traits.PowerAcceptor { var strength = Settings.get.maxWirelessRange @@ -25,6 +26,8 @@ class AccessPoint extends Switch with WirelessEndpoint with traits.PowerAcceptor withComponent("access_point"). create()) + override def isWirelessEnabled = true + // ----------------------------------------------------------------------- // @SideOnly(Side.CLIENT) @@ -78,7 +81,7 @@ class AccessPoint extends Switch with WirelessEndpoint with traits.PowerAcceptor override protected def relayPacket(sourceSide: Option[ForgeDirection], packet: Packet) { super.relayPacket(sourceSide, packet) - if (strength > 0 && (sourceSide != None || isRepeater)) { + if (strength > 0 && (sourceSide.isDefined || isRepeater)) { val cost = Settings.get.wirelessCostPerRange val tryChangeBuffer = sourceSide match { case Some(side) => diff --git a/src/main/scala/li/cil/oc/common/tileentity/Relay.scala b/src/main/scala/li/cil/oc/common/tileentity/Relay.scala new file mode 100644 index 000000000..81ddfeeb4 --- /dev/null +++ b/src/main/scala/li/cil/oc/common/tileentity/Relay.scala @@ -0,0 +1,282 @@ +package li.cil.oc.common.tileentity + +import com.google.common.base.Charsets +import cpw.mods.fml.relauncher.Side +import cpw.mods.fml.relauncher.SideOnly +import dan200.computercraft.api.peripheral.IComputerAccess +import li.cil.oc.Constants +import li.cil.oc.Localization +import li.cil.oc.Settings +import li.cil.oc.api +import li.cil.oc.api.Driver +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.Analyzable +import li.cil.oc.api.network.Connector +import li.cil.oc.api.network.Node +import li.cil.oc.api.network.Packet +import li.cil.oc.api.network.Visibility +import li.cil.oc.api.network.WirelessEndpoint +import li.cil.oc.common.InventorySlots +import li.cil.oc.common.Slot +import li.cil.oc.common.item +import li.cil.oc.common.item.Delegator +import li.cil.oc.integration.Mods +import li.cil.oc.integration.opencomputers.DriverLinkedCard +import li.cil.oc.server.network.QuantumNetwork +import li.cil.oc.util.ExtendedNBT._ +import net.minecraft.entity.player.EntityPlayer +import net.minecraft.item.ItemStack +import net.minecraft.nbt.NBTTagCompound +import net.minecraftforge.common.util.Constants.NBT +import net.minecraftforge.common.util.ForgeDirection + +class Relay extends traits.SwitchLike with traits.ComponentInventory with traits.PowerAcceptor with Analyzable with WirelessEndpoint with QuantumNetwork.QuantumNode { + lazy final val WirelessNetworkCard = api.Items.get(Constants.ItemName.WirelessNetworkCard) + lazy final val LinkedCard = api.Items.get(Constants.ItemName.LinkedCard) + + var strength = Settings.get.maxWirelessRange + + var isRepeater = true + + var isWirelessEnabled = false + + var isLinkedEnabled = false + + var tunnel = "creative" + + val componentNodes = Array.fill(6)(api.Network.newNode(this, Visibility.Network). + withComponent("access_point"). + create()) + + override def canUpdate = isServer + + // ----------------------------------------------------------------------- // + + @SideOnly(Side.CLIENT) + override protected def hasConnector(side: ForgeDirection) = true + + override protected def connector(side: ForgeDirection) = sidedNode(side) match { + case connector: Connector => Option(connector) + case _ => None + } + + override def energyThroughput = Settings.get.accessPointRate + + // ----------------------------------------------------------------------- // + + override def onAnalyze(player: EntityPlayer, side: Int, hitX: Float, hitY: Float, hitZ: Float): Array[Node] = { + if (isWirelessEnabled) { + player.addChatMessage(Localization.Analyzer.WirelessStrength(strength)) + Array(componentNodes(side)) + } + else null + } + + // ----------------------------------------------------------------------- // + + @Callback(direct = true, doc = """function():number -- Get the signal strength (range) used when relaying messages.""") + def getStrength(context: Context, args: Arguments): Array[AnyRef] = synchronized(result(strength)) + + @Callback(doc = """function(strength:number):number -- Set the signal strength (range) used when relaying messages.""") + def setStrength(context: Context, args: Arguments): Array[AnyRef] = synchronized { + strength = math.max(args.checkDouble(0), math.min(0, Settings.get.maxWirelessRange)) + result(strength) + } + + @Callback(direct = true, doc = """function():boolean -- Get whether the access point currently acts as a repeater (resend received wireless packets wirelessly).""") + def isRepeater(context: Context, args: Arguments): Array[AnyRef] = synchronized(result(isRepeater)) + + @Callback(doc = """function(enabled:boolean):boolean -- Set whether the access point should act as a repeater.""") + def setRepeater(context: Context, args: Arguments): Array[AnyRef] = synchronized { + isRepeater = args.checkBoolean(0) + result(isRepeater) + } + + // ----------------------------------------------------------------------- // + + protected def queueMessage(source: String, destination: String, port: Int, answerPort: Int, args: Array[AnyRef]) { + for (computer <- computers.map(_.asInstanceOf[IComputerAccess])) { + val address = s"cc${computer.getID}_${computer.getAttachmentName}" + if (source != address && Option(destination).forall(_ == address) && openPorts(computer).contains(port)) + computer.queueEvent("modem_message", Array(Seq(computer.getAttachmentName, Int.box(port), Int.box(answerPort)) ++ args.map { + case x: Array[Byte] => new String(x, Charsets.UTF_8) + case x => x + }: _*)) + } + } + + // ----------------------------------------------------------------------- // + + override def receivePacket(packet: Packet, source: WirelessEndpoint): Unit = { + if (isWirelessEnabled) { + tryEnqueuePacket(None, packet) + } + } + + override def receivePacket(packet: Packet): Unit = { + if (isLinkedEnabled) { + tryEnqueuePacket(None, packet) + } + } + + override def tryEnqueuePacket(sourceSide: Option[ForgeDirection], packet: Packet): Boolean = { + if (Mods.ComputerCraft.isAvailable) { + packet.data.headOption match { + case Some(answerPort: java.lang.Double) => queueMessage(packet.source, packet.destination, packet.port, answerPort.toInt, packet.data.drop(1)) + case _ => queueMessage(packet.source, packet.destination, packet.port, -1, packet.data) + } + } + super.tryEnqueuePacket(sourceSide, packet) + } + + override protected def relayPacket(sourceSide: Option[ForgeDirection], packet: Packet): Unit = { + super.relayPacket(sourceSide, packet) + + val tryChangeBuffer = sourceSide match { + case Some(side) => + (amount: Double) => plugs(side.ordinal).node.asInstanceOf[Connector].tryChangeBuffer(amount) + case _ => + (amount: Double) => plugs.exists(_.node.asInstanceOf[Connector].tryChangeBuffer(amount)) + } + + if (isWirelessEnabled && strength > 0 && (sourceSide.isDefined || isRepeater)) { + val cost = Settings.get.wirelessCostPerRange + if (tryChangeBuffer(-strength * cost)) { + api.Network.sendWirelessPacket(this, strength, packet) + } + } + + if (isLinkedEnabled && (sourceSide.isDefined || isRepeater)) { + val cost = packet.size / 32.0 + Settings.get.wirelessCostPerRange * Settings.get.maxWirelessRange * 5 + if (tryChangeBuffer(-cost)) { + val endpoints = QuantumNetwork.getEndpoints(tunnel).filter(_ != this) + for (endpoint <- endpoints) { + endpoint.receivePacket(packet) + } + } + } + + onSwitchActivity() + } + + // ----------------------------------------------------------------------- // + + override protected def createNode(plug: Plug) = api.Network.newNode(plug, Visibility.Network). + withConnector(math.round(Settings.get.bufferAccessPoint)). + create() + + override protected def onPlugConnect(plug: Plug, node: Node) { + super.onPlugConnect(plug, node) + if (node == plug.node) { + api.Network.joinWirelessNetwork(this) + } + if (plug.isPrimary) + plug.node.connect(componentNodes(plug.side.ordinal())) + else + componentNodes(plug.side.ordinal).remove() + } + + override protected def onPlugDisconnect(plug: Plug, node: Node) { + super.onPlugDisconnect(plug, node) + if (node == plug.node) { + api.Network.leaveWirelessNetwork(this) + } + if (plug.isPrimary && node != plug.node) + plug.node.connect(componentNodes(plug.side.ordinal())) + else + componentNodes(plug.side.ordinal).remove() + } + + // ----------------------------------------------------------------------- // + + override protected def onItemAdded(slot: Int, stack: ItemStack) { + super.onItemAdded(slot, stack) + updateLimits(slot, stack) + } + + private def updateLimits(slot: Int, stack: ItemStack) { + Option(Driver.driverFor(stack, getClass)) match { + case Some(driver) if driver.slot(stack) == Slot.CPU => + relayDelay = math.max(1, relayBaseDelay - ((driver.tier(stack) + 1) * relayDelayPerUpgrade)) + case Some(driver) if driver.slot(stack) == Slot.Memory => + relayAmount = math.max(1, relayBaseAmount + (Delegator.subItem(stack) match { + case Some(ram: item.Memory) => (ram.tier + 1) * relayAmountPerUpgrade + case _ => (driver.tier(stack) + 1) * (relayAmountPerUpgrade * 2) + })) + case Some(driver) if driver.slot(stack) == Slot.HDD => + maxQueueSize = math.max(1, queueBaseSize + (driver.tier(stack) + 1) * queueSizePerUpgrade) + case Some(driver) if driver.slot(stack) == Slot.Card => + val descriptor = api.Items.get(stack) + if (descriptor == WirelessNetworkCard) { + isWirelessEnabled = true + } + if (descriptor == LinkedCard) { + val data = DriverLinkedCard.dataTag(stack) + if (data.hasKey(Settings.namespace + "tunnel")) { + tunnel = data.getString(Settings.namespace + "tunnel") + isLinkedEnabled = true + QuantumNetwork.add(this) + } + } + case _ => // Dafuq u doin. + } + } + + override protected def onItemRemoved(slot: Int, stack: ItemStack) { + super.onItemRemoved(slot, stack) + Driver.driverFor(stack, getClass) match { + case driver if driver.slot(stack) == Slot.CPU => relayDelay = relayBaseDelay + case driver if driver.slot(stack) == Slot.Memory => relayAmount = relayBaseAmount + case driver if driver.slot(stack) == Slot.HDD => maxQueueSize = queueBaseSize + case driver if driver.slot(stack) == Slot.Card => + isWirelessEnabled = false + isLinkedEnabled = false + QuantumNetwork.remove(this) + } + } + + override def getSizeInventory = InventorySlots.relay.length + + override def isItemValidForSlot(slot: Int, stack: ItemStack) = + Option(Driver.driverFor(stack, getClass)).fold(false)(driver => { + val provided = InventorySlots.relay(slot) + val tierSatisfied = driver.slot(stack) == provided.slot && driver.tier(stack) <= provided.tier + val cardTypeSatisfied = if (provided.slot == Slot.Card) api.Items.get(stack) == WirelessNetworkCard || api.Items.get(stack) == LinkedCard else true + tierSatisfied && cardTypeSatisfied + }) + + // ----------------------------------------------------------------------- // + + override def readFromNBTForServer(nbt: NBTTagCompound) { + super.readFromNBTForServer(nbt) + for (slot <- items.indices) items(slot) collect { + case stack => updateLimits(slot, stack) + } + + if (nbt.hasKey(Settings.namespace + "strength")) { + strength = nbt.getDouble(Settings.namespace + "strength") max 0 min Settings.get.maxWirelessRange + } + if (nbt.hasKey(Settings.namespace + "isRepeater")) { + isRepeater = nbt.getBoolean(Settings.namespace + "isRepeater") + } + nbt.getTagList(Settings.namespace + "componentNodes", NBT.TAG_COMPOUND).toArray[NBTTagCompound]. + zipWithIndex.foreach { + case (tag, index) => componentNodes(index).load(tag) + } + } + + override def writeToNBTForServer(nbt: NBTTagCompound) = { + super.writeToNBTForServer(nbt) + nbt.setDouble(Settings.namespace + "strength", strength) + nbt.setBoolean(Settings.namespace + "isRepeater", isRepeater) + nbt.setNewTagList(Settings.namespace + "componentNodes", componentNodes.map { + case node: Node => + val tag = new NBTTagCompound() + node.save(tag) + tag + case _ => new NBTTagCompound() + }) + } +} diff --git a/src/main/scala/li/cil/oc/common/tileentity/Switch.scala b/src/main/scala/li/cil/oc/common/tileentity/Switch.scala index 1ee39015a..794893d9a 100644 --- a/src/main/scala/li/cil/oc/common/tileentity/Switch.scala +++ b/src/main/scala/li/cil/oc/common/tileentity/Switch.scala @@ -3,26 +3,21 @@ package li.cil.oc.common.tileentity import com.google.common.base.Charsets import dan200.computercraft.api.peripheral.IComputerAccess import li.cil.oc.api.Driver -import li.cil.oc.api.network.Message import li.cil.oc.api.network.Packet import li.cil.oc.common.InventorySlots import li.cil.oc.common.Slot import li.cil.oc.common.item import li.cil.oc.common.item.Delegator import li.cil.oc.integration.Mods -import li.cil.oc.server.PacketSender import net.minecraft.item.ItemStack import net.minecraft.nbt.NBTTagCompound import net.minecraftforge.common.util.ForgeDirection -import scala.collection.mutable +// TODO Remove in 1.7 +class Switch extends traits.SwitchLike with traits.NotAnalyzable with traits.ComponentInventory { + override def isWirelessEnabled = false -class Switch extends traits.Hub with traits.NotAnalyzable with traits.ComponentInventory { - var lastMessage = 0L - - val computers = mutable.Buffer.empty[AnyRef] - - val openPorts = mutable.Map.empty[AnyRef, mutable.Set[Int]] + override def isLinkedEnabled = false override def canUpdate = isServer @@ -41,29 +36,19 @@ class Switch extends traits.Hub with traits.NotAnalyzable with traits.ComponentI // ----------------------------------------------------------------------- // - override protected def relayPacket(sourceSide: Option[ForgeDirection], packet: Packet) { - super.relayPacket(sourceSide, packet) - val now = System.currentTimeMillis() - if (now - lastMessage >= (relayDelay - 1) * 50) { - lastMessage = now - PacketSender.sendSwitchActivity(this) - } - } - - override protected def onPlugMessage(plug: Plug, message: Message) { - super.onPlugMessage(plug, message) - if (message.name == "network.message" && Mods.ComputerCraft.isAvailable) { - message.data match { - case Array(packet: Packet) => - packet.data.headOption match { - case Some(answerPort: java.lang.Double) => - queueMessage(packet.source, packet.destination, packet.port, answerPort.toInt, packet.data.drop(1)) - case _ => - queueMessage(packet.source, packet.destination, packet.port, -1, packet.data) - } - case _ => + override def tryEnqueuePacket(sourceSide: Option[ForgeDirection], packet: Packet): Boolean = { + if (Mods.ComputerCraft.isAvailable) { + packet.data.headOption match { + case Some(answerPort: java.lang.Double) => queueMessage(packet.source, packet.destination, packet.port, answerPort.toInt, packet.data.drop(1)) + case _ => queueMessage(packet.source, packet.destination, packet.port, -1, packet.data) } } + super.tryEnqueuePacket(sourceSide, packet) + } + + override protected def relayPacket(sourceSide: Option[ForgeDirection], packet: Packet) { + super.relayPacket(sourceSide, packet) + onSwitchActivity() } // ----------------------------------------------------------------------- // diff --git a/src/main/scala/li/cil/oc/common/tileentity/traits/SwitchLike.scala b/src/main/scala/li/cil/oc/common/tileentity/traits/SwitchLike.scala new file mode 100644 index 000000000..9b14c128a --- /dev/null +++ b/src/main/scala/li/cil/oc/common/tileentity/traits/SwitchLike.scala @@ -0,0 +1,27 @@ +package li.cil.oc.common.tileentity.traits + +import li.cil.oc.server.PacketSender + +import scala.collection.mutable + +trait SwitchLike extends Hub { + def relayDelay: Int + + def isWirelessEnabled: Boolean + + def isLinkedEnabled: Boolean + + val computers = mutable.Buffer.empty[AnyRef] + + val openPorts = mutable.Map.empty[AnyRef, mutable.Set[Int]] + + var lastMessage = 0L + + def onSwitchActivity(): Unit = { + val now = System.currentTimeMillis() + if (now - lastMessage >= (relayDelay - 1) * 50) { + lastMessage = now + PacketSender.sendSwitchActivity(this) + } + } +} diff --git a/src/main/scala/li/cil/oc/integration/computercraft/PeripheralProvider.scala b/src/main/scala/li/cil/oc/integration/computercraft/PeripheralProvider.scala index b2e54e940..5f17cf9df 100644 --- a/src/main/scala/li/cil/oc/integration/computercraft/PeripheralProvider.scala +++ b/src/main/scala/li/cil/oc/integration/computercraft/PeripheralProvider.scala @@ -2,7 +2,7 @@ package li.cil.oc.integration.computercraft import dan200.computercraft.api.ComputerCraftAPI import dan200.computercraft.api.peripheral.IPeripheralProvider -import li.cil.oc.common.tileentity.Switch +import li.cil.oc.common.tileentity.traits.SwitchLike import net.minecraft.world.World object PeripheralProvider extends IPeripheralProvider { @@ -11,7 +11,7 @@ object PeripheralProvider extends IPeripheralProvider { } override def getPeripheral(world: World, x: Int, y: Int, z: Int, side: Int) = world.getTileEntity(x, y, z) match { - case switch: Switch => new SwitchPeripheral(switch) + case switch: SwitchLike => new SwitchPeripheral(switch) case _ => null } } 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 804b6bb47..234e93e4b 100644 --- a/src/main/scala/li/cil/oc/integration/computercraft/SwitchPeripheral.scala +++ b/src/main/scala/li/cil/oc/integration/computercraft/SwitchPeripheral.scala @@ -8,8 +8,7 @@ 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.common.tileentity.traits.SwitchLike import li.cil.oc.util.ResultWrapper._ import net.minecraftforge.common.util.ForgeDirection @@ -17,7 +16,7 @@ import scala.collection.convert.WrapAsJava._ import scala.collection.convert.WrapAsScala._ import scala.collection.mutable -class SwitchPeripheral(val switch: Switch) extends IPeripheral { +class SwitchPeripheral(val switch: SwitchLike) extends IPeripheral { private val methods = Map[String, (IComputerAccess, ILuaContext, Array[AnyRef]) => Array[AnyRef]]( // Generic modem methods. "open" -> ((computer, context, arguments) => { @@ -86,7 +85,10 @@ class SwitchPeripheral(val switch: Switch) extends IPeripheral { // OC specific. "isAccessPoint" -> ((computer, context, arguments) => { - result(switch.isInstanceOf[AccessPoint]) + result(switch.isWirelessEnabled) + }), + "isTunnel" -> ((computer, context, arguments) => { + result(switch.isLinkedEnabled) }), "maxPacketSize" -> ((computer, context, arguments) => { result(Settings.get.maxNetworkPacketSize) diff --git a/src/main/scala/li/cil/oc/server/PacketSender.scala b/src/main/scala/li/cil/oc/server/PacketSender.scala index df0ba86e4..406462a4a 100644 --- a/src/main/scala/li/cil/oc/server/PacketSender.scala +++ b/src/main/scala/li/cil/oc/server/PacketSender.scala @@ -392,7 +392,7 @@ object PacketSender { pb.sendToPlayersNearTileEntity(t) } - def sendSwitchActivity(t: tileentity.Switch) { + def sendSwitchActivity(t: tileentity.traits.SwitchLike) { val pb = new SimplePacketBuilder(PacketType.SwitchActivity) pb.writeTileEntity(t) diff --git a/src/main/scala/li/cil/oc/server/component/LinkedCard.scala b/src/main/scala/li/cil/oc/server/component/LinkedCard.scala index be88a0bc4..62fadcb94 100644 --- a/src/main/scala/li/cil/oc/server/component/LinkedCard.scala +++ b/src/main/scala/li/cil/oc/server/component/LinkedCard.scala @@ -12,7 +12,7 @@ import net.minecraft.nbt.NBTTagCompound import scala.collection.convert.WrapAsScala._ -class LinkedCard extends prefab.ManagedEnvironment { +class LinkedCard extends prefab.ManagedEnvironment with QuantumNetwork.QuantumNode { override val node = Network.newNode(this, Visibility.Network). withComponent("tunnel", Visibility.Neighbors). withConnector(). @@ -28,8 +28,8 @@ class LinkedCard extends prefab.ManagedEnvironment { // Cast to iterable to use Scala's toArray instead of the Arguments' one (which converts byte arrays to Strings). val packet = Network.newPacket(node.address, null, 0, args.asInstanceOf[java.lang.Iterable[AnyRef]].toArray) if (node.tryChangeBuffer(-(packet.size / 32.0 + Settings.get.wirelessCostPerRange * Settings.get.maxWirelessRange * 5))) { - for (card <- endpoints) { - card.receivePacket(packet) + for (endpoint <- endpoints) { + endpoint.receivePacket(packet) } result(true) } diff --git a/src/main/scala/li/cil/oc/server/network/QuantumNetwork.scala b/src/main/scala/li/cil/oc/server/network/QuantumNetwork.scala index ce56d5f01..ca6284836 100644 --- a/src/main/scala/li/cil/oc/server/network/QuantumNetwork.scala +++ b/src/main/scala/li/cil/oc/server/network/QuantumNetwork.scala @@ -1,20 +1,27 @@ package li.cil.oc.server.network -import li.cil.oc.server.component.LinkedCard +import li.cil.oc.api.network.Packet import scala.collection.mutable // Just because the name if so fancy! object QuantumNetwork { - val tunnels = mutable.Map.empty[String, mutable.WeakHashMap[LinkedCard, Unit]] + val tunnels = mutable.Map.empty[String, mutable.WeakHashMap[QuantumNode, Unit]] - def add(card: LinkedCard) { + def add(card: QuantumNode) { tunnels.getOrElseUpdate(card.tunnel, mutable.WeakHashMap.empty).put(card, Unit) } - def remove(card: LinkedCard) { + def remove(card: QuantumNode) { tunnels.get(card.tunnel).foreach(_.remove(card)) } - def getEndpoints(tunnel: String) = tunnels.get(tunnel).fold(Iterable.empty[LinkedCard])(_.keys) + def getEndpoints(tunnel: String) = tunnels.get(tunnel).fold(Iterable.empty[QuantumNode])(_.keys) + + trait QuantumNode { + def tunnel: String + + def receivePacket(packet: Packet): Unit + } + } From 4644bf8541fe1617f340a2e4965826a0d584fb44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Sun, 23 Aug 2015 22:05:48 +0200 Subject: [PATCH 13/30] Change component name of relay to relay; never act as repeater for tunnel messages. --- src/main/scala/li/cil/oc/OpenComputers.scala | 2 +- src/main/scala/li/cil/oc/common/tileentity/Relay.scala | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/scala/li/cil/oc/OpenComputers.scala b/src/main/scala/li/cil/oc/OpenComputers.scala index 4f6aae03e..2749f0993 100644 --- a/src/main/scala/li/cil/oc/OpenComputers.scala +++ b/src/main/scala/li/cil/oc/OpenComputers.scala @@ -19,7 +19,7 @@ object OpenComputers { final val Name = "OpenComputers" - final val Version = "@VERSION@" + final val Version = "1.5.16" var log = LogManager.getLogger(Name) diff --git a/src/main/scala/li/cil/oc/common/tileentity/Relay.scala b/src/main/scala/li/cil/oc/common/tileentity/Relay.scala index 81ddfeeb4..b10b10d3e 100644 --- a/src/main/scala/li/cil/oc/common/tileentity/Relay.scala +++ b/src/main/scala/li/cil/oc/common/tileentity/Relay.scala @@ -47,7 +47,7 @@ class Relay extends traits.SwitchLike with traits.ComponentInventory with traits var tunnel = "creative" val componentNodes = Array.fill(6)(api.Network.newNode(this, Visibility.Network). - withComponent("access_point"). + withComponent("relay"). create()) override def canUpdate = isServer @@ -148,7 +148,7 @@ class Relay extends traits.SwitchLike with traits.ComponentInventory with traits } } - if (isLinkedEnabled && (sourceSide.isDefined || isRepeater)) { + if (isLinkedEnabled && sourceSide.isDefined) { val cost = packet.size / 32.0 + Settings.get.wirelessCostPerRange * Settings.get.maxWirelessRange * 5 if (tryChangeBuffer(-cost)) { val endpoints = QuantumNetwork.getEndpoints(tunnel).filter(_ != this) From f0f31f9fa9e4e4d683e2476712073cb92f4279c9 Mon Sep 17 00:00:00 2001 From: Kodos Atoz Date: Sun, 23 Aug 2015 16:28:06 -0500 Subject: [PATCH 14/30] Update greetings.txt Updated 'Switches' to Relays, fixed a misspelling. --- .../assets/opencomputers/loot/OpenOS/usr/misc/greetings.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/resources/assets/opencomputers/loot/OpenOS/usr/misc/greetings.txt b/src/main/resources/assets/opencomputers/loot/OpenOS/usr/misc/greetings.txt index 041959f85..68d49726b 100644 --- a/src/main/resources/assets/opencomputers/loot/OpenOS/usr/misc/greetings.txt +++ b/src/main/resources/assets/opencomputers/loot/OpenOS/usr/misc/greetings.txt @@ -12,7 +12,7 @@ Most programs can be interrupted by pressing Ctrl+Alt+C. Paste the contents of the clipboard using the middle mouse button or a configurable key (default: insert). Computers will consume less power while idling - i.e. when os.sleep(n > 0.05) is called. Screens will consume more power the more lit characters they display. -Most blocks act as 'cables' - use switches and power distributers to create separate networks. +Most blocks act as 'cables' - use relays and power distributors to create separate networks. Welcome to the dark side - here, have some cookies. Screens can display Unicode - paste the special chars or use unicode.char. Run `help` or `man programname` for ingame help on programs shipped with OpenOS - start with `man man`. @@ -25,4 +25,4 @@ Have you tried turning it off and on again? To disable this greeting, install OpenOS to a writeable medium and delete `/etc/motd`. Did you know OpenComputers has a forum? No? Well, it's at http://oc.cil.li/. Please report bugs on the Github issue tracker, thank you! -Beware of cycles when building networks, or you may get duplicate messages! \ No newline at end of file +Beware of cycles when building networks, or you may get duplicate messages! From fdf5e334100dd5a61179dea76739a723ed549042 Mon Sep 17 00:00:00 2001 From: cyber01 Date: Mon, 24 Aug 2015 14:44:07 +0400 Subject: [PATCH 15/30] Added Relay Correction Correction2 --- .../opencomputers/doc/ru_RU/block/accessPoint.md | 2 ++ .../assets/opencomputers/doc/ru_RU/block/index.md | 1 + .../opencomputers/doc/ru_RU/block/netSplitter.md | 2 +- .../assets/opencomputers/doc/ru_RU/block/relay.md | 13 +++++++++++++ .../opencomputers/doc/ru_RU/block/serverRack.md | 2 +- .../assets/opencomputers/doc/ru_RU/block/switch.md | 2 ++ .../assets/opencomputers/doc/ru_RU/item/lanCard.md | 2 +- .../resources/assets/opencomputers/lang/ru_RU.lang | 6 ++++-- 8 files changed, 25 insertions(+), 5 deletions(-) create mode 100644 src/main/resources/assets/opencomputers/doc/ru_RU/block/relay.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 744abec69..faa4a62bf 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 @@ -2,6 +2,8 @@ ![AAA](oredict:oc:accessPoint) +*Đ­Ń‚ĐŸŃ‚ Đ±Đ»ĐŸĐș ŃƒŃŃ‚Đ°Ń€Đ”Đ» Đž Đ±ŃƒĐŽĐ”Ń‚ ŃƒĐŽĐ°Đ»Đ”Đœ ĐČ ŃĐ»Đ”ĐŽŃƒŃŽŃ‰ĐžŃ… ĐČĐ”Ń€ŃĐžŃŃ….* Đ—Đ°ĐŒĐ”ĐœĐžŃ‚Đ” Đ”ĐłĐŸ ĐœĐ° [Ń€Đ”Ń‚Ń€Đ°ĐœŃĐ»ŃŃ‚ĐŸŃ€](relay.md). + ĐąĐŸŃ‡ĐșĐž ĐŽĐŸŃŃ‚ŃƒĐżĐ°, ŃŃ‚ĐŸ Đ±Đ”ŃĐżŃ€ĐŸĐČĐŸĐŽĐœŃ‹Đ” ĐČДрсОО [ĐșĐŸĐŒĐŒŃƒŃ‚Đ°Ń‚ĐŸŃ€ĐŸĐČ](switch.md). ĐžĐœĐž ĐŒĐŸĐłŃƒŃ‚ Đ±Ń‹Ń‚ŃŒ ĐžŃĐżĐŸĐ»ŃŒĐ·ĐŸĐČĐ°ĐœŃ‹, ĐșĐŸĐłĐŽĐ° Ń‚Ń€Đ”Đ±ŃƒĐ”Ń‚ŃŃ Ń€Đ°Đ·ĐŽĐ”Đ»ĐžŃ‚ŃŒ ĐżĐŸĐŽŃĐ”Ń‚Đž, Ń‡Ń‚ĐŸĐ±Ń‹ ŃƒŃŃ‚Ń€ĐŸĐčстĐČа ĐœĐ” ĐČОЎДлО [ĐșĐŸĐŒĐżĐŸĐœĐ”ĐœŃ‚Ń‹](../general/computer.md) ĐČ ĐŽŃ€ŃƒĐłĐžŃ… ŃĐ”Ń‚ŃŃ…, ĐŸĐŽĐœĐ°ĐșĐŸ ŃĐŸŃ…Ń€Đ°ĐœŃŃ про ŃŃ‚ĐŸĐŒ ĐČĐŸĐ·ĐŒĐŸĐ¶ĐœĐŸŃŃ‚ŃŒ пДрДЎачО ŃĐŸĐŸĐ±Ń‰Đ”ĐœĐžĐč ĐŒĐ”Đ¶ĐŽŃƒ ĐżĐŸĐŽŃĐ”Ń‚ŃĐŒĐž. В ĐŽĐŸĐżĐŸĐ»ĐœĐ”ĐœĐžĐ” Đș ŃŃ‚ĐŸĐŒŃƒ, Ń‚ĐŸŃ‡ĐșĐž ĐŽĐŸŃŃ‚ŃƒĐżĐ° ĐŒĐŸĐłŃƒŃ‚ ĐžŃĐżĐŸĐ»ŃŒĐ·ĐŸĐČаться ĐșаĐș ĐżĐŸĐČŃ‚ĐŸŃ€ĐžŃ‚Đ”Đ»Đž: ĐŸĐœĐž ĐŒĐŸĐłŃƒŃ‚ ĐżĐ”Ń€Đ”ĐœĐ°ĐżŃ€Đ°ĐČĐ»ŃŃ‚ŃŒ ŃĐŸĐŸĐ±Ń‰Đ”ĐœĐžŃ Оз ĐżŃ€ĐŸĐČĐŸĐŽĐœĐŸĐč Đ»ĐžĐœĐžĐž ĐŽŃ€ŃƒĐłĐžĐŒ ŃƒŃŃ‚Ń€ĐŸĐčстĐČĐ°ĐŒ; ОлО Đ±Đ”ŃĐżŃ€ĐŸĐČĐŸĐŽĐœŃ‹Đ” ŃĐŸĐŸĐ±Ń‰Đ”ĐœĐžŃ ĐșаĐș ĐżŃ€ĐŸĐČĐŸĐŽĐœŃ‹Đ”, таĐș Đž Đ±Đ”ŃĐżŃ€ĐŸĐČĐŸĐŽĐœŃ‹Đ”. diff --git a/src/main/resources/assets/opencomputers/doc/ru_RU/block/index.md b/src/main/resources/assets/opencomputers/doc/ru_RU/block/index.md index a1e604531..ce0ebf1d9 100644 --- a/src/main/resources/assets/opencomputers/doc/ru_RU/block/index.md +++ b/src/main/resources/assets/opencomputers/doc/ru_RU/block/index.md @@ -39,6 +39,7 @@ * [ĐąĐŸŃ‡Đșа ĐŽĐŸŃŃ‚ŃƒĐżĐ°](accessPoint.md) * [ĐšĐ°Đ±Đ”Đ»ŃŒ](cable.md) * [ХДтДĐČĐŸĐč пДрДĐșĐ»ŃŽŃ‡Đ°Ń‚Đ”Đ»ŃŒ](netSplitter.md) +* [Đ Đ”Ń‚Ń€Đ°ĐœŃĐ»ŃŃ‚ĐŸŃ€](relay.md) * [ĐšĐŸĐŒĐŒŃƒŃ‚Đ°Ń‚ĐŸŃ€](switch.md) ## УпраĐČĐ»Đ”ĐœĐžĐ” ĐżĐžŃ‚Đ°ĐœĐžĐ”ĐŒ diff --git a/src/main/resources/assets/opencomputers/doc/ru_RU/block/netSplitter.md b/src/main/resources/assets/opencomputers/doc/ru_RU/block/netSplitter.md index 37e4bc296..e3725dcb5 100644 --- a/src/main/resources/assets/opencomputers/doc/ru_RU/block/netSplitter.md +++ b/src/main/resources/assets/opencomputers/doc/ru_RU/block/netSplitter.md @@ -2,6 +2,6 @@ ![*.net *.split](oredict:oc:netSplitter) -ХДтДĐČĐŸĐč пДрДĐșĐ»ŃŽŃ‡Đ°Ń‚Đ”Đ»ŃŒ ĐżĐŸĐ·ĐČĐŸĐ»ŃĐ”Ń‚ ĐșĐŸĐœŃ‚Ń€ĐŸĐ»ĐžŃ€ĐŸĐČать ŃĐŸĐ”ĐŽĐžĐœĐ”ĐœĐžĐ” ĐŒĐ”Đ¶ĐŽŃƒ ĐżĐŸĐŽŃĐ”Ń‚ŃĐŒĐž. В ĐŸŃ‚Đ»ĐžŃ‡ĐžĐ” ĐŸŃ‚ [ĐșĐŸĐŒĐŒŃƒŃ‚Đ°Ń‚ĐŸŃ€Đ°](switch.md) ОлО [ĐșĐŸĐœĐČДртДра ŃĐœĐ”Ń€ĐłĐžĐž](powerConverter.md) ĐżĐŸĐ·ĐČĐŸĐ»ŃĐ”Ń‚ ĐœĐ”ĐżĐŸŃŃ€Đ”ĐŽŃŃ‚ĐČĐ”ĐœĐœĐŸ ŃĐŸĐ”ĐŽĐžĐœĐžŃ‚ŃŒ ĐżĐŸĐŽŃĐ”Ń‚Đž, ĐŽĐ”Đ»Đ°Ń про ŃŃ‚ĐŸĐŒ ĐŽĐŸŃŃ‚ŃƒĐżĐœŃ‹ĐŒĐž ĐČсД ĐșĐŸĐŒĐżĐŸĐœĐ”ĐœŃ‚Ń‹. ĐĄĐŸĐ”ĐŽĐžĐœĐ”ĐœĐžĐ” ĐșĐ°Đ¶ĐŽĐŸĐč ŃŃ‚ĐŸŃ€ĐŸĐœŃ‹ пДрДĐșĐ»ŃŽŃ‡Đ°Đ”Ń‚ŃŃ [ĐșĐ»ŃŽŃ‡Đ”ĐŒ](../item/wrench.md). Про ĐżĐŸĐŽĐ°Ń‡Đ” Ń€Đ”ĐŽŃŃ‚ĐŸŃƒĐœ-ŃĐžĐłĐœĐ°Đ»Đ° ĐČсД ŃĐŸĐ”ĐŽĐžĐœĐ”ĐœĐžŃ ĐžĐœĐČĐ”Ń€Ń‚ĐžŃ€ŃƒŃŽŃ‚ŃŃ. +ХДтДĐČĐŸĐč пДрДĐșĐ»ŃŽŃ‡Đ°Ń‚Đ”Đ»ŃŒ ĐżĐŸĐ·ĐČĐŸĐ»ŃĐ”Ń‚ ĐșĐŸĐœŃ‚Ń€ĐŸĐ»ĐžŃ€ĐŸĐČать ŃĐŸĐ”ĐŽĐžĐœĐ”ĐœĐžĐ” ĐŒĐ”Đ¶ĐŽŃƒ ĐżĐŸĐŽŃĐ”Ń‚ŃĐŒĐž. В ĐŸŃ‚Đ»ĐžŃ‡ĐžĐ” ĐŸŃ‚ [Ń€Đ”Ń‚Ń€Đ°ĐœŃĐ»ŃŃ‚ĐŸŃ€Đ°](relay.md) ОлО [ĐșĐŸĐœĐČДртДра ŃĐœĐ”Ń€ĐłĐžĐž](powerConverter.md) ĐżĐŸĐ·ĐČĐŸĐ»ŃĐ”Ń‚ ĐœĐ”ĐżĐŸŃŃ€Đ”ĐŽŃŃ‚ĐČĐ”ĐœĐœĐŸ ŃĐŸĐ”ĐŽĐžĐœĐžŃ‚ŃŒ ĐżĐŸĐŽŃĐ”Ń‚Đž, ĐŽĐ”Đ»Đ°Ń про ŃŃ‚ĐŸĐŒ ĐŽĐŸŃŃ‚ŃƒĐżĐœŃ‹ĐŒĐž ĐČсД ĐșĐŸĐŒĐżĐŸĐœĐ”ĐœŃ‚Ń‹. ĐĄĐŸĐ”ĐŽĐžĐœĐ”ĐœĐžĐ” ĐșĐ°Đ¶ĐŽĐŸĐč ŃŃ‚ĐŸŃ€ĐŸĐœŃ‹ пДрДĐșĐ»ŃŽŃ‡Đ°Đ”Ń‚ŃŃ [ĐșĐ»ŃŽŃ‡Đ”ĐŒ](../item/wrench.md). Про ĐżĐŸĐŽĐ°Ń‡Đ” Ń€Đ”ĐŽŃŃ‚ĐŸŃƒĐœ-ŃĐžĐłĐœĐ°Đ»Đ° ĐČсД ŃĐŸĐ”ĐŽĐžĐœĐ”ĐœĐžŃ ĐžĐœĐČĐ”Ń€Ń‚ĐžŃ€ŃƒŃŽŃ‚ŃŃ. йаĐșĐžĐŒ ĐŸĐ±Ń€Đ°Đ·ĐŸĐŒ, ŃŃ‚ĐŸŃ‚ Đ±Đ»ĐŸĐș ĐŒĐŸĐ¶Đ”Ń‚ Đ±Ń‹Ń‚ŃŒ ĐžŃĐżĐŸĐ»ŃŒĐ·ĐŸĐČĐ°Đœ ĐŽĐ»Ń пДрДĐșĐ»ŃŽŃ‡Đ”ĐœĐžŃ ŃĐŸĐ”ĐŽĐžĐœĐ”ĐœĐžŃ ĐŸĐżŃ€Đ”ĐŽĐ”Đ»Đ”ĐœĐœŃ‹Ń… ĐșĐŸĐŒĐżĐŸĐœĐ”ĐœŃ‚ĐŸĐČ ŃĐ”Ń‚Đž. Đ˜ŃĐżĐŸĐ»ŃŒĐ·ŃƒĐčтД [Ń€Đ”ĐŽŃŃ‚ĐŸŃƒĐœ-I/O](redstone.md) ОлО [Ń€Đ”ĐŽŃŃ‚ĐŸŃƒĐœ Đșарты](../item/redstoneCard1.md) ĐŽĐ»Ń аĐČŃ‚ĐŸĐŒĐ°Ń‚ĐžĐ·Đ°Ń†ĐžĐž сДтДĐČĐŸĐłĐŸ пДрДĐșĐ»ŃŽŃ‡Đ°Ń‚Đ”Đ»Ń. \ No newline at end of file diff --git a/src/main/resources/assets/opencomputers/doc/ru_RU/block/relay.md b/src/main/resources/assets/opencomputers/doc/ru_RU/block/relay.md new file mode 100644 index 000000000..64caecb9f --- /dev/null +++ b/src/main/resources/assets/opencomputers/doc/ru_RU/block/relay.md @@ -0,0 +1,13 @@ +# Đ Đ”Ń‚Ń€Đ°ĐœŃĐ»ŃŃ‚ĐŸŃ€ + +![ĐĄŃ‚Ń€ĐŸĐžŃ‚ ĐŒĐŸŃŃ‚Ń‹.](oredict:oc:relay) + +Đ Đ”Ń‚Ń€Đ°ĐœŃĐ»ŃŃ‚ĐŸŃ€ ĐžŃĐżĐŸĐ»ŃŒĐ·ŃƒĐ”Ń‚ŃŃ ĐŽĐ»Ń пДрДЎачО ŃĐŸĐŸĐ±Ń‰Đ”ĐœĐžĐč ĐŒĐ”Đ¶ĐŽŃƒ ĐœĐ”ŃĐșĐŸĐ»ŃŒĐșĐžĐŒĐž ĐżĐŸĐŽŃĐ”Ń‚ŃĐŒĐž, ĐžĐ·ĐŸĐ»ĐžŃ€ŃƒŃ ĐșĐŸĐŒĐżĐŸĐœĐ”ĐœŃ‚Ń‹ [ĐșĐŸĐŒĐżŃŒŃŽŃ‚Đ”Ń€ĐŸĐČ](../general/computer.md) ĐČ ĐŽŃ€ŃƒĐłĐžŃ… ŃĐ”Ń‚ŃŃ…. ĐĄĐŸŃ…Ń€Đ°ĐœĐ”ĐœĐžĐ” ĐșĐŸĐŒĐżĐŸĐœĐ”ĐœŃ‚ĐŸĐČ, ĐșаĐș праĐČĐžĐ»ĐŸ, Ń…ĐŸŃ€ĐŸŃˆĐ°Ń ĐžĐŽĐ”Ń, Ń‡Ń‚ĐŸ ĐœĐ” ĐżĐŸĐ·ĐČĐŸĐ»ŃĐ”Ń‚ [ĐșĐŸĐŒĐżŃŒŃŽŃ‚Đ”Ń€Đ°ĐŒ](../general/computer.md) ĐžŃĐżĐŸĐ»ŃŒĐ·ĐŸĐČать ĐœĐ”ĐČĐ”Ń€ĐœŃ‹Đč [ĐŒĐŸĐœĐžŃ‚ĐŸŃ€](screen1.md) ОлО ĐœĐ” ĐżĐŸĐ·ĐČĐŸĐ»ŃĐ”Ń‚ ĐżĐ”Ń€Đ”ĐœĐ°ĐłŃ€ŃƒĐ¶Đ°Ń‚ŃŒ ох (ĐČ Ń€Đ”Đ·ŃƒĐ»ŃŒŃ‚Đ°Ń‚Đ” Ń‡Đ”ĐłĐŸ [ĐșĐŸĐŒĐżŃŒŃŽŃ‚Đ”Ń€Ń‹](../general/computer.md) ĐČыĐșĐ»ŃŽŃ‡Đ°Ń‚ŃŃ Đž ĐŸŃ‚ĐșазыĐČаются Đ·Đ°ĐłŃ€ŃƒĐ¶Đ°Ń‚ŃŒŃŃ). + +ĐœĐŸĐ¶Đ”Ń‚ Đ±Ń‹Ń‚ŃŒ ŃƒĐ»ŃƒŃ‡ŃˆĐ”Đœ ĐŽĐŸĐ±Đ°ĐČĐ»Đ”ĐœĐžĐ”ĐŒ [Đ±Đ”ŃĐżŃ€ĐŸĐČĐŸĐŽĐœĐŸĐč сДтДĐČĐŸĐč Đșарты](../item/wlanCard.md), Ń‡Ń‚ĐŸ ĐżĐŸĐ·ĐČĐŸĐ»ĐžŃ‚ Ń€Đ”Ń‚Ń€Đ°ĐœŃĐ»ĐžŃ€ĐŸĐČать Đ±Đ”ŃĐżŃ€ĐŸĐČĐŸĐŽĐœŃ‹Đ” ŃĐŸĐŸĐ±Ń‰Đ”ĐœĐžŃ. ĐĄĐŸĐŸĐ±Ń‰Đ”ĐœĐžŃ, ĐżĐ”Ń€Đ”ĐŽĐ°ĐœĐœŃ‹Đ” ĐżĐŸ Đ±Đ”ŃĐżŃ€ĐŸĐČĐŸĐŽĐœĐŸĐč Đ»ĐžĐœĐžĐž ĐŒĐŸĐłŃƒŃ‚ Đ±Ń‹Ń‚ŃŒ ĐżĐŸĐ»ŃƒŃ‡Đ”ĐœŃ‹ ОлО ĐżĐ”Ń€Đ”ĐœĐ°ĐżŃ€Đ°ĐČĐ»Đ”ĐœŃ‹ ĐŽŃ€ŃƒĐłĐžĐŒĐž Ń€Đ”Ń‚Ń€Đ°ĐœŃĐ»ŃŃ‚ĐŸŃ€Đ°ĐŒĐž ОлО [ĐșĐŸĐŒĐżŃŒŃŽŃ‚Đ”Ń€Đ°ĐŒĐž](../general/computer.md) с [Đ±Đ”ŃĐżŃ€ĐŸĐČĐŸĐŽĐœĐŸĐč сДтДĐČĐŸĐč ĐșĐ°Ń€Ń‚ĐŸĐč](../item/wlanCard.md). + +йаĐșжД Ń€Đ”Ń‚Ń€Đ°ĐœŃĐ»ŃŃ‚ĐŸŃ€ ĐŒĐŸĐ¶Đ”Ń‚ Đ±Ń‹Ń‚ŃŒ ŃƒĐ»ŃƒŃ‡ŃˆĐ”Đœ с ĐżĐŸĐŒĐŸŃ‰ŃŒŃŽ [ŃĐŸĐ”ĐŽĐžĐœĐ”ĐœĐœĐŸĐč Đșарты](../item/linkedCard.md). Đ­Ń‚ĐŸ ĐżĐŸĐ·ĐČĐŸĐ»ĐžŃ‚ пДрДЎаĐČать ŃĐŸĐŸĐ±Ń‰Đ”ĐœĐžŃ ĐČĐœŃƒŃ‚Ń€Đž Ń‚ŃƒĐœĐœĐ”Đ»Ń, ĐżŃ€Đ”ĐŽĐŸŃŃ‚Đ°ĐČĐ»Đ”ĐœĐœĐŸĐłĐŸ ĐșĐ°Ń€Ń‚ĐŸĐč, таĐșжД; с ĐŸĐ±Ń‹Ń‡ĐœŃ‹ĐŒĐž Đ·Đ°Ń‚Ń€Đ°Ń‚Đ°ĐŒĐž ŃĐœĐ”Ń€ĐłĐžĐž, ĐżĐŸŃŃ‚ĐŸĐŒŃƒ ŃƒĐ±Đ”ĐŽĐžŃ‚Đ”ŃŃŒ, Ń‡Ń‚ĐŸ ĐœĐ° Ń€Đ”Ń‚Ń€Đ°ĐœŃĐ»ŃŃ‚ĐŸŃ€ ĐżĐŸŃŃ‚ŃƒĐżĐ°Đ”Ń‚ ĐœŃƒĐ¶ĐœĐŸĐ” ĐșĐŸĐ»ĐžŃ‡Đ”ŃŃ‚ĐČĐŸ ŃĐœĐ”Ń€ĐłĐžĐž. + +Đ Đ”Ń‚Ń€Đ°ĐœŃĐ»ŃŃ‚ĐŸŃ€Ń‹ *ĐœĐ”* ĐŸŃ‚ŃĐ»Đ”Đ¶ĐžĐČают, ĐșаĐșОД паĐșДты Đž ĐșуЎа ĐŸĐœĐž пДрДЎалО, ĐżĐŸŃŃ‚ĐŸĐŒŃƒ ĐŽĐ»Ń ĐČ ŃĐ”Ń‚Đž ĐŒĐŸĐłŃƒŃ‚ ĐŸĐ±Ń€Đ°Đ·ĐŸĐČыĐČаться пДтлО ОлО ĐČы ĐŒĐŸĐ¶Đ”Ń‚Đ” ĐżĐŸĐ»ŃƒŃ‡Đ°Ń‚ŃŒ ĐŸĐŽĐœĐŸ ŃĐŸĐŸĐ±Ń‰Đ”ĐœĐžĐ” ĐœĐ”ŃĐșĐŸĐ»ŃŒĐșĐŸ раз. Из-за ĐŸĐłŃ€Đ°ĐœĐžŃ‡Đ”ĐœĐœĐŸĐłĐŸ Đ±ŃƒŃ„Đ”Ń€Đ° ŃĐŸĐŸĐ±Ń‰Đ”ĐœĐžĐč ĐșĐŸĐŒĐŒŃƒŃ‚Đ°Ń‚ĐŸŃ€Đ°, Ń‡Đ°ŃŃ‚ĐŸĐ” ĐŸŃ‚ĐżŃ€Đ°ĐČĐ»Đ”ĐœĐžĐ” ŃĐŸĐŸĐ±Ń‰Đ”ĐœĐžĐč проĐČĐŸĐŽĐžŃ‚ Đș ох ĐżĐŸŃ‚Đ”Ń€Đ”. Вы ĐŒĐŸĐ¶Đ”Ń‚Đ” ŃƒĐ»ŃƒŃ‡ŃˆĐžŃ‚ŃŒ Ń€Đ”Ń‚Ń€Đ°ĐœŃĐ»ŃŃ‚ĐŸŃ€ ĐŽĐ»Ń уĐČĐ”Đ»ĐžŃ‡Đ”ĐœĐžŃ сĐșĐŸŃ€ĐŸŃŃ‚Đž ĐŸĐ±Ń€Đ°Đ±ĐŸŃ‚ĐșĐž ŃĐŸĐŸĐ±Ń‰Đ”ĐœĐžĐč, а таĐșжД уĐČĐ”Đ»ĐžŃ‡Đ”ĐœĐžŃ Ń€Đ°Đ·ĐŒĐ”Ń€Đ° ŃĐŸĐŸĐ±Ń‰Đ”ĐœĐžĐč. + +ĐĄĐŸĐŸĐ±Ń‰Đ”ĐœĐžŃ, ĐŒĐŸĐłŃƒŃ‚ ĐżĐ”Ń€Đ”ĐœĐ°ĐżŃ€Đ°ĐČĐ»Đ”ĐœŃ‹ ĐČŃĐ”ĐłĐŸ ĐœĐ”ŃĐșĐŸĐ»ŃŒĐșĐŸ раз, ĐżĐŸŃŃ‚ĐŸĐŒŃƒ Ń†Đ”ĐżĐŸŃ‡ĐșĐž с ĐżŃ€ĐŸĐžĐ·ĐČĐŸĐ»ŃŒĐœŃ‹ĐŒ ĐșĐŸĐ»ĐžŃ‡Đ”ŃŃ‚ĐČĐŸĐŒ Ń€Đ”Ń‚Ń€Đ°ĐœŃĐ»ŃŃ‚ĐŸŃ€ĐŸĐČ ĐœĐ”ĐČĐŸĐ·ĐŒĐŸĐ¶ĐœŃ‹. ĐŸĐŸ ŃƒĐŒĐŸĐ»Ń‡Đ°ĐœĐžŃŽ, ŃĐŸĐŸĐ±Ń‰Đ”ĐœĐžĐ” ĐŒĐŸĐ¶Đ”Ń‚ Đ±Ń‹Ń‚ŃŒ ĐżĐ”Ń€Đ”ĐœĐ°ĐżŃ€Đ°ĐČĐ»Đ”ĐœĐŸ пять раз. \ No newline at end of file diff --git a/src/main/resources/assets/opencomputers/doc/ru_RU/block/serverRack.md b/src/main/resources/assets/opencomputers/doc/ru_RU/block/serverRack.md index 4a5af4ef2..850d739ed 100644 --- a/src/main/resources/assets/opencomputers/doc/ru_RU/block/serverRack.md +++ b/src/main/resources/assets/opencomputers/doc/ru_RU/block/serverRack.md @@ -6,4 +6,4 @@ КажЎыĐč [сДрĐČДр](../item/server1.md) ĐČ ŃĐ”Ń€ĐČĐ”Ń€ĐœĐŸĐč ŃŃ‚ĐŸĐčĐșĐ” ĐŒĐŸĐ¶Đ”Ń‚ ĐČĐ·Đ°ĐžĐŒĐŸĐŽĐ”ĐčстĐČĐŸĐČать Ń‚ĐŸĐ»ŃŒĐșĐŸ с ĐŸĐŽĐœĐŸĐč "ŃŃ‚ĐŸŃ€ĐŸĐœĐŸĐč" ŃŃ‚ĐŸĐčĐșĐž ОлО ĐœĐž с ĐșаĐșĐŸĐč. К ĐșаĐșĐŸĐč ŃŃ‚ĐŸŃ€ĐŸĐœĐ”, ĐșаĐșĐŸĐč [сДрĐČДр](../item/server1.md) ĐżĐŸĐŽĐșĐ»ŃŽŃ‡Đ”Đœ, ĐœĐ°ŃŃ‚Ń€Đ°ĐžĐČĐ°Đ”Ń‚ŃŃ ĐČ ĐžĐœŃ‚Đ”Ń€Ń„Đ”ĐčсД ŃŃ‚ĐŸĐčĐșĐž. Đ‘ŃƒĐŽŃŒŃ‚Đ” ĐČĐœĐžĐŒĐ°Ń‚Đ”Đ»ŃŒĐœŃ‹, ŃŃ‚ĐŸŃ€ĐŸĐœŃ‹ счотаются ĐŸŃ‚ĐœĐŸŃĐžŃ‚Đ”Đ»ŃŒĐœĐŸ ŃĐ°ĐŒĐŸĐč ŃŃ‚ĐŸĐčĐșĐž, ĐœĐ°ĐżŃ€ĐžĐŒĐ”Ń€, ДслО ĐČы ŃĐŒĐŸŃ‚Ń€ĐžŃ‚Đ” ĐœĐ° ŃŃ‚ĐŸĐčĐșу спДрДЎО, Ń‚ĐŸ `праĐČая ŃŃ‚ĐŸŃ€ĐŸĐœĐ°` ŃŃ‚ĐŸĐčĐșĐž ĐŽĐ»Ń ĐČас Đ±ŃƒĐŽĐ”Ń‚ слДĐČа. -ХДрĐČĐ”Ń€ĐœŃ‹Đ” ŃŃ‚ĐŸĐčĐșĐž ĐČĐ·Đ°ĐžĐŒĐŸĐŽĐ”ĐčстĐČуют с [ĐșĐŸĐŒĐŒŃƒŃ‚Đ°Ń‚ĐŸŃ€Đ°ĐŒĐž](switch.md) Đž [Ń€Đ°ŃĐżŃ€Đ”ĐŽĐ”Đ»ĐžŃ‚Đ”Đ»ŃĐŒĐž ŃĐœĐ”Ń€ĐłĐžĐž](powerDistributor.md). ĐŸĐ”Ń€Đ”ĐșĐ»ŃŽŃ‡Đ°Ń‚Đ”Đ»ŃŒ Ń€Đ”Đ¶ĐžĐŒĐŸĐČ Ń€Đ°Đ±ĐŸŃ‚Ń‹ ŃŃ‚ĐŸĐčĐșĐž, ĐŒĐŸĐ¶Đ”Ń‚ Đ±Ń‹Ń‚ŃŒ ĐœĐ°ŃŃ‚Ń€ĐŸĐ”Đœ ĐČ ĐžĐœŃ‚Đ”Ń€Ń„Đ”ĐčсД ŃĐ°ĐŒĐŸĐč ŃŃ‚ĐŸĐčĐșĐž, ĐŸĐœ ĐžĐŒĐ”Đ”Ń‚ 2 Ń€Đ”Đ¶ĐžĐŒĐ°: ĐČĐœĐ”ŃˆĐœĐžĐč Đž ĐČĐœŃƒŃ‚Ń€Đ”ĐœĐœĐžĐč. Đ’ĐŸ ĐČĐœĐ”ŃˆĐœĐ”ĐŒ Ń€Đ”Đ¶ĐžĐŒĐ” сДрĐČДр Đ±ŃƒĐŽĐ”Ń‚ Ń€Đ°Đ±ĐŸŃ‚Đ°Ń‚ŃŒ ĐșаĐș ĐŸĐ±Ń‹Ń‡ĐœŃ‹Đč [ĐșĐŸĐŒĐŒŃƒŃ‚Đ°Ń‚ĐŸŃ€](switch.md). Đ’ĐŸ ĐČĐœŃƒŃ‚Ń€Đ”ĐœĐœĐ”ĐŒ Ń€Đ”Đ¶ĐžĐŒĐ”, ŃĐŸĐŸĐ±Ń‰Đ”ĐœĐžŃ Đ±ŃƒĐŽŃƒŃ‚ пДрДЎаĐČаться Ń‚ĐŸĐ»ŃŒĐșĐŸ Đș [сДрĐČĐ”Ń€Đ°ĐŒ](../item/server1.md) ĐČ ŃŃ‚ĐŸĐčĐșĐ” Đž ĐœĐ” Đ±ŃƒĐŽŃƒŃ‚ аĐČŃ‚ĐŸĐŒĐ°Ń‚ĐžŃ‡Đ”ŃĐșĐž сĐČŃĐ·Đ°ĐœŃ‹ ŃĐŸ ŃŃ‚ĐŸŃ€ĐŸĐœĐ°ĐŒĐž ŃŃ‚ĐŸĐčĐșĐž. [ХДрĐČДры](../item/server1.md) ĐČсД таĐșжД Đ±ŃƒĐŽŃƒŃ‚ ĐžĐŒĐ”Ń‚ŃŒ ĐČĐŸĐ·ĐŒĐŸĐ¶ĐœĐŸŃŃ‚ŃŒ пДрДЎачО ŃĐŸĐŸĐ±Ń‰Đ”ĐœĐžĐč Юруг Юругу. Đ­Ń‚ĐŸ ĐżĐŸĐ·ĐČĐŸĐ»ŃĐ”Ń‚ ĐžŃĐżĐŸĐ»ŃŒĐ·ĐŸĐČать сДрĐČĐ”Ń€ĐœŃ‹Đ” ŃŃ‚ĐŸĐčĐșĐž ĐșаĐș ĐżŃ€ĐŸĐŽĐČĐžĐœŃƒŃ‚Ń‹Đ” [ĐșĐŸĐŒĐŒŃƒŃ‚Đ°Ń‚ĐŸŃ€Ń‹](switch.md) ĐŽĐ»Ń ĐŸĐżĐ”Ń€Đ°Ń†ĐžĐč Ń„ĐžĐ»ŃŒŃ‚Ń€Đ°Ń†ĐžĐž Đž ĐœĐ°ĐżŃ€Đ°ĐČĐ»Đ”ĐœĐžŃ ĐŽĐ°ĐœĐœŃ‹Ń…, ĐœĐ°ĐżŃ€ĐžĐŒĐ”Ń€. +ХДрĐČĐ”Ń€ĐœŃ‹Đ” ŃŃ‚ĐŸĐčĐșĐž ĐČĐ·Đ°ĐžĐŒĐŸĐŽĐ”ĐčстĐČуют с [Ń€Đ”Ń‚Ń€Đ°ĐœŃĐ»ŃŃ‚ĐŸŃ€Đ°ĐŒĐž](relay.md) Đž [Ń€Đ°ŃĐżŃ€Đ”ĐŽĐ”Đ»ĐžŃ‚Đ”Đ»ŃĐŒĐž ŃĐœĐ”Ń€ĐłĐžĐž](powerDistributor.md). ĐŸĐ”Ń€Đ”ĐșĐ»ŃŽŃ‡Đ°Ń‚Đ”Đ»ŃŒ Ń€Đ”Đ¶ĐžĐŒĐŸĐČ Ń€Đ°Đ±ĐŸŃ‚Ń‹ ŃŃ‚ĐŸĐčĐșĐž, ĐŒĐŸĐ¶Đ”Ń‚ Đ±Ń‹Ń‚ŃŒ ĐœĐ°ŃŃ‚Ń€ĐŸĐ”Đœ ĐČ ĐžĐœŃ‚Đ”Ń€Ń„Đ”ĐčсД ŃĐ°ĐŒĐŸĐč ŃŃ‚ĐŸĐčĐșĐž, ĐŸĐœ ĐžĐŒĐ”Đ”Ń‚ 2 Ń€Đ”Đ¶ĐžĐŒĐ°: ĐČĐœĐ”ŃˆĐœĐžĐč Đž ĐČĐœŃƒŃ‚Ń€Đ”ĐœĐœĐžĐč. Đ’ĐŸ ĐČĐœĐ”ŃˆĐœĐ”ĐŒ Ń€Đ”Đ¶ĐžĐŒĐ” сДрĐČДр Đ±ŃƒĐŽĐ”Ń‚ Ń€Đ°Đ±ĐŸŃ‚Đ°Ń‚ŃŒ ĐșаĐș ĐŸĐ±Ń‹Ń‡ĐœŃ‹Đč [Ń€Đ”Ń‚Ń€Đ°ĐœŃĐ»ŃŃ‚ĐŸŃ€](relay.md). Đ’ĐŸ ĐČĐœŃƒŃ‚Ń€Đ”ĐœĐœĐ”ĐŒ Ń€Đ”Đ¶ĐžĐŒĐ”, ŃĐŸĐŸĐ±Ń‰Đ”ĐœĐžŃ Đ±ŃƒĐŽŃƒŃ‚ пДрДЎаĐČаться Ń‚ĐŸĐ»ŃŒĐșĐŸ Đș [сДрĐČĐ”Ń€Đ°ĐŒ](../item/server1.md) ĐČ ŃŃ‚ĐŸĐčĐșĐ” Đž ĐœĐ” Đ±ŃƒĐŽŃƒŃ‚ аĐČŃ‚ĐŸĐŒĐ°Ń‚ĐžŃ‡Đ”ŃĐșĐž сĐČŃĐ·Đ°ĐœŃ‹ ŃĐŸ ŃŃ‚ĐŸŃ€ĐŸĐœĐ°ĐŒĐž ŃŃ‚ĐŸĐčĐșĐž. [ХДрĐČДры](../item/server1.md) ĐČсД таĐșжД Đ±ŃƒĐŽŃƒŃ‚ ĐžĐŒĐ”Ń‚ŃŒ ĐČĐŸĐ·ĐŒĐŸĐ¶ĐœĐŸŃŃ‚ŃŒ пДрДЎачО ŃĐŸĐŸĐ±Ń‰Đ”ĐœĐžĐč Юруг Юругу. Đ­Ń‚ĐŸ ĐżĐŸĐ·ĐČĐŸĐ»ŃĐ”Ń‚ ĐžŃĐżĐŸĐ»ŃŒĐ·ĐŸĐČать сДрĐČĐ”Ń€ĐœŃ‹Đ” ŃŃ‚ĐŸĐčĐșĐž ĐșаĐș ĐżŃ€ĐŸĐŽĐČĐžĐœŃƒŃ‚Ń‹Đ” [Ń€Đ”Ń‚Ń€Đ°ĐœŃĐ»ŃŃ‚ĐŸŃ€Ń‹](relay.md) ĐŽĐ»Ń ĐŸĐżĐ”Ń€Đ°Ń†ĐžĐč Ń„ĐžĐ»ŃŒŃ‚Ń€Đ°Ń†ĐžĐž Đž ĐœĐ°ĐżŃ€Đ°ĐČĐ»Đ”ĐœĐžŃ ĐŽĐ°ĐœĐœŃ‹Ń…, ĐœĐ°ĐżŃ€ĐžĐŒĐ”Ń€. diff --git a/src/main/resources/assets/opencomputers/doc/ru_RU/block/switch.md b/src/main/resources/assets/opencomputers/doc/ru_RU/block/switch.md index 56445e17f..27b172988 100644 --- a/src/main/resources/assets/opencomputers/doc/ru_RU/block/switch.md +++ b/src/main/resources/assets/opencomputers/doc/ru_RU/block/switch.md @@ -2,6 +2,8 @@ ![ĐĄŃ‚Ń€ĐŸĐžŃ‚ ĐŒĐŸŃŃ‚Ń‹.](oredict:oc:switch) +*Đ­Ń‚ĐŸŃ‚ Đ±Đ»ĐŸĐș ŃƒŃŃ‚Đ°Ń€Đ”Đ» Đž Đ±ŃƒĐŽĐ”Ń‚ ŃƒĐŽĐ°Đ»Đ”Đœ ĐČ ŃĐ»Đ”ĐŽŃƒŃŽŃ‰ĐžŃ… ĐČĐ”Ń€ŃĐžŃŃ….* Đ—Đ°ĐŒĐ”ĐœĐžŃ‚Đ” Đ”ĐłĐŸ ĐœĐ° [Ń€Đ”Ń‚Ń€Đ°ĐœŃĐ»ŃŃ‚ĐŸŃ€](relay.md). + ĐšĐŸĐŒĐŒŃƒŃ‚Đ°Ń‚ĐŸŃ€ ĐžŃĐżĐŸĐ»ŃŒĐ·ŃƒĐ”Ń‚ŃŃ ĐŽĐ»Ń пДрДЎачО ŃĐŸĐŸĐ±Ń‰Đ”ĐœĐžĐč ĐŒĐ”Đ¶ĐŽŃƒ ĐœĐ”ŃĐșĐŸĐ»ŃŒĐșĐžĐŒĐž ĐżĐŸĐŽŃĐ”Ń‚ŃĐŒĐž, ĐœĐ” ĐžŃĐżĐŸĐ»ŃŒĐ·ŃƒŃ ĐșĐŸĐŒĐżĐŸĐœĐ”ĐœŃ‚Ń‹ [ĐșĐŸĐŒĐżŃŒŃŽŃ‚Đ”Ń€ĐŸĐČ](../general/computer.md) ĐČ ĐŽŃ€ŃƒĐłĐžŃ… ŃĐ”Ń‚ŃŃ…. ĐĄĐŸŃ…Ń€Đ°ĐœĐ”ĐœĐžĐ” ĐșĐŸĐŒĐżĐŸĐœĐ”ĐœŃ‚ĐŸĐČ, ĐșаĐș праĐČĐžĐ»ĐŸ, Ń…ĐŸŃ€ĐŸŃˆĐ°Ń ĐžĐŽĐ”Ń, Ń‡Ń‚ĐŸ ĐœĐ” ĐżĐŸĐ·ĐČĐŸĐ»ŃĐ”Ń‚ [ĐșĐŸĐŒĐżŃŒŃŽŃ‚Đ”Ń€Đ°ĐŒ](../general/computer.md) ĐžŃĐżĐŸĐ»ŃŒĐ·ĐŸĐČать ĐœĐ”ĐČĐ”Ń€ĐœŃ‹Đč [ĐŒĐŸĐœĐžŃ‚ĐŸŃ€](screen1.md) ОлО ĐœĐ” ĐżĐŸĐ·ĐČĐŸĐ»ŃĐ”Ń‚ ĐżĐ”Ń€Đ”ĐœĐ°ĐłŃ€ŃƒĐ¶Đ°Ń‚ŃŒ ох (ĐČ Ń€Đ”Đ·ŃƒĐ»ŃŒŃ‚Đ°Ń‚Đ” Ń‡Đ”ĐłĐŸ [ĐșĐŸĐŒĐżŃŒŃŽŃ‚Đ”Ń€Ń‹](../general/computer.md) ĐČыĐșĐ»ŃŽŃ‡Đ°Ń‚ŃŃ Đž ĐŸŃ‚ĐșазыĐČаются Đ·Đ°ĐłŃ€ŃƒĐ¶Đ°Ń‚ŃŒŃŃ). йаĐșжД Đ”ŃŃ‚ŃŒ Đ±Đ”ŃĐżŃ€ĐŸĐČĐŸĐŽĐœĐ°Ń ĐČĐ”Ń€ŃĐžŃ ĐșĐŸĐŒĐŒŃƒŃ‚Đ°Ń‚ĐŸŃ€Đ°, ĐœĐ°Đ·Ń‹ĐČĐ°Đ”ĐŒĐ°Ń [Ń‚ĐŸŃ‡Đșа ĐŽĐŸŃŃ‚ŃƒĐżĐ°](accessPoint.md), с ДД ĐżĐŸĐŒĐŸŃ‰ŃŒŃŽ ŃĐŸĐŸĐ±Ń‰Đ”ĐœĐžŃ ĐżĐ”Ń€Đ”ĐŽĐ°ŃŽŃ‚ŃŃ ĐżĐŸ Đ±Đ”ŃĐżŃ€ĐŸĐČĐŸĐŽĐœĐŸĐč Đ»ĐžĐœĐžĐž. ĐĄĐŸĐŸĐ±Ń‰Đ”ĐœĐžŃ, ĐżĐ”Ń€Đ”ĐŽĐ°ĐœĐœŃ‹Đ” ĐżĐŸ Đ±Đ”ŃĐżŃ€ĐŸĐČĐŸĐŽĐœĐŸĐč Đ»ĐžĐœĐžĐž ĐŒĐŸĐłŃƒŃ‚ Đ±Ń‹Ń‚ŃŒ ĐżĐŸĐ»ŃƒŃ‡Đ”ĐœŃ‹ ОлО ĐżĐ”Ń€Đ”ĐœĐ°ĐżŃ€Đ°ĐČĐ»Đ”ĐœŃ‹ ĐŽŃ€ŃƒĐłĐžĐŒĐž [Ń‚ĐŸŃ‡ĐșĐ°ĐŒĐž ĐŽĐŸŃŃ‚ŃƒĐżĐ°](accessPoint.md) ОлО [ĐșĐŸĐŒĐżŃŒŃŽŃ‚Đ”Ń€Đ°ĐŒĐž](../general/computer.md) с [Đ±Đ”ŃĐżŃ€ĐŸĐČĐŸĐŽĐœĐŸĐč сДтДĐČĐŸĐč ĐșĐ°Ń€Ń‚ĐŸĐč](../item/wlanCard.md). diff --git a/src/main/resources/assets/opencomputers/doc/ru_RU/item/lanCard.md b/src/main/resources/assets/opencomputers/doc/ru_RU/item/lanCard.md index 7094ef65b..6a25e7b07 100644 --- a/src/main/resources/assets/opencomputers/doc/ru_RU/item/lanCard.md +++ b/src/main/resources/assets/opencomputers/doc/ru_RU/item/lanCard.md @@ -2,4 +2,4 @@ ![Đ’ĐŸĐčĐŽĐž ĐČ ŃĐ”Ń‚ŃŒ.](oredict:oc:lanCard) -ХДтДĐČая Đșарта ĐżĐŸĐ·ĐČĐŸĐ»ŃĐ”Ń‚ [ĐșĐŸĐŒĐżŃŒŃŽŃ‚Đ”Ń€Đ°ĐŒ](../general/computer.md) ĐŸŃ‚ĐżŃ€Đ°ĐČĐ»ŃŃ‚ŃŒ Đž ĐżĐŸĐ»ŃƒŃ‡Đ°Ń‚ŃŒ сДтДĐČыД ŃĐŸĐŸĐ±Ń‰Đ”ĐœĐžŃ. ĐĄĐŸĐŸĐ±Ń‰Đ”ĐœĐžŃ (ОлО паĐșДты) Đ±ŃƒĐŽŃƒŃ‚ ĐŸŃ‚ĐżŃ€Đ°ĐČĐ»Đ”ĐœŃ‹ ĐČŃĐ”ĐŒ ĐżŃ€ĐžĐœĐžĐŒĐ°ŃŽŃ‰ĐžĐŒ ŃƒŃŃ‚Ń€ĐŸĐčстĐČĐ°ĐŒ ĐČ ĐżĐŸĐŽŃĐ”Ń‚Đž ОлО ĐșĐŸĐœĐșŃ€Đ”Ń‚ĐœĐŸĐč сДтДĐČĐŸĐč ĐșартД (ĐżĐŸŃĐ»Đ” уĐșĐ°Đ·Đ°ĐœĐžŃ ДД аЎрДса). [ĐšĐŸĐŒĐŒŃƒŃ‚Đ°Ń‚ĐŸŃ€Ń‹](../block/switch.md) Đž [Ń‚ĐŸŃ‡ĐșĐž ĐŽĐŸŃŃ‚ŃƒĐżĐ°](../block/accessPoint.md) ĐŒĐŸĐłŃƒŃ‚ Đ±Ń‹Ń‚ŃŒ ĐžŃĐżĐŸĐ»ŃŒĐ·ĐŸĐČĐ°ĐœŃ‹ ĐŽĐ»Ń сĐČŃĐ·Đž ĐœĐ”ŃĐșĐŸĐ»ŃŒĐșох ĐżĐŸĐŽŃĐ”Ń‚Đ”Đč Юруг с ĐŽŃ€ŃƒĐłĐŸĐŒ, ĐŽĐ»Ń пДрДЎачО ŃĐŸĐŸĐ±Ń‰Đ”ĐœĐžĐč ĐČ ĐœĐžŃ…. йаĐșжД ĐČĐŸĐ·ĐŒĐŸĐ¶ĐœĐŸ ĐŸŃ‚ĐżŃ€Đ°ĐČоть ĐżĐžŃŃŒĐŒĐŸ ĐżĐŸĐ»ŃƒŃ‡Đ°Ń‚Đ”Đ»ŃŽ, ЎажД ДслО ĐŸĐœ ĐœĐ°Ń…ĐŸĐŽĐžŃ‚ŃŃ ĐČ ĐŽŃ€ŃƒĐłĐŸĐč ĐżĐŸĐŽŃĐ”Ń‚Đž, ДслО ŃĐ”Ń‚ŃŒ ĐżĐŸĐŽĐșĐ»ŃŽŃ‡Đ”ĐœĐ° Đș ĐŸĐŽĐœĐŸĐŒŃƒ ОлО ĐœĐ”ŃĐșĐŸĐ»ŃŒĐșĐžĐŒ [ĐșĐŸĐŒĐŒŃƒŃ‚Đ°Ń‚ĐŸŃ€Đ°ĐŒ](../block/switch.md). +ХДтДĐČая Đșарта ĐżĐŸĐ·ĐČĐŸĐ»ŃĐ”Ń‚ [ĐșĐŸĐŒĐżŃŒŃŽŃ‚Đ”Ń€Đ°ĐŒ](../general/computer.md) ĐŸŃ‚ĐżŃ€Đ°ĐČĐ»ŃŃ‚ŃŒ Đž ĐżĐŸĐ»ŃƒŃ‡Đ°Ń‚ŃŒ сДтДĐČыД ŃĐŸĐŸĐ±Ń‰Đ”ĐœĐžŃ. ĐĄĐŸĐŸĐ±Ń‰Đ”ĐœĐžŃ (ОлО паĐșДты) Đ±ŃƒĐŽŃƒŃ‚ ĐŸŃ‚ĐżŃ€Đ°ĐČĐ»Đ”ĐœŃ‹ ĐČŃĐ”ĐŒ ĐżŃ€ĐžĐœĐžĐŒĐ°ŃŽŃ‰ĐžĐŒ ŃƒŃŃ‚Ń€ĐŸĐčстĐČĐ°ĐŒ ĐČ ĐżĐŸĐŽŃĐ”Ń‚Đž ОлО ĐșĐŸĐœĐșŃ€Đ”Ń‚ĐœĐŸĐč сДтДĐČĐŸĐč ĐșартД (про уĐșĐ°Đ·Đ°ĐœĐžĐž Дё аЎрДса). [Đ Đ”Ń‚Ń€Đ°ĐœŃĐ»ŃŃ‚ĐŸŃ€Ń‹](../block/relay.md) ĐŒĐŸĐłŃƒŃ‚ Đ±Ń‹Ń‚ŃŒ ĐžŃĐżĐŸĐ»ŃŒĐ·ĐŸĐČĐ°ĐœŃ‹ ĐŽĐ»Ń сĐČŃĐ·Đž ĐœĐ”ŃĐșĐŸĐ»ŃŒĐșох ĐżĐŸĐŽŃĐ”Ń‚Đ”Đč Юруг с ĐŽŃ€ŃƒĐłĐŸĐŒ Đž пДрДЎачО ŃĐŸĐŸĐ±Ń‰Đ”ĐœĐžĐč. йаĐșжД ĐČĐŸĐ·ĐŒĐŸĐ¶ĐœĐŸ ĐŸŃ‚ĐżŃ€Đ°ĐČоть ĐżĐžŃŃŒĐŒĐŸ ĐżĐŸĐ»ŃƒŃ‡Đ°Ń‚Đ”Đ»ŃŽ, ЎажД ДслО ĐŸĐœ ĐœĐ°Ń…ĐŸĐŽĐžŃ‚ŃŃ ĐČ ĐŽŃ€ŃƒĐłĐŸĐč ĐżĐŸĐŽŃĐ”Ń‚Đž, ДслО ŃĐ”Ń‚ŃŒ ĐżĐŸĐŽĐșĐ»ŃŽŃ‡Đ”ĐœĐ° Đș ĐŸĐŽĐœĐŸĐŒŃƒ ОлО ĐœĐ”ŃĐșĐŸĐ»ŃŒĐșĐžĐŒ [Ń€Đ”Ń‚Ń€Đ°ŃĐ»ŃŃ‚ĐŸŃ€Đ°ĐŒĐž](../block/relay.md). diff --git a/src/main/resources/assets/opencomputers/lang/ru_RU.lang b/src/main/resources/assets/opencomputers/lang/ru_RU.lang index a1ab2d83f..85700e6ba 100644 --- a/src/main/resources/assets/opencomputers/lang/ru_RU.lang +++ b/src/main/resources/assets/opencomputers/lang/ru_RU.lang @@ -3,7 +3,7 @@ # Use [nl] to for a line break. # Blocks -tile.oc.accessPoint.name=ĐąĐŸŃ‡Đșа ĐŽĐŸŃŃ‚ŃƒĐżĐ° +tile.oc.accessPoint.name=§cĐąĐŸŃ‡Đșа ĐŽĐŸŃŃ‚ŃƒĐżĐ°Â§7 tile.oc.adapter.name=АЎаптДр tile.oc.assembler.name=ĐĄĐ±ĐŸŃ€Ń‰ĐžĐș Ń€ĐŸĐ±ĐŸŃ‚ĐŸĐČ tile.oc.cable.name=ĐšĐ°Đ±Đ”Đ»ŃŒ @@ -35,7 +35,7 @@ tile.oc.screen1.name=ĐœĐŸĐœĐžŃ‚ĐŸŃ€ (1-ыĐč ŃƒŃ€ĐŸĐČĐ”ĐœŃŒ) tile.oc.screen2.name=ĐœĐŸĐœĐžŃ‚ĐŸŃ€ (2-ĐŸĐč ŃƒŃ€ĐŸĐČĐ”ĐœŃŒ) tile.oc.screen3.name=ĐœĐŸĐœĐžŃ‚ĐŸŃ€ (3-ĐžĐč ŃƒŃ€ĐŸĐČĐ”ĐœŃŒ) tile.oc.serverRack.name=ХДрĐČĐ”Ń€ĐœĐ°Ń ŃŃ‚ĐŸĐčĐșа -tile.oc.switch.name=ĐšĐŸĐŒĐŒŃƒŃ‚Đ°Ń‚ĐŸŃ€ +tile.oc.switch.name=§cĐšĐŸĐŒĐŒŃƒŃ‚Đ°Ń‚ĐŸŃ€Â§7 tile.oc.netSplitter.name=ХДтДĐČĐŸĐč пДрДĐșĐ»ŃŽŃ‡Đ°Ń‚Đ”Đ»ŃŒ tile.oc.waypoint.name=ĐŸŃƒŃ‚Đ”ĐČая Ń‚ĐŸŃ‡Đșа @@ -229,6 +229,7 @@ oc:container.Disassembler=Đ Đ°Đ·Đ±ĐŸŃ€Ń‰ĐžĐș oc:container.DiskDrive=ДосĐșĐŸĐČĐŸĐŽ oc:container.Printer=ĐŸŃ€ĐžĐœŃ‚Đ”Ń€ oc:container.Raid=RAID +oc:container.Relay=Đ Đ”Ń‚Ń€Đ°ĐœŃĐ»ŃŃ‚ĐŸŃ€ oc:container.Server=ХДрĐČДр oc:container.ServerRack=ХДрĐČĐ”Ń€ĐœĐ°Ń ŃŃ‚ĐŸĐčĐșа oc:container.Switch=ĐšĐŸĐŒĐŒŃƒŃ‚Đ°Ń‚ĐŸŃ€ @@ -319,6 +320,7 @@ oc:tooltip.RedstoneCard.RedNet=ĐœĐŸĐŽ §fRedNet§7 §aĐżĐŸĐŽĐŽĐ”Ń€Đ¶ĐžĐČаДтс oc:tooltip.RedstoneCard.WirelessCBE=ĐœĐŸĐŽ §fWireless Redstone (ChickenBones)§7 §aĐżĐŸĐŽĐŽĐ”Ń€Đ¶ĐžĐČĐ°Đ”Ń‚ŃŃÂ§7. oc:tooltip.RedstoneCard.WirelessSV=ĐœĐŸĐŽ §fWireless Redstone (SlimeVoid)§7 §aĐżĐŸĐŽĐŽĐ”Ń€Đ¶ĐžĐČĐ°Đ”Ń‚ŃŃÂ§7. oc:tooltip.RedstoneCard=ĐŸĐŸĐ·ĐČĐŸĐ»ŃĐ”Ń‚ ĐżŃ€ĐžĐœĐžĐŒĐ°Ń‚ŃŒ Đž ĐžĐ·Đ»ŃƒŃ‡Đ°Ń‚ŃŒ ŃĐžĐłĐœĐ°Đ»Ń‹ ĐșŃ€Đ°ŃĐœĐŸĐłĐŸ ĐșĐ°ĐŒĐœŃ ĐČĐŸĐșруг ĐșĐŸĐŒĐżŃŒŃŽŃ‚Đ”Ń€Đ° ОлО Ń€ĐŸĐ±ĐŸŃ‚Đ°. +oc:tooltip.Relay=ĐŸĐŸĐ·ĐČĐŸĐ»ŃĐ”Ń‚ ŃĐŸĐ”ĐŽĐžĐœŃŃ‚ŃŒ Ń€Đ°Đ·Đ»ĐžŃ‡ĐœŃ‹Đ” сДтО ĐŒĐ”Đ¶ĐŽŃƒ ŃĐŸĐ±ĐŸĐč. ĐŸĐ”Ń€Đ”ĐŽĐ°ŃŽŃ‚ŃŃ Ń‚ĐŸĐ»ŃŒĐșĐŸ ŃĐŸĐŸĐ±Ń‰Đ”ĐœĐžŃ, ĐșĐŸĐŒĐżĐŸĐœĐ”ĐœŃ‚Ń‹ ĐŒĐ”Đ¶ĐŽŃƒ ŃĐ”Ń‚ŃĐŒĐž ĐœĐ”ĐŽĐŸŃŃ‚ŃƒĐżĐœŃ‹. Đ˜ŃĐżĐŸĐ»ŃŒĐ·ŃƒĐčтД Đ”ĐłĐŸ ĐŽĐ»Ń Ń€Đ°Đ·ĐŽĐ”Đ»Đ”ĐœĐžŃ сДтДĐč с ĐČĐŸĐ·ĐŒĐŸĐ¶ĐœĐŸŃŃ‚ŃŒŃŽ ĐżĐ”Ń€Đ”ŃŃ‹Đ»Đ°Ń‚ŃŒ ŃĐŸĐŸĐ±Ń‰Đ”ĐœĐžŃ ĐŒĐ”Đ¶ĐŽŃƒ ĐœĐžĐŒĐž. oc:tooltip.Robot=В ĐŸŃ‚Đ»ĐžŃ‡ĐžĐ” ĐŸŃ‚ ĐșĐŸĐŒĐżŃŒŃŽŃ‚Đ”Ń€ĐŸĐČ, Ń€ĐŸĐ±ĐŸŃ‚Ń‹ ĐŒĐŸĐłŃƒŃ‚ пДрДЎĐČогаться Đž ĐČĐ·Đ°ĐžĐŒĐŸĐŽĐ”ĐčстĐČĐŸĐČать с ĐŒĐžŃ€ĐŸĐŒ, ĐșаĐș ĐžĐłŃ€ĐŸĐș.[nl] §cĐĐ” ĐŒĐŸĐłŃƒŃ‚ ĐČĐ·Đ°ĐžĐŒĐŸĐŽĐ”ĐčстĐČĐŸĐČать с ĐČĐœĐ”ŃˆĐœĐžĐŒĐž ĐșĐŸĐŒĐżĐŸĐœĐ”ĐœŃ‚Đ°ĐŒĐž.§7 # The underscore makes sure this isn't hidden with the rest of the tooltip. oc:tooltip.Robot_Level=§fĐŁŃ€ĐŸĐČĐ”ĐœŃŒÂ§7: §a%s§7. From 4e66556892a42973efb742fd77e4626b04e39795 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Tue, 25 Aug 2015 22:37:57 +0200 Subject: [PATCH 16/30] Added getter and setter for CPU architecture in computer API, closes #1390. Also potentially fixes a possible deadlock... maybe. Or breaks even more \o/ --- src/main/java/li/cil/oc/api/API.java | 2 +- .../oc/api/driver/item/MutableProcessor.java | 27 ++++++++++ .../assets/opencomputers/lua/machine.lua | 17 +++++++ src/main/scala/li/cil/oc/OpenComputers.scala | 2 +- .../cil/oc/common/item/traits/CPULike.scala | 45 ++++------------ .../integration/opencomputers/DriverCPU.scala | 22 +++++++- .../li/cil/oc/server/machine/Machine.scala | 8 +-- .../oc/server/machine/luac/ComputerAPI.scala | 51 +++++++++++++++++++ .../oc/server/machine/luaj/ComputerAPI.scala | 40 +++++++++++++++ 9 files changed, 170 insertions(+), 44 deletions(-) create mode 100644 src/main/java/li/cil/oc/api/driver/item/MutableProcessor.java diff --git a/src/main/java/li/cil/oc/api/API.java b/src/main/java/li/cil/oc/api/API.java index 051bcb5d8..471ef36e7 100644 --- a/src/main/java/li/cil/oc/api/API.java +++ b/src/main/java/li/cil/oc/api/API.java @@ -12,7 +12,7 @@ import li.cil.oc.api.detail.*; */ public class API { public static final String ID_OWNER = "OpenComputers|Core"; - public static final String VERSION = "5.5.3"; + public static final String VERSION = "5.5.4"; public static DriverAPI driver = null; public static FileSystemAPI fileSystem = null; diff --git a/src/main/java/li/cil/oc/api/driver/item/MutableProcessor.java b/src/main/java/li/cil/oc/api/driver/item/MutableProcessor.java new file mode 100644 index 000000000..04cc07634 --- /dev/null +++ b/src/main/java/li/cil/oc/api/driver/item/MutableProcessor.java @@ -0,0 +1,27 @@ +package li.cil.oc.api.driver.item; + +import li.cil.oc.api.machine.Architecture; +import net.minecraft.item.ItemStack; + +/** + * May be implemented in processor drivers of processors that can be reconfigured. + *

+ * This is the case for OC's built-in CPUs, for example, which can be reconfigured + * to any registered architecture. It a CPU has such a driver, it may also be + * reconfigured by the machine it is running in (e.g. in the Lua case via + * computer.setArchitecture). + */ +public interface MutableProcessor extends Processor { + /** + * Get a list of all architectures supported by this processor. + */ + java.util.Collection> allArchitectures(); + + /** + * Set the architecture to use for the specified processor. + * + * @param stack the processor to set the architecture for. + * @param architecture the architecture to use on the processor. + */ + void setArchitecture(ItemStack stack, Class architecture); +} diff --git a/src/main/resources/assets/opencomputers/lua/machine.lua b/src/main/resources/assets/opencomputers/lua/machine.lua index 56e79e3c0..238fd4f51 100644 --- a/src/main/resources/assets/opencomputers/lua/machine.lua +++ b/src/main/resources/assets/opencomputers/lua/machine.lua @@ -1320,6 +1320,23 @@ local libcomputer = { beep = function(...) libcomponent.invoke(computer.address(), "beep", ...) + end, + + getArchitectures = function(...) + return spcall(computer.getArchitectures, ...) + end, + getArchitecture = function(...) + return spcall(computer.getArchitecture, ...) + end, + setArchitecture = function(...) + local result, reason = spcall(computer.setArchitecture, ...) + if not result then + if reason then + return result, reason + end + else + coroutine.yield(true) -- reboot + end end } sandbox.computer = libcomputer diff --git a/src/main/scala/li/cil/oc/OpenComputers.scala b/src/main/scala/li/cil/oc/OpenComputers.scala index 2749f0993..4f6aae03e 100644 --- a/src/main/scala/li/cil/oc/OpenComputers.scala +++ b/src/main/scala/li/cil/oc/OpenComputers.scala @@ -19,7 +19,7 @@ object OpenComputers { final val Name = "OpenComputers" - final val Version = "1.5.16" + final val Version = "@VERSION@" var log = LogManager.getLogger(Name) diff --git a/src/main/scala/li/cil/oc/common/item/traits/CPULike.scala b/src/main/scala/li/cil/oc/common/item/traits/CPULike.scala index 31d20a765..4b26ca417 100644 --- a/src/main/scala/li/cil/oc/common/item/traits/CPULike.scala +++ b/src/main/scala/li/cil/oc/common/item/traits/CPULike.scala @@ -3,12 +3,10 @@ package li.cil.oc.common.item.traits import java.util import li.cil.oc.Settings -import li.cil.oc.api -import li.cil.oc.api.machine.Architecture +import li.cil.oc.integration.opencomputers.DriverCPU import li.cil.oc.util.Tooltip import net.minecraft.entity.player.EntityPlayer import net.minecraft.item.ItemStack -import net.minecraft.nbt.NBTTagCompound import net.minecraft.util.ChatComponentTranslation import net.minecraft.world.World @@ -21,37 +19,19 @@ trait CPULike extends Delegate { override protected def tooltipData: Seq[Any] = Seq(Settings.get.cpuComponentSupport(cpuTier)) override protected def tooltipExtended(stack: ItemStack, tooltip: util.List[String]) { - (if (stack.hasTagCompound) { - Option(stack.getTagCompound.getString(Settings.namespace + "archName")) - } - else { - val architectures = allArchitectures - architectures.headOption.map(_._2) - }) match { - case Some(archName) if !archName.isEmpty => tooltip.addAll(Tooltip.get("CPU.Architecture", archName)) - case _ => allArchitectures.headOption.collect { - case ((_, name)) => tooltip.addAll(Tooltip.get("CPU.Architecture", name)) - } - } + tooltip.addAll(Tooltip.get("CPU.Architecture", DriverCPU.getArchitectureName(DriverCPU.architecture(stack)))) } override def onItemRightClick(stack: ItemStack, world: World, player: EntityPlayer) = { if (player.isSneaking) { if (!world.isRemote) { - val architectures = allArchitectures - if (architectures.length > 0) { - val currentIndex = if (stack.hasTagCompound) { - val currentArch = stack.getTagCompound.getString(Settings.namespace + "archClass") - architectures.indexWhere(_._1.getName == currentArch) - } - else { - stack.setTagCompound(new NBTTagCompound()) - -1 - } - val index = (currentIndex + 1) % architectures.length - val (archClass, archName) = architectures(index) - stack.getTagCompound.setString(Settings.namespace + "archClass", archClass.getName) - stack.getTagCompound.setString(Settings.namespace + "archName", archName) + val architectures = DriverCPU.allArchitectures.toList + if (architectures.nonEmpty) { + val currentIndex = architectures.indexOf(DriverCPU.architecture(stack)) + val newIndex = (currentIndex + 1) % architectures.length + val archClass = architectures(newIndex) + val archName = DriverCPU.getArchitectureName(archClass) + DriverCPU.setArchitecture(stack, archClass) player.addChatMessage(new ChatComponentTranslation(Settings.namespace + "tooltip.CPU.Architecture", archName)) } player.swingItem() @@ -59,11 +39,4 @@ trait CPULike extends Delegate { } stack } - - private def allArchitectures = api.Machine.architectures.map { arch => - arch.getAnnotation(classOf[Architecture.Name]) match { - case annotation: Architecture.Name => (arch, annotation.value) - case _ => (arch, arch.getSimpleName) - } - }.toArray } diff --git a/src/main/scala/li/cil/oc/integration/opencomputers/DriverCPU.scala b/src/main/scala/li/cil/oc/integration/opencomputers/DriverCPU.scala index 14db12664..62e8557d3 100644 --- a/src/main/scala/li/cil/oc/integration/opencomputers/DriverCPU.scala +++ b/src/main/scala/li/cil/oc/integration/opencomputers/DriverCPU.scala @@ -5,7 +5,7 @@ import li.cil.oc.OpenComputers import li.cil.oc.Settings import li.cil.oc.api import li.cil.oc.api.driver.EnvironmentHost -import li.cil.oc.api.driver.item.Processor +import li.cil.oc.api.driver.item.MutableProcessor import li.cil.oc.api.machine.Architecture import li.cil.oc.api.network.ManagedEnvironment import li.cil.oc.common.Slot @@ -14,12 +14,14 @@ import li.cil.oc.common.item import li.cil.oc.common.item.Delegator import li.cil.oc.server.machine.luac.NativeLuaArchitecture import net.minecraft.item.ItemStack +import net.minecraft.nbt.NBTTagCompound +import scala.collection.convert.WrapAsJava._ import scala.collection.convert.WrapAsScala._ object DriverCPU extends DriverCPU -abstract class DriverCPU extends Item with Processor { +abstract class DriverCPU extends Item with MutableProcessor { override def worksWith(stack: ItemStack) = isOneOf(stack, api.Items.get(Constants.ItemName.CPUTier1), api.Items.get(Constants.ItemName.CPUTier2), @@ -39,6 +41,8 @@ abstract class DriverCPU extends Item with Processor { override def supportedComponents(stack: ItemStack) = Settings.get.cpuComponentSupport(cpuTier(stack)) + override def allArchitectures = api.Machine.architectures.toList + override def architecture(stack: ItemStack): Class[_ <: Architecture] = { if (stack.hasTagCompound) { val archClass = stack.getTagCompound.getString(Settings.namespace + "archClass") match { @@ -57,4 +61,18 @@ abstract class DriverCPU extends Item with Processor { } api.Machine.architectures.headOption.orNull } + + override def setArchitecture(stack: ItemStack, architecture: Class[_ <: Architecture]): Unit = { + if (!worksWith(stack)) throw new IllegalArgumentException("Unsupported processor type.") + if (!stack.hasTagCompound) stack.setTagCompound(new NBTTagCompound()) + stack.getTagCompound.setString(Settings.namespace + "archClass", architecture.getName) + stack.getTagCompound.setString(Settings.namespace + "archName", getArchitectureName(architecture)) + } + + // TODO Move to Machine API in 1.6 + def getArchitectureName(architecture: Class[_ <: Architecture]) = + architecture.getAnnotation(classOf[Architecture.Name]) match { + case annotation: Architecture.Name => annotation.value + case _ => architecture.getSimpleName + } } 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 0118a25b3..0b5a256e7 100644 --- a/src/main/scala/li/cil/oc/server/machine/Machine.scala +++ b/src/main/scala/li/cil/oc/server/machine/Machine.scala @@ -478,7 +478,7 @@ class Machine(val host: MachineHost) extends prefab.ManagedEnvironment with mach // Check if we should switch states. These are all the states in which we're // guaranteed that the executor thread isn't running anymore. - state.synchronized(state.top match { + state.synchronized(state.top) match { // Booting up. case Machine.State.Starting => verifyComponents() @@ -539,10 +539,8 @@ class Machine(val host: MachineHost) extends prefab.ManagedEnvironment with mach finally { inSynchronizedCall = false } - - assert(!isExecuting) case _ => // Nothing special to do, just avoid match errors. - }) + } // Finally check if we should stop the computer. We cannot lock the state // because we may have to wait for the executor thread to finish, which @@ -946,6 +944,8 @@ class Machine(val host: MachineHost) extends prefab.ManagedEnvironment with mach case Machine.State.Stopping => state.clear() state.push(Machine.State.Stopping) + case Machine.State.Restarting => + // Nothing to do! case _ => throw new AssertionError("Invalid state in executor post-processing.") } assert(!isExecuting) diff --git a/src/main/scala/li/cil/oc/server/machine/luac/ComputerAPI.scala b/src/main/scala/li/cil/oc/server/machine/luac/ComputerAPI.scala index cf3b18f37..c92ea091b 100644 --- a/src/main/scala/li/cil/oc/server/machine/luac/ComputerAPI.scala +++ b/src/main/scala/li/cil/oc/server/machine/luac/ComputerAPI.scala @@ -1,9 +1,15 @@ package li.cil.oc.server.machine.luac import li.cil.oc.Settings +import li.cil.oc.api +import li.cil.oc.api.driver.item.MutableProcessor +import li.cil.oc.api.driver.item.Processor import li.cil.oc.api.network.Connector +import li.cil.oc.integration.opencomputers.DriverCPU import li.cil.oc.util.ExtendedLuaState.extendLuaState +import scala.collection.convert.WrapAsScala._ + class ComputerAPI(owner: NativeLuaArchitecture) extends NativeLuaAPI(owner) { def initialize() { // Computer API, stuff that kinda belongs to os, but we don't want to @@ -105,6 +111,51 @@ class ComputerAPI(owner: NativeLuaArchitecture) extends NativeLuaAPI(owner) { }) lua.setField(-2, "maxEnergy") + lua.pushScalaFunction(lua => { + machine.host.internalComponents.map(stack => (stack, api.Driver.driverFor(stack))).collectFirst { + case (stack, processor: MutableProcessor) => processor.allArchitectures.toSeq + case (stack, processor: Processor) => Seq(processor.architecture(stack)) + } match { + case Some(architectures) => + lua.pushValue(architectures.map(DriverCPU.getArchitectureName)) + case _ => + lua.newTable() + } + 1 + }) + lua.setField(-2, "getArchitectures") + + lua.pushScalaFunction(lua => { + machine.host.internalComponents.map(stack => (stack, api.Driver.driverFor(stack))).collectFirst { + case (stack, processor: Processor) => + lua.pushString(DriverCPU.getArchitectureName(processor.architecture(stack))) + 1 + }.getOrElse(0) + }) + lua.setField(-2, "getArchitecture") + + lua.pushScalaFunction(lua => { + val archName = lua.checkString(1) + machine.host.internalComponents.map(stack => (stack, api.Driver.driverFor(stack))).collectFirst { + case (stack, processor: MutableProcessor) => processor.allArchitectures.find(arch => DriverCPU.getArchitectureName(arch) == archName) match { + case Some(archClass) => + if (archClass != processor.architecture(stack)) { + processor.setArchitecture(stack, archClass) + lua.pushBoolean(true) + } + else { + lua.pushBoolean(false) + } + 1 + case _ => + lua.pushNil() + lua.pushString("unknown architecture") + 2 + } + }.getOrElse(0) + }) + lua.setField(-2, "setArchitecture") + // Set the computer table. lua.setGlobal("computer") } diff --git a/src/main/scala/li/cil/oc/server/machine/luaj/ComputerAPI.scala b/src/main/scala/li/cil/oc/server/machine/luaj/ComputerAPI.scala index d27b826cb..cb87c1180 100644 --- a/src/main/scala/li/cil/oc/server/machine/luaj/ComputerAPI.scala +++ b/src/main/scala/li/cil/oc/server/machine/luaj/ComputerAPI.scala @@ -1,11 +1,17 @@ package li.cil.oc.server.machine.luaj import li.cil.oc.Settings +import li.cil.oc.api +import li.cil.oc.api.driver.item.MutableProcessor +import li.cil.oc.api.driver.item.Processor import li.cil.oc.api.network.Connector +import li.cil.oc.integration.opencomputers.DriverCPU import li.cil.oc.util.ScalaClosure._ import li.cil.repack.org.luaj.vm2.LuaValue import li.cil.repack.org.luaj.vm2.Varargs +import scala.collection.convert.WrapAsScala._ + class ComputerAPI(owner: LuaJLuaArchitecture) extends LuaJAPI(owner) { override def initialize() { // Computer API, stuff that kinda belongs to os, but we don't want to @@ -54,6 +60,40 @@ class ComputerAPI(owner: LuaJLuaArchitecture) extends LuaJAPI(owner) { computer.set("maxEnergy", (_: Varargs) => LuaValue.valueOf(node.asInstanceOf[Connector].globalBufferSize)) + computer.set("getArchitectures", (args: Varargs) => { + machine.host.internalComponents.map(stack => (stack, api.Driver.driverFor(stack))).collectFirst { + case (stack, processor: MutableProcessor) => processor.allArchitectures.toSeq + case (stack, processor: Processor) => Seq(processor.architecture(stack)) + } match { + case Some(architectures) => LuaValue.listOf(architectures.map(DriverCPU.getArchitectureName).map(LuaValue.valueOf).toArray) + case _ => LuaValue.tableOf() + } + }) + + computer.set("getArchitecture", (args: Varargs) => { + machine.host.internalComponents.map(stack => (stack, api.Driver.driverFor(stack))).collectFirst { + case (stack, processor: Processor) => LuaValue.valueOf(DriverCPU.getArchitectureName(processor.architecture(stack))) + }.getOrElse(LuaValue.NONE) + }) + + computer.set("setArchitecture", (args: Varargs) => { + val archName = args.checkjstring(1) + machine.host.internalComponents.map(stack => (stack, api.Driver.driverFor(stack))).collectFirst { + case (stack, processor: MutableProcessor) => processor.allArchitectures.find(arch => DriverCPU.getArchitectureName(arch) == archName) match { + case Some(archClass) => + if (archClass != processor.architecture(stack)) { + processor.setArchitecture(stack, archClass) + LuaValue.TRUE + } + else { + LuaValue.FALSE + } + case _ => + LuaValue.varargsOf(LuaValue.NIL, LuaValue.valueOf("unknown architecture")) + } + }.getOrElse(LuaValue.NONE) + }) + // Set the computer table. lua.set("computer", computer) } From fb816b9da7de630253f52cab63653852796d1b0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Sat, 29 Aug 2015 02:27:22 +0200 Subject: [PATCH 17/30] Added transposer block for moving items and fluids between adjacent blocks. Closes #1244. Also refactored fluid stuffs quite a bit; may lead to slight changes in behavior here and there (e.g. returning empty table for tank info instead of "no tank" errors). --- src/main/resources/application.conf | 4 + .../doc/en_US/block/transposer.md | 9 + .../assets/opencomputers/lang/en_US.lang | 4 +- .../opencomputers/recipes/default.recipes | 6 + .../textures/blocks/TransposerOn.png | Bin 0 -> 154 bytes .../textures/blocks/TransposerSide.png | Bin 0 -> 523 bytes .../textures/blocks/TransposerTop.png | Bin 0 -> 425 bytes src/main/scala/li/cil/oc/Constants.scala | 3 +- src/main/scala/li/cil/oc/Settings.scala | 1 + .../li/cil/oc/client/PacketHandler.scala | 27 +-- src/main/scala/li/cil/oc/client/Proxy.scala | 3 +- .../scala/li/cil/oc/client/Textures.scala | 4 + .../client/renderer/block/BlockRenderer.scala | 20 ++- .../oc/client/renderer/block/Transposer.scala | 124 ++++++++++++++ .../tileentity/TransposerRenderer.scala | 77 +++++++++ .../scala/li/cil/oc/common/PacketType.scala | 3 +- .../li/cil/oc/common/block/Geolyzer.scala | 3 + .../li/cil/oc/common/block/NetSplitter.scala | 4 +- .../li/cil/oc/common/block/Transposer.scala | 36 ++++ .../scala/li/cil/oc/common/init/Blocks.scala | 6 +- .../cil/oc/common/tileentity/Transposer.scala | 25 +++ .../scala/li/cil/oc/server/PacketSender.scala | 28 ++-- .../cil/oc/server/component/Transposer.scala | 68 ++++++++ .../component/traits/TankWorldControl.scala | 118 ++++--------- .../component/traits/WorldTankAnalytics.scala | 16 +- .../li/cil/oc/util/ExtendedArguments.scala | 3 +- .../scala/li/cil/oc/util/ExtendedBlock.scala | 11 ++ .../scala/li/cil/oc/util/FluidUtils.scala | 157 ++++++++++++++++++ .../scala/li/cil/oc/util/InventoryUtils.scala | 42 +++++ 29 files changed, 673 insertions(+), 129 deletions(-) create mode 100644 src/main/resources/assets/opencomputers/doc/en_US/block/transposer.md create mode 100644 src/main/resources/assets/opencomputers/textures/blocks/TransposerOn.png create mode 100644 src/main/resources/assets/opencomputers/textures/blocks/TransposerSide.png create mode 100644 src/main/resources/assets/opencomputers/textures/blocks/TransposerTop.png create mode 100644 src/main/scala/li/cil/oc/client/renderer/block/Transposer.scala create mode 100644 src/main/scala/li/cil/oc/client/renderer/tileentity/TransposerRenderer.scala create mode 100644 src/main/scala/li/cil/oc/common/block/Transposer.scala create mode 100644 src/main/scala/li/cil/oc/common/tileentity/Transposer.scala create mode 100644 src/main/scala/li/cil/oc/server/component/Transposer.scala create mode 100644 src/main/scala/li/cil/oc/util/FluidUtils.scala diff --git a/src/main/resources/application.conf b/src/main/resources/application.conf index c35bc1bf2..9c7884f0d 100644 --- a/src/main/resources/application.conf +++ b/src/main/resources/application.conf @@ -767,6 +767,10 @@ opencomputers { # Per-byte cost for ECDSA operation is controlled by `complex` value, # because data is hashed with SHA256 before signing/verifying dataCardAsymmetric: 10.0 + + # Energy required for one transposer operation (regardless of the number + # of items / fluid volume moved). + transposer: 1 } # The rate at which different blocks accept external power. All of these diff --git a/src/main/resources/assets/opencomputers/doc/en_US/block/transposer.md b/src/main/resources/assets/opencomputers/doc/en_US/block/transposer.md new file mode 100644 index 000000000..ccc3e07ff --- /dev/null +++ b/src/main/resources/assets/opencomputers/doc/en_US/block/transposer.md @@ -0,0 +1,9 @@ +# Transposer + +![Such a poser.](oredict:oc:transposer) + +The transposer bridges the gap between redstone controlled hoppers and [robots](robot.md), allowing [computer](../general/computer.md)-controlled transferral of items and fluids between adjacent blocks. + +*Note that this block has no internal inventory.* + +Besides moving things around, it can also be used to inspect the contents of the adjacent inventories, like an [adapter](adapter.md) with an [inventory controller upgrade](../item/inventoryControllerUpgrade.md) could, and the contents of adjacent tanks, like and adapter with a [tank controller upgrade](../item/tankControllerUpgrade.md) could. diff --git a/src/main/resources/assets/opencomputers/lang/en_US.lang b/src/main/resources/assets/opencomputers/lang/en_US.lang index 12020008f..d656c91a3 100644 --- a/src/main/resources/assets/opencomputers/lang/en_US.lang +++ b/src/main/resources/assets/opencomputers/lang/en_US.lang @@ -23,6 +23,7 @@ tile.oc.hologram2.name=Hologram Projector (Tier 2) tile.oc.keyboard.name=Keyboard tile.oc.microcontroller.name=Microcontroller tile.oc.motionSensor.name=Motion Sensor +tile.oc.netSplitter.name=Net Splitter tile.oc.powerConverter.name=Power Converter tile.oc.powerDistributor.name=Power Distributor tile.oc.print.name=3D Print @@ -37,7 +38,7 @@ tile.oc.screen2.name=Screen (Tier 2) tile.oc.screen3.name=Screen (Tier 3) tile.oc.serverRack.name=Server Rack tile.oc.switch.name=§cSwitch§7 -tile.oc.netSplitter.name=Net Splitter +tile.oc.transposer.name=Transposer tile.oc.waypoint.name=Waypoint # Items @@ -348,6 +349,7 @@ oc:tooltip.Tier=§8Tier %s oc:tooltip.NetSplitter=Acts as a dynamic connector. Connectivity of each side can be toggled by hitting it with a wrench. Connectivity of all sides can be inverted by applying a redstone signal. oc:tooltip.TooLong=Hold [§f%s§7] for a detailed tooltip. oc:tooltip.Transistor=A basic element in most other computer parts. It's a bit twisted, but it does the job. +oc:tooltip.Transposer=Allows automated transferral of items and fluids between adjacent inventories and fluid containers. oc:tooltip.UpgradeAngel=Allows robots to place blocks in thin air, even if there is no point of reference. oc:tooltip.UpgradeBattery=Increase the amount of energy a device can store, allowing it work longer without having to be recharged. [nl] Capacity: §f%s§7 oc:tooltip.UpgradeChunkloader=If a robot moves in a forest and no one is around to see it, does it really move? This upgrades makes sure it does. It keeps the chunk a device is in loaded, but continually consumes energy while active. diff --git a/src/main/resources/assets/opencomputers/recipes/default.recipes b/src/main/resources/assets/opencomputers/recipes/default.recipes index 2350ace4a..79eedf014 100644 --- a/src/main/resources/assets/opencomputers/recipes/default.recipes +++ b/src/main/resources/assets/opencomputers/recipes/default.recipes @@ -634,6 +634,12 @@ screen3 { [yellowDust, "oc:circuitChip3", glass] [obsidian, yellowDust, obsidian]] } +transposer { + input: [[ingotIron, "oc:inventoryControllerUpgrade", ingotIron] + [hopper, bucket, hopper] + [ingotIron, "oc:tankControllerUpgrade", ingotIron]] + output: 4 +} waypoint { input: [[ingotIron, "oc:circuitChip1", ingotIron] ["oc:materialTransistor", "oc:materialInterweb", "oc:materialTransistor"], diff --git a/src/main/resources/assets/opencomputers/textures/blocks/TransposerOn.png b/src/main/resources/assets/opencomputers/textures/blocks/TransposerOn.png new file mode 100644 index 0000000000000000000000000000000000000000..0f2a818a7a4d31a43a585a26e9268dc8b50e964c GIT binary patch literal 154 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbL!WQl7;NpOBzNqJ&XDuZK6ep0G} zXKrG8YEWuoN@d~6R2!fowg8_HSK~9r|NsAg>9fNdD8f_{FVdQ&MBb@0JnE6JOBUy literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/opencomputers/textures/blocks/TransposerSide.png b/src/main/resources/assets/opencomputers/textures/blocks/TransposerSide.png new file mode 100644 index 0000000000000000000000000000000000000000..8d10906de865a04c23ded7b18434eaead239daf8 GIT binary patch literal 523 zcmV+m0`&cfP)e zI5-*_8b3cj3=9kp4-XL$5fBg%5)u*}9UUhpCkF=yHa0d;P*6lfL^U-vLPA0c3JMz= z8#y^SM@L6JJv}}?K2A5Ku z2nh*OQ&Sij7$G4cNJvN{BO^mYLk$fLS65e6RaI0}R69C4Gcz+hJUl8YDh>_~FfcGa zK0PijE+Qf#GBPqvO-(N^FDNJ|H#av84h=&?LYmX%82|tP)k#D_RCwAfkcV!=FbqUb zmaJ`A-f?!)z4zYj|Nm2|qK5+sJb>hZU`fcq$f*HZH{GhaXu6s17IT8SC{$e^zSp%Y z!WF=tegEm5x6Zr1yrz+vDofY*oO_hz4S?yHwU%cYKk@9~n841)a-IO^=i?m6tBn=e zpZM#zpdIb%`yYtYpD_pC^y85rB)C}WhH`w|Z^Jec*jB1_1by4(oas9u@!q N002ovPDHLkV1j96u+9Jg literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/opencomputers/textures/blocks/TransposerTop.png b/src/main/resources/assets/opencomputers/textures/blocks/TransposerTop.png new file mode 100644 index 0000000000000000000000000000000000000000..63f2b8fd035707086d939034665181e18ffeab18 GIT binary patch literal 425 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbL!WQl7;NpOBzNqJ&XDuZK6ep0G} zXKrG8YEWuoN@d~6R2!h8x&WULS4l}p2?+@-;o;#f zE-o@MG7%9GuCA`m&d$QZ!m+Wjva+(Fp`nhBjz&gC0s;bdc6K^CIwhTDx{@nfY zR^7n(QyZQueKBO35oW-7Qk*kUru0aBuu_@}r)DHW1&>nGbZ)j+pBEkAKXigiBKBh6 zvb!FyuimKjD|Me(-%uze%_{uz*#3z&VX~Gx7Bs|P%nfsN7vY#_c`15>?F{RU-0zN` zomj9>(!g#-*KQA?=x8O8zo9#6Mooz|3Itn)8oF`NqjW P&oFqp`njxgN@xNA>Klzn literal 0 HcmV?d00001 diff --git a/src/main/scala/li/cil/oc/Constants.scala b/src/main/scala/li/cil/oc/Constants.scala index 78b5ac786..9638f6b4f 100644 --- a/src/main/scala/li/cil/oc/Constants.scala +++ b/src/main/scala/li/cil/oc/Constants.scala @@ -25,6 +25,7 @@ object Constants { final val Keyboard = "keyboard" final val Microcontroller = "microcontroller" final val MotionSensor = "motionSensor" + final val NetSplitter = "netSplitter" final val PowerConverter = "powerConverter" final val PowerDistributor = "powerDistributor" final val Print = "print" @@ -39,7 +40,7 @@ object Constants { final val ScreenTier3 = "screen3" final val ServerRack = "serverRack" final val Switch = "switch" - final val NetSplitter = "netSplitter" + final val Transposer = "transposer" final val Waypoint = "waypoint" def Case(tier: Int) = ItemUtils.caseNameWithTierSuffix("case", tier) diff --git a/src/main/scala/li/cil/oc/Settings.scala b/src/main/scala/li/cil/oc/Settings.scala index baeed46bf..0846170be 100644 --- a/src/main/scala/li/cil/oc/Settings.scala +++ b/src/main/scala/li/cil/oc/Settings.scala @@ -201,6 +201,7 @@ class Settings(val config: Config) { val dataCardComplex = config.getDouble("power.cost.dataCardComplex") max 0 val dataCardComplexByte = config.getDouble("power.cost.dataCardComplexByte") max 0 val dataCardAsymmetric = config.getDouble("power.cost.dataCardAsymmetric") max 0 + val transposerCost = config.getDouble("power.cost.transposer") max 0 // power.rate val accessPointRate = config.getDouble("power.rate.accessPoint") max 0 diff --git a/src/main/scala/li/cil/oc/client/PacketHandler.scala b/src/main/scala/li/cil/oc/client/PacketHandler.scala index e05f3c4d9..e2f16d984 100644 --- a/src/main/scala/li/cil/oc/client/PacketHandler.scala +++ b/src/main/scala/li/cil/oc/client/PacketHandler.scala @@ -9,11 +9,11 @@ import li.cil.oc.Settings import li.cil.oc.api.component import li.cil.oc.api.event.FileSystemAccessEvent import li.cil.oc.client.renderer.PetRenderer +import li.cil.oc.common.Loot import li.cil.oc.common.PacketType import li.cil.oc.common.container import li.cil.oc.common.tileentity._ import li.cil.oc.common.tileentity.traits._ -import li.cil.oc.common.Loot import li.cil.oc.common.{PacketHandler => CommonPacketHandler} import li.cil.oc.util.Audio import li.cil.oc.util.ExtendedWorld._ @@ -79,6 +79,7 @@ object PacketHandler extends CommonPacketHandler { case PacketType.ServerPresence => onServerPresence(p) case PacketType.Sound => onSound(p) case PacketType.SoundPattern => onSoundPattern(p) + case PacketType.TransposerActivity => onTransposerActivity(p) case PacketType.WaypointLabel => onWaypointLabel(p) case _ => // Invalid packet. } @@ -263,6 +264,15 @@ object PacketHandler extends CommonPacketHandler { } } + def onNetSplitterState(p: PacketParser) = + p.readTileEntity[NetSplitter]() match { + case Some(t) => + t.isInverted = p.readBoolean() + t.openSides = t.uncompressSides(p.readByte()) + t.world.markBlockForUpdate(t.x, t.y, t.z) + case _ => // Invalid packet. + } + def onParticleEffect(p: PacketParser) = { val dimension = p.readInt() world(p.player, dimension) match { @@ -592,15 +602,6 @@ object PacketHandler extends CommonPacketHandler { buffer.rawSetForeground(col, row, color) } - def onNetSplitterState(p: PacketParser) = - p.readTileEntity[NetSplitter]() match { - case Some(t) => - t.isInverted = p.readBoolean() - t.openSides = t.uncompressSides(p.readByte()) - t.world.markBlockForUpdate(t.x, t.y, t.z) - case _ => // Invalid packet. - } - def onScreenTouchMode(p: PacketParser) = p.readTileEntity[Screen]() match { case Some(t) => t.invertTouchMode = p.readBoolean() @@ -641,6 +642,12 @@ object PacketHandler extends CommonPacketHandler { } } + def onTransposerActivity(p: PacketParser) = + p.readTileEntity[Transposer]() match { + case Some(transposer) => transposer.lastOperation = System.currentTimeMillis() + case _ => // Invalid packet. + } + def onWaypointLabel(p: PacketParser) = p.readTileEntity[Waypoint]() match { case Some(waypoint) => waypoint.label = p.readUTF() diff --git a/src/main/scala/li/cil/oc/client/Proxy.scala b/src/main/scala/li/cil/oc/client/Proxy.scala index 45930095c..c5a174afb 100644 --- a/src/main/scala/li/cil/oc/client/Proxy.scala +++ b/src/main/scala/li/cil/oc/client/Proxy.scala @@ -61,6 +61,7 @@ private[oc] class Proxy extends CommonProxy { else ClientRegistry.bindTileEntitySpecialRenderer(classOf[tileentity.Hologram], HologramRendererFallback) ClientRegistry.bindTileEntitySpecialRenderer(classOf[tileentity.Microcontroller], MicrocontrollerRenderer) + ClientRegistry.bindTileEntitySpecialRenderer(classOf[tileentity.NetSplitter], NetSplitterRenderer) ClientRegistry.bindTileEntitySpecialRenderer(classOf[tileentity.PowerDistributor], PowerDistributorRenderer) ClientRegistry.bindTileEntitySpecialRenderer(classOf[tileentity.Printer], PrinterRenderer) ClientRegistry.bindTileEntitySpecialRenderer(classOf[tileentity.Raid], RaidRenderer) @@ -70,7 +71,7 @@ private[oc] class Proxy extends CommonProxy { ClientRegistry.bindTileEntitySpecialRenderer(classOf[tileentity.Relay], SwitchRenderer) ClientRegistry.bindTileEntitySpecialRenderer(classOf[tileentity.RobotProxy], RobotRenderer) ClientRegistry.bindTileEntitySpecialRenderer(classOf[tileentity.Screen], ScreenRenderer) - ClientRegistry.bindTileEntitySpecialRenderer(classOf[tileentity.NetSplitter], NetSplitterRenderer) + ClientRegistry.bindTileEntitySpecialRenderer(classOf[tileentity.Transposer], TransposerRenderer) MinecraftForgeClient.registerItemRenderer(Items.get(Constants.ItemName.Floppy).createItemStack(1).getItem, ItemRenderer) MinecraftForgeClient.registerItemRenderer(Items.get(Constants.BlockName.Print).createItemStack(1).getItem, ItemRenderer) diff --git a/src/main/scala/li/cil/oc/client/Textures.scala b/src/main/scala/li/cil/oc/client/Textures.scala index 195f400da..e229115ae 100644 --- a/src/main/scala/li/cil/oc/client/Textures.scala +++ b/src/main/scala/li/cil/oc/client/Textures.scala @@ -104,6 +104,10 @@ object Textures { var iconOn: IIcon = _ } + object Transposer { + var iconOn: IIcon = _ + } + def init(tm: TextureManager) { tm.bindTexture(fontAntiAliased) tm.bindTexture(fontAliased) diff --git a/src/main/scala/li/cil/oc/client/renderer/block/BlockRenderer.scala b/src/main/scala/li/cil/oc/client/renderer/block/BlockRenderer.scala index 782c7dcc9..8b6a1c051 100644 --- a/src/main/scala/li/cil/oc/client/renderer/block/BlockRenderer.scala +++ b/src/main/scala/li/cil/oc/client/renderer/block/BlockRenderer.scala @@ -67,6 +67,13 @@ object BlockRenderer extends ISimpleBlockRenderingHandler { Tessellator.instance.draw() RenderState.checkError(getClass.getName + ".renderInventoryBlock: splitter") + case _: Transposer => + GL11.glTranslatef(-0.5f, -0.5f, -0.5f) + Tessellator.instance.startDrawingQuads() + Transposer.render(block, metadata, renderer) + Tessellator.instance.draw() + + RenderState.checkError(getClass.getName + ".renderInventoryBlock: transposer") case _ => block match { case simple: SimpleBlock => @@ -103,7 +110,7 @@ object BlockRenderer extends ISimpleBlockRenderingHandler { RenderState.checkError(getClass.getName + ".renderWorldBlock: assembler") true - case cable: tileentity.Cable => + case _: tileentity.Cable => Cable.render(world, x, y, z, block, renderer) RenderState.checkError(getClass.getName + ".renderWorldBlock: cable") @@ -127,7 +134,7 @@ object BlockRenderer extends ISimpleBlockRenderingHandler { RenderState.checkError(getClass.getName + ".renderWorldBlock: print") true - case printer: tileentity.Printer => + case _: tileentity.Printer => Printer.render(block, x, y, z, renderer) RenderState.checkError(getClass.getName + ".renderWorldBlock: printer") @@ -144,6 +151,12 @@ object BlockRenderer extends ISimpleBlockRenderingHandler { RenderState.checkError(getClass.getName + ".renderWorldBlock: splitter") + true + case _: tileentity.Transposer => + Transposer.render(block, x, y, z, renderer) + + RenderState.checkError(getClass.getName + ".renderWorldBlock: transposer") + true case _ => val result = renderer.renderStandardBlock(block, x, y, z) @@ -158,7 +171,8 @@ object BlockRenderer extends ISimpleBlockRenderingHandler { block.isInstanceOf[Hologram] || block.isInstanceOf[Printer] || block.isInstanceOf[Print] || - block.isInstanceOf[NetSplitter] + block.isInstanceOf[NetSplitter] || + block.isInstanceOf[Transposer] // The texture flip this works around only seems to occur for blocks with custom block renderers? def patchedRenderer(renderer: RenderBlocks, block: Block) = diff --git a/src/main/scala/li/cil/oc/client/renderer/block/Transposer.scala b/src/main/scala/li/cil/oc/client/renderer/block/Transposer.scala new file mode 100644 index 000000000..7d22756a5 --- /dev/null +++ b/src/main/scala/li/cil/oc/client/renderer/block/Transposer.scala @@ -0,0 +1,124 @@ +package li.cil.oc.client.renderer.block + +import net.minecraft.block.Block +import net.minecraft.client.renderer.RenderBlocks + +object Transposer { + def render(block: Block, x: Int, y: Int, z: Int, renderer: RenderBlocks) { + val previousRenderAllFaces = renderer.renderAllFaces + renderer.renderAllFaces = true + + // Corners. + renderer.setRenderBounds(0 / 16f, 0 / 16f, 0 / 16f, 7 / 16f, 7 / 16f, 7 / 16f) + renderer.renderStandardBlock(block, x, y, z) + renderer.setRenderBounds(0 / 16f, 0 / 16f, 9 / 16f, 7 / 16f, 7 / 16f, 16 / 16f) + renderer.renderStandardBlock(block, x, y, z) + renderer.setRenderBounds(0 / 16f, 9 / 16f, 0 / 16f, 7 / 16f, 16 / 16f, 7 / 16f) + renderer.renderStandardBlock(block, x, y, z) + renderer.setRenderBounds(0 / 16f, 9 / 16f, 9 / 16f, 7 / 16f, 16 / 16f, 16 / 16f) + renderer.renderStandardBlock(block, x, y, z) + renderer.setRenderBounds(9 / 16f, 0 / 16f, 0 / 16f, 16 / 16f, 7 / 16f, 7 / 16f) + renderer.renderStandardBlock(block, x, y, z) + renderer.setRenderBounds(9 / 16f, 0 / 16f, 9 / 16f, 16 / 16f, 7 / 16f, 16 / 16f) + renderer.renderStandardBlock(block, x, y, z) + renderer.setRenderBounds(9 / 16f, 9 / 16f, 0 / 16f, 16 / 16f, 16 / 16f, 7 / 16f) + renderer.renderStandardBlock(block, x, y, z) + renderer.setRenderBounds(9 / 16f, 9 / 16f, 9 / 16f, 16 / 16f, 16 / 16f, 16 / 16f) + renderer.renderStandardBlock(block, x, y, z) + + // Gaps. + renderer.setRenderBounds(0 / 16f, 0 / 16f, 7 / 16f, 5 / 16f, 5 / 16f, 9 / 16f) + renderer.renderStandardBlock(block, x, y, z) + renderer.setRenderBounds(0 / 16f, 11 / 16f, 7 / 16f, 5 / 16f, 16 / 16f, 9 / 16f) + renderer.renderStandardBlock(block, x, y, z) + renderer.setRenderBounds(11 / 16f, 0 / 16f, 7 / 16f, 16 / 16f, 5 / 16f, 9 / 16f) + renderer.renderStandardBlock(block, x, y, z) + renderer.setRenderBounds(11 / 16f, 11 / 16f, 7 / 16f, 16 / 16f, 16 / 16f, 9 / 16f) + renderer.renderStandardBlock(block, x, y, z) + + renderer.setRenderBounds(0 / 16f, 7 / 16f, 0 / 16f, 5 / 16f, 9 / 16f, 5 / 16f) + renderer.renderStandardBlock(block, x, y, z) + renderer.setRenderBounds(0 / 16f, 7 / 16f, 11 / 16f, 5 / 16f, 9 / 16f, 16 / 16f) + renderer.renderStandardBlock(block, x, y, z) + renderer.setRenderBounds(11 / 16f, 7 / 16f, 0 / 16f, 16 / 16f, 9 / 16f, 5 / 16f) + renderer.renderStandardBlock(block, x, y, z) + renderer.setRenderBounds(11 / 16f, 7 / 16f, 11 / 16f, 16 / 16f, 9 / 16f, 16 / 16f) + renderer.renderStandardBlock(block, x, y, z) + + renderer.setRenderBounds(7 / 16f, 0 / 16f, 0 / 16f, 9 / 16f, 5 / 16f, 5 / 16f) + renderer.renderStandardBlock(block, x, y, z) + renderer.setRenderBounds(7 / 16f, 0 / 16f, 11 / 16f, 9 / 16f, 5 / 16f, 16 / 16f) + renderer.renderStandardBlock(block, x, y, z) + renderer.setRenderBounds(7 / 16f, 11 / 16f, 0 / 16f, 9 / 16f, 16 / 16f, 5 / 16f) + renderer.renderStandardBlock(block, x, y, z) + renderer.setRenderBounds(7 / 16f, 11 / 16f, 11 / 16f, 9 / 16f, 16 / 16f, 16 / 16f) + renderer.renderStandardBlock(block, x, y, z) + + // Core. + renderer.setRenderBounds(1 / 16f, 1 / 16f, 1 / 16f, 15 / 16f, 15 / 16f, 15 / 16f) + renderer.renderStandardBlock(block, x, y, z) + + renderer.renderAllFaces = previousRenderAllFaces + } + + def render(block: Block, metadata: Int, renderer: RenderBlocks) { + // Corners. + renderer.setRenderBounds(0 / 16f, 0 / 16f, 0 / 16f, 7 / 16f, 7 / 16f, 7 / 16f) + renderAllFaces(block, metadata, renderer) + renderer.setRenderBounds(0 / 16f, 0 / 16f, 9 / 16f, 7 / 16f, 7 / 16f, 16 / 16f) + renderAllFaces(block, metadata, renderer) + renderer.setRenderBounds(0 / 16f, 9 / 16f, 0 / 16f, 7 / 16f, 16 / 16f, 7 / 16f) + renderAllFaces(block, metadata, renderer) + renderer.setRenderBounds(0 / 16f, 9 / 16f, 9 / 16f, 7 / 16f, 16 / 16f, 16 / 16f) + renderAllFaces(block, metadata, renderer) + renderer.setRenderBounds(9 / 16f, 0 / 16f, 0 / 16f, 16 / 16f, 7 / 16f, 7 / 16f) + renderAllFaces(block, metadata, renderer) + renderer.setRenderBounds(9 / 16f, 0 / 16f, 9 / 16f, 16 / 16f, 7 / 16f, 16 / 16f) + renderAllFaces(block, metadata, renderer) + renderer.setRenderBounds(9 / 16f, 9 / 16f, 0 / 16f, 16 / 16f, 16 / 16f, 7 / 16f) + renderAllFaces(block, metadata, renderer) + renderer.setRenderBounds(9 / 16f, 9 / 16f, 9 / 16f, 16 / 16f, 16 / 16f, 16 / 16f) + renderAllFaces(block, metadata, renderer) + + // Gaps. + renderer.setRenderBounds(0 / 16f, 0 / 16f, 7 / 16f, 5 / 16f, 5 / 16f, 9 / 16f) + renderAllFaces(block, metadata, renderer) + renderer.setRenderBounds(0 / 16f, 11 / 16f, 7 / 16f, 5 / 16f, 16 / 16f, 9 / 16f) + renderAllFaces(block, metadata, renderer) + renderer.setRenderBounds(11 / 16f, 0 / 16f, 7 / 16f, 16 / 16f, 5 / 16f, 9 / 16f) + renderAllFaces(block, metadata, renderer) + renderer.setRenderBounds(11 / 16f, 11 / 16f, 7 / 16f, 16 / 16f, 16 / 16f, 9 / 16f) + renderAllFaces(block, metadata, renderer) + + renderer.setRenderBounds(0 / 16f, 7 / 16f, 0 / 16f, 5 / 16f, 9 / 16f, 5 / 16f) + renderAllFaces(block, metadata, renderer) + renderer.setRenderBounds(0 / 16f, 7 / 16f, 11 / 16f, 5 / 16f, 9 / 16f, 16 / 16f) + renderAllFaces(block, metadata, renderer) + renderer.setRenderBounds(11 / 16f, 7 / 16f, 0 / 16f, 16 / 16f, 9 / 16f, 5 / 16f) + renderAllFaces(block, metadata, renderer) + renderer.setRenderBounds(11 / 16f, 7 / 16f, 11 / 16f, 16 / 16f, 9 / 16f, 16 / 16f) + renderAllFaces(block, metadata, renderer) + + renderer.setRenderBounds(7 / 16f, 0 / 16f, 0 / 16f, 9 / 16f, 5 / 16f, 5 / 16f) + renderAllFaces(block, metadata, renderer) + renderer.setRenderBounds(7 / 16f, 0 / 16f, 11 / 16f, 9 / 16f, 5 / 16f, 16 / 16f) + renderAllFaces(block, metadata, renderer) + renderer.setRenderBounds(7 / 16f, 11 / 16f, 0 / 16f, 9 / 16f, 16 / 16f, 5 / 16f) + renderAllFaces(block, metadata, renderer) + renderer.setRenderBounds(7 / 16f, 11 / 16f, 11 / 16f, 9 / 16f, 16 / 16f, 16 / 16f) + renderAllFaces(block, metadata, renderer) + + // Core. + renderer.setRenderBounds(1 / 16f, 1 / 16f, 1 / 16f, 15 / 16f, 15 / 16f, 15 / 16f) + renderAllFaces(block, metadata, renderer) + } + + private def renderAllFaces(block: Block, metadata: Int, renderer: RenderBlocks): Unit = { + BlockRenderer.renderFaceYPos(block, metadata, renderer) + BlockRenderer.renderFaceYNeg(block, metadata, renderer) + BlockRenderer.renderFaceXPos(block, metadata, renderer) + BlockRenderer.renderFaceXNeg(block, metadata, renderer) + BlockRenderer.renderFaceZPos(block, metadata, renderer) + BlockRenderer.renderFaceZNeg(block, metadata, renderer) + } +} diff --git a/src/main/scala/li/cil/oc/client/renderer/tileentity/TransposerRenderer.scala b/src/main/scala/li/cil/oc/client/renderer/tileentity/TransposerRenderer.scala new file mode 100644 index 000000000..ccd146088 --- /dev/null +++ b/src/main/scala/li/cil/oc/client/renderer/tileentity/TransposerRenderer.scala @@ -0,0 +1,77 @@ +package li.cil.oc.client.renderer.tileentity + +import li.cil.oc.client.Textures +import li.cil.oc.common.tileentity +import li.cil.oc.util.RenderState +import net.minecraft.client.renderer.Tessellator +import net.minecraft.client.renderer.texture.TextureMap +import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer +import net.minecraft.tileentity.TileEntity +import org.lwjgl.opengl.GL11 + +object TransposerRenderer extends TileEntitySpecialRenderer { + override def renderTileEntityAt(tileEntity: TileEntity, x: Double, y: Double, z: Double, f: Float) { + RenderState.checkError(getClass.getName + ".renderTileEntityAt: entering (aka: wasntme)") + + val transposer = tileEntity.asInstanceOf[tileentity.Transposer] + val activity = math.max(0, 1 - (System.currentTimeMillis() - transposer.lastOperation) / 1000.0) + if (activity > 0) { + GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS) + + RenderState.disableLighting() + RenderState.makeItBlend() + RenderState.setBlendAlpha(activity.toFloat) + + GL11.glPushMatrix() + + GL11.glTranslated(x + 0.5, y + 0.5, z + 0.5) + GL11.glScaled(1.0025, -1.0025, 1.0025) + GL11.glTranslatef(-0.5f, -0.5f, -0.5f) + + bindTexture(TextureMap.locationBlocksTexture) + val t = Tessellator.instance + t.startDrawingQuads() + + val icon = Textures.Transposer.iconOn + + t.addVertexWithUV(0, 1, 0, icon.getMaxU, icon.getMinV) + t.addVertexWithUV(1, 1, 0, icon.getMinU, icon.getMinV) + t.addVertexWithUV(1, 1, 1, icon.getMinU, icon.getMaxV) + t.addVertexWithUV(0, 1, 1, icon.getMaxU, icon.getMaxV) + + t.addVertexWithUV(0, 0, 0, icon.getMaxU, icon.getMaxV) + t.addVertexWithUV(0, 0, 1, icon.getMaxU, icon.getMinV) + t.addVertexWithUV(1, 0, 1, icon.getMinU, icon.getMinV) + t.addVertexWithUV(1, 0, 0, icon.getMinU, icon.getMaxV) + + t.addVertexWithUV(1, 1, 0, icon.getMinU, icon.getMaxV) + t.addVertexWithUV(0, 1, 0, icon.getMaxU, icon.getMaxV) + t.addVertexWithUV(0, 0, 0, icon.getMaxU, icon.getMinV) + t.addVertexWithUV(1, 0, 0, icon.getMinU, icon.getMinV) + + t.addVertexWithUV(0, 1, 1, icon.getMinU, icon.getMaxV) + t.addVertexWithUV(1, 1, 1, icon.getMaxU, icon.getMaxV) + t.addVertexWithUV(1, 0, 1, icon.getMaxU, icon.getMinV) + t.addVertexWithUV(0, 0, 1, icon.getMinU, icon.getMinV) + + t.addVertexWithUV(0, 1, 0, icon.getMinU, icon.getMaxV) + t.addVertexWithUV(0, 1, 1, icon.getMaxU, icon.getMaxV) + t.addVertexWithUV(0, 0, 1, icon.getMaxU, icon.getMinV) + t.addVertexWithUV(0, 0, 0, icon.getMinU, icon.getMinV) + + t.addVertexWithUV(1, 1, 1, icon.getMinU, icon.getMaxV) + t.addVertexWithUV(1, 1, 0, icon.getMaxU, icon.getMaxV) + t.addVertexWithUV(1, 0, 0, icon.getMaxU, icon.getMinV) + t.addVertexWithUV(1, 0, 1, icon.getMinU, icon.getMinV) + + t.draw() + + RenderState.enableLighting() + + GL11.glPopMatrix() + GL11.glPopAttrib() + } + + RenderState.checkError(getClass.getName + ".renderTileEntityAt: leaving") + } +} diff --git a/src/main/scala/li/cil/oc/common/PacketType.scala b/src/main/scala/li/cil/oc/common/PacketType.scala index 24ad97452..16f9be361 100644 --- a/src/main/scala/li/cil/oc/common/PacketType.scala +++ b/src/main/scala/li/cil/oc/common/PacketType.scala @@ -21,6 +21,7 @@ object PacketType extends Enumeration { HologramTranslation, HologramValues, LootDisk, + NetSplitterState, ParticleEffect, PetVisibility, // Goes both ways. PowerState, @@ -50,11 +51,11 @@ object PacketType extends Enumeration { TextBufferMultiRawSetBackground, TextBufferMultiRawSetForeground, TextBufferPowerChange, - NetSplitterState, ScreenTouchMode, ServerPresence, Sound, SoundPattern, + TransposerActivity, WaypointLabel, // Goes both ways. // Client -> Server diff --git a/src/main/scala/li/cil/oc/common/block/Geolyzer.scala b/src/main/scala/li/cil/oc/common/block/Geolyzer.scala index b79c2ea03..725cca253 100644 --- a/src/main/scala/li/cil/oc/common/block/Geolyzer.scala +++ b/src/main/scala/li/cil/oc/common/block/Geolyzer.scala @@ -1,5 +1,7 @@ package li.cil.oc.common.block +import cpw.mods.fml.relauncher.Side +import cpw.mods.fml.relauncher.SideOnly import li.cil.oc.Settings import li.cil.oc.client.Textures import li.cil.oc.common.tileentity @@ -19,6 +21,7 @@ class Geolyzer extends SimpleBlock { Some("GeolyzerSide") ) + @SideOnly(Side.CLIENT) override def registerBlockIcons(iconRegister: IIconRegister) = { super.registerBlockIcons(iconRegister) Textures.Geolyzer.iconTopOn = iconRegister.registerIcon(Settings.resourceDomain + ":GeolyzerTopOn") diff --git a/src/main/scala/li/cil/oc/common/block/NetSplitter.scala b/src/main/scala/li/cil/oc/common/block/NetSplitter.scala index 64892defa..609592753 100644 --- a/src/main/scala/li/cil/oc/common/block/NetSplitter.scala +++ b/src/main/scala/li/cil/oc/common/block/NetSplitter.scala @@ -23,8 +23,8 @@ class NetSplitter extends RedstoneAware { Some("NetSplitterSide") ) - @SideOnly(Side.CLIENT) override - def registerBlockIcons(iconRegister: IIconRegister): Unit = { + @SideOnly(Side.CLIENT) + override def registerBlockIcons(iconRegister: IIconRegister): Unit = { super.registerBlockIcons(iconRegister) Textures.NetSplitter.iconOn = iconRegister.registerIcon(Settings.resourceDomain + ":NetSplitterOn") } diff --git a/src/main/scala/li/cil/oc/common/block/Transposer.scala b/src/main/scala/li/cil/oc/common/block/Transposer.scala new file mode 100644 index 000000000..d0c717149 --- /dev/null +++ b/src/main/scala/li/cil/oc/common/block/Transposer.scala @@ -0,0 +1,36 @@ +package li.cil.oc.common.block + +import cpw.mods.fml.relauncher.Side +import cpw.mods.fml.relauncher.SideOnly +import li.cil.oc.Settings +import li.cil.oc.client.Textures +import li.cil.oc.common.tileentity +import net.minecraft.client.renderer.texture.IIconRegister +import net.minecraft.world.IBlockAccess +import net.minecraft.world.World +import net.minecraftforge.common.util.ForgeDirection + +class Transposer extends SimpleBlock { + override protected def customTextures = Array( + Some("TransposerTop"), + Some("TransposerTop"), + Some("TransposerSide"), + Some("TransposerSide"), + Some("TransposerSide"), + Some("TransposerSide") + ) + + @SideOnly(Side.CLIENT) + override def registerBlockIcons(iconRegister: IIconRegister): Unit = { + super.registerBlockIcons(iconRegister) + Textures.Transposer.iconOn = iconRegister.registerIcon(Settings.resourceDomain + ":TransposerOn") + } + + override def isSideSolid(world: IBlockAccess, x: Int, y: Int, z: Int, side: ForgeDirection): Boolean = false + + // ----------------------------------------------------------------------- // + + override def hasTileEntity(metadata: Int) = true + + override def createTileEntity(world: World, metadata: Int) = new tileentity.Transposer() +} diff --git a/src/main/scala/li/cil/oc/common/init/Blocks.scala b/src/main/scala/li/cil/oc/common/init/Blocks.scala index 73ea7bea2..feda54fbb 100644 --- a/src/main/scala/li/cil/oc/common/init/Blocks.scala +++ b/src/main/scala/li/cil/oc/common/init/Blocks.scala @@ -24,6 +24,7 @@ object Blocks { GameRegistry.registerTileEntity(classOf[tileentity.Geolyzer], Settings.namespace + "geolyzer") GameRegistry.registerTileEntity(classOf[tileentity.Microcontroller], Settings.namespace + "microcontroller") GameRegistry.registerTileEntity(classOf[tileentity.MotionSensor], Settings.namespace + "motion_sensor") + GameRegistry.registerTileEntity(classOf[tileentity.NetSplitter], Settings.namespace + "netSplitter") GameRegistry.registerTileEntity(classOf[tileentity.PowerConverter], Settings.namespace + "power_converter") GameRegistry.registerTileEntity(classOf[tileentity.PowerDistributor], Settings.namespace + "power_distributor") GameRegistry.registerTileEntity(classOf[tileentity.Print], Settings.namespace + "print") @@ -35,7 +36,7 @@ object Blocks { GameRegistry.registerTileEntity(classOf[tileentity.Switch], Settings.namespace + "switch") GameRegistry.registerTileEntity(classOf[tileentity.Screen], Settings.namespace + "screen") GameRegistry.registerTileEntity(classOf[tileentity.ServerRack], Settings.namespace + "serverRack") - GameRegistry.registerTileEntity(classOf[tileentity.NetSplitter], Settings.namespace + "netSplitter") + GameRegistry.registerTileEntity(classOf[tileentity.Transposer], Settings.namespace + "transposer") GameRegistry.registerTileEntity(classOf[tileentity.Waypoint], Settings.namespace + "waypoint") Items.registerBlock(new AccessPoint(), Constants.BlockName.AccessPoint) @@ -81,5 +82,8 @@ object Blocks { // v1.5.14 Recipes.addBlock(new NetSplitter(), Constants.BlockName.NetSplitter, "oc:netSplitter") + + // v1.5.16 + Recipes.addBlock(new Transposer(), Constants.BlockName.Transposer, "oc:transposer") } } diff --git a/src/main/scala/li/cil/oc/common/tileentity/Transposer.scala b/src/main/scala/li/cil/oc/common/tileentity/Transposer.scala new file mode 100644 index 000000000..b3e43b9f4 --- /dev/null +++ b/src/main/scala/li/cil/oc/common/tileentity/Transposer.scala @@ -0,0 +1,25 @@ +package li.cil.oc.common.tileentity + +import li.cil.oc.server.component +import net.minecraft.nbt.NBTTagCompound + +class Transposer extends traits.Environment { + val transposer = new component.Transposer(this) + + def node = transposer.node + + // Used on client side to check whether to render activity indicators. + var lastOperation = 0L + + override def canUpdate = false + + override def readFromNBTForServer(nbt: NBTTagCompound) { + super.readFromNBTForServer(nbt) + transposer.load(nbt) + } + + override def writeToNBTForServer(nbt: NBTTagCompound) { + super.writeToNBTForServer(nbt) + transposer.save(nbt) + } +} diff --git a/src/main/scala/li/cil/oc/server/PacketSender.scala b/src/main/scala/li/cil/oc/server/PacketSender.scala index 406462a4a..59e35652a 100644 --- a/src/main/scala/li/cil/oc/server/PacketSender.scala +++ b/src/main/scala/li/cil/oc/server/PacketSender.scala @@ -234,6 +234,16 @@ object PacketSender { } } + def sendNetSplitterState(t: tileentity.NetSplitter): Unit = { + val pb = new SimplePacketBuilder(PacketType.NetSplitterState) + + pb.writeTileEntity(t) + pb.writeBoolean(t.isInverted) + pb.writeByte(t.compressSides) + + pb.sendToPlayersNearTileEntity(t) + } + def sendParticleEffect(position: BlockPosition, name: String, count: Int, velocity: Double, direction: Option[ForgeDirection] = None): Unit = if (count > 0) { val pb = new SimplePacketBuilder(PacketType.ParticleEffect) @@ -529,16 +539,6 @@ object PacketSender { pb.sendToPlayersNearHost(host) } - def sendNetSplitterState(t: tileentity.NetSplitter): Unit = { - val pb = new SimplePacketBuilder(PacketType.NetSplitterState) - - pb.writeTileEntity(t) - pb.writeBoolean(t.isInverted) - pb.writeByte(t.compressSides) - - pb.sendToPlayersNearTileEntity(t) - } - def sendScreenTouchMode(t: tileentity.Screen, value: Boolean) { val pb = new SimplePacketBuilder(PacketType.ScreenTouchMode) @@ -619,6 +619,14 @@ object PacketSender { pb.sendToNearbyPlayers(world, x, y, z, Option(32)) } + def sendTransposerActivity(t: tileentity.Transposer) { + val pb = new SimplePacketBuilder(PacketType.TransposerActivity) + + pb.writeTileEntity(t) + + pb.sendToPlayersNearTileEntity(t, Option(32)) + } + def sendWaypointLabel(t: Waypoint): Unit = { val pb = new SimplePacketBuilder(PacketType.WaypointLabel) diff --git a/src/main/scala/li/cil/oc/server/component/Transposer.scala b/src/main/scala/li/cil/oc/server/component/Transposer.scala new file mode 100644 index 000000000..636e1e27e --- /dev/null +++ b/src/main/scala/li/cil/oc/server/component/Transposer.scala @@ -0,0 +1,68 @@ +package li.cil.oc.server.component + +import li.cil.oc.Settings +import li.cil.oc.api +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 li.cil.oc.common.tileentity +import li.cil.oc.server.{PacketSender => ServerPacketSender} +import li.cil.oc.util.BlockPosition +import li.cil.oc.util.ExtendedArguments._ +import li.cil.oc.util.FluidUtils +import li.cil.oc.util.InventoryUtils +import net.minecraftforge.common.util.ForgeDirection + +import scala.language.existentials + +class Transposer(val host: tileentity.Transposer) extends prefab.ManagedEnvironment with traits.WorldInventoryAnalytics with traits.WorldTankAnalytics { + override val node = api.Network.newNode(this, Visibility.Network). + withComponent("transposer"). + withConnector(). + create() + + override def position = BlockPosition(host) + + override protected def checkSideForAction(args: Arguments, n: Int) = + args.checkSide(n, ForgeDirection.VALID_DIRECTIONS: _*) + + @Callback(doc = """function(sourceSide:number, sinkSide:number[, count:number[, sourceSlot:number, sinkSlot:number]]):number -- Transfer some items between two inventories.""") + def transferItem(context: Context, args: Arguments): Array[AnyRef] = { + val sourceSide = checkSideForAction(args, 0) + val sourcePos = position.offset(sourceSide) + val sinkSide = checkSideForAction(args, 1) + val sinkPos = position.offset(sinkSide) + val count = args.optItemCount(2) + + if (node.tryChangeBuffer(-Settings.get.transposerCost)) { + ServerPacketSender.sendTransposerActivity(host) + + if (args.count > 3) { + val sourceSlot = args.checkSlot(InventoryUtils.inventoryAt(sourcePos).getOrElse(throw new IllegalArgumentException("no inventory")), 3) + val sinkSlot = args.checkSlot(InventoryUtils.inventoryAt(sinkPos).getOrElse(throw new IllegalArgumentException("no inventory")), 4) + + result(InventoryUtils.transferBetweenInventoriesSlotsAt(sourcePos, sourceSide.getOpposite, sourceSlot, sinkPos, Option(sinkSide.getOpposite), sinkSlot, count)) + } + else result(InventoryUtils.transferBetweenInventoriesAt(sourcePos, sourceSide.getOpposite, sinkPos, Option(sinkSide.getOpposite), count)) + } + else result(Unit, "not enough energy") + } + + @Callback(doc = """function(sourceSide:number, sinkSide:number[, count:number]):number -- Transfer some items between two inventories.""") + def transferFluid(context: Context, args: Arguments): Array[AnyRef] = { + val sourceSide = checkSideForAction(args, 0) + val sourcePos = position.offset(sourceSide) + val sinkSide = checkSideForAction(args, 1) + val sinkPos = position.offset(sinkSide) + val count = args.optFluidCount(2) + + if (node.tryChangeBuffer(-Settings.get.transposerCost)) { + ServerPacketSender.sendTransposerActivity(host) + + result(FluidUtils.transferBetweenFluidHandlersAt(sourcePos, sourceSide.getOpposite, sinkPos, sinkSide.getOpposite, count)) + } + else result(Unit, "not enough energy") + } +} 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 91a08b8fd..ee6254298 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 @@ -4,14 +4,9 @@ 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.util.ExtendedArguments._ -import li.cil.oc.util.ExtendedBlock._ -import li.cil.oc.util.ExtendedWorld._ +import li.cil.oc.util.FluidUtils 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 { @Callback(doc = "function(side:number):boolean -- Compare the fluid in the selected tank with the fluid on the specified side. Returns true if equal.") @@ -19,16 +14,10 @@ trait TankWorldControl extends TankAware with WorldAware with SideRestricted { val side = checkSideForAction(args, 0) fluidInTank(selectedTank) match { case Some(stack) => - val blockPos = position.offset(side) - if (world.blockExists(blockPos)) world.getTileEntity(blockPos) match { - case handler: IFluidHandler => - result(Option(handler.getTankInfo(side.getOpposite)).exists(_.exists(other => stack.isFluidEqual(other.fluid)))) - case _ => - val block = world.getBlock(blockPos) - val fluid = FluidRegistry.lookupFluidForBlock(block) - result(stack.getFluid == fluid) + FluidUtils.fluidHandlerAt(position.offset(side)) match { + case Some(handler) => result(Option(handler.getTankInfo(side.getOpposite)).exists(_.exists(other => stack.isFluidEqual(other.fluid)))) + case _ => result(false) } - else result(false) case _ => result(false) } } @@ -36,18 +25,14 @@ trait TankWorldControl extends TankAware with WorldAware with SideRestricted { @Callback(doc = "function(side:boolean[, amount:number=1000]):boolean, number or string -- Drains the specified amount of fluid from the specified side. Returns the amount drained, or an error message.") def drain(context: Context, args: Arguments): Array[AnyRef] = { val facing = checkSideForAction(args, 0) - val count = args.optFluidCount(1) + val count = args.optFluidCount(1) max 0 getTank(selectedTank) match { case Some(tank) => val space = tank.getCapacity - tank.getFluidAmount val amount = math.min(count, space) - if (count > 0 && amount == 0) { - result(Unit, "tank is full") - } - else { - val blockPos = position.offset(facing) - if (world.blockExists(blockPos)) world.getTileEntity(blockPos) match { - case handler: IFluidHandler => + if (count < 1 || amount > 0) { + FluidUtils.fluidHandlerAt(position.offset(facing)) match { + case Some(handler) => tank.getFluid match { case stack: FluidStack => val drained = handler.drain(facing.getOpposite, new FluidStack(stack, amount), true) @@ -60,36 +45,10 @@ trait TankWorldControl extends TankAware with WorldAware with SideRestricted { val transferred = tank.fill(handler.drain(facing.getOpposite, amount, true), true) result(transferred > 0, transferred) } - 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") - } + case _ => result(Unit, "incompatible or no fluid") } - else result(Unit, "incompatible or no fluid") } + else result(Unit, "tank is full") case _ => result(Unit, "no tank selected") } } @@ -97,49 +56,28 @@ trait TankWorldControl extends TankAware with WorldAware with SideRestricted { @Callback(doc = "function(side:number[, amount:number=1000]):boolean, number of string -- Eject the specified amount of fluid to the specified side. Returns the amount ejected or an error message.") def fill(context: Context, args: Arguments): Array[AnyRef] = { val facing = checkSideForAction(args, 0) - val count = args.optFluidCount(1) + val count = args.optFluidCount(1) max 0 getTank(selectedTank) match { case Some(tank) => val amount = math.min(count, tank.getFluidAmount) - if (count > 0 && amount == 0) { - result(Unit, "tank is empty") + if (count < 1 || amount > 0) { + FluidUtils.fluidHandlerAt(position.offset(facing)) match { + case Some(handler) => + tank.getFluid match { + case stack: FluidStack => + val filled = handler.fill(facing.getOpposite, new FluidStack(stack, amount), true) + if (filled > 0 || amount == 0) { + tank.drain(filled, true) + result(true, filled) + } + else result(Unit, "incompatible or no fluid") + case _ => + result(Unit, "tank is empty") + } + case _ => result(Unit, "no space") + } } - val blockPos = position.offset(facing) - if (world.blockExists(blockPos)) world.getTileEntity(blockPos) match { - case handler: IFluidHandler => - tank.getFluid match { - case stack: FluidStack => - val filled = handler.fill(facing.getOpposite, new FluidStack(stack, amount), true) - if (filled > 0 || amount == 0) { - tank.drain(filled, true) - result(true, filled) - } - else result(Unit, "incompatible or no fluid") - case _ => - result(Unit, "tank is empty") - } - case _ => - val block = world.getBlock(blockPos) - if (!block.isAir(blockPos) && !block.isReplaceable(blockPos)) { - result(Unit, "no space") - } - else if (tank.getFluidAmount < 1000) { - result(Unit, "tank is empty") - } - else if (!tank.getFluid.getFluid.canBePlacedInWorld) { - result(Unit, "incompatible fluid") - } - else { - val fluidBlock = tank.getFluid.getFluid.getBlock - tank.drain(1000, true) - world.breakBlock(blockPos) - world.setBlock(blockPos, fluidBlock) - // This fake neighbor update is required to get stills to start flowing. - world.notifyBlockOfNeighborChange(blockPos, world.getBlock(position)) - result(true, 1000) - } - } - else result(Unit, "no space") + else result(Unit, "tank is empty") case _ => result(Unit, "no tank selected") } } diff --git a/src/main/scala/li/cil/oc/server/component/traits/WorldTankAnalytics.scala b/src/main/scala/li/cil/oc/server/component/traits/WorldTankAnalytics.scala index a0a863fd1..ec7950223 100644 --- a/src/main/scala/li/cil/oc/server/component/traits/WorldTankAnalytics.scala +++ b/src/main/scala/li/cil/oc/server/component/traits/WorldTankAnalytics.scala @@ -5,15 +5,15 @@ 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.server.component.result -import li.cil.oc.util.ExtendedWorld._ -import net.minecraftforge.fluids.IFluidHandler +import li.cil.oc.util.FluidUtils trait WorldTankAnalytics extends WorldAware with SideRestricted { @Callback(doc = """function(side:number):number -- Get the amount of fluid in the tank on the specified side.""") def getTankLevel(context: Context, args: Arguments): Array[AnyRef] = { val facing = checkSideForAction(args, 0) - world.getTileEntity(position.offset(facing)) match { - case handler: IFluidHandler => + + FluidUtils.fluidHandlerAt(position.offset(facing)) match { + case Some(handler) => result(handler.getTankInfo(facing.getOpposite).map(info => Option(info.fluid).fold(0)(_.amount)).sum) case _ => result(Unit, "no tank") } @@ -22,8 +22,8 @@ trait WorldTankAnalytics extends WorldAware with SideRestricted { @Callback(doc = """function(side:number):number -- Get the capacity of the tank on the specified side.""") def getTankCapacity(context: Context, args: Arguments): Array[AnyRef] = { val facing = checkSideForAction(args, 0) - world.getTileEntity(position.offset(facing)) match { - case handler: IFluidHandler => + FluidUtils.fluidHandlerAt(position.offset(facing)) match { + case Some(handler) => result(handler.getTankInfo(facing.getOpposite).map(_.capacity).foldLeft(0)((max, capacity) => math.max(max, capacity))) case _ => result(Unit, "no tank") } @@ -32,8 +32,8 @@ trait WorldTankAnalytics extends WorldAware with SideRestricted { @Callback(doc = """function(side:number):table -- Get a description of the fluid in the the tank on the specified side.""") def getFluidInTank(context: Context, args: Arguments): Array[AnyRef] = if (Settings.get.allowItemStackInspection) { val facing = checkSideForAction(args, 0) - world.getTileEntity(position.offset(facing)) match { - case handler: IFluidHandler => + FluidUtils.fluidHandlerAt(position.offset(facing)) match { + case Some(handler) => result(handler.getTankInfo(facing.getOpposite)) case _ => result(Unit, "no tank") } diff --git a/src/main/scala/li/cil/oc/util/ExtendedArguments.scala b/src/main/scala/li/cil/oc/util/ExtendedArguments.scala index d6dcc1dbf..06bc49d89 100644 --- a/src/main/scala/li/cil/oc/util/ExtendedArguments.scala +++ b/src/main/scala/li/cil/oc/util/ExtendedArguments.scala @@ -4,6 +4,7 @@ import li.cil.oc.api.internal.MultiTank import li.cil.oc.api.machine.Arguments import net.minecraft.inventory.IInventory import net.minecraftforge.common.util.ForgeDirection +import net.minecraftforge.fluids.FluidContainerRegistry import scala.language.implicitConversions @@ -16,7 +17,7 @@ object ExtendedArguments { if (!isDefined(index) || !hasValue(index)) default else math.max(0, math.min(64, args.checkInteger(index))) - def optFluidCount(index: Int, default: Int = 1000) = + def optFluidCount(index: Int, default: Int = FluidContainerRegistry.BUCKET_VOLUME) = if (!isDefined(index) || !hasValue(index)) default else math.max(0, args.checkInteger(index)) diff --git a/src/main/scala/li/cil/oc/util/ExtendedBlock.scala b/src/main/scala/li/cil/oc/util/ExtendedBlock.scala index 6cfabdd76..5dcc0eb77 100644 --- a/src/main/scala/li/cil/oc/util/ExtendedBlock.scala +++ b/src/main/scala/li/cil/oc/util/ExtendedBlock.scala @@ -1,6 +1,7 @@ package li.cil.oc.util import net.minecraft.block.Block +import net.minecraftforge.fluids.IFluidBlock import scala.language.implicitConversions @@ -20,4 +21,14 @@ object ExtendedBlock { def getCollisionBoundingBoxFromPool(position: BlockPosition) = block.getCollisionBoundingBoxFromPool(position.world.get, position.x, position.y, position.z) } + implicit def extendedFluidBlock(block: IFluidBlock): ExtendedFluidBlock = new ExtendedFluidBlock(block) + + class ExtendedFluidBlock(val block: IFluidBlock) { + def drain(position: BlockPosition, doDrain: Boolean) = block.drain(position.world.get, position.x, position.y, position.z, doDrain) + + def canDrain(position: BlockPosition) = block.canDrain(position.world.get, position.x, position.y, position.z) + + def getFilledPercentage(position: BlockPosition) = block.getFilledPercentage(position.world.get, position.x, position.y, position.z) + } + } diff --git a/src/main/scala/li/cil/oc/util/FluidUtils.scala b/src/main/scala/li/cil/oc/util/FluidUtils.scala new file mode 100644 index 000000000..754c22b93 --- /dev/null +++ b/src/main/scala/li/cil/oc/util/FluidUtils.scala @@ -0,0 +1,157 @@ +package li.cil.oc.util + +import li.cil.oc.util.ExtendedBlock._ +import li.cil.oc.util.ExtendedWorld._ +import net.minecraft.block.Block +import net.minecraft.block.BlockLiquid +import net.minecraftforge.common.util.ForgeDirection +import net.minecraftforge.fluids.Fluid +import net.minecraftforge.fluids.FluidContainerRegistry +import net.minecraftforge.fluids.FluidRegistry +import net.minecraftforge.fluids.FluidStack +import net.minecraftforge.fluids.FluidTank +import net.minecraftforge.fluids.FluidTankInfo +import net.minecraftforge.fluids.IFluidBlock +import net.minecraftforge.fluids.IFluidHandler + +object FluidUtils { + /** + * Retrieves an actual fluid handler implementation for a specified world coordinate. + *

+ * This performs special handling for in-world liquids. + */ + def fluidHandlerAt(position: BlockPosition): Option[IFluidHandler] = position.world match { + case Some(world) if world.blockExists(position) => world.getTileEntity(position) match { + case handler: IFluidHandler => Option(handler) + case _ => Option(new GenericBlockWrapper(position)) + } + case _ => None + } + + /** + * Transfers some fluid between two fluid handlers. + *

+ * This will try to extract up the specified amount of fluid from any handler, + * then insert it into the specified sink handler. If the insertion fails, the + * fluid will remain in the source handler. + *

+ * This returns true if some fluid was transferred. + */ + def transferBetweenFluidHandlers(source: IFluidHandler, sourceSide: ForgeDirection, sink: IFluidHandler, sinkSide: ForgeDirection, limit: Int = FluidContainerRegistry.BUCKET_VOLUME) = { + val drained = source.drain(sourceSide, limit, false) + val filled = sink.fill(sinkSide, drained, false) + sink.fill(sinkSide, source.drain(sourceSide, filled, true), true) + } + + /** + * Utility method for calling transferBetweenFluidHandlers on handlers + * in the world. + *

+ * This uses the fluidHandlerAt method, and therefore handles special + * cases such as fluid blocks. + */ + def transferBetweenFluidHandlersAt(sourcePos: BlockPosition, sourceSide: ForgeDirection, sinkPos: BlockPosition, sinkSide: ForgeDirection, limit: Int = FluidContainerRegistry.BUCKET_VOLUME) = + fluidHandlerAt(sourcePos).fold(0)(source => + fluidHandlerAt(sinkPos).fold(0)(sink => + transferBetweenFluidHandlers(source, sourceSide, sink, sinkSide, limit))) + + // ----------------------------------------------------------------------- // + + private class GenericBlockWrapper(position: BlockPosition) extends IFluidHandler { + override def canDrain(from: ForgeDirection, fluid: Fluid): Boolean = currentWrapper.fold(false)(_.canDrain(from, fluid)) + + override def drain(from: ForgeDirection, resource: FluidStack, doDrain: Boolean): FluidStack = currentWrapper.fold(null: FluidStack)(_.drain(from, resource, doDrain)) + + override def drain(from: ForgeDirection, maxDrain: Int, doDrain: Boolean): FluidStack = currentWrapper.fold(null: FluidStack)(_.drain(from, maxDrain, doDrain)) + + override def canFill(from: ForgeDirection, fluid: Fluid): Boolean = currentWrapper.fold(false)(_.canFill(from, fluid)) + + override def fill(from: ForgeDirection, resource: FluidStack, doFill: Boolean): Int = currentWrapper.fold(0)(_.fill(from, resource, doFill)) + + override def getTankInfo(from: ForgeDirection): Array[FluidTankInfo] = currentWrapper.fold(Array.empty[FluidTankInfo])(_.getTankInfo(from)) + + def currentWrapper = if (position.world.get.blockExists(position)) position.world.get.getBlock(position) match { + case block: IFluidBlock => Option(new FluidBlockWrapper(position, block)) + case block: BlockLiquid if FluidRegistry.lookupFluidForBlock(block) != null => Option(new LiquidBlockWrapper(position, block)) + case block: Block if block.isAir(position) || block.isReplaceable(position) => Option(new AirBlockWrapper(position, block)) + case _ => None + } + else None + } + + private trait BlockWrapperBase extends IFluidHandler { + protected def uncheckedDrain(doDrain: Boolean): FluidStack + + override def drain(from: ForgeDirection, resource: FluidStack, doDrain: Boolean): FluidStack = { + val drained = uncheckedDrain(false) + if (drained != null && (resource == null || (drained.getFluid == resource.getFluid && drained.amount <= resource.amount))) { + uncheckedDrain(doDrain) + } + else null + } + + override def drain(from: ForgeDirection, maxDrain: Int, doDrain: Boolean): FluidStack = { + val drained = uncheckedDrain(false) + if (drained != null && drained.amount <= maxDrain) { + uncheckedDrain(doDrain) + } + else null + } + + override def canFill(from: ForgeDirection, fluid: Fluid): Boolean = false + + override def fill(from: ForgeDirection, resource: FluidStack, doFill: Boolean): Int = 0 + } + + private class FluidBlockWrapper(val position: BlockPosition, val block: IFluidBlock) extends BlockWrapperBase { + final val AssumedCapacity = FluidContainerRegistry.BUCKET_VOLUME + + override def canDrain(from: ForgeDirection, fluid: Fluid): Boolean = block.canDrain(position) + + override def getTankInfo(from: ForgeDirection): Array[FluidTankInfo] = Array(new FluidTankInfo(new FluidTank(block.getFluid, (block.getFilledPercentage(position) * AssumedCapacity).toInt, AssumedCapacity))) + + override protected def uncheckedDrain(doDrain: Boolean): FluidStack = block.drain(position, doDrain) + } + + private class LiquidBlockWrapper(val position: BlockPosition, val block: BlockLiquid) extends BlockWrapperBase { + val fluid = FluidRegistry.lookupFluidForBlock(block) + + override def canDrain(from: ForgeDirection, fluid: Fluid): Boolean = true + + override def getTankInfo(from: ForgeDirection): Array[FluidTankInfo] = Array(new FluidTankInfo(new FluidTank(fluid, FluidContainerRegistry.BUCKET_VOLUME, FluidContainerRegistry.BUCKET_VOLUME))) + + override protected def uncheckedDrain(doDrain: Boolean): FluidStack = { + if (doDrain) { + position.world.get.setBlockToAir(position) + } + new FluidStack(fluid, FluidContainerRegistry.BUCKET_VOLUME) + } + } + + private class AirBlockWrapper(val position: BlockPosition, val block: Block) extends IFluidHandler { + override def canDrain(from: ForgeDirection, fluid: Fluid): Boolean = false + + override def drain(from: ForgeDirection, resource: FluidStack, doDrain: Boolean): FluidStack = null + + override def drain(from: ForgeDirection, maxDrain: Int, doDrain: Boolean): FluidStack = null + + override def canFill(from: ForgeDirection, fluid: Fluid): Boolean = fluid.canBePlacedInWorld + + override def fill(from: ForgeDirection, resource: FluidStack, doFill: Boolean): Int = { + if (resource != null && resource.getFluid.canBePlacedInWorld && resource.getFluid.getBlock != null) { + if (doFill) { + val world = position.world.get + world.breakBlock(position) + world.setBlock(position, resource.getFluid.getBlock) + // This fake neighbor update is required to get stills to start flowing. + world.notifyBlockOfNeighborChange(position, world.getBlock(position)) + } + FluidContainerRegistry.BUCKET_VOLUME + } + else 0 + } + + override def getTankInfo(from: ForgeDirection): Array[FluidTankInfo] = Array.empty + } + +} diff --git a/src/main/scala/li/cil/oc/util/InventoryUtils.scala b/src/main/scala/li/cil/oc/util/InventoryUtils.scala index 951498bd9..35a691e66 100644 --- a/src/main/scala/li/cil/oc/util/InventoryUtils.scala +++ b/src/main/scala/li/cil/oc/util/InventoryUtils.scala @@ -221,6 +221,48 @@ object InventoryUtils { def extractFromInventoryAt(consumer: (ItemStack) => Unit, position: BlockPosition, side: ForgeDirection, limit: Int = 64) = inventoryAt(position).exists(extractFromInventory(consumer, _, side, limit)) + /** + * Transfers some items between two inventories. + *

+ * This will try to extract up the specified number of items from any inventory, + * then insert it into the specified sink inventory. If the insertion fails, the + * items will remain in the source inventory. + *

+ * This uses the extractFromInventory and insertIntoInventory + * methods, and therefore handles special cases such as sided inventories and + * stack size limits. + *

+ * This returns true if at least one item was transferred. + */ + def transferBetweenInventories(source: IInventory, sourceSide: ForgeDirection, sink: IInventory, sinkSide: Option[ForgeDirection], limit: Int = 64) = + extractFromInventory( + insertIntoInventory(_, sink, sinkSide, limit), source, sourceSide, limit) + + /** + * Like transferBetweenInventories but moving between specific slots. + */ + def transferBetweenInventoriesSlots(source: IInventory, sourceSide: ForgeDirection, sourceSlot: Int, sink: IInventory, sinkSide: Option[ForgeDirection], sinkSlot: Int, limit: Int = 64) = + extractFromInventorySlot( + insertIntoInventorySlot(_, sink, sinkSide, sinkSlot, limit), source, sourceSide, sourceSlot, limit) + + /** + * Utility method for calling transferBetweenInventories on inventories + * in the world. + */ + def transferBetweenInventoriesAt(source: BlockPosition, sourceSide: ForgeDirection, sink: BlockPosition, sinkSide: Option[ForgeDirection], limit: Int = 64) = + inventoryAt(source).exists(sourceInventory => + inventoryAt(sink).exists(sinkInventory => + transferBetweenInventories(sourceInventory, sourceSide, sinkInventory, sinkSide, limit))) + + /** + * Utility method for calling transferBetweenInventoriesSlots on inventories + * in the world. + */ + def transferBetweenInventoriesSlotsAt(sourcePos: BlockPosition, sourceSide: ForgeDirection, sourceSlot: Int, sinkPos: BlockPosition, sinkSide: Option[ForgeDirection], sinkSlot: Int, limit: Int = 64) = + inventoryAt(sourcePos).exists(sourceInventory => + inventoryAt(sinkPos).exists(sinkInventory => + transferBetweenInventoriesSlots(sourceInventory, sourceSide, sourceSlot, sinkInventory, sinkSide, sinkSlot, limit))) + /** * Utility method for dropping contents from a single inventory slot into * the world. From 4f5cbf9badc72d7405ab9b93534d07e52a4e87b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Sat, 29 Aug 2015 02:43:11 +0200 Subject: [PATCH 18/30] Missed that earlier... --- .../resources/assets/opencomputers/blockstates/relay.json | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 src/main/resources/assets/opencomputers/blockstates/relay.json diff --git a/src/main/resources/assets/opencomputers/blockstates/relay.json b/src/main/resources/assets/opencomputers/blockstates/relay.json new file mode 100644 index 000000000..bb0444909 --- /dev/null +++ b/src/main/resources/assets/opencomputers/blockstates/relay.json @@ -0,0 +1,5 @@ +{ + "variants": { + "normal": { "model": "opencomputers:relay" } + } +} From 3f353dbadffcd591159264d83f854445fa5e304f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Sat, 29 Aug 2015 03:49:03 +0200 Subject: [PATCH 19/30] Adjustments for 1.8. --- .../opencomputers/blockstates/transposer.json | 5 + .../models/block/transposer.json | 221 ++++++++++++++++++ .../opencomputers/models/item/transposer.json | 10 + .../{TransposerTop.png => Transposer_top.png} | Bin .../transposer_on.png} | Bin ...TransposerSide.png => transposer_side.png} | Bin .../tileentity/TransposerRenderer.scala | 16 +- 7 files changed, 244 insertions(+), 8 deletions(-) create mode 100644 src/main/resources/assets/opencomputers/blockstates/transposer.json create mode 100644 src/main/resources/assets/opencomputers/models/block/transposer.json create mode 100644 src/main/resources/assets/opencomputers/models/item/transposer.json rename src/main/resources/assets/opencomputers/textures/blocks/{TransposerTop.png => Transposer_top.png} (100%) rename src/main/resources/assets/opencomputers/textures/blocks/{TransposerOn.png => overlay/transposer_on.png} (100%) rename src/main/resources/assets/opencomputers/textures/blocks/{TransposerSide.png => transposer_side.png} (100%) diff --git a/src/main/resources/assets/opencomputers/blockstates/transposer.json b/src/main/resources/assets/opencomputers/blockstates/transposer.json new file mode 100644 index 000000000..32bd3dad6 --- /dev/null +++ b/src/main/resources/assets/opencomputers/blockstates/transposer.json @@ -0,0 +1,5 @@ +{ + "variants": { + "normal": { "model": "opencomputers:transposer" } + } +} diff --git a/src/main/resources/assets/opencomputers/models/block/transposer.json b/src/main/resources/assets/opencomputers/models/block/transposer.json new file mode 100644 index 000000000..5e20eb017 --- /dev/null +++ b/src/main/resources/assets/opencomputers/models/block/transposer.json @@ -0,0 +1,221 @@ +{ + "textures": { + "bottom": "opencomputers:blocks/transposer_top", + "top": "opencomputers:blocks/transposer_top", + "side": "opencomputers:blocks/transposer_side", + "particle": "opencomputers:blocks/generic_top" + }, + "elements": [ + { "from": [ 0, 0, 0 ], + "to": [ 7, 7, 7 ], + "faces": { + "up": { "uv": [ 0, 0, 7, 7 ], "texture": "#top" }, + "down": { "uv": [ 0, 9, 7, 16 ], "texture": "#bottom" }, + "north": { "uv": [ 9, 9, 16, 16 ], "texture": "#side" }, + "south": { "uv": [ 0, 9, 7, 16 ], "texture": "#side" }, + "west": { "uv": [ 0, 9, 7, 16 ], "texture": "#side" }, + "east": { "uv": [ 9, 9, 16, 16 ], "texture": "#side" } + } + }, + { "from": [ 0, 0, 9 ], + "to": [ 7, 7, 16 ], + "faces": { + "up": { "uv": [ 0, 9, 7, 16 ], "texture": "#top" }, + "down": { "uv": [ 0, 0, 7, 7 ], "texture": "#bottom" }, + "north": { "uv": [ 9, 9, 16, 16 ], "texture": "#side" }, + "south": { "uv": [ 0, 9, 7, 16 ], "texture": "#side" }, + "west": { "uv": [ 9, 9, 16, 16 ], "texture": "#side" }, + "east": { "uv": [ 0, 9, 7, 16 ], "texture": "#side" } + } + }, + { "from": [ 0, 9, 0 ], + "to": [ 7, 16, 7 ], + "faces": { + "up": { "uv": [ 0, 0, 7, 7 ], "texture": "#top" }, + "down": { "uv": [ 0, 9, 7, 16 ], "texture": "#bottom" }, + "north": { "uv": [ 9, 0, 16, 7 ], "texture": "#side" }, + "south": { "uv": [ 0, 0, 7, 7 ], "texture": "#side" }, + "west": { "uv": [ 0, 0, 7, 7 ], "texture": "#side" }, + "east": { "uv": [ 9, 0, 16, 7 ], "texture": "#side" } + } + }, + { "from": [ 0, 9, 9 ], + "to": [ 7, 16, 16 ], + "faces": { + "up": { "uv": [ 0, 9, 7, 16 ], "texture": "#top" }, + "down": { "uv": [ 0, 0, 7, 7 ], "texture": "#bottom" }, + "north": { "uv": [ 9, 0, 16, 7 ], "texture": "#side" }, + "south": { "uv": [ 0, 0, 7, 7 ], "texture": "#side" }, + "west": { "uv": [ 9, 0, 16, 7 ], "texture": "#side" }, + "east": { "uv": [ 0, 0, 7, 7 ], "texture": "#side" } + } + }, + { "from": [ 9, 0, 0 ], + "to": [ 16, 7, 7 ], + "faces": { + "up": { "uv": [ 9, 0, 16, 7 ], "texture": "#top" }, + "down": { "uv": [ 9, 9, 16, 16 ], "texture": "#bottom" }, + "north": { "uv": [ 0, 9, 7, 16 ], "texture": "#side" }, + "south": { "uv": [ 9, 9, 16, 16 ], "texture": "#side" }, + "west": { "uv": [ 0, 9, 7, 16 ], "texture": "#side" }, + "east": { "uv": [ 9, 9, 16, 16 ], "texture": "#side" } + } + }, + { "from": [ 9, 0, 9 ], + "to": [ 16, 7, 16 ], + "faces": { + "up": { "uv": [ 9, 9, 16, 16 ], "texture": "#top" }, + "down": { "uv": [ 9, 0, 16, 7 ], "texture": "#bottom" }, + "north": { "uv": [ 0, 9, 7, 16 ], "texture": "#side" }, + "south": { "uv": [ 9, 9, 16, 16 ], "texture": "#side" }, + "west": { "uv": [ 9, 9, 16, 16 ], "texture": "#side" }, + "east": { "uv": [ 0, 9, 7, 16 ], "texture": "#side" } + } + }, + { "from": [ 9, 9, 0 ], + "to": [ 16, 16, 7 ], + "faces": { + "up": { "uv": [ 9, 0, 16, 7 ], "texture": "#top" }, + "down": { "uv": [ 9, 9, 16, 16 ], "texture": "#bottom" }, + "north": { "uv": [ 0, 0, 7, 7 ], "texture": "#side" }, + "south": { "uv": [ 9, 0, 16, 7 ], "texture": "#side" }, + "west": { "uv": [ 0, 0, 7, 7 ], "texture": "#side" }, + "east": { "uv": [ 9, 0, 16, 7 ], "texture": "#side" } + } + }, + { "from": [ 9, 9, 9 ], + "to": [ 16, 16, 16 ], + "faces": { + "up": { "uv": [ 9, 9, 16, 16 ], "texture": "#top" }, + "down": { "uv": [ 9, 0, 16, 7 ], "texture": "#bottom" }, + "north": { "uv": [ 0, 0, 7, 7 ], "texture": "#side" }, + "south": { "uv": [ 9, 0, 16, 7 ], "texture": "#side" }, + "west": { "uv": [ 9, 0, 16, 7 ], "texture": "#side" }, + "east": { "uv": [ 0, 0, 7, 7 ], "texture": "#side" } + } + }, + + { "from": [ 0, 0, 7 ], + "to": [ 5, 5, 9 ], + "faces": { + "up": { "uv": [ 0, 7, 5, 9 ], "texture": "#top" }, + "down": { "uv": [ 0, 7, 5, 9 ], "texture": "#bottom" }, + "west": { "uv": [ 7, 11, 9, 16 ], "texture": "#side" }, + "east": { "uv": [ 7, 11, 9, 16 ], "texture": "#side" } + } + }, + { "from": [ 0, 11, 7 ], + "to": [ 5, 16, 9 ], + "faces": { + "up": { "uv": [ 0, 7, 5, 9 ], "texture": "#top" }, + "down": { "uv": [ 0, 7, 5, 9 ], "texture": "#bottom" }, + "west": { "uv": [ 7, 0, 9, 5 ], "texture": "#side" }, + "east": { "uv": [ 7, 0, 9, 5 ], "texture": "#side" } + } + }, + { "from": [ 11, 0, 7 ], + "to": [ 16, 5, 9 ], + "faces": { + "up": { "uv": [ 11, 7, 16, 9 ], "texture": "#top" }, + "down": { "uv": [ 11, 7, 16, 9 ], "texture": "#bottom" }, + "west": { "uv": [ 7, 11, 9, 16 ], "texture": "#side" }, + "east": { "uv": [ 7, 11, 9, 16 ], "texture": "#side" } + } + }, + { "from": [ 11, 11, 7 ], + "to": [ 16, 16, 9 ], + "faces": { + "up": { "uv": [ 11, 7, 16, 9 ], "texture": "#top" }, + "down": { "uv": [ 11, 7, 16, 9 ], "texture": "#bottom" }, + "west": { "uv": [ 7, 0, 9, 5 ], "texture": "#side" }, + "east": { "uv": [ 7, 0, 9, 5 ], "texture": "#side" } + } + }, + + { "from": [ 0, 7, 0 ], + "to": [ 5, 9, 5 ], + "faces": { + "north": { "uv": [ 11, 7, 16, 9 ], "texture": "#side" }, + "south": { "uv": [ 0, 7, 5, 9 ], "texture": "#side" }, + "west": { "uv": [ 0, 7, 5, 9 ], "texture": "#side" }, + "east": { "uv": [ 11, 7, 16, 9 ], "texture": "#side" } + } + }, + { "from": [ 0, 7, 11 ], + "to": [ 5, 9, 16 ], + "faces": { + "north": { "uv": [ 11, 7, 16, 9 ], "texture": "#side" }, + "south": { "uv": [ 0, 7, 5, 9 ], "texture": "#side" }, + "west": { "uv": [ 11, 7, 16, 9 ], "texture": "#side" }, + "east": { "uv": [ 0, 7, 5, 9 ], "texture": "#side" } + } + }, + { "from": [ 11, 7, 0 ], + "to": [ 16, 9, 5 ], + "faces": { + "north": { "uv": [ 0, 7, 5, 9 ], "texture": "#side" }, + "south": { "uv": [ 11, 7, 16, 9 ], "texture": "#side" }, + "west": { "uv": [ 0, 7, 5, 9 ], "texture": "#side" }, + "east": { "uv": [ 11, 7, 16, 9 ], "texture": "#side" } + } + }, + { "from": [ 11, 7, 11 ], + "to": [ 16, 9, 16 ], + "faces": { + "north": { "uv": [ 0, 7, 5, 9 ], "texture": "#side" }, + "south": { "uv": [ 11, 7, 16, 9 ], "texture": "#side" }, + "west": { "uv": [ 11, 7, 16, 9 ], "texture": "#side" }, + "east": { "uv": [ 0, 7, 5, 9 ], "texture": "#side" } + } + }, + + { "from": [ 7, 0, 0 ], + "to": [ 9, 5, 5 ], + "faces": { + "up": { "uv": [ 7, 0, 9, 5 ], "texture": "#top" }, + "down": { "uv": [ 7, 11, 9, 16 ], "texture": "#bottom" }, + "north": { "uv": [ 7, 11, 9, 16 ], "texture": "#side" }, + "south": { "uv": [ 7, 11, 9, 16 ], "texture": "#side" } + } + }, + { "from": [ 7, 0, 11 ], + "to": [ 9, 5, 16 ], + "faces": { + "up": { "uv": [ 7, 11, 9, 16 ], "texture": "#top" }, + "down": { "uv": [ 7, 0, 9, 5 ], "texture": "#bottom" }, + "north": { "uv": [ 7, 11, 9, 16 ], "texture": "#side" }, + "south": { "uv": [ 7, 11, 9, 16 ], "texture": "#side" } + } + }, + { "from": [ 7, 11, 0 ], + "to": [ 9, 16, 5 ], + "faces": { + "up": { "uv": [ 7, 0, 9, 5 ], "texture": "#top" }, + "down": { "uv": [ 7, 11, 9, 16 ], "texture": "#bottom" }, + "north": { "uv": [ 7, 0, 9, 5 ], "texture": "#side" }, + "south": { "uv": [ 7, 0, 9, 5 ], "texture": "#side" } + } + }, + { "from": [ 7, 11, 11 ], + "to": [ 9, 16, 16 ], + "faces": { + "up": { "uv": [ 7, 11, 9, 16 ], "texture": "#top" }, + "down": { "uv": [ 7, 0, 9, 5 ], "texture": "#bottom" }, + "north": { "uv": [ 7, 0, 9, 5 ], "texture": "#side" }, + "south": { "uv": [ 7, 0, 9, 5 ], "texture": "#side" } + } + }, + + { "from": [ 1, 1, 1 ], + "to": [ 15, 15, 15 ], + "faces": { + "up": { "uv": [ 1, 1, 15, 15 ], "texture": "#top" }, + "down": { "uv": [ 1, 1, 15, 15 ], "texture": "#bottom" }, + "north": { "uv": [ 1, 1, 15, 15 ], "texture": "#side" }, + "south": { "uv": [ 1, 1, 15, 15 ], "texture": "#side" }, + "west": { "uv": [ 1, 1, 15, 15 ], "texture": "#side" }, + "east": { "uv": [ 1, 1, 15, 15 ], "texture": "#side" } + } + } + ] +} diff --git a/src/main/resources/assets/opencomputers/models/item/transposer.json b/src/main/resources/assets/opencomputers/models/item/transposer.json new file mode 100644 index 000000000..843975aad --- /dev/null +++ b/src/main/resources/assets/opencomputers/models/item/transposer.json @@ -0,0 +1,10 @@ +{ + "parent": "opencomputers:block/transposer", + "display": { + "thirdperson": { + "rotation": [ 10, -45, 170 ], + "translation": [ 0, 1.5, -2.75 ], + "scale": [ 0.375, 0.375, 0.375 ] + } + } +} diff --git a/src/main/resources/assets/opencomputers/textures/blocks/TransposerTop.png b/src/main/resources/assets/opencomputers/textures/blocks/Transposer_top.png similarity index 100% rename from src/main/resources/assets/opencomputers/textures/blocks/TransposerTop.png rename to src/main/resources/assets/opencomputers/textures/blocks/Transposer_top.png diff --git a/src/main/resources/assets/opencomputers/textures/blocks/TransposerOn.png b/src/main/resources/assets/opencomputers/textures/blocks/overlay/transposer_on.png similarity index 100% rename from src/main/resources/assets/opencomputers/textures/blocks/TransposerOn.png rename to src/main/resources/assets/opencomputers/textures/blocks/overlay/transposer_on.png diff --git a/src/main/resources/assets/opencomputers/textures/blocks/TransposerSide.png b/src/main/resources/assets/opencomputers/textures/blocks/transposer_side.png similarity index 100% rename from src/main/resources/assets/opencomputers/textures/blocks/TransposerSide.png rename to src/main/resources/assets/opencomputers/textures/blocks/transposer_side.png diff --git a/src/main/scala/li/cil/oc/client/renderer/tileentity/TransposerRenderer.scala b/src/main/scala/li/cil/oc/client/renderer/tileentity/TransposerRenderer.scala index 6d34630f7..f922d64c1 100644 --- a/src/main/scala/li/cil/oc/client/renderer/tileentity/TransposerRenderer.scala +++ b/src/main/scala/li/cil/oc/client/renderer/tileentity/TransposerRenderer.scala @@ -16,25 +16,25 @@ object TransposerRenderer extends TileEntitySpecialRenderer { val transposer = tileEntity.asInstanceOf[tileentity.Transposer] val activity = math.max(0, 1 - (System.currentTimeMillis() - transposer.lastOperation) / 1000.0) if (activity > 0) { - GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS) + RenderState.pushAttrib() - RenderState.disableLighting() + RenderState.disableEntityLighting() RenderState.makeItBlend() RenderState.setBlendAlpha(activity.toFloat) - GL11.glPushMatrix() + RenderState.pushMatrix() GL11.glTranslated(x + 0.5, y + 0.5, z + 0.5) GL11.glScaled(1.0025, -1.0025, 1.0025) GL11.glTranslatef(-0.5f, -0.5f, -0.5f) - bindTexture(TextureMap.locationBlocksTexture) val t = Tessellator.getInstance val r = t.getWorldRenderer + + Textures.Block.bind() r.startDrawingQuads() val icon = Textures.getSprite(Textures.Block.TransposerOn) - r.addVertexWithUV(0, 1, 0, icon.getMaxU, icon.getMinV) r.addVertexWithUV(1, 1, 0, icon.getMinU, icon.getMinV) r.addVertexWithUV(1, 1, 1, icon.getMinU, icon.getMaxV) @@ -67,10 +67,10 @@ object TransposerRenderer extends TileEntitySpecialRenderer { t.draw() - RenderState.enableLighting() + RenderState.enableEntityLighting() - GL11.glPopMatrix() - GL11.glPopAttrib() + RenderState.popMatrix() + RenderState.popAttrib() } RenderState.checkError(getClass.getName + ".renderTileEntityAt: leaving") From 362b62341bfbf9b7949ecce09f135b724ea59b77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Sat, 29 Aug 2015 12:07:45 +0200 Subject: [PATCH 20/30] Added option to enable 'fuzzy' wake on LAN (ignoring additional arguments instead of requiring an exact match). Closes #1368. --- .../cil/oc/server/component/NetworkCard.scala | 22 ++++++++++++++----- 1 file changed, 17 insertions(+), 5 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 111e76ff2..a62f92b10 100644 --- a/src/main/scala/li/cil/oc/server/component/NetworkCard.scala +++ b/src/main/scala/li/cil/oc/server/component/NetworkCard.scala @@ -24,6 +24,8 @@ class NetworkCard(val host: EnvironmentHost) extends prefab.ManagedEnvironment { protected var wakeMessage: Option[String] = None + protected var wakeMessageFuzzy = false + // ----------------------------------------------------------------------- // @Callback(doc = """function(port:number):boolean -- Opens the specified port. Returns true if the port was opened.""") @@ -39,7 +41,7 @@ class NetworkCard(val host: EnvironmentHost) extends prefab.ManagedEnvironment { @Callback(doc = """function([port:number]):boolean -- Closes the specified port (default: all ports). Returns true if ports were closed.""") def close(context: Context, args: Arguments): Array[AnyRef] = { if (args.count == 0) { - val closed = openPorts.size > 0 + val closed = openPorts.nonEmpty openPorts.clear() result(closed) } @@ -78,17 +80,21 @@ 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(direct = true, doc = """function():string, boolean -- Get the current wake-up message.""") + def getWakeMessage(context: Context, args: Arguments): Array[AnyRef] = result(wakeMessage.orNull, wakeMessageFuzzy) - @Callback(doc = """function(message:string):string -- Set the wake-up message.""") + @Callback(doc = """function(message:string[, fuzzy:boolean]):string -- Set the wake-up message and whether to ignore additional data/parameters.""") def setWakeMessage(context: Context, args: Arguments): Array[AnyRef] = { val oldMessage = wakeMessage + val oldFuzzy = wakeMessageFuzzy + if (args.optAny(0, null) == null) wakeMessage = None else wakeMessage = Option(args.checkString(0)) - result(oldMessage.orNull) + wakeMessageFuzzy = args.optBoolean(1, wakeMessageFuzzy) + + result(oldMessage.orNull, oldFuzzy) } protected def doSend(packet: Packet) { @@ -136,6 +142,10 @@ class NetworkCard(val host: EnvironmentHost) extends prefab.ManagedEnvironment { node.sendToNeighbors("computer.start") case Array(message: String) if wakeMessage.contains(message) => node.sendToNeighbors("computer.start") + case Array(message: Array[Byte], _*) if wakeMessageFuzzy && wakeMessage.contains(new String(message, Charsets.UTF_8)) => + node.sendToNeighbors("computer.start") + case Array(message: String, _*) if wakeMessageFuzzy && wakeMessage.contains(message) => + node.sendToNeighbors("computer.start") case _ => } } @@ -151,6 +161,7 @@ class NetworkCard(val host: EnvironmentHost) extends prefab.ManagedEnvironment { if (nbt.hasKey("wakeMessage")) { wakeMessage = Option(nbt.getString("wakeMessage")) } + wakeMessageFuzzy = nbt.getBoolean("wakeMessageFuzzy") } override def save(nbt: NBTTagCompound) { @@ -158,6 +169,7 @@ class NetworkCard(val host: EnvironmentHost) extends prefab.ManagedEnvironment { nbt.setIntArray("openPorts", openPorts.toArray) wakeMessage.foreach(nbt.setString("wakeMessage", _)) + nbt.setBoolean("wakeMessageFuzzy", wakeMessageFuzzy) } // ----------------------------------------------------------------------- // From 01c92dee28f6fbf940c331f03e72bc6908fba896 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Sat, 29 Aug 2015 12:08:32 +0200 Subject: [PATCH 21/30] Ignoring calls to change wireless frequency / value if nothing changes, avoid resetting state. Closes #1363. --- .../server/component/RedstoneWireless.scala | 28 ++++++++++++------- 1 file changed, 18 insertions(+), 10 deletions(-) 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 37df26e97..67e759a32 100644 --- a/src/main/scala/li/cil/oc/server/component/RedstoneWireless.scala +++ b/src/main/scala/li/cil/oc/server/component/RedstoneWireless.scala @@ -41,11 +41,16 @@ trait RedstoneWireless extends RedstoneSignaller with WirelessReceivingDevice wi @Callback(doc = """function(value:boolean):boolean -- Set the wireless redstone output.""") def setWirelessOutput(context: Context, args: Arguments): Array[AnyRef] = { val oldValue = wirelessOutput - wirelessOutput = args.checkBoolean(0) + val newValue = args.checkBoolean(0) - util.WirelessRedstone.updateOutput(this) + if (oldValue != newValue) { + wirelessOutput = newValue + + util.WirelessRedstone.updateOutput(this) + + context.pause(0.1) + } - context.pause(0.1) result(oldValue) } @@ -57,16 +62,19 @@ trait RedstoneWireless extends RedstoneSignaller with WirelessReceivingDevice wi val oldValue = wirelessFrequency val newValue = args.checkInteger(0) - util.WirelessRedstone.removeReceiver(this) - util.WirelessRedstone.removeTransmitter(this) + if (oldValue != newValue) { + util.WirelessRedstone.removeReceiver(this) + util.WirelessRedstone.removeTransmitter(this) - wirelessFrequency = newValue - wirelessInput = false - wirelessOutput = false + wirelessFrequency = newValue + wirelessInput = false + wirelessOutput = false - util.WirelessRedstone.addReceiver(this) + util.WirelessRedstone.addReceiver(this) + + context.pause(0.5) + } - context.pause(0.5) result(oldValue) } From f11faeeea54b1fda92af0ce275ac6ccfbbe0f6ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Sat, 29 Aug 2015 12:10:53 +0200 Subject: [PATCH 22/30] Slight change to returned values from transposer.transferFluid (unified with erroneous case). Some throttling to fluid movement speed. --- src/main/scala/li/cil/oc/server/component/Transposer.scala | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/scala/li/cil/oc/server/component/Transposer.scala b/src/main/scala/li/cil/oc/server/component/Transposer.scala index 636e1e27e..f3d4efb82 100644 --- a/src/main/scala/li/cil/oc/server/component/Transposer.scala +++ b/src/main/scala/li/cil/oc/server/component/Transposer.scala @@ -61,7 +61,9 @@ class Transposer(val host: tileentity.Transposer) extends prefab.ManagedEnvironm if (node.tryChangeBuffer(-Settings.get.transposerCost)) { ServerPacketSender.sendTransposerActivity(host) - result(FluidUtils.transferBetweenFluidHandlersAt(sourcePos, sourceSide.getOpposite, sinkPos, sinkSide.getOpposite, count)) + val moved = FluidUtils.transferBetweenFluidHandlersAt(sourcePos, sourceSide.getOpposite, sinkPos, sinkSide.getOpposite, count) + if (moved > 0) context.pause(moved / 1000 * 0.25) // Allow up to 4 buckets per second. + result(moved > 0, moved) } else result(Unit, "not enough energy") } From 03872647431925304227e57d71c619684b8cf5a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Sat, 29 Aug 2015 12:19:49 +0200 Subject: [PATCH 23/30] Updated PSD with transposer textures. --- assets/blocks.psd | Bin 176246 -> 155564 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/assets/blocks.psd b/assets/blocks.psd index 950f8f81331487bfc7af6950f7a79978de23883f..12c4eac52c7b8c41bd58f993fae7254e79f0d3f2 100644 GIT binary patch delta 7328 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Ν!Q?ZbyK9t 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 Date: Sat, 29 Aug 2015 12:31:19 +0200 Subject: [PATCH 24/30] Added term.reset(). Closes #1377. --- .../assets/opencomputers/loot/OpenOS/lib/term.lua | 10 ++++++++++ 1 file changed, 10 insertions(+) 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 1131c3f7c..e89b2acd2 100644 --- a/src/main/resources/assets/opencomputers/loot/OpenOS/lib/term.lua +++ b/src/main/resources/assets/opencomputers/loot/OpenOS/lib/term.lua @@ -31,6 +31,16 @@ function term.clear() cursorX, cursorY = 1, 1 end +function term.reset() + if term.isAvailable() then + local maxw, maxh = component.gpu.maxResolution() + component.gpu.setResolution(maxw, maxh) + component.gpu.setBackground(0x000000) + component.gpu.setForeground(0xFFFFFF) + term.clear() + end +end + function term.clearLine() if term.isAvailable() then local w = component.gpu.getResolution() From a6988ed1ec03e85e83874f5948145f3d8c5386bb Mon Sep 17 00:00:00 2001 From: cyber01 Date: Sat, 29 Aug 2015 15:58:46 +0400 Subject: [PATCH 25/30] Added Transposer --- .../assets/opencomputers/doc/ru_RU/block/transposer.md | 9 +++++++++ src/main/resources/assets/opencomputers/lang/ru_RU.lang | 4 +++- 2 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 src/main/resources/assets/opencomputers/doc/ru_RU/block/transposer.md diff --git a/src/main/resources/assets/opencomputers/doc/ru_RU/block/transposer.md b/src/main/resources/assets/opencomputers/doc/ru_RU/block/transposer.md new file mode 100644 index 000000000..ea9c615e0 --- /dev/null +++ b/src/main/resources/assets/opencomputers/doc/ru_RU/block/transposer.md @@ -0,0 +1,9 @@ +# ĐąŃ€Đ°ĐœŃĐżĐŸĐ·Đ”Ń€ + +![йаĐșая ĐżŃ€ĐŸĐ±Đ»Đ”ĐŒĐșа.](oredict:oc:transposer) + +ĐąŃ€Đ°ĐœŃĐżĐŸĐ·Đ”Ń€ Đ·Đ°ĐżĐŸĐ»ĐœŃĐ”Ń‚ ĐżŃ€ĐŸĐ±Đ”Đ» ĐŒĐ”Đ¶ĐŽŃƒ ĐČĐŸŃ€ĐŸĐœĐșĐ°ĐŒĐž, ĐșĐŸĐœŃ‚Ń€ĐŸĐ»ĐžŃ€ŃƒĐ”ĐŒŃ‹ĐŒĐž Ń€Đ”ĐŽŃŃ‚ĐŸŃƒĐœ-ŃĐžĐłĐœĐ°Đ»ĐŸĐŒ Đž [Ń€ĐŸĐ±ĐŸŃ‚Đ°ĐŒĐž](robot.md), ĐżĐŸĐ·ĐČĐŸĐ»ŃŃ [ĐșĐŸĐŒĐżŃŒŃŽŃ‚Đ”Ń€Đ°ĐŒ](../general/computer.md) ĐșĐŸĐœŃ‚Ń€ĐŸĐ»ĐžŃ€ĐŸĐČать ĐżĐ”Ń€Đ”ĐŒĐ”Ń‰Đ”ĐœĐžĐ” ĐżŃ€Đ”ĐŽĐŒĐ”Ń‚ĐŸĐČ Đž жОЎĐșĐŸŃŃ‚Đ”Đč ĐŒĐ”Đ¶ĐŽŃƒ ŃĐŸŃĐ”ĐŽĐœĐžĐŒĐž Đ±Đ»ĐŸĐșĐ°ĐŒĐž. + +*Đ”Đ°ĐœĐœŃ‹Đč Đ±Đ»ĐŸĐș ĐœĐ” ĐžĐŒĐ”Đ”Ń‚ ĐČĐœŃƒŃ‚Ń€Đ”ĐœĐœĐ”ĐłĐŸ ĐžĐœĐČĐ”ĐœŃ‚Đ°Ń€Ń.* + +ĐšŃ€ĐŸĐŒĐ” ĐżĐ”Ń€Đ”ĐŒĐ”Ń‰Đ”ĐœĐžŃ Đ±Đ»ĐŸĐșĐŸĐČ, ĐŸĐœ таĐșжД ĐŒĐŸĐ¶Đ”Ń‚ Đ±Ń‹Ń‚ŃŒ ĐžŃĐżĐŸĐ»ŃŒĐ·ĐŸĐČĐ°Đœ ĐŽĐ»Ń ĐżŃ€ĐŸĐČДрĐșĐž ŃĐŸĐŽĐ”Ń€Đ¶ĐžĐŒĐŸĐłĐŸ ŃĐŸŃĐ”ĐŽĐœĐžŃ… ĐžĐœĐČĐ”ĐœŃ‚Đ°Ń€Đ”Đč, ĐżĐŸĐŽĐŸĐ±ĐœĐŸ [Đ°ĐŽĐ°ĐżŃ‚Đ”Ń€Ńƒ](adapter.md) с [ĐșĐŸĐœŃ‚Ń€ĐŸĐ»Đ»Đ”Ń€ĐŸĐŒ ĐžĐœĐČĐ”ĐœŃ‚Đ°Ń€Ń](../item/inventoryControllerUpgrade.md), Đž ŃĐŸĐŽĐ”Ń€Đ¶ĐžĐŒĐŸĐłĐŸ ŃĐŸŃĐ”ĐŽĐœĐžŃ… Ń…Ń€Đ°ĐœĐžĐ»ĐžŃ‰ жОЎĐșĐŸŃŃ‚Đž, ĐżĐŸĐŽĐŸĐ±ĐœĐŸ Đ°ĐŽĐ°ĐżŃ‚Đ”Ń€Ńƒ с [ĐșĐŸĐœŃ‚Ń€ĐŸĐ»Đ»Đ”Ń€ĐŸĐŒ жОЎĐșĐŸŃŃ‚Đž](../item/tankControllerUpgrade.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 85700e6ba..fc7aa043c 100644 --- a/src/main/resources/assets/opencomputers/lang/ru_RU.lang +++ b/src/main/resources/assets/opencomputers/lang/ru_RU.lang @@ -23,6 +23,7 @@ tile.oc.hologram2.name=Đ“ĐŸĐ»ĐŸĐłŃ€Đ°Ń„ĐžŃ‡Đ”ŃĐșĐžĐč ĐżŃ€ĐŸĐ”ĐșŃ‚ĐŸŃ€ (2-ĐŸĐč tile.oc.keyboard.name=КлаĐČоатура tile.oc.microcontroller.name=МоĐșŃ€ĐŸĐșĐŸĐœŃ‚Ń€ĐŸĐ»Đ»Đ”Ń€ tile.oc.motionSensor.name=ДатчоĐș ĐŽĐČĐžĐ¶Đ”ĐœĐžŃ +tile.oc.netSplitter.name=ХДтДĐČĐŸĐč пДрДĐșĐ»ŃŽŃ‡Đ°Ń‚Đ”Đ»ŃŒ tile.oc.powerConverter.name=ĐŸŃ€Đ”ĐŸĐ±Ń€Đ°Đ·ĐŸĐČĐ°Ń‚Đ”Đ»ŃŒ ŃĐœĐ”Ń€ĐłĐžĐž tile.oc.powerDistributor.name=Đ Đ°ŃĐżŃ€Đ”ĐŽĐ”Đ»ĐžŃ‚Đ”Đ»ŃŒ ŃĐœĐ”Ń€ĐłĐžĐž tile.oc.print.name=3D ĐŒĐŸĐŽĐ”Đ»ŃŒ @@ -36,7 +37,7 @@ tile.oc.screen2.name=ĐœĐŸĐœĐžŃ‚ĐŸŃ€ (2-ĐŸĐč ŃƒŃ€ĐŸĐČĐ”ĐœŃŒ) tile.oc.screen3.name=ĐœĐŸĐœĐžŃ‚ĐŸŃ€ (3-ĐžĐč ŃƒŃ€ĐŸĐČĐ”ĐœŃŒ) tile.oc.serverRack.name=ХДрĐČĐ”Ń€ĐœĐ°Ń ŃŃ‚ĐŸĐčĐșа tile.oc.switch.name=§cĐšĐŸĐŒĐŒŃƒŃ‚Đ°Ń‚ĐŸŃ€Â§7 -tile.oc.netSplitter.name=ХДтДĐČĐŸĐč пДрДĐșĐ»ŃŽŃ‡Đ°Ń‚Đ”Đ»ŃŒ +tile.oc.transposer.name=ĐąŃ€Đ°ĐœŃĐżĐŸĐ·Đ”Ń€ tile.oc.waypoint.name=ĐŸŃƒŃ‚Đ”ĐČая Ń‚ĐŸŃ‡Đșа # Items @@ -338,6 +339,7 @@ oc:tooltip.Tier=§8ĐŁŃ€ĐŸĐČĐ”ĐœŃŒ %s oc:tooltip.NetSplitter=Đ Đ°Đ±ĐŸŃ‚Đ°Đ”Ń‚ ĐșаĐș пДрДĐșĐ»ŃŽŃ‡Đ°Ń‚Đ”Đ»ŃŒ. ĐĄĐŸĐ”ĐŽĐžĐœĐ”ĐœĐžĐ” ĐșĐ°Đ¶ĐŽĐŸĐč ŃŃ‚ĐŸŃ€ĐŸĐœŃ‹ пДрДĐșĐ»ŃŽŃ‡Đ°Đ”Ń‚ŃŃ ĐșĐ»ŃŽŃ‡Đ”ĐŒ. Про ĐżĐŸĐŽĐ°Ń‡Đ” ŃĐžĐłĐœĐ°Đ»Đ° ĐșŃ€Đ°ŃĐœĐŸĐłĐŸ ĐșĐ°ĐŒĐœŃ ĐČсД ŃĐŸĐ”ĐŽĐžĐœĐ”ĐœĐžŃ ĐžĐœĐČĐ”Ń€Ń‚ĐžŃ€ŃƒŃŽŃ‚ŃŃ. oc:tooltip.TooLong=УЎДржОĐČаĐčтД [§f%s§7], Ń‡Ń‚ĐŸĐ±Ń‹ ĐŸŃ‚ĐŸĐ±Ń€Đ°Đ·ĐžŃ‚ŃŒ ĐŸĐżĐžŃĐ°ĐœĐžĐ”. oc:tooltip.Transistor=Đ‘Đ°Đ·ĐŸĐČыĐč ŃĐ»Đ”ĐŒĐ”ĐœŃ‚ ĐŽĐ»Ń Юругох частДĐč ĐșĐŸĐŒĐżŃŒŃŽŃ‚Đ”Ń€Đ°. ĐžĐœ ĐœĐ”ĐŒĐœĐŸĐłĐŸ ĐŽĐ”Ń„ĐŸŃ€ĐŒĐžŃ€ĐŸĐČĐ°Đœ, ĐœĐŸ ĐŸŃ‚Đ»ĐžŃ‡ĐœĐŸ ĐČŃ‹ĐżĐŸĐ»ĐœŃĐ”Ń‚ сĐČĐŸŃŽ Ń€Đ°Đ±ĐŸŃ‚Ńƒ. +oc:tooltip.Transposer=ĐŸĐŸĐ·ĐČĐŸĐ»ŃĐ”Ń‚ аĐČŃ‚ĐŸĐŒĐ°Ń‚ĐžĐ·ĐžŃ€ĐŸĐČать ĐżĐ”Ń€Đ”ĐŒĐ”Ń‰Đ”ĐœĐžĐ” Đ±Đ»ĐŸĐșĐŸĐČ Đž жОЎĐșĐŸŃŃ‚Đ”Đč ĐŒĐ”Đ¶ĐŽŃƒ ŃĐŸŃĐ”ĐŽĐœĐžĐŒĐž ĐžĐœĐČĐ”ĐœŃ‚Đ°Ń€ŃĐŒĐž Đž Ń…Ń€Đ°ĐœĐžĐ»ĐžŃ‰Đ°ĐŒĐž жОЎĐșĐŸŃŃ‚Đž. oc:tooltip.UpgradeAngel=ĐŸĐŸĐ·ĐČĐŸĐ»ŃĐ”Ń‚ Ń€ĐŸĐ±ĐŸŃ‚Đ°ĐŒ Ń€Đ°Đ·ĐŒĐ”Ń‰Đ°Ń‚ŃŒ Đ±Đ»ĐŸĐșĐž ĐČ ĐČĐŸĐ·ĐŽŃƒŃ…Đ”, ЎажД ДслО ĐŸŃ‚ŃŃƒŃ‚ŃŃ‚ĐČŃƒĐ”Ń‚ Ń‚ĐŸŃ‡Đșа ĐŸĐżĐŸŃ€Ń‹. oc:tooltip.UpgradeBattery=ĐŁĐČДлОчОĐČаДт ĐșĐŸĐ»ĐžŃ‡Đ”ŃŃ‚ĐČĐŸ ŃĐœĐ”Ń€ĐłĐžĐž, ĐșĐŸŃ‚ĐŸŃ€ŃƒŃŽ Ń€ĐŸĐ±ĐŸŃ‚ ĐŒĐŸĐ¶Đ”Ń‚ Ń…Ń€Đ°ĐœĐžŃ‚ŃŒ, ŃŃ‚ĐŸ ĐżĐŸĐ·ĐČĐŸĐ»ŃĐ”Ń‚ Đ”ĐŒŃƒ Ń€Đ°Đ±ĐŸŃ‚Đ°Ń‚ŃŒ ĐŽĐŸĐ»ŃŒŃˆĐ” бДз ĐżĐ”Ń€Đ”Đ·Đ°Ń€ŃĐŽĐșĐž. oc:tooltip.UpgradeChunkloader=ЕслО Ń€ĐŸĐ±ĐŸŃ‚ ĐŽĐČĐžĐ¶Đ”Ń‚ŃŃ ĐČ Đ»Đ”ŃŃƒ Đž ĐœĐžĐșŃ‚ĐŸ Đ”ĐłĐŸ ĐœĐ” ĐČоЮот, ĐŽĐ”ĐčстĐČĐžŃ‚Đ”Đ»ŃŒĐœĐŸ лО ĐŸĐœ ĐŽĐČĐžĐ¶Đ”Ń‚ŃŃ? Đ­Ń‚ĐŸ ŃƒĐ»ŃƒŃ‡ŃˆĐ”ĐœĐžĐ” ĐłĐ°Ń€Đ°ĐœŃ‚ĐžŃ€ŃƒĐ”Ń‚, Ń‡Ń‚ĐŸ ĐŽĐČĐžĐ¶Đ”Ń‚ŃŃ. ĐžĐœĐŸ ЎДржОт Ń‡Đ°ĐœĐș, ĐœĐ° ĐșĐŸŃ‚ĐŸŃ€ĐŸĐŒ ĐœĐ°Ń…ĐŸĐŽĐžŃ‚ŃŃ Ń€ĐŸĐ±ĐŸŃ‚, Đ·Đ°ĐłŃ€ŃƒĐ¶Đ”ĐœĐœŃ‹ĐŒ, ĐœĐŸ ĐżĐŸŃŃ‚ĐŸŃĐœĐœĐŸ ĐżĐŸŃ‚Ń€Đ”Đ±Đ»ŃĐ”Ń‚ ŃĐœĐ”Ń€ĐłĐžŃŽ. From 83ce705a99e381ea1cb495d81637d8909cfaafce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Sat, 29 Aug 2015 15:10:44 +0200 Subject: [PATCH 26/30] Finished migrating crop stuff to Geolyzer/converter logic (mostly because I cba to make new graphics >_>). Also added AgriCraft API as JAR lib because getting the Gradle dep to work is a royal pita and I wasted too much time on trying that already... --- ...riCraft-1.7.10-1.4.0-beta-2-1.7.10-api.jar | Bin 0 -> 31863 bytes .../cil/oc/common/item/UpgradeFarming.scala | 5 -- .../scala/li/cil/oc/integration/Mods.scala | 2 +- .../oc/integration/agricraft/ApiHandler.scala | 17 +++++ .../agricraft/ConverterSeeds.scala | 31 ++++++++ .../agricraft/EventHandlerAgriCraft.scala | 31 ++++++++ .../integration/agricraft/ModAgriCraft.scala | 37 +++------- .../li/cil/oc/integration/util/Crop.scala | 26 ------- .../vanilla/EventHandlerVanilla.scala | 28 ++++++++ .../oc/integration/vanilla/ModVanilla.scala | 67 ++---------------- .../oc/server/component/UpgradeFarming.scala | 33 --------- 11 files changed, 122 insertions(+), 155 deletions(-) create mode 100644 libs/AgriCraft-1.7.10-1.4.0-beta-2-1.7.10-api.jar delete mode 100644 src/main/scala/li/cil/oc/common/item/UpgradeFarming.scala create mode 100644 src/main/scala/li/cil/oc/integration/agricraft/ApiHandler.scala create mode 100644 src/main/scala/li/cil/oc/integration/agricraft/ConverterSeeds.scala create mode 100644 src/main/scala/li/cil/oc/integration/agricraft/EventHandlerAgriCraft.scala delete mode 100644 src/main/scala/li/cil/oc/integration/util/Crop.scala create mode 100644 src/main/scala/li/cil/oc/integration/vanilla/EventHandlerVanilla.scala delete mode 100644 src/main/scala/li/cil/oc/server/component/UpgradeFarming.scala diff --git a/libs/AgriCraft-1.7.10-1.4.0-beta-2-1.7.10-api.jar b/libs/AgriCraft-1.7.10-1.4.0-beta-2-1.7.10-api.jar new file mode 100644 index 0000000000000000000000000000000000000000..470234700050a4bdd7b942ca34ef95187615dd64 GIT binary patch literal 31863 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 literal 0 HcmV?d00001 diff --git a/src/main/scala/li/cil/oc/common/item/UpgradeFarming.scala b/src/main/scala/li/cil/oc/common/item/UpgradeFarming.scala deleted file mode 100644 index bbb076041..000000000 --- a/src/main/scala/li/cil/oc/common/item/UpgradeFarming.scala +++ /dev/null @@ -1,5 +0,0 @@ -package li.cil.oc.common.item - -class UpgradeFarming (val parent: Delegator) extends traits.Delegate with traits.ItemTier{ - -} diff --git a/src/main/scala/li/cil/oc/integration/Mods.scala b/src/main/scala/li/cil/oc/integration/Mods.scala index 853beeaa6..2d0d158f4 100644 --- a/src/main/scala/li/cil/oc/integration/Mods.scala +++ b/src/main/scala/li/cil/oc/integration/Mods.scala @@ -19,7 +19,7 @@ object Mods { def All = knownMods.clone() - val AgriCraft = new SimpleMod(IDs.AgriCraft) + val AgriCraft = new SimpleMod(IDs.AgriCraft, version = "@[1.4.0,)") val AppliedEnergistics2 = new SimpleMod(IDs.AppliedEnergistics2, version = "@[rv1,)", providesPower = true) val BattleGear2 = new SimpleMod(IDs.BattleGear2) val BetterRecords = new SimpleMod(IDs.BetterRecords) diff --git a/src/main/scala/li/cil/oc/integration/agricraft/ApiHandler.scala b/src/main/scala/li/cil/oc/integration/agricraft/ApiHandler.scala new file mode 100644 index 000000000..03d5b3bc3 --- /dev/null +++ b/src/main/scala/li/cil/oc/integration/agricraft/ApiHandler.scala @@ -0,0 +1,17 @@ +package li.cil.oc.integration.agricraft + +import com.InfinityRaider.AgriCraft + +object ApiHandler { + lazy val Api = AgriCraft.api.API.getAPI(1) match { + case api: AgriCraft.api.v1.APIv1 if isApiUsable(api) => Option(api) + case _ => None + } + + private def isApiUsable(api: AgriCraft.api.APIBase) = { + val status = api.getStatus + status == AgriCraft.api.APIStatus.OK || + status == AgriCraft.api.APIStatus.BACKLEVEL_OK || + status == AgriCraft.api.APIStatus.BACKLEVEL_LIMITED + } +} diff --git a/src/main/scala/li/cil/oc/integration/agricraft/ConverterSeeds.scala b/src/main/scala/li/cil/oc/integration/agricraft/ConverterSeeds.scala new file mode 100644 index 000000000..e6b4c5a4d --- /dev/null +++ b/src/main/scala/li/cil/oc/integration/agricraft/ConverterSeeds.scala @@ -0,0 +1,31 @@ +package li.cil.oc.integration.agricraft + +import java.util + +import com.InfinityRaider.AgriCraft.api.v1.ISeedStats +import li.cil.oc.api.driver.Converter +import net.minecraft.item.ItemStack + +import scala.collection.convert.WrapAsScala._ + +object ConverterSeeds extends Converter { + override def convert(value: scala.Any, output: util.Map[AnyRef, AnyRef]): Unit = { + value match { + case stack: ItemStack => ApiHandler.Api.foreach(api => { + if (api.isHandledByAgricraft(stack) && stack.hasTagCompound && stack.getTagCompound.getBoolean("analyzed")) api.getSeedStats(stack) match { + case stats: ISeedStats => + output += "agricraft" -> Map( + "gain" -> float2Float(stats.getGain), + "maxGain" -> float2Float(stats.getMaxGain), + "growth" -> float2Float(stats.getGrowth), + "maxGrowth" -> float2Float(stats.getMaxGrowth), + "strength" -> float2Float(stats.getStrength), + "maxStrength" -> float2Float(stats.getMaxStrength) + ) + case _ => + } + }) + case _ => + } + } +} diff --git a/src/main/scala/li/cil/oc/integration/agricraft/EventHandlerAgriCraft.scala b/src/main/scala/li/cil/oc/integration/agricraft/EventHandlerAgriCraft.scala new file mode 100644 index 000000000..5dc941772 --- /dev/null +++ b/src/main/scala/li/cil/oc/integration/agricraft/EventHandlerAgriCraft.scala @@ -0,0 +1,31 @@ +package li.cil.oc.integration.agricraft + +import com.InfinityRaider.AgriCraft.api.v1.ISeedStats +import cpw.mods.fml.common.eventhandler.SubscribeEvent +import li.cil.oc.api.event.GeolyzerEvent + +import scala.collection.convert.WrapAsScala._ + +object EventHandlerAgriCraft { + @SubscribeEvent + def onGeolyzerAnalyze(e: GeolyzerEvent.Analyze) { + val world = e.host.world + + ApiHandler.Api.foreach(api => if (api.isCrops(world, e.x, e.y, e.z)) { + e.data += "growth" -> float2Float(if (api.isMature(world, e.x, e.y, e.z)) 1f else 0f) + + if (api.isAnalyzed(world, e.x, e.y, e.z)) { + api.getStats(world, e.x, e.y, e.z) match { + case stats: ISeedStats => + e.data += "gain" -> float2Float(stats.getGain) + e.data += "maxGain" -> float2Float(stats.getMaxGain) + e.data += "growth" -> float2Float(stats.getGrowth) + e.data += "maxGrowth" -> float2Float(stats.getMaxGrowth) + e.data += "strength" -> float2Float(stats.getStrength) + e.data += "maxStrength" -> float2Float(stats.getMaxStrength) + case _ => // Invalid crop. + } + } + }) + } +} diff --git a/src/main/scala/li/cil/oc/integration/agricraft/ModAgriCraft.scala b/src/main/scala/li/cil/oc/integration/agricraft/ModAgriCraft.scala index c4c82eee0..f3325428f 100644 --- a/src/main/scala/li/cil/oc/integration/agricraft/ModAgriCraft.scala +++ b/src/main/scala/li/cil/oc/integration/agricraft/ModAgriCraft.scala @@ -1,38 +1,17 @@ package li.cil.oc.integration.agricraft -import com.InfinityRaider.AgriCraft.blocks.BlockCrop -import li.cil.oc.integration.util.Crop -import li.cil.oc.integration.util.Crop.CropProvider -import li.cil.oc.integration.{Mods, Mod, ModProxy} -import li.cil.oc.server.component._ -import li.cil.oc.util.BlockPosition -import net.minecraft.block.Block -import net.minecraft.item.Item +import li.cil.oc.api.Driver +import li.cil.oc.integration.Mod +import li.cil.oc.integration.ModProxy +import li.cil.oc.integration.Mods +import net.minecraftforge.common.MinecraftForge -object ModAgriCraft extends ModProxy with CropProvider { +object ModAgriCraft extends ModProxy { override def getMod: Mod = Mods.AgriCraft override def initialize(): Unit = { - Crop.addProvider(this) - } + Driver.add(ConverterSeeds) - override def getInformation(pos: BlockPosition): Array[AnyRef] = { - val world = pos.world.get - val target = world.getBlock(pos.x,pos.y,pos.z) - target match { - case crop:BlockCrop=>{ - val meta = world.getBlockMetadata(pos.x, pos.y, pos.z) - val value = meta * 100 / 2 - result(Item.itemRegistry.getNameForObject(crop.getSeed)) - } - case _=>result(Unit,"not a thing") - } - } - - override def isValidFor(block: Block): Boolean = { - block match { - case _: BlockCrop => true - case _ => false - } + MinecraftForge.EVENT_BUS.register(EventHandlerAgriCraft) } } diff --git a/src/main/scala/li/cil/oc/integration/util/Crop.scala b/src/main/scala/li/cil/oc/integration/util/Crop.scala deleted file mode 100644 index b90b5ff1f..000000000 --- a/src/main/scala/li/cil/oc/integration/util/Crop.scala +++ /dev/null @@ -1,26 +0,0 @@ -package li.cil.oc.integration.util - -import li.cil.oc.util.BlockPosition -import net.minecraft.block.Block - -import scala.collection.mutable - -object Crop { - - - val providers = mutable.Buffer.empty[CropProvider] - - def addProvider(provider: CropProvider): Unit = providers += provider - - def getProviderForBlock(block: Block): Option[CropProvider] = { - providers.find(_.isValidFor(block)) - } - - trait CropProvider { - def getInformation(pos: BlockPosition): Array[AnyRef] - - def isValidFor(block: Block): Boolean - } - - -} diff --git a/src/main/scala/li/cil/oc/integration/vanilla/EventHandlerVanilla.scala b/src/main/scala/li/cil/oc/integration/vanilla/EventHandlerVanilla.scala new file mode 100644 index 000000000..650b9775c --- /dev/null +++ b/src/main/scala/li/cil/oc/integration/vanilla/EventHandlerVanilla.scala @@ -0,0 +1,28 @@ +package li.cil.oc.integration.vanilla + +import cpw.mods.fml.common.eventhandler.SubscribeEvent +import li.cil.oc.api.event.GeolyzerEvent +import net.minecraft.block.BlockCrops +import net.minecraft.init.Blocks + +import scala.collection.convert.WrapAsScala._ + +object EventHandlerVanilla { + @SubscribeEvent + def onGeolyzerAnalyze(e: GeolyzerEvent.Analyze) { + val world = e.host.world + val block = world.getBlock(e.x, e.y, e.z) + if (block.isInstanceOf[BlockCrops] || block == Blocks.melon_stem || block == Blocks.pumpkin_stem || block == Blocks.carrots || block == Blocks.potatoes) { + e.data += "growth" -> float2Float((world.getBlockMetadata(e.x, e.y, e.z) / 7f) max 0 min 1) + } + if (block == Blocks.cocoa) { + e.data += "growth" -> float2Float(((world.getBlockMetadata(e.x, e.y, e.z) >> 2) / 2f) max 0 min 1) + } + if (block == Blocks.nether_wart) { + e.data += "growth" -> float2Float((world.getBlockMetadata(e.x, e.y, e.z) / 3f) max 0 min 1) + } + if (block == Blocks.melon_block || block == Blocks.pumpkin || block == Blocks.cactus || block == Blocks.reeds) { + e.data += "growth" -> float2Float(1f) + } + } +} 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 1f3f1a8fd..2c7933aa2 100644 --- a/src/main/scala/li/cil/oc/integration/vanilla/ModVanilla.scala +++ b/src/main/scala/li/cil/oc/integration/vanilla/ModVanilla.scala @@ -4,18 +4,15 @@ 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.{Crop, BundledRedstone} +import li.cil.oc.integration.util.BundledRedstone import li.cil.oc.integration.util.BundledRedstone.RedstoneProvider -import li.cil.oc.integration.util.Crop.CropProvider -import li.cil.oc.server.component._ import li.cil.oc.util.BlockPosition import li.cil.oc.util.ExtendedWorld._ -import net.minecraft.block._ -import net.minecraft.init.{Items, Blocks} -import net.minecraft.item.Item +import net.minecraft.init.Blocks +import net.minecraftforge.common.MinecraftForge import net.minecraftforge.common.util.ForgeDirection -object ModVanilla extends ModProxy with RedstoneProvider with CropProvider { +object ModVanilla extends ModProxy with RedstoneProvider { def getMod = Mods.Minecraft def initialize() { @@ -48,7 +45,8 @@ object ModVanilla extends ModProxy with RedstoneProvider with CropProvider { RecipeHandler.init() BundledRedstone.addProvider(this) - Crop.addProvider(this) + + MinecraftForge.EVENT_BUS.register(EventHandlerVanilla) } override def computeInput(pos: BlockPosition, side: ForgeDirection): Int = { @@ -58,57 +56,4 @@ object ModVanilla extends ModProxy with RedstoneProvider with CropProvider { } override def computeBundledInput(pos: BlockPosition, side: ForgeDirection): Array[Int] = null - - override def getInformation(pos: BlockPosition): Array[AnyRef] = { - val world = pos.world.get - val target = world.getBlock(pos.x, pos.y, pos.z) - target match { - case crop: BlockBush => { - val meta = world.getBlockMetadata(pos.x, pos.y, pos.z) - var name = crop.getLocalizedName - var modifier = 7 - crop match { - - case Blocks.wheat => { - name = Item.itemRegistry.getNameForObject(Items.wheat) - } - case Blocks.melon_stem => { - //Localize this? - name = "Melon stem" - } - case Blocks.pumpkin_stem => { - name = "Pumpkin stem" - } - case Blocks.nether_wart => { - modifier = 3 - } - case _ => - } - result(name, meta * 100 / modifier) - } - case cocoa: BlockCocoa => { - val meta = world.getBlockMetadata(pos.x, pos.y, pos.z) - val value = meta * 100 / 2 - - result(cocoa.getLocalizedName, Math.min(value, 100)) - } - case _: BlockMelon | _: BlockPumpkin => { - result(target.getLocalizedName, 100) - } - case _: BlockCactus | _: BlockReed => { - val meta = world.getBlockMetadata(pos.x, pos.y, pos.z) - result(target.getLocalizedName, meta) - } - case _ => result(Unit, "Not a crop") - } - } - - override def isValidFor(block: Block): Boolean = { - block match { - //has to be specified for crops otherwise overriding blocks of other mods might not get their own Provider - case _: BlockStem | Blocks.wheat | Blocks.carrots | Blocks.potatoes | _: BlockCocoa | _: BlockMelon | _: BlockPumpkin | _: BlockCactus | _: BlockReed => true - case _ => false - } - - } } diff --git a/src/main/scala/li/cil/oc/server/component/UpgradeFarming.scala b/src/main/scala/li/cil/oc/server/component/UpgradeFarming.scala deleted file mode 100644 index 7224528ef..000000000 --- a/src/main/scala/li/cil/oc/server/component/UpgradeFarming.scala +++ /dev/null @@ -1,33 +0,0 @@ -package li.cil.oc.server.component - -import li.cil.oc.api.driver.EnvironmentHost -import li.cil.oc.api.machine.{Callback, Arguments, Context} -import li.cil.oc.api.network.Visibility -import li.cil.oc.api.{Network, prefab, internal} -import li.cil.oc.integration.util.Crop -import li.cil.oc.integration.util.Crop.CropProvider -import li.cil.oc.util.BlockPosition -import net.minecraft.block._ -import net.minecraft.init.{Items, Blocks} -import net.minecraft.item.Item -import net.minecraftforge.common.IPlantable -import net.minecraftforge.common.util.ForgeDirection - -class UpgradeFarming(val host: EnvironmentHost with internal.Robot) extends prefab.ManagedEnvironment { - override val node = Network.newNode(this, Visibility.Network). - withComponent("farming"). - create() - - @Callback(doc = """function([count:number]):boolean -- checks the ripeness of the seed.""") - def check(context: Context, args: Arguments): Array[AnyRef] = { - val hostPos = BlockPosition(host) - val targetPos = hostPos.offset(ForgeDirection.DOWN) - val target = host.world.getBlock(targetPos.x, targetPos.y, targetPos.z) - Crop.getProviderForBlock(target) match { - case Some(provider) => provider.getInformation(BlockPosition(targetPos.x, targetPos.y, targetPos.z, host.world)) - case _ => result(Unit, "Not a crop") - } - - } - -} From 931a04c61b254ca3ae2128d3d66b8af3b8151fcf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Sat, 29 Aug 2015 15:55:38 +0200 Subject: [PATCH 27/30] Taking into account ISidedInventory.getAccessibleSlotsFromSide in InventoryUtils, because some inventories are... special. E.g. AgriCraft's Analyzer has getInventorySize = 2, but there are no slots 0 and 1, only slots 36 and 37 (or so; anyway, something way out of the range of to be expected valid indices). --- src/main/scala/li/cil/oc/util/InventoryUtils.scala | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/main/scala/li/cil/oc/util/InventoryUtils.scala b/src/main/scala/li/cil/oc/util/InventoryUtils.scala index 35a691e66..c2f21a5ec 100644 --- a/src/main/scala/li/cil/oc/util/InventoryUtils.scala +++ b/src/main/scala/li/cil/oc/util/InventoryUtils.scala @@ -155,7 +155,10 @@ object InventoryUtils { (stack != null && limit > 0) && { var success = false var remaining = limit - val range = slots.getOrElse(0 until inventory.getSizeInventory) + val range = slots.getOrElse(inventory match { + case sided: ISidedInventory => sided.getAccessibleSlotsFromSide(side.getOrElse(ForgeDirection.UNKNOWN).ordinal).toIterable + case _ => 0 until inventory.getSizeInventory + }) if (range.nonEmpty) { // This is a special case for inserting with an explicit ordering, @@ -204,8 +207,13 @@ object InventoryUtils { *

* This returns true if at least one item was extracted. */ - def extractFromInventory(consumer: (ItemStack) => Unit, inventory: IInventory, side: ForgeDirection, limit: Int = 64) = - (0 until inventory.getSizeInventory).exists(slot => extractFromInventorySlot(consumer, inventory, side, slot, limit)) + def extractFromInventory(consumer: (ItemStack) => Unit, inventory: IInventory, side: ForgeDirection, limit: Int = 64) = { + val range = inventory match { + case sided: ISidedInventory => sided.getAccessibleSlotsFromSide(side.ordinal).toIterable + case _ => 0 until inventory.getSizeInventory + } + range.exists(slot => extractFromInventorySlot(consumer, inventory, side, slot, limit)) + } /** * Utility method for calling insertIntoInventory on an inventory From e23378b6623f63de45cbf55a9042b2428bd58dc8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Sat, 29 Aug 2015 16:24:43 +0200 Subject: [PATCH 28/30] Added setting to change delay enforced when changing redstone output. --- src/main/resources/application.conf | 5 +++++ src/main/scala/li/cil/oc/Settings.scala | 1 + .../scala/li/cil/oc/server/component/RedstoneBundled.scala | 7 +++++-- .../scala/li/cil/oc/server/component/RedstoneVanilla.scala | 4 +++- .../li/cil/oc/server/component/RedstoneWireless.scala | 4 +++- 5 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/main/resources/application.conf b/src/main/resources/application.conf index 9c7884f0d..792fd0b6f 100644 --- a/src/main/resources/application.conf +++ b/src/main/resources/application.conf @@ -1194,6 +1194,11 @@ opencomputers { # properties, i.e. througput, frequency and buffer size. # Valid values are: 0 = none, 1 = tier 1, 2 = tier 2, 3 = tier 3. serverRackSwitchTier: 1 + + # Enforced delay when changing a redstone emitting component's output, + # such as the redstone card and redstone I/O block. Lowering this can + # have very negative impact on server TPS, so beware. + redstoneDelay: 0.1 } # Settings for mod integration (the mod previously known as OpenComponents). diff --git a/src/main/scala/li/cil/oc/Settings.scala b/src/main/scala/li/cil/oc/Settings.scala index 0846170be..809615034 100644 --- a/src/main/scala/li/cil/oc/Settings.scala +++ b/src/main/scala/li/cil/oc/Settings.scala @@ -335,6 +335,7 @@ class Settings(val config: Config) { val dataCardHardLimit = config.getInt("misc.dataCardHardLimit") max 0 val dataCardTimeout = config.getDouble("misc.dataCardTimeout") max 0 val serverRackSwitchTier = (config.getInt("misc.serverRackSwitchTier") - 1) max Tier.None min Tier.Three + val redstoneDelay = config.getDouble("misc.redstoneDelay") max 0 // ----------------------------------------------------------------------- // // printer 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 bfa7120cb..fd6f6ecac 100644 --- a/src/main/scala/li/cil/oc/server/component/RedstoneBundled.scala +++ b/src/main/scala/li/cil/oc/server/component/RedstoneBundled.scala @@ -1,5 +1,6 @@ package li.cil.oc.server.component +import li.cil.oc.Settings import li.cil.oc.api.driver.EnvironmentHost import li.cil.oc.api.machine.Arguments import li.cil.oc.api.machine.Callback @@ -36,14 +37,16 @@ trait RedstoneBundled extends RedstoneVanilla { case (color, number: Number) => redstone.bundledOutput(side, color, number.intValue()) case _ => } - context.pause(0.1) + if (Settings.get.redstoneDelay > 0) + context.pause(Settings.get.redstoneDelay) result(true) } else { val color = checkColor(args, 1) val value = args.checkInteger(2) redstone.bundledOutput(side, color, value) - context.pause(0.1) + if (Settings.get.redstoneDelay > 0) + context.pause(Settings.get.redstoneDelay) 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 index 87b2b552d..c52690c1b 100644 --- a/src/main/scala/li/cil/oc/server/component/RedstoneVanilla.scala +++ b/src/main/scala/li/cil/oc/server/component/RedstoneVanilla.scala @@ -1,5 +1,6 @@ package li.cil.oc.server.component +import li.cil.oc.Settings import li.cil.oc.api.driver.EnvironmentHost import li.cil.oc.api.machine.Arguments import li.cil.oc.api.machine.Callback @@ -30,7 +31,8 @@ trait RedstoneVanilla extends RedstoneSignaller { val side = checkSide(args, 0) val value = args.checkInteger(1) redstone.output(side, value) - context.pause(0.1) + if (Settings.get.redstoneDelay > 0) + context.pause(Settings.get.redstoneDelay) result(redstone.output(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 67e759a32..c62710d65 100644 --- a/src/main/scala/li/cil/oc/server/component/RedstoneWireless.scala +++ b/src/main/scala/li/cil/oc/server/component/RedstoneWireless.scala @@ -4,6 +4,7 @@ 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.Settings import li.cil.oc.api.driver.EnvironmentHost import li.cil.oc.api.machine.Arguments import li.cil.oc.api.machine.Callback @@ -48,7 +49,8 @@ trait RedstoneWireless extends RedstoneSignaller with WirelessReceivingDevice wi util.WirelessRedstone.updateOutput(this) - context.pause(0.1) + if (Settings.get.redstoneDelay > 0) + context.pause(Settings.get.redstoneDelay) } result(oldValue) From 06705e3891f9de3a1db36a8dd2eadc71099a2c26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Sun, 30 Aug 2015 15:28:49 +0200 Subject: [PATCH 29/30] Update plan9k MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Ɓukasz Magiera --- .../opencomputers/loot/Plan9k/bin/cat.lua | 2 +- .../opencomputers/loot/Plan9k/bin/dd.lua | 2 + .../opencomputers/loot/Plan9k/bin/df.lua | 3 +- .../opencomputers/loot/Plan9k/bin/edit.lua | 13 +- .../opencomputers/loot/Plan9k/bin/getty.lua | 2 + .../loot/Plan9k/bin/ifconfig.lua | 17 +- .../opencomputers/loot/Plan9k/bin/init.lua | 24 +- .../opencomputers/loot/Plan9k/bin/lua.lua | 10 + .../opencomputers/loot/Plan9k/bin/more.lua | 44 +++ .../opencomputers/loot/Plan9k/bin/sh.lua | 1 + .../opencomputers/loot/Plan9k/bin/tee.lua | 4 +- .../loot/Plan9k/lib/modules/base/10_devfs.lua | 26 +- .../Plan9k/lib/modules/base/10_procfs.lua | 39 ++- .../Plan9k/lib/modules/base/15_userspace.lua | 14 +- .../Plan9k/lib/modules/base/16_require.lua | 27 +- .../loot/Plan9k/lib/modules/base/17_data.lua | 47 +++ .../loot/Plan9k/lib/modules/base/17_drive.lua | 117 ++++++++ .../Plan9k/lib/modules/base/17_network.lua | 1 + .../loot/Plan9k/lib/modules/base/17_tape.lua | 27 +- .../Plan9k/lib/modules/base/20_threading.lua | 4 +- .../Plan9k/lib/modules/base/21_threadUtil.lua | 5 +- .../opencomputers/loot/Plan9k/lib/term.lua | 277 +++++++++++++++++- .../loot/Plan9k/usr/bin/base64.lua | 42 +++ .../loot/Plan9k/usr/bin/deflate.lua | 25 ++ .../opencomputers/loot/Plan9k/usr/bin/gpg.lua | 244 +++++++++++++++ .../loot/Plan9k/usr/bin/inflate.lua | 25 ++ .../loot/Plan9k/usr/bin/md5sum.lua | 27 ++ .../opencomputers/loot/Plan9k/usr/bin/mpt.lua | 22 +- .../loot/Plan9k/usr/bin/sha256sum.lua | 27 ++ .../loot/Plan9k/usr/lib/data.lua | 26 ++ .../loot/Plan9k/var/lib/mpt/config.db | 2 +- .../loot/Plan9k/var/lib/mpt/mpt.db | 2 +- 32 files changed, 1097 insertions(+), 51 deletions(-) create mode 100644 src/main/resources/assets/opencomputers/loot/Plan9k/bin/more.lua create mode 100644 src/main/resources/assets/opencomputers/loot/Plan9k/lib/modules/base/17_data.lua create mode 100644 src/main/resources/assets/opencomputers/loot/Plan9k/lib/modules/base/17_drive.lua create mode 100644 src/main/resources/assets/opencomputers/loot/Plan9k/usr/bin/base64.lua create mode 100644 src/main/resources/assets/opencomputers/loot/Plan9k/usr/bin/deflate.lua create mode 100644 src/main/resources/assets/opencomputers/loot/Plan9k/usr/bin/gpg.lua create mode 100644 src/main/resources/assets/opencomputers/loot/Plan9k/usr/bin/inflate.lua create mode 100644 src/main/resources/assets/opencomputers/loot/Plan9k/usr/bin/md5sum.lua create mode 100644 src/main/resources/assets/opencomputers/loot/Plan9k/usr/bin/sha256sum.lua create mode 100644 src/main/resources/assets/opencomputers/loot/Plan9k/usr/lib/data.lua diff --git a/src/main/resources/assets/opencomputers/loot/Plan9k/bin/cat.lua b/src/main/resources/assets/opencomputers/loot/Plan9k/bin/cat.lua index b292f2291..d1fd62ba5 100644 --- a/src/main/resources/assets/opencomputers/loot/Plan9k/bin/cat.lua +++ b/src/main/resources/assets/opencomputers/loot/Plan9k/bin/cat.lua @@ -8,7 +8,7 @@ if #args == 0 then until not read else for i = 1, #args do - local file, reason = io.open(args[i]) + local file, reason = io.open(args[i],"rb")--TODO: make b an option if not file then io.stderr:write(reason .. "\n") return diff --git a/src/main/resources/assets/opencomputers/loot/Plan9k/bin/dd.lua b/src/main/resources/assets/opencomputers/loot/Plan9k/bin/dd.lua index de4509434..afcf298c0 100644 --- a/src/main/resources/assets/opencomputers/loot/Plan9k/bin/dd.lua +++ b/src/main/resources/assets/opencomputers/loot/Plan9k/bin/dd.lua @@ -67,6 +67,8 @@ for n = 1, options.count do end if options.wait then os.sleep(tonumber(options.wait)) + else + os.sleep(0) end end diff --git a/src/main/resources/assets/opencomputers/loot/Plan9k/bin/df.lua b/src/main/resources/assets/opencomputers/loot/Plan9k/bin/df.lua index 9cbc74107..041514da9 100644 --- a/src/main/resources/assets/opencomputers/loot/Plan9k/bin/df.lua +++ b/src/main/resources/assets/opencomputers/loot/Plan9k/bin/df.lua @@ -5,7 +5,8 @@ local text = require("text") local args, options = shell.parse(...) local function formatSize(size) - if not options.h then + size = tonumber(size) or size + if not options.h or type(size) ~= "number" then return tostring(size) end local sizes = {"", "K", "M", "G"} diff --git a/src/main/resources/assets/opencomputers/loot/Plan9k/bin/edit.lua b/src/main/resources/assets/opencomputers/loot/Plan9k/bin/edit.lua index f178f7eec..c1943cd7c 100644 --- a/src/main/resources/assets/opencomputers/loot/Plan9k/bin/edit.lua +++ b/src/main/resources/assets/opencomputers/loot/Plan9k/bin/edit.lua @@ -73,6 +73,7 @@ local code = "" codeHandler = function(char) if char == "[" then code = code .. char elseif char == "0" then code = code .. char + elseif char == "3" then code = code .. char elseif code == "[" and char == "A" then charHandler = baseHandler if y - 1 < 1 then return end @@ -139,6 +140,16 @@ codeHandler = function(char) out:write(text) out:close() end + elseif code == "[3" and char == "~" then + charHandler = baseHandler + if x > unicode.len(lines[y]) then + lines[y] = lines[y] .. (lines[y + 1] or "") + table.remove(lines, y + 1) + render(y, atline + edith - y) + return + end + lines[y] = lines[y]:sub(1, x-1) .. lines[y]:sub(x+1) + render(y, 1) else charHandler = baseHandler end @@ -149,7 +160,7 @@ baseHandler = function(char) code = "" charHandler = codeHandler elseif char == "\n" then - line = lines[y] + local line = lines[y] lines[y] = unicode.sub(line or "", 1, x - 1) table.insert(lines, y + 1, unicode.sub(line or "", x)) x = 1 diff --git a/src/main/resources/assets/opencomputers/loot/Plan9k/bin/getty.lua b/src/main/resources/assets/opencomputers/loot/Plan9k/bin/getty.lua index 2f2a21992..9cedb28e2 100644 --- a/src/main/resources/assets/opencomputers/loot/Plan9k/bin/getty.lua +++ b/src/main/resources/assets/opencomputers/loot/Plan9k/bin/getty.lua @@ -199,6 +199,8 @@ local commandList = {} -- \x1b9[Row];[Col];[Height];[Width]F -- fill -- \x1b9[Row];[Col];[Height];[Width];[Dest Row];[Dest Col]c -- copy +--Add fake gpu component for compat(?) + function charHandlers.control(char) if char == "\x1b" then commandList = {} diff --git a/src/main/resources/assets/opencomputers/loot/Plan9k/bin/ifconfig.lua b/src/main/resources/assets/opencomputers/loot/Plan9k/bin/ifconfig.lua index e7a9ba5cd..42a9f4862 100644 --- a/src/main/resources/assets/opencomputers/loot/Plan9k/bin/ifconfig.lua +++ b/src/main/resources/assets/opencomputers/loot/Plan9k/bin/ifconfig.lua @@ -2,6 +2,21 @@ local network = require "network" local computer = require "computer" local args = {...} +local function formatSize(size) + size = tonumber(size) or size + if type(size) ~= "number" then + return tostring(size) + end + local sizes = {"", "K", "M", "G"} + local unit = 1 + local power = 1024 + while size > power and unit < #sizes do + unit = unit + 1 + size = size / power + end + return math.floor(size * 10) / 10 .. sizes[unit] +end + local function align(txt)return txt .. (" "):sub(#txt+1)end if #args < 1 then @@ -14,7 +29,7 @@ if #args < 1 then local pktIn, pktOut, bytesIn, bytesOut = network.info.getInterfaceInfo(node) print(" RX packets:"..tostring(pktIn)) print(" TX packets:"..tostring(pktOut)) - print(" RX bytes:"..tostring(bytesIn).." TX bytes:"..tostring(bytesOut)) + print(" RX bytes: ".. tostring(bytesIn) .. " (" ..formatSize(bytesIn).. ") TX bytes: " ..tostring(bytesOut) .. " (".. formatSize(bytesOut) .. ")") end elseif args[1] == "bind" and args[2] then print("Address attached") diff --git a/src/main/resources/assets/opencomputers/loot/Plan9k/bin/init.lua b/src/main/resources/assets/opencomputers/loot/Plan9k/bin/init.lua index 71146c458..02a8042b3 100644 --- a/src/main/resources/assets/opencomputers/loot/Plan9k/bin/init.lua +++ b/src/main/resources/assets/opencomputers/loot/Plan9k/bin/init.lua @@ -1,13 +1,28 @@ --Plan9k userspace init for pipes kernel + +--TODO: pcall all + emergency shell(or do it higher, in pipes) + local pipes = require("pipes") -local component = require("component") local filesystem = require("filesystem") +local component = require("component") os.setenv("LIBPATH", "/lib/?.lua;/usr/lib/?.lua;/home/lib/?.lua;./?.lua;/lib/?/init.lua;/usr/lib/?/init.lua;/home/lib/?/init.lua;./?/init.lua") os.setenv("PATH", "/usr/local/bin:/usr/bin:/bin:.") os.setenv("PWD", "/") os.setenv("PS1", "\x1b[33m$PWD\x1b[31m#\x1b[39m ") +pipes.log("INIT: Mounting filesystems") + +if filesystem.exists("/etc/fstab") then + for entry in io.lines("/etc/fstab") do + if entry:sub(1,1) ~= "#" then + + end + end +end + +pipes.log("INIT: Starting terminals") + if not filesystem.exists("/root") then filesystem.makeDirectory("/root") end @@ -37,7 +52,6 @@ end local sin, sout - local screens = component.list("screen") for gpu in component.list("gpu") do local screen = screens() @@ -85,7 +99,11 @@ end pcall(services) local kout = io.popen(function() - pipes.setThreadName("/bin/tee.lua") + if filesystem.exists("/kern.log") then + filesystem.remove("/kern.log.old") + filesystem.rename("/kern.log", "/kern.log.old") + end + pipes.setThreadName("[init]/logd") io.output(sout) loadfile("/bin/tee.lua", nil, _G)("/kern.log") end, "w") diff --git a/src/main/resources/assets/opencomputers/loot/Plan9k/bin/lua.lua b/src/main/resources/assets/opencomputers/loot/Plan9k/bin/lua.lua index fe946e194..f00045057 100644 --- a/src/main/resources/assets/opencomputers/loot/Plan9k/bin/lua.lua +++ b/src/main/resources/assets/opencomputers/loot/Plan9k/bin/lua.lua @@ -1,5 +1,8 @@ local serialization = require("serialization") local term = require("term") +local fs = require("filesystem") + +local args = {...} local env = setmetatable({}, {__index = _ENV}) @@ -10,6 +13,13 @@ local function optrequire(...) end end +if args[1] and fs.exists(args[1]) then --non standard, require -i !!! + local f = io.open(args[1]) + local code = load(f:read("*all"), "="..args[1], "t", env) + f:close() + xpcall(code, debug.traceback) +end + local hist = {} while true do io.write(tostring(env._PROMPT or "lua> ")) diff --git a/src/main/resources/assets/opencomputers/loot/Plan9k/bin/more.lua b/src/main/resources/assets/opencomputers/loot/Plan9k/bin/more.lua new file mode 100644 index 000000000..648ef31c5 --- /dev/null +++ b/src/main/resources/assets/opencomputers/loot/Plan9k/bin/more.lua @@ -0,0 +1,44 @@ +local term = require("term") + +function usage() + print( +[[Usage: + more [options] ... + +A file perusal filter for CRT viewing.]]) +end + +local args = {...} +local file = args[1] +if not file then usage() return end + +file = io.open(file) + +if not file then + print("File not found") + return +end + +term.clear() +local _, h = term.getResolution() +io.write("\x1b[1;1H") +print("...",h) +for i = 1, h - 2 do + local line = file:read("*l") + if not line then print("input end")return end + print(line) +end + +io.write("\x1b47m\x1b30m--More--\x1b39m\x1b49m") + +while true do + local c = io.read(1) + if c == "\n" then + local line = file:read("*l") + if not line then return end + print("\r\x1b[K" .. line) + io.write("\x1b47m\x1b30m--More--\x1b39m\x1b49m") + elseif c == "q" then + return + end +end diff --git a/src/main/resources/assets/opencomputers/loot/Plan9k/bin/sh.lua b/src/main/resources/assets/opencomputers/loot/Plan9k/bin/sh.lua index 5fb8c378c..db4c3b3ef 100644 --- a/src/main/resources/assets/opencomputers/loot/Plan9k/bin/sh.lua +++ b/src/main/resources/assets/opencomputers/loot/Plan9k/bin/sh.lua @@ -203,6 +203,7 @@ while run do if term.getCursor() > 1 then io.write("\n") end + io.write("\x1b49m\x1b39m") io.write(expand(os.getenv("PS1"))) local cmd = term.read(history)--io.read("*l") --print("--IN: ", cmd) diff --git a/src/main/resources/assets/opencomputers/loot/Plan9k/bin/tee.lua b/src/main/resources/assets/opencomputers/loot/Plan9k/bin/tee.lua index 828335ac3..41e324564 100644 --- a/src/main/resources/assets/opencomputers/loot/Plan9k/bin/tee.lua +++ b/src/main/resources/assets/opencomputers/loot/Plan9k/bin/tee.lua @@ -3,7 +3,7 @@ local args = {...} local f = io.open(args[1], "a") while true do - local data = io.read(1) + local data = io.read("*L") if not data then f:close() return @@ -11,7 +11,7 @@ while true do if io.input().remaining() > 0 then data = data .. io.read(io.input().remaining()) end + io.write(data) f:write(data) f:flush() - io.write(data) end diff --git a/src/main/resources/assets/opencomputers/loot/Plan9k/lib/modules/base/10_devfs.lua b/src/main/resources/assets/opencomputers/loot/Plan9k/lib/modules/base/10_devfs.lua index 806a414c6..61b03bd22 100644 --- a/src/main/resources/assets/opencomputers/loot/Plan9k/lib/modules/base/10_devfs.lua +++ b/src/main/resources/assets/opencomputers/loot/Plan9k/lib/modules/base/10_devfs.lua @@ -9,7 +9,6 @@ proxy.isReadOnly = function() return true end proxy.rename = function() error("Permission Denied") end proxy.remove = function() error("Permission Denied") end proxy.setLabel = function() error("Permission Denied") end -proxy.seek = function() error("Not supported") end proxy.size = function(path) local seg = kernel.modules.vfs.segments(path) local file = data @@ -22,7 +21,17 @@ proxy.getLabel = function() return "devfs" end local allocator, handles = kernel.modules.util.getAllocator() -proxy.exists = function()end +proxy.exists = function(path) + local seg = kernel.modules.vfs.segments(path) + local file = data + for _, d in pairs(seg) do + if not file[d] then + return false + end + file = file[d] + end + return file and true or false +end proxy.open = function(path) local seg = kernel.modules.vfs.segments(path) local file = data @@ -48,6 +57,9 @@ end proxy.write = function(h, ...) return handles[h].file.write(handles[h], ...) end +proxy.seek = function(h, ...) + return handles[h].file.seek(handles[h], ...) +end proxy.isDirectory = function(path) local seg = kernel.modules.vfs.segments(path) local dir = data @@ -69,8 +81,8 @@ proxy.list = function(path) error("File is not a directory") end local list = {} - for f in pairs(dir) do - list[#list + 1] = f + for f, node in pairs(dir) do + list[#list + 1] = f .. (node.__type and "" or "/") end return list end @@ -80,6 +92,12 @@ data.null = { __type = "f", write = function()end } +data.kmsg = { + __type = "f", + write = function(h, data) + kernel.io.println(data) + end +} data.zero = { __type = "f", read = function(h, c) diff --git a/src/main/resources/assets/opencomputers/loot/Plan9k/lib/modules/base/10_procfs.lua b/src/main/resources/assets/opencomputers/loot/Plan9k/lib/modules/base/10_procfs.lua index 7c60579b2..91a41d1a1 100644 --- a/src/main/resources/assets/opencomputers/loot/Plan9k/lib/modules/base/10_procfs.lua +++ b/src/main/resources/assets/opencomputers/loot/Plan9k/lib/modules/base/10_procfs.lua @@ -15,6 +15,7 @@ proxy.getLabel = function() return "procfs" end local allocator, handles = kernel.modules.util.getAllocator() proxy.exists = function()end + proxy.open = function(path) local seg = kernel.modules.vfs.segments(path) local file = data @@ -32,16 +33,21 @@ proxy.open = function(path) end return hnd.id end + proxy.read = function(h, n) return handles[h]:read(n) end + proxy.close = function(h) allocator:unset(handles[h]) end + proxy.write = function() error("Permission Denied") end + proxy.isDirectory = function() end + proxy.list = function(path) local seg = kernel.modules.vfs.segments(path) local dir = data @@ -51,11 +57,11 @@ proxy.list = function(path) local list = {} for pid, thr in pairs(kernel.modules.threading.threads) do if thr.coro and dir == data then - list[#list + 1] = tostring(pid) + list[#list + 1] = tostring(pid) .. "/" end end - for f in pairs(dir) do - list[#list + 1] = f + for f, node in pairs(dir) do + list[#list + 1] = f .. (type(node) == "table" and "/" or "") end return list end @@ -72,13 +78,36 @@ data.cpuinfo = function() "cpu family : 1\n" .. "model : 1\n" .. "model name : OpenComputers Lua CPU @ unkown Tier\n" .. - "microcode : 0x52\n" .. + "microcode : " .. (string.pack and "0x53" or "0x52") .. "\n" .. "physical id : 0\n" end +data.uptime = function() + return tostring(computer.uptime()) +end + setmetatable(data, {__index = function(_, k) if tonumber(k) and kernel.modules.threading.threads[tonumber(k)] and kernel.modules.threading.threads[tonumber(k)].coro then - return {comm = function()return kernel.modules.threading.threads[tonumber(k)].name end} + return { + comm = function()return kernel.modules.threading.threads[tonumber(k)].name end, + limits = function() + local limits = "Limit Units Soft Limit\n" + limits = limits .. "Max pending signals signals " .. kernel.modules.threading.threads[tonumber(k)].maxPendingSignals .. "\n" + limits = limits .. "Max open files files " .. kernel.modules.threading.threads[tonumber(k)].maxOpenFiles .. "\n" + return limits + end, + status = function() + local status = "" + status = status .. "Name: " .. kernel.modules.threading.threads[tonumber(k)].name .. "\n" + status = status .. "State: " .. coroutine.status(kernel.modules.threading.threads[tonumber(k)].coro) .. "\n" + status = status .. "Pid: " .. kernel.modules.threading.threads[tonumber(k)].pid .. "\n" + status = status .. "Uid: " .. kernel.modules.threading.threads[tonumber(k)].uid .. "\n" + + --TODO: count actual signals + status = status .. "SigQ: " .. #kernel.modules.threading.threads[tonumber(k)].eventQueue .. "/" .. kernel.modules.threading.threads[tonumber(k)].maxPendingSignals .. "\n" + return status + end + } end end}) diff --git a/src/main/resources/assets/opencomputers/loot/Plan9k/lib/modules/base/15_userspace.lua b/src/main/resources/assets/opencomputers/loot/Plan9k/lib/modules/base/15_userspace.lua index 5efd66a64..18cc75312 100644 --- a/src/main/resources/assets/opencomputers/loot/Plan9k/lib/modules/base/15_userspace.lua +++ b/src/main/resources/assets/opencomputers/loot/Plan9k/lib/modules/base/15_userspace.lua @@ -78,6 +78,7 @@ end function kernel.userspace.os.exit() kernel.modules.threading.kill(kernel.modules.threading.currentThread.pid) + coroutine.yield("yield", 0) end function kernel.userspace.os.sleep(time) @@ -142,7 +143,12 @@ end kernel.userspace.coroutine = {} -kernel.userspace.coroutine.yield = function(...) - return coroutine.yield(...)--TODO: FIX; move to debug -end - +--lua 5.3 <-> 5.2 compat +kernel.userspace.bit32 = bit32 or load([[return { + band = function(a, b) return a & b end, + bor = function(a, b) return a | b end, + bxor = function(a, b) return a ~ b end, + bnot = function(a) return ~a end, + rshift = function(a, n) return a >> n end, + lshift = function(a, n) return a << n end, +}]])() diff --git a/src/main/resources/assets/opencomputers/loot/Plan9k/lib/modules/base/16_require.lua b/src/main/resources/assets/opencomputers/loot/Plan9k/lib/modules/base/16_require.lua index bb72e1a5a..e25ba7113 100644 --- a/src/main/resources/assets/opencomputers/loot/Plan9k/lib/modules/base/16_require.lua +++ b/src/main/resources/assets/opencomputers/loot/Plan9k/lib/modules/base/16_require.lua @@ -39,18 +39,17 @@ end local function pathSearcher(module) local filepath, reason = kernel.userspace.package.searchpath(module, kernel.userspace.os.getenv("LIBPATH")) if filepath then - local loader, reason = kernel.userspace.loadfile(filepath, "bt", setmetatable({},{__index = kernel.userspace})) + local loader + loader, reason = kernel.userspace.loadfile(filepath, "bt", setmetatable({},{__index = kernel.userspace})) if loader then - local state, mod = pcall(loader) + local state + state, reason = pcall(loader) if state then - return mod - else - kernel.io.println("Module '" .. tostring(module) .. "' loading failed: " .. tostring(mod)) + return reason end end - else - return nil, reason end + return nil, reason end kernel.userspace.package.searchers[#kernel.userspace.package.searchers + 1] = preloadSearcher @@ -65,19 +64,23 @@ kernel.userspace.require = function(module) if kernel.userspace.package.loading[module] then error("Already loading "..tostring(module)) else + local reason + kernel.userspace.package.loading[module] = true for _, searcher in ipairs(kernel.userspace.package.searchers) do - local res, mod, reason = pcall(searcher, module) - if res and mod then + local success, mod, res = pcall(searcher, module) + if success and mod then kernel.userspace.package.loading[module] = nil kernel.userspace.package.loaded[module] = mod return mod - elseif not mod and reason then - kernel.io.println("Searcher for '" .. tostring(module) .. "' loading failed: " .. tostring(reason)) + elseif (not success) and mod then + reason = mod + elseif res then + reason = res end end kernel.userspace.package.loading[module] = nil - error("Could not load module " .. tostring(module)) + error(string.format("Could not load module '%s': %s", module, reason or "module returned nil")) end end end diff --git a/src/main/resources/assets/opencomputers/loot/Plan9k/lib/modules/base/17_data.lua b/src/main/resources/assets/opencomputers/loot/Plan9k/lib/modules/base/17_data.lua new file mode 100644 index 000000000..4676746f4 --- /dev/null +++ b/src/main/resources/assets/opencomputers/loot/Plan9k/lib/modules/base/17_data.lua @@ -0,0 +1,47 @@ +cards = {} + + +local function buildDevfs() + for file in pairs(kernel.modules.devfs.data) do + if file == "urandom" then + kernel.modules.devfs.data[file] = nil + end + end + + kernel.modules.devfs.data["urandom"] = { + __type = "f", + read = function(h, len) + return component.invoke(cards[1], "random", len) + end + } +end + +local function onComponentAdded(_, address, componentType) + if componentType == "data" then + cards[#cards + 1] = address + buildDevfs() + end +end + +local function onComponentRemoved(_, address, componentType) + if componentType == "data" then + local t + for i, card in ipairs(cards) do + if card == address then + t = i + break + end + end + table.remove(cards, t) + buildDevfs() + end +end + +--function start() + --for card, t in component.list("data") do + -- onComponentAdded(_, card, t) + --end +--end + +kernel.modules.keventd.listen("component_added", onComponentAdded) +kernel.modules.keventd.listen("component_removed", onComponentRemoved) diff --git a/src/main/resources/assets/opencomputers/loot/Plan9k/lib/modules/base/17_drive.lua b/src/main/resources/assets/opencomputers/loot/Plan9k/lib/modules/base/17_drive.lua new file mode 100644 index 000000000..a080514d7 --- /dev/null +++ b/src/main/resources/assets/opencomputers/loot/Plan9k/lib/modules/base/17_drive.lua @@ -0,0 +1,117 @@ +drives = {} + +function writeSectors(drive, data, at) + local sectorSize = component.invoke(drive, "getSectorSize") + repeat + local atSector = math.floor((at - 1) / sectorSize) + 1 + + local inSectorStart = (at - 1) % sectorSize + 1 + local writable = math.min(#data, sectorSize - inSectorStart + 1) + + local old = component.invoke(drive, "readSector", atSector) + + local before = old:sub(0, inSectorStart - 1) + local after = old:sub(inSectorStart + writable) + + local toWrite = before .. data:sub(1, writable) .. after + data = data:sub(writable + 1) + + kernel.io.println("Wd: " .. atSector .. "/" .. #toWrite .. ": "..inSectorStart.." [ " .. writable .. " ] "..(inSectorStart + writable) .. " #old="..#old) + component.invoke(drive, "writeSector", atSector, toWrite) + + at = at + writable + until #data < 1 +end + +function readSectors(drive, at, len) + local data = "" + local sectorSize = component.invoke(drive, "getSectorSize") + repeat + local atSector = math.floor(at / sectorSize) + 1 + + sector = component.invoke(drive, "readSector", atSector) + kernel.io.println("Rsect " .. atSector .. ": " .. tostring((at - 1) % sectorSize + 1) .. " -> " .. tostring(math.min((at - 1) % sectorSize + len - #data, sectorSize))) + local read = sector:sub((at - 1) % sectorSize + 1, math.min((at - 1) % sectorSize + len - #data, sectorSize)) + + data = data .. read + at = at + #read + until #data >= len + return data +end + +local function buildDevfs() + for file in pairs(kernel.modules.devfs.data) do + if file:match("^sd") then + kernel.modules.devfs.data[file] = nil + end + end + for k, drive in ipairs(drives) do + kernel.modules.devfs.data["sd" .. string.char(k + 96)] = { + __type = "f", + open = function(hnd) + --component.invoke(drive, "seek", -math.huge) + hnd.drive = drive + hnd.pos = 1 + --kernel.io.println("Od: " .. hnd.pos .. "/" .. component.invoke(drive, "getCapacity")) + end, + size = function() + return component.invoke(drive, "getCapacity") + end, + write = function(h, data) + + writeSectors(drive, data, h.pos) + --kernel.io.println("Wd: " .. h.pos .. "(+" .. #data .. ")/" .. component.invoke(drive, "getCapacity")) + h.pos = h.pos + #data + return not (h.pos >= component.invoke(drive, "getCapacity")) + --TODO: do this correctly + end, + read = function(h, len) + len = math.ceil(len) + kernel.io.println("Rd " .. tostring(len) .. ": " .. h.pos .. "/" .. component.invoke(drive, "getCapacity")) + if h.pos >= component.invoke(drive, "getCapacity") then + return + end + local data = readSectors(drive, h.pos, len) + h.pos = h.pos + len + return data + end, + seek = function(h, whence, offset) + offset = offset or 0 + if whence == "end" then + h.pos = math.min(component.invoke(drive, "getCapacity"), math.max(1, component.invoke(drive, "getCapacity") - offset)) + return h.pos - 1 + elseif whence == "set" then + h.pos = math.min(component.invoke(drive, "getCapacity"), math.max(1, 1 + offset)) + return h.pos - 1 + else + h.pos = math.min(component.invoke(drive, "getCapacity"), math.max(1, h.pos + offset)) + return h.pos - 1 + end + return math.floor(h.pos) + end + } + end +end + +local function onComponentAdded(_, address, componentType) + if componentType == "drive" then + drives[#drives + 1] = address + buildDevfs() + end +end + +local function onComponentRemoved(_, address, componentType) + if componentType == "drive" then + local t + for i, drive in ipairs(drives) do + if drive == address then + t = i + break + end + end + table.remove(drives, t) + buildDevfs() + end +end +kernel.modules.keventd.listen("component_added", onComponentAdded) +kernel.modules.keventd.listen("component_removed", onComponentRemoved) diff --git a/src/main/resources/assets/opencomputers/loot/Plan9k/lib/modules/base/17_network.lua b/src/main/resources/assets/opencomputers/loot/Plan9k/lib/modules/base/17_network.lua index 33ad4d5ff..84ba412ed 100644 --- a/src/main/resources/assets/opencomputers/loot/Plan9k/lib/modules/base/17_network.lua +++ b/src/main/resources/assets/opencomputers/loot/Plan9k/lib/modules/base/17_network.lua @@ -321,6 +321,7 @@ startNetwork = function() end sent = nil else + --we've already requested this addr so if we get the route --we'll respond routeRequests[dest][#routeRequests[dest]+1] = {type = "R", host = origin} diff --git a/src/main/resources/assets/opencomputers/loot/Plan9k/lib/modules/base/17_tape.lua b/src/main/resources/assets/opencomputers/loot/Plan9k/lib/modules/base/17_tape.lua index faaf7efe9..359163dde 100644 --- a/src/main/resources/assets/opencomputers/loot/Plan9k/lib/modules/base/17_tape.lua +++ b/src/main/resources/assets/opencomputers/loot/Plan9k/lib/modules/base/17_tape.lua @@ -15,20 +15,33 @@ local function buildDevfs() end component.invoke(tape, "seek", -math.huge) hnd.tape = tape + hnd.pos = 0 end, size = function() return component.invoke(tape, "getSize") end, write = function(h, data) component.invoke(tape, "write", data) - return not component.invoke(tape, "isEnd", data) + h.pos = h.pos + #data + return not (h.pos >= component.invoke(tape, "getSize")) --TODO: do this correctly end, read = function(h, len) - if component.invoke(tape, "isEnd", data) then + if h.pos >= component.invoke(tape, "getSize") then return end + h.pos = h.pos + len return component.invoke(tape, "read", len) + end, + seek = function(h, whence, offset) + if whence == "end" then + h.pos = h.pos + component.invoke(tape, "seek", component.invoke(tape, "getSize") - h.pos - (offset or 0)) + elseif whence == "set" then + h.pos = h.pos + component.invoke(tape, "seek", (offset or 0) - h.pos) + else + h.pos = h.pos + component.invoke(tape, "seek", offset or 0) + end + return math.floor(h.pos) end } end @@ -55,11 +68,11 @@ local function onComponentRemoved(_, address, componentType) end end -function start() - for tape, t in component.list("tape_drive") do - onComponentAdded(_, tape, t) - end -end +--function start() +-- for tape, t in component.list("tape_drive") do +-- onComponentAdded(_, tape, t) +-- end +--end kernel.modules.keventd.listen("component_added", onComponentAdded) kernel.modules.keventd.listen("component_removed", onComponentRemoved) diff --git a/src/main/resources/assets/opencomputers/loot/Plan9k/lib/modules/base/20_threading.lua b/src/main/resources/assets/opencomputers/loot/Plan9k/lib/modules/base/20_threading.lua index 8dd4b8f2a..7d7015ed3 100644 --- a/src/main/resources/assets/opencomputers/loot/Plan9k/lib/modules/base/20_threading.lua +++ b/src/main/resources/assets/opencomputers/loot/Plan9k/lib/modules/base/20_threading.lua @@ -71,6 +71,8 @@ function spawn(exec, child, name, isthread, _, ...) currentHandlerArg = nil, eventQueue = {{"arg", ...}}, name = name or "unnamed", + maxPendingSignals = 32, + maxOpenFiles = 8, uid = nextUid } @@ -132,7 +134,7 @@ local function processSignals() for _, thread in ipairs(threads) do if thread.coro then local nsig, oldest = countThreadSignals(thread, "signal") - if nsig > 32 then --TODO: make it a bit more intelligent + if nsig > thread.maxPendingSignals then --TODO: make it a bit more intelligent table.remove(thread.eventQueue, oldest) end if thread.currentHandler == "yield" then diff --git a/src/main/resources/assets/opencomputers/loot/Plan9k/lib/modules/base/21_threadUtil.lua b/src/main/resources/assets/opencomputers/loot/Plan9k/lib/modules/base/21_threadUtil.lua index d755e06ad..8c473878c 100644 --- a/src/main/resources/assets/opencomputers/loot/Plan9k/lib/modules/base/21_threadUtil.lua +++ b/src/main/resources/assets/opencomputers/loot/Plan9k/lib/modules/base/21_threadUtil.lua @@ -1,4 +1,5 @@ function joinThread(pid) + --coroutine.yield("yield", 0) while true do local dead = coroutine.yield("kill") if pid == dead then @@ -30,7 +31,7 @@ function userKill(pid, signal, ...) local args = {...} local thread = kernel.modules.threading.threads[pid] kernel.modules.manageg.protect(thread.sandbox) - --TODO: probably ser threading.currentThread here + --TODO: probably set threading.currentThread here local res, reason = pcall(function() thread.kill[signal](table.unpack(args)) end) @@ -41,7 +42,7 @@ function userKill(pid, signal, ...) return true end -function setKillHandler(signal, handler) +function setKillHandler(signal, handler) --WAT if not kernel.modules.threading.threads[pid] or not kernel.modules.threading.threads[pid].coro then return nil, "Thread does not exists" diff --git a/src/main/resources/assets/opencomputers/loot/Plan9k/lib/term.lua b/src/main/resources/assets/opencomputers/loot/Plan9k/lib/term.lua index 21fda1bf1..5942d8322 100644 --- a/src/main/resources/assets/opencomputers/loot/Plan9k/lib/term.lua +++ b/src/main/resources/assets/opencomputers/loot/Plan9k/lib/term.lua @@ -1,6 +1,8 @@ local term = {} -local function read(from, to) +term.escape = "\x1b" +local write = function(text) io.write(term.escape..text) end +local read = function(from, to) local started, data while true do local char = io.read(1) @@ -19,6 +21,279 @@ local function read(from, to) end end end + +term.color={} +term.color.black=30 +term.color.red=31 +term.color.green=32 +term.color.yellow=33 +term.color.blue=34 +term.color.magenta=35 +term.color.cyan=36 +term.color.white=37 + +term.attr={} +term.attr.resetAllAttr=0 +term.attr.bright=1 +term.attr.dim=2 +term.attr.blink=5 +term.attr.reverse=7 +term.attr.hidden=8 + +------------------------------------------ +--Set Display Attributes +------------------------------------------ + +--Set Attribute Mode *ESC*[{attr1};...;{attrn}m +function term.setAttr(attr) + write(attr.."m") +end + +function term.setForeground(color) + write(color.."m") +end + +function term.setBackground(color) + write((color+10).."m") +end + +------------------------------------------ +--Erasing Text +------------------------------------------ + +--Erase End of Line *ESC*[K +--Erases from the current cursor position to the end of the current line. +function term.eraseEndOfLine() + write("[K") +end + +--Erase Start of Line *ESC*[1K +--Erases from the current cursor position to the start of the current line. +function term.eraseStartOfLine() + write("[1K") +end + +--Erase Line *ESC*[2K +--Erases the entire current line. +function term.eraseLine() + write("[2K") +end +term.clearLine = term.eraseLine + +--Erase Down *ESC*[J +--Erases the screen from the current line down to the bottom of the screen. +function term.eraseDown() + write("[J") +end + +--Erase Up *ESC*[1J +--Erases the screen from the current line up to the top of the screen. +function term.eraseUp() + write("[1J") +end + +--Erase Screen *ESC*[2J +--Erases the screen with the background colour and moves the cursor to home. +function term.clear() + write("[2J") +end + + +------------------------------------------- +--Tab Control +------------------------------------------ + +--Set Tab *ESC*H +--Sets a tab at the current position. +function term.tab() + write("[H") +end + +--Clear Tab *ESC*[g +--Clears tab at the current position. +function term.clearTab() + write("[g") +end + +--Clear All Tabs *ESC*[3g +--Clears all tabs. +function term.clearTabs() + write("[3g") +end + + +------------------------------------------ +--Scrolling +------------------------------------------ + +--Scroll Screen *ESC*[r +--Enable scrolling for entire display. +function term.enableScroll() + write("[r") +end + +--Scroll Screen *ESC*[{start};{end}r +--Enable scrolling from row {start} to row {end}. +function term.scrollScreen(from,to) + write(string.format("[%d;%dr",from,to)) +end + +--Scroll Down *ESC*D +--Scroll display down one line. +function term.scrollScreenDown() + write("D") +end + +--Scroll Up *ESC*M +--Scroll display up one line. +function term.scrollScreenUp() + write("M") +end + + +------------------------------------------ +--Cursor Control +------------------------------------------ + +--Cursor Home *ESC*[{ROW};{COLUMN}H +--Sets the cursor position where subsequent text will begin. If no row/column parameters are provided (ie. *ESC*[H), the cursor will move to the home position, at the upper left of the screen. +function term.setCursorPosition(row,col) + write(string.format("[%d;%dH", row, col)) +end + +function term.resetCursor() + write("[H") +end + +--Cursor Up *ESC*[{COUNT}A +--Moves the cursor up by COUNT rows; the default count is 1. +function term.cursorUp(count) + write(string.format("[%dA",(count or 1))) +end + +--Cursor Down *ESC*[{COUNT}B +--Moves the cursor down by COUNT rows; the default count is 1. +function term.cursorDown(count) + write(string.format("[%dB",(count or 1))) +end + +--Cursor Forward *ESC*[{COUNT}C +--Moves the cursor forward by COUNT columns; the default count is 1. +function term.cursorForward(count) + write(string.format("[%dC",(count or 1))) +end + +--Cursor Backward *ESC*[{COUNT}D +--Moves the cursor backward by COUNT columns; the default count is 1. +function term.cursorBackward(count) + write(string.format("[%dD",(count or 1))) +end + +--Force Cursor Position *ESC*[{ROW};{COLUMN}f +--Identical to Cursor Home. +function term.forceCursorPosition(row, col) + write(string.format("[%d;%df", row, col)) +end + +--Save Cursor *ESC*[s +--Save current cursor position. +function term.saveCursor() + write("[s") +end + +--Unsave Cursor *ESC*[u +--Restores cursor position after a Save Cursor. +function term.restoreCursor() + write("[u") +end + +--Save Cursor & Attrs *ESC*7 +--Save current cursor position. +function term.saveCursorAndAttr() + write("7") +end + +--Restore Cursor & Attrs *ESC*8 +--Restores cursor position after a Save Cursor. +function term.restoreCursorAndAttr() + write("8") +end + + +------------------------------------------ +--Terminal Setup +------------------------------------------ + +--Reset Device *ESC*c +--Reset all terminal settings to default. +function term.reset() + write("c") +end + +--Enable Line Wrap *ESC*[7h +--Text wraps to next line if longer than the length of the display area. +function term.enableLineWrap() + write("[7h") +end + +--Disable Line Wrap *ESC*[7l +--Disables line wrapping. +function term.disableLineWrap() + write("[7l") +end + +------------------------------------------ +--Plan9k codes +------------------------------------------ + +-- \x1b9[H];[W]R - set resolution +function term.setResolution(height,width) + write(string.format("9%d;%dR", height, width)) +end + +-- \x1b9[Row];[Col];[Height];[Width]F -- fill +function term.fill(row, col, height, width) + write(string.format("9%d;%d;%d;%dF", row, col, height, width)) +end + +-- \x1b9[Row];[Col];[Height];[Width];[Dest Row];[Dest Col]c -- copy +function term.copy(row, col, height, width, destRow, destCol) + write(string.format("9%d;%d;%d;%d;%d;%dc", row, col, height, width, destRow, destCol )) +end + +--get resolution +function term.getResolution() + local y, x = term.getCursorPosition() + term.setCursorPosition(999,999) + local h, w = term.getCursorPosition() + term.setCursorPosition(y,x) + return tonumber(h), tonumber(w) +end + + + + + + + + + + + + + + + + + + + + + + + + + function term.clear() io.write("\x1b[2J") diff --git a/src/main/resources/assets/opencomputers/loot/Plan9k/usr/bin/base64.lua b/src/main/resources/assets/opencomputers/loot/Plan9k/usr/bin/base64.lua new file mode 100644 index 000000000..2a5d9d58f --- /dev/null +++ b/src/main/resources/assets/opencomputers/loot/Plan9k/usr/bin/base64.lua @@ -0,0 +1,42 @@ +local shell = require("shell") +local data = require("data") + + +local args, parms = shell.parse(...) +if parms.h or parms.help then + io.stderr:write("See: man base64" .. "\n") + os.exit(true) +end +local encodingfun = nil +local encode +if parms.d or parms.decode then + encodingfun = data.decode64 + encode = false +else + encodingfun = data.encode64 + encode = true +end + +if #args == 0 then + repeat + local read = io.read(encode and 3 or 4) + if read then + io.write(encodingfun(read)) + end + until not read +else + for i = 1, #args do + local file, reason = io.open(shell.resolve(args[i])) + if not file then + io.stderr:write(tostring(reason) .. "\n") + os.exit(false) + end + repeat + local line = file:read(encode and 3 or 4) + if line then + io.write(encodingfun(line)) + end + until not line + file:close() + end +end diff --git a/src/main/resources/assets/opencomputers/loot/Plan9k/usr/bin/deflate.lua b/src/main/resources/assets/opencomputers/loot/Plan9k/usr/bin/deflate.lua new file mode 100644 index 000000000..cd8660ac2 --- /dev/null +++ b/src/main/resources/assets/opencomputers/loot/Plan9k/usr/bin/deflate.lua @@ -0,0 +1,25 @@ +local shell = require("shell") +local data = require("data") + +local args = shell.parse(...) +if #args == 0 then + local read = "" + repeat + local current = io.read("*a") + read = read .. current + until current ~= "" + io.write(data.deflate(read)) +else + local read = "" + local file, reason = io.open(shell.resolve(args[1])) + if not file then + io.stderr:write(tostring(reason) .. "\n") + os.exit(false) + end + repeat + local current = file:read("*a") + read = read .. current + until current ~= "" + file:close() + io.write(data.deflate(read)) +end diff --git a/src/main/resources/assets/opencomputers/loot/Plan9k/usr/bin/gpg.lua b/src/main/resources/assets/opencomputers/loot/Plan9k/usr/bin/gpg.lua new file mode 100644 index 000000000..5b2f5ad41 --- /dev/null +++ b/src/main/resources/assets/opencomputers/loot/Plan9k/usr/bin/gpg.lua @@ -0,0 +1,244 @@ +--[[ +-- A program that allows user to perform all crypto operations provided by Tier II / Tier III data cards +-- Author: makkarpov +--]] + +local shell = require("shell") +local data = require("data") +local term = require("term") +local filesystem = require("filesystem") +local serialization = require("serialization") + +local args, options = shell.parse(...) + +local function writeFile(path, data) + if filesystem.exists(path) then + io.stderr:write("gpg: failed to write file: " .. path .. "\n") + io.stderr:write("gpg: error was: file already exists\n") + return false + end + + if type(data) == "table" then + data = serialization.serialize(data) + end + + local h, err = io.open(path, "wb") + + if not h then + io.stderr:write("gpg: failed to write file: " .. path .. "\n") + io.stderr:write("gpg: error was: " .. err .. "\n") + return false + end + + h:write(data) + h:close() + return true +end + +local function readFile(path, deserialize) + local h = io.open(path, "rb") + local r = h:read("*a") + h:close() + + if deserialize then + r = serialization.unserialize(r) + end + + return r +end + +local function parseKey(path, isPublic) + local d = readFile(path, true) + local k, err = data.deserializeKey(d.d, d.t) + + if not k then + io.stderr:write("gpg: failed to parse key: " .. err .. "\n") + return nil + end + + if k.isPublic() ~= isPublic then + io.stderr:write("gpg: wrong key type\n") + return nil + end + + return k +end + +local function deriveName(base, encrypt) + if encrypt then + return base .. ".gpg" + else + local d = base:gsub(".gpg", "") + if d == base then + d = d .. ".dec" + io.write("gpg: decrypting to " .. d .. "\n") + end + return d + end +end + +local function ensureMethods(...) + if not require("component").isAvailable("data") then + io.stderr:write("gpg: you must have data card in order to run this program\n") + error("data card is absent") + end + + local names = table.pack(...) + for i = 1, names.n do + if names[i] and not data[names[i]] then + io.stderr:write("gpg: method " .. names[i] .. " required on data card to run this program\n") + error("data card tier insufficient") + end + end +end + +if options['g'] and (#args == 2) then + ensureMethods("generateKeyPair") + local pub, priv = data.generateKeyPair(384) + + priv = { t = priv.keyType(), d = priv.serialize() } + pub = { t = pub.keyType(), d = pub.serialize() } + + if not writeFile(args[1], priv) then + io.stderr:write("gpg: failed to write private key, aborting\n") + return false + end + + if not writeFile(args[2], pub) then + io.stderr:write("gpg: failed to write public key, aborting\n") + return false + end + + return true +end + +if options['c'] and (options['e'] or options['d']) and (#args == 1) then + ensureMethods("md5", "sha256", "encrypt", "decrypt", "random") + if options['d'] and options['e'] then + io.stderr:write("gpg: please specify either -d or -e\n") + return false + end + + io.write("gpg: enter password: ") + local aesKey = data.md5(term.read(nil, nil, nil, "*")) + local checkValue = data.sha256(aesKey) + + if options['e'] then + local iv = data.random(16) + local d = data.encrypt(readFile(args[1]), aesKey, iv) + + return writeFile(deriveName(args[1], true), { + t = "pwd", + kdf = "md5", + iv = iv, + cv = checkValue, + d = d + }) + else + local d = readFile(args[1], true) + + if d.t ~= "pwd" then + io.stderr:write("gpg: file is not encrypted with a password\n") + return false + end + + if checkValue ~= d.cv then + io.stderr:write("gpg: password incorrect\n") + return false + end + + return writeFile(deriveName(args[1], false), data.decrypt(d.d, aesKey, d.iv)) + end +end + +if (options['d'] or options['e']) and (#args == 2) then + ensureMethods("md5", "sha256", "encrypt", "decrypt", "random", "generateKeyPair", "deserializeKey", "ecdh") + if options['d'] and options['e'] then + io.stderr:write("gpg: please specify either -d or -e\n") + return false + end + + if options['e'] then + local userPub = parseKey(args[1], true) + local tmpPub, tmpPriv = data.generateKeyPair(384) + local aesKey = data.md5(data.ecdh(tmpPriv, userPub)) + local checkValue = data.sha256(aesKey) + local iv = data.random(16) + + local d = data.encrypt(readFile(args[2]), aesKey, iv) + return writeFile(deriveName(args[2], true), { + t = "ecdh", + kdf = "md5", + iv = iv, + cv = checkValue, + k = { + t = tmpPub.keyType(), + d = tmpPub.serialize() + }, + d = d + }) + else + local userPriv = parseKey(args[1], false) + local d = readFile(args[2], true) + + if d.t ~= "ecdh" then + io.stderr:write("gpg: file is not encrypted with a key\n") + return false + end + + local tmpPub = data.deserializeKey(d.k.d, d.k.t) + local aesKey = data.md5(data.ecdh(userPriv, tmpPub)) + + if d.cv ~= data.sha256(aesKey) then + io.stderr:write("gpg: invalid key\n") + return false + end + + return writeFile(deriveName(args[2], false), data.decrypt(d.d, aesKey, d.iv)) + end +end + +if (options['s'] or options['v']) and (#args == 2) then + ensureMethods("deserializeKey", "ecdsa") + if options['s'] and options['v'] then + io.stderr:write("gpg: please specify either -s or -v\n") + return false + end + + if options['s'] then + local userPriv = parseKey(args[1], false) + local sign = data.ecdsa(readFile(args[2]), userPriv) + + return writeFile(args[2] .. ".sig", { + t = "ecdsa", + s = sign + }) + else + local userPub = parseKey(args[1], true) + local sign = readFile(args[2] .. ".sig", true) + + if sign.t ~= "ecdsa" then + io.stderr:write("gpg: unsupported signature type\n") + return false + end + + if not data.ecdsa(readFile(args[2]), userPub, sign.s) then + io.stderr:write("gpg: signature verification failed\n") + return false + end + + io.write("gpg: signature is valid\n") + + return true + end +end + +io.write("Usages:\n") +io.write("gpg -ce -- encrypt file with password\n") +io.write("gpg -cd -- decrypt file with password\n") +io.write("gpg -e -- encrypt file\n") +io.write("gpg -d -- decrypt file\n") +io.write("gpg -g -- generate keypair\n") +io.write("gpg -s -- sign file\n") +io.write("gpg -v -- verify file\n") +return false diff --git a/src/main/resources/assets/opencomputers/loot/Plan9k/usr/bin/inflate.lua b/src/main/resources/assets/opencomputers/loot/Plan9k/usr/bin/inflate.lua new file mode 100644 index 000000000..349c5f18b --- /dev/null +++ b/src/main/resources/assets/opencomputers/loot/Plan9k/usr/bin/inflate.lua @@ -0,0 +1,25 @@ +local shell = require("shell") +local data = require("data") + +local args = shell.parse(...) +if #args == 0 then + local read = "" + repeat + local current = io.read("*a") + read = read .. current + until current ~= "" + io.write(data.inflate(read)) +else + local read = "" + local file, reason = io.open(shell.resolve(args[1])) + if not file then + io.stderr:write(tostring(reason) .. "\n") + os.exit(false) + end + repeat + local current = file:read("*a") + read = read .. current + until current ~= "" + file:close() + io.write(data.inflate(read)) +end diff --git a/src/main/resources/assets/opencomputers/loot/Plan9k/usr/bin/md5sum.lua b/src/main/resources/assets/opencomputers/loot/Plan9k/usr/bin/md5sum.lua new file mode 100644 index 000000000..37cba695f --- /dev/null +++ b/src/main/resources/assets/opencomputers/loot/Plan9k/usr/bin/md5sum.lua @@ -0,0 +1,27 @@ +local shell = require("shell") +local data = require("data") + +local args = shell.parse(...) +if #args == 0 then + local read = "" + repeat + local current = io.read("*a") + read = read .. current + until current ~= "" + io.write(data.toHex(data.md5(read))) +else + for i = 1, #args do + local read = "" + local file, reason = io.open(args[i]) + if not file then + io.stderr:write(tostring(reason) .. "\n") + os.exit(false) + end + repeat + local current = file:read("*a") + read = read .. current + until current ~= "" + file:close() + io.write(data.toHex(data.md5(read)) .. "\t".. args[i] .. "\n") + end +end diff --git a/src/main/resources/assets/opencomputers/loot/Plan9k/usr/bin/mpt.lua b/src/main/resources/assets/opencomputers/loot/Plan9k/usr/bin/mpt.lua index 5f9ef04de..49cdb030e 100644 --- a/src/main/resources/assets/opencomputers/loot/Plan9k/usr/bin/mpt.lua +++ b/src/main/resources/assets/opencomputers/loot/Plan9k/usr/bin/mpt.lua @@ -81,17 +81,25 @@ ocBackend = { print(" Upgrade all packages that are out-of-date on the") print(" local system. Only package versions are used to find outdated packages;") print(" replacements are not checked here. This is a ?remove-then-add? process.") + print(" -f, --force") + print(" Force operation, in case of upgrade it redownloads all packages") print(" --root='/some/dir'") print(" Set alternative root directory") print(" -v") print(" More output") print(" -y") print(" Don't ask any questions, answer automatically") + print(" -r, --reboot") + print(" reboot after operation") return end if options.v then loglevel = 0 end + if options.f or options.force then + core.data.force = true + end + if options.S or options.sync then for _, pack in ipairs(args) do core.install(pack) @@ -114,6 +122,8 @@ ocBackend = { if options.y then ocBackend.prompt = function()return true end end + + core.reboot = optionsr or options.reboot core.doWork() end, @@ -208,7 +218,8 @@ ocBackend = { if p:sub(1,1):upper() ~= "Y" then error("User stopped") end - end + end, + reboot = function()computer.shutdown(true) end } local mptFrontend @@ -249,7 +260,7 @@ mptFrontend = { local toCheck = {} for pack, data in pairs(base.installed) do if data.frontend == mptFrontend.name then - toCheck[pack] = base.installed[pack].data.checksum + toCheck[pack] = base.installed[pack].data.checksum .. (core.data.force and "WAT" or "") end end local updateResp = backend.getText(config.frontend.mpt.api.."update", toCheck) @@ -368,6 +379,8 @@ core = { upgrade = false, remove = false, + force = false, + --User requested packages userInstall = {}, @@ -603,7 +616,8 @@ end core.log(1, "Main", "> Saving settings") core.finalize() - - +if core.reboot then + backend.reboot() +end diff --git a/src/main/resources/assets/opencomputers/loot/Plan9k/usr/bin/sha256sum.lua b/src/main/resources/assets/opencomputers/loot/Plan9k/usr/bin/sha256sum.lua new file mode 100644 index 000000000..33d5b25c7 --- /dev/null +++ b/src/main/resources/assets/opencomputers/loot/Plan9k/usr/bin/sha256sum.lua @@ -0,0 +1,27 @@ +local shell = require("shell") +local data = require("data") + +local args = shell.parse(...) +if #args == 0 then + local read = "" + repeat + local current = io.read("*a") + read = read .. current + until current ~= "" + io.write(data.toHex(data.sha256(read))) +else + for i = 1, #args do + local read = "" + local file, reason = io.open(shell.resolve(args[i])) + if not file then + io.stderr:write(tostring(reason) .. "\n") + os.exit(false) + end + repeat + local current = file:read("*a") + read = read .. current + until current ~= "" + file:close() + io.write(data.toHex(data.sha256(read)) .. "\t".. args[i] .. "\n") + end +end diff --git a/src/main/resources/assets/opencomputers/loot/Plan9k/usr/lib/data.lua b/src/main/resources/assets/opencomputers/loot/Plan9k/usr/lib/data.lua new file mode 100644 index 000000000..04fa9ff9c --- /dev/null +++ b/src/main/resources/assets/opencomputers/loot/Plan9k/usr/lib/data.lua @@ -0,0 +1,26 @@ +local component = require("component") + +local data = {} + +------------------------------------------------------------------------------- + +-- Converts binary data into hexadecimal string. +function data.toHex(data) + return (data:gsub('.', function (c) + return string.format('%02X', string.byte(c)) + end)) +end + +-- Converts hexadecimal string into binary data. +function data.fromHex(hex) + return (hex:gsub('..', function (cc) + return string.char(tonumber(cc, 16)) + end)) +end + +-- Forward everything else to the primary data card. +setmetatable(data, { __index = function(_, key) return component.data[key] end }) + +------------------------------------------------------------------------------- + +return data diff --git a/src/main/resources/assets/opencomputers/loot/Plan9k/var/lib/mpt/config.db b/src/main/resources/assets/opencomputers/loot/Plan9k/var/lib/mpt/config.db index 92ac3946c..38823c26c 100644 --- a/src/main/resources/assets/opencomputers/loot/Plan9k/var/lib/mpt/config.db +++ b/src/main/resources/assets/opencomputers/loot/Plan9k/var/lib/mpt/config.db @@ -1 +1 @@ -{cacheDir="/var/lib/mpt/cache/",database="/var/lib/mpt/base.db",frontend={mpt={api="http://mpt.magik6k.net/api/"}}} \ No newline at end of file +{frontend={mpt={api="http://mpt.magik6k.net/api/"}},database="/var/lib/mpt/base.db",cacheDir="/var/lib/mpt/cache/"} \ No newline at end of file diff --git a/src/main/resources/assets/opencomputers/loot/Plan9k/var/lib/mpt/mpt.db b/src/main/resources/assets/opencomputers/loot/Plan9k/var/lib/mpt/mpt.db index 4c7665a18..22c695591 100644 --- a/src/main/resources/assets/opencomputers/loot/Plan9k/var/lib/mpt/mpt.db +++ b/src/main/resources/assets/opencomputers/loot/Plan9k/var/lib/mpt/mpt.db @@ -1 +1 @@ -{installed={["plan9k-drivers"]={frontend="MPT",data={name="plan9k-drivers",repo="plan9k",checksum="-2327b14292d5c08f547d24e9b5122349",files={"/lib/modules/base/17_tape.lua","/lib/modules/base/17_eeprom.lua","/lib/modules/base/17_nfc.lua","/lib/modules/base/17_chatbox.lua"},dependencies={}},deps={}},["plan9k-shell"]={frontend="MPT",data={name="plan9k-shell",repo="plan9k",checksum="-4ebb18f6dedde575d4d61460494b3bbb",files={"/bin/sh.lua"},dependencies={}},deps={}},["plan9k-corelibs"]={frontend="MPT",data={name="plan9k-corelibs",repo="plan9k",checksum="1d01d437b10e8561a39cb9f108cc3d47",files={"/lib/serialization.lua","/lib/term.lua","/lib/text.lua","/lib/shell.lua","/lib/event.lua"},dependencies={}},deps={}},mpt={frontend="MPT",data={name="mpt",repo="mpt",checksum="f9d7744571e5c46c658f405043c656",files={"/usr/bin/mpt.lua"},dependencies={}},deps={}},["plan9k-fsutil"]={frontend="MPT",data={name="plan9k-fsutil",repo="plan9k",checksum="aded7c8083efcdcfe43908183370687",files={"/bin/cat.lua","/bin/ln.lua","/bin/ls.lua","/bin/mv.lua","/bin/rm.lua","/bin/tee.lua","/bin/df.lua","/bin/dd.lua","/bin/cp.lua","/bin/touch.lua","/bin/mount.lua","/bin/mount.cow.lua","/bin/mkdir.lua","/bin/pwd.lua"},dependencies={"plan9k-corelibs"}},deps={"plan9k-corelibs"}},["plan9k-network"]={frontend="MPT",data={name="plan9k-network",repo="plan9k",checksum="-29d10c88b7ed4116d5b4eacd019d5ad9",files={"/lib/internet.lua","/bin/pastebin.lua","/bin/wget.lua","/lib/modules/base/17_network.lua","/lib/modules/base/19_libnetwork.lua","/bin/arp.lua","/bin/ifconfig.lua","/bin/ping.lua","/bin/route.lua","/lib/modules/network/loopback.lua","/lib/modules/network/modem.lua","/usr/bin/nc.lua","/lib/modules/network/tunnel.lua"},dependencies={}},deps={}},pipes={frontend="MPT",data={name="pipes",repo="plan9k",checksum="6d088970fd4fb29b78279eef4d417646",files={"/boot/kernel/pipes","/lib/modules/base/05_vfs.lua","/lib/modules/base/20_threading.lua","/lib/modules/base/19_manageg.lua","/lib/modules/base/25_init.lua","/lib/modules/base/15_userspace.lua","/usr/man/pipes","/lib/modules/base/16_buffer.lua","/lib/modules/base/17_io.lua","/lib/modules/base/16_require.lua","/lib/modules/base/18_syscall.lua","/lib/modules/base/21_threadUtil.lua","/lib/modules/base/21_timer.lua","/lib/modules/base/16_component.lua","/lib/modules/base/15_keventd.lua","/lib/modules/base/10_procfs.lua","/lib/modules/base/01_util.lua","/lib/modules/base/10_devfs.lua","/lib/modules/base/18_pty.lua","/lib/modules/base/17_keyboard.lua","/lib/modules/base/06_cowfs.lua","/lib/modules/base/09_rootfs.lua","/lib/modules/base/01_gc.lua"},dependencies={"openloader-init"}},deps={"openloader-init"}},["plan9k-edit"]={frontend="MPT",data={name="plan9k-edit",repo="plan9k",checksum="fed5f4ee1212297b07247afa1cfe3a2",files={"/bin/edit.lua"},dependencies={}},deps={}},["plan9k-core"]={frontend="MPT",data={name="plan9k-core",repo="plan9k",checksum="-4f5e4f44875482035444a2b61e96243d",files={"/bin/init.lua","/bin/getty.lua","/bin/readkey.lua","/lib/rc.lua","/bin/rc.lua"},dependencies={"pipes","plan9k-coreutil","plan9k-shell"}},deps={"pipes","plan9k-coreutil","plan9k-shell"}},plan9k={frontend="MPT",data={name="plan9k",repo="plan9k",checksum="-c16ccdf21a1ff13be8f6258d1a17d89",files={},dependencies={"plan9k-core","plan9k-network","plan9k-drivers","plan9k-edit"}},deps={"plan9k-core","plan9k-network","plan9k-drivers","plan9k-edit"}},["plan9k-installer"]={frontend="MPT",data={name="plan9k-installer",repo="plan9k",checksum="52c8f82357c966ce3e19c97bf3942012",files={"/bin/install.lua"},dependencies={"plan9k","mpt"}},deps={"plan9k","mpt"}},["openloader-init"]={frontend="MPT",data={name="openloader-init",repo="disks",checksum="-45e6d7b1e41468c1d335952ee3b89e13",files={"/init.lua"},dependencies={}},deps={}},["plan9k-coreutil"]={frontend="MPT",data={name="plan9k-coreutil",repo="plan9k",checksum="-50d3cee571b07b6cb05f6fb01989997c",files={"/bin/echo.lua","/bin/wc.lua","/bin/ps.lua","/bin/lua.lua","/bin/kill.lua","/bin/reboot.lua","/bin/sleep.lua","/bin/clear.lua","/bin/components.lua","/bin/hostname.lua","/bin/dmesg.lua","/bin/shutdown.lua","/bin/label.lua","/bin/uptime.lua","/bin/resolution.lua"},dependencies={"plan9k-corelibs","plan9k-fsutil"}},deps={"plan9k-corelibs","plan9k-fsutil"}}}} \ No newline at end of file +{installed={["plan9k-corelibs"]={deps={},data={checksum="1cb7fa12e1a1a35fc168409b60cfe552",repo="plan9k",name="plan9k-corelibs",dependencies={},files={"/lib/serialization.lua","/lib/term.lua","/lib/text.lua","/lib/shell.lua","/lib/event.lua"}},frontend="MPT"},["plan9k-core"]={deps={"pipes","plan9k-coreutil","plan9k-shell"},data={checksum="-6f77a020200f96eefd1559dcd8af14a5",repo="plan9k",name="plan9k-core",dependencies={"pipes","plan9k-coreutil","plan9k-shell"},files={"/bin/init.lua","/bin/getty.lua","/bin/readkey.lua","/lib/rc.lua","/bin/rc.lua"}},frontend="MPT"},["openloader-init"]={deps={},data={checksum="-45e6d7b1e41468c1d335952ee3b89e13",repo="disks",name="openloader-init",dependencies={},files={"/init.lua"}},frontend="MPT"},["plan9k-edit"]={deps={},data={checksum="34b1046ac9b7a87a1cdd74f8c03f27ea",repo="plan9k",name="plan9k-edit",dependencies={},files={"/bin/edit.lua"}},frontend="MPT"},["plan9k-coreutil"]={deps={"plan9k-corelibs","plan9k-fsutil"},data={checksum="5fa7e70e3aba17fef97ed65489efb0ca",repo="plan9k",name="plan9k-coreutil",dependencies={"plan9k-corelibs","plan9k-fsutil"},files={"/bin/echo.lua","/bin/wc.lua","/bin/ps.lua","/bin/lua.lua","/bin/kill.lua","/bin/reboot.lua","/bin/sleep.lua","/bin/clear.lua","/bin/components.lua","/bin/hostname.lua","/bin/dmesg.lua","/bin/shutdown.lua","/bin/label.lua","/bin/uptime.lua","/bin/resolution.lua"}},frontend="MPT"},["plan9k-shell"]={deps={},data={checksum="517b9e0693e734a4ab516f12a6798f14",repo="plan9k",name="plan9k-shell",dependencies={},files={"/bin/sh.lua"}},frontend="MPT"},["plan9k-fsutil"]={deps={"plan9k-corelibs"},data={checksum="6a974a71f62315e6e2294eae132d1751",repo="plan9k",name="plan9k-fsutil",dependencies={"plan9k-corelibs"},files={"/bin/cat.lua","/bin/ln.lua","/bin/ls.lua","/bin/mv.lua","/bin/rm.lua","/bin/tee.lua","/bin/df.lua","/bin/dd.lua","/bin/cp.lua","/bin/touch.lua","/bin/mount.lua","/bin/mount.cow.lua","/bin/mkdir.lua","/bin/pwd.lua","/bin/more.lua"}},frontend="MPT"},pipes={deps={"openloader-init"},data={checksum="7ef3909b40d2390e31f418b31eff03d8",repo="plan9k",name="pipes",dependencies={"openloader-init"},files={"/boot/kernel/pipes","/lib/modules/base/05_vfs.lua","/lib/modules/base/20_threading.lua","/lib/modules/base/19_manageg.lua","/lib/modules/base/25_init.lua","/lib/modules/base/15_userspace.lua","/usr/man/pipes","/lib/modules/base/16_buffer.lua","/lib/modules/base/17_io.lua","/lib/modules/base/16_require.lua","/lib/modules/base/18_syscall.lua","/lib/modules/base/21_threadUtil.lua","/lib/modules/base/21_timer.lua","/lib/modules/base/16_component.lua","/lib/modules/base/15_keventd.lua","/lib/modules/base/10_procfs.lua","/lib/modules/base/01_util.lua","/lib/modules/base/10_devfs.lua","/lib/modules/base/18_pty.lua","/lib/modules/base/17_keyboard.lua","/lib/modules/base/06_cowfs.lua","/lib/modules/base/09_rootfs.lua","/lib/modules/base/01_gc.lua"}},frontend="MPT"},plan9k={deps={"plan9k-core","plan9k-network","plan9k-drivers","plan9k-edit","plan9k-data"},data={checksum="-2d8f4b84ea60b0c9d5846f57e9f1691c",repo="plan9k",name="plan9k",dependencies={"plan9k-core","plan9k-network","plan9k-drivers","plan9k-edit","plan9k-data"},files={}},frontend="MPT"},["plan9k-network"]={deps={},data={checksum="6e06e6cf5028583fe54047ba9e19abc6",repo="plan9k",name="plan9k-network",dependencies={},files={"/lib/internet.lua","/bin/pastebin.lua","/bin/wget.lua","/lib/modules/base/17_network.lua","/lib/modules/base/19_libnetwork.lua","/bin/arp.lua","/bin/ifconfig.lua","/bin/ping.lua","/bin/route.lua","/lib/modules/network/loopback.lua","/lib/modules/network/modem.lua","/usr/bin/nc.lua","/lib/modules/network/tunnel.lua"}},frontend="MPT"},["plan9k-drivers"]={deps={},data={checksum="-35f098652460458c13f83499b4633e2d",repo="plan9k",name="plan9k-drivers",dependencies={},files={"/lib/modules/base/17_tape.lua","/lib/modules/base/17_eeprom.lua","/lib/modules/base/17_nfc.lua","/lib/modules/base/17_chatbox.lua","/lib/modules/base/17_data.lua","/lib/modules/base/17_drive.lua"}},frontend="MPT"},["plan9k-data"]={deps={},data={checksum="480a898a741b2bf424f9e0e86e5072ba",repo="plan9k",name="plan9k-data",dependencies={},files={"/usr/bin/base64.lua","/usr/lib/data.lua","/usr/bin/deflate.lua","/usr/bin/inflate.lua","/usr/bin/md5sum.lua","/usr/bin/sha256sum.lua","/usr/bin/gpg.lua"}},frontend="MPT"}}} \ No newline at end of file From 3656ed941ff4886b68d3e859f1fc49d065213892 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Sun, 30 Aug 2015 16:50:15 +0200 Subject: [PATCH 30/30] Fixed stderr not being passed in os.spawn in Plan9k MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Ɓukasz Magiera --- .../opencomputers/loot/Plan9k/lib/modules/base/15_userspace.lua | 1 + .../assets/opencomputers/loot/Plan9k/var/lib/mpt/config.db | 2 +- .../assets/opencomputers/loot/Plan9k/var/lib/mpt/mpt.db | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/resources/assets/opencomputers/loot/Plan9k/lib/modules/base/15_userspace.lua b/src/main/resources/assets/opencomputers/loot/Plan9k/lib/modules/base/15_userspace.lua index 18cc75312..4be9c6c50 100644 --- a/src/main/resources/assets/opencomputers/loot/Plan9k/lib/modules/base/15_userspace.lua +++ b/src/main/resources/assets/opencomputers/loot/Plan9k/lib/modules/base/15_userspace.lua @@ -51,6 +51,7 @@ function kernel.userspace.os.spawn(prog, ...) local thread = kernel.modules.threading.spawn(prog, 0, name, isThread, _, ...) thread.io_output = kernel.modules.threading.currentThread.io_output thread.io_input = kernel.modules.threading.currentThread.io_input + thread.io_error = kernel.modules.threading.currentThread.io_error return thread.pid end diff --git a/src/main/resources/assets/opencomputers/loot/Plan9k/var/lib/mpt/config.db b/src/main/resources/assets/opencomputers/loot/Plan9k/var/lib/mpt/config.db index 38823c26c..3ecc57b30 100644 --- a/src/main/resources/assets/opencomputers/loot/Plan9k/var/lib/mpt/config.db +++ b/src/main/resources/assets/opencomputers/loot/Plan9k/var/lib/mpt/config.db @@ -1 +1 @@ -{frontend={mpt={api="http://mpt.magik6k.net/api/"}},database="/var/lib/mpt/base.db",cacheDir="/var/lib/mpt/cache/"} \ No newline at end of file +{database="/var/lib/mpt/base.db",cacheDir="/var/lib/mpt/cache/",frontend={mpt={api="http://mpt.magik6k.net/api/"}}} \ No newline at end of file diff --git a/src/main/resources/assets/opencomputers/loot/Plan9k/var/lib/mpt/mpt.db b/src/main/resources/assets/opencomputers/loot/Plan9k/var/lib/mpt/mpt.db index 22c695591..d64373528 100644 --- a/src/main/resources/assets/opencomputers/loot/Plan9k/var/lib/mpt/mpt.db +++ b/src/main/resources/assets/opencomputers/loot/Plan9k/var/lib/mpt/mpt.db @@ -1 +1 @@ -{installed={["plan9k-corelibs"]={deps={},data={checksum="1cb7fa12e1a1a35fc168409b60cfe552",repo="plan9k",name="plan9k-corelibs",dependencies={},files={"/lib/serialization.lua","/lib/term.lua","/lib/text.lua","/lib/shell.lua","/lib/event.lua"}},frontend="MPT"},["plan9k-core"]={deps={"pipes","plan9k-coreutil","plan9k-shell"},data={checksum="-6f77a020200f96eefd1559dcd8af14a5",repo="plan9k",name="plan9k-core",dependencies={"pipes","plan9k-coreutil","plan9k-shell"},files={"/bin/init.lua","/bin/getty.lua","/bin/readkey.lua","/lib/rc.lua","/bin/rc.lua"}},frontend="MPT"},["openloader-init"]={deps={},data={checksum="-45e6d7b1e41468c1d335952ee3b89e13",repo="disks",name="openloader-init",dependencies={},files={"/init.lua"}},frontend="MPT"},["plan9k-edit"]={deps={},data={checksum="34b1046ac9b7a87a1cdd74f8c03f27ea",repo="plan9k",name="plan9k-edit",dependencies={},files={"/bin/edit.lua"}},frontend="MPT"},["plan9k-coreutil"]={deps={"plan9k-corelibs","plan9k-fsutil"},data={checksum="5fa7e70e3aba17fef97ed65489efb0ca",repo="plan9k",name="plan9k-coreutil",dependencies={"plan9k-corelibs","plan9k-fsutil"},files={"/bin/echo.lua","/bin/wc.lua","/bin/ps.lua","/bin/lua.lua","/bin/kill.lua","/bin/reboot.lua","/bin/sleep.lua","/bin/clear.lua","/bin/components.lua","/bin/hostname.lua","/bin/dmesg.lua","/bin/shutdown.lua","/bin/label.lua","/bin/uptime.lua","/bin/resolution.lua"}},frontend="MPT"},["plan9k-shell"]={deps={},data={checksum="517b9e0693e734a4ab516f12a6798f14",repo="plan9k",name="plan9k-shell",dependencies={},files={"/bin/sh.lua"}},frontend="MPT"},["plan9k-fsutil"]={deps={"plan9k-corelibs"},data={checksum="6a974a71f62315e6e2294eae132d1751",repo="plan9k",name="plan9k-fsutil",dependencies={"plan9k-corelibs"},files={"/bin/cat.lua","/bin/ln.lua","/bin/ls.lua","/bin/mv.lua","/bin/rm.lua","/bin/tee.lua","/bin/df.lua","/bin/dd.lua","/bin/cp.lua","/bin/touch.lua","/bin/mount.lua","/bin/mount.cow.lua","/bin/mkdir.lua","/bin/pwd.lua","/bin/more.lua"}},frontend="MPT"},pipes={deps={"openloader-init"},data={checksum="7ef3909b40d2390e31f418b31eff03d8",repo="plan9k",name="pipes",dependencies={"openloader-init"},files={"/boot/kernel/pipes","/lib/modules/base/05_vfs.lua","/lib/modules/base/20_threading.lua","/lib/modules/base/19_manageg.lua","/lib/modules/base/25_init.lua","/lib/modules/base/15_userspace.lua","/usr/man/pipes","/lib/modules/base/16_buffer.lua","/lib/modules/base/17_io.lua","/lib/modules/base/16_require.lua","/lib/modules/base/18_syscall.lua","/lib/modules/base/21_threadUtil.lua","/lib/modules/base/21_timer.lua","/lib/modules/base/16_component.lua","/lib/modules/base/15_keventd.lua","/lib/modules/base/10_procfs.lua","/lib/modules/base/01_util.lua","/lib/modules/base/10_devfs.lua","/lib/modules/base/18_pty.lua","/lib/modules/base/17_keyboard.lua","/lib/modules/base/06_cowfs.lua","/lib/modules/base/09_rootfs.lua","/lib/modules/base/01_gc.lua"}},frontend="MPT"},plan9k={deps={"plan9k-core","plan9k-network","plan9k-drivers","plan9k-edit","plan9k-data"},data={checksum="-2d8f4b84ea60b0c9d5846f57e9f1691c",repo="plan9k",name="plan9k",dependencies={"plan9k-core","plan9k-network","plan9k-drivers","plan9k-edit","plan9k-data"},files={}},frontend="MPT"},["plan9k-network"]={deps={},data={checksum="6e06e6cf5028583fe54047ba9e19abc6",repo="plan9k",name="plan9k-network",dependencies={},files={"/lib/internet.lua","/bin/pastebin.lua","/bin/wget.lua","/lib/modules/base/17_network.lua","/lib/modules/base/19_libnetwork.lua","/bin/arp.lua","/bin/ifconfig.lua","/bin/ping.lua","/bin/route.lua","/lib/modules/network/loopback.lua","/lib/modules/network/modem.lua","/usr/bin/nc.lua","/lib/modules/network/tunnel.lua"}},frontend="MPT"},["plan9k-drivers"]={deps={},data={checksum="-35f098652460458c13f83499b4633e2d",repo="plan9k",name="plan9k-drivers",dependencies={},files={"/lib/modules/base/17_tape.lua","/lib/modules/base/17_eeprom.lua","/lib/modules/base/17_nfc.lua","/lib/modules/base/17_chatbox.lua","/lib/modules/base/17_data.lua","/lib/modules/base/17_drive.lua"}},frontend="MPT"},["plan9k-data"]={deps={},data={checksum="480a898a741b2bf424f9e0e86e5072ba",repo="plan9k",name="plan9k-data",dependencies={},files={"/usr/bin/base64.lua","/usr/lib/data.lua","/usr/bin/deflate.lua","/usr/bin/inflate.lua","/usr/bin/md5sum.lua","/usr/bin/sha256sum.lua","/usr/bin/gpg.lua"}},frontend="MPT"}}} \ No newline at end of file +{installed={["plan9k-shell"]={deps={},frontend="MPT",data={checksum="517b9e0693e734a4ab516f12a6798f14",files={"/bin/sh.lua"},name="plan9k-shell",repo="plan9k",dependencies={}}},plan9k={deps={"plan9k-core","plan9k-network","plan9k-drivers","plan9k-edit","plan9k-data"},frontend="MPT",data={checksum="-2d8f4b84ea60b0c9d5846f57e9f1691c",files={},name="plan9k",repo="plan9k",dependencies={"plan9k-core","plan9k-network","plan9k-drivers","plan9k-edit","plan9k-data"}}},["plan9k-fsutil"]={deps={"plan9k-corelibs"},frontend="MPT",data={checksum="6a974a71f62315e6e2294eae132d1751",files={"/bin/cat.lua","/bin/ln.lua","/bin/ls.lua","/bin/mv.lua","/bin/rm.lua","/bin/tee.lua","/bin/df.lua","/bin/dd.lua","/bin/cp.lua","/bin/touch.lua","/bin/mount.lua","/bin/mount.cow.lua","/bin/mkdir.lua","/bin/pwd.lua","/bin/more.lua"},name="plan9k-fsutil",repo="plan9k",dependencies={"plan9k-corelibs"}}},["plan9k-edit"]={deps={},frontend="MPT",data={checksum="34b1046ac9b7a87a1cdd74f8c03f27ea",files={"/bin/edit.lua"},name="plan9k-edit",repo="plan9k",dependencies={}}},["plan9k-core"]={deps={"pipes","plan9k-coreutil","plan9k-shell"},frontend="MPT",data={checksum="-6f77a020200f96eefd1559dcd8af14a5",files={"/bin/init.lua","/bin/getty.lua","/bin/readkey.lua","/lib/rc.lua","/bin/rc.lua"},name="plan9k-core",repo="plan9k",dependencies={"pipes","plan9k-coreutil","plan9k-shell"}}},["plan9k-installer"]={deps={"plan9k","mpt"},frontend="MPT",data={checksum="52c8f82357c966ce3e19c97bf3942012",files={"/bin/install.lua"},name="plan9k-installer",repo="plan9k",dependencies={"plan9k","mpt"}}},["plan9k-drivers"]={deps={},frontend="MPT",data={checksum="-35f098652460458c13f83499b4633e2d",files={"/lib/modules/base/17_tape.lua","/lib/modules/base/17_eeprom.lua","/lib/modules/base/17_nfc.lua","/lib/modules/base/17_chatbox.lua","/lib/modules/base/17_data.lua","/lib/modules/base/17_drive.lua"},name="plan9k-drivers",repo="plan9k",dependencies={}}},["plan9k-coreutil"]={deps={"plan9k-corelibs","plan9k-fsutil"},frontend="MPT",data={checksum="5fa7e70e3aba17fef97ed65489efb0ca",files={"/bin/echo.lua","/bin/wc.lua","/bin/ps.lua","/bin/lua.lua","/bin/kill.lua","/bin/reboot.lua","/bin/sleep.lua","/bin/clear.lua","/bin/components.lua","/bin/hostname.lua","/bin/dmesg.lua","/bin/shutdown.lua","/bin/label.lua","/bin/uptime.lua","/bin/resolution.lua"},name="plan9k-coreutil",repo="plan9k",dependencies={"plan9k-corelibs","plan9k-fsutil"}}},["openloader-init"]={deps={},frontend="MPT",data={checksum="-45e6d7b1e41468c1d335952ee3b89e13",files={"/init.lua"},name="openloader-init",repo="disks",dependencies={}}},mpt={deps={},frontend="MPT",data={checksum="-3435ded79cf9de20e7185f403eee4a28",files={"/usr/bin/mpt.lua"},name="mpt",repo="mpt",dependencies={}}},pipes={deps={"openloader-init"},frontend="MPT",data={checksum="123b56992859cf05cd03af825437d734",files={"/boot/kernel/pipes","/lib/modules/base/05_vfs.lua","/lib/modules/base/20_threading.lua","/lib/modules/base/19_manageg.lua","/lib/modules/base/25_init.lua","/lib/modules/base/15_userspace.lua","/usr/man/pipes","/lib/modules/base/16_buffer.lua","/lib/modules/base/17_io.lua","/lib/modules/base/16_require.lua","/lib/modules/base/18_syscall.lua","/lib/modules/base/21_threadUtil.lua","/lib/modules/base/21_timer.lua","/lib/modules/base/16_component.lua","/lib/modules/base/15_keventd.lua","/lib/modules/base/10_procfs.lua","/lib/modules/base/01_util.lua","/lib/modules/base/10_devfs.lua","/lib/modules/base/18_pty.lua","/lib/modules/base/17_keyboard.lua","/lib/modules/base/06_cowfs.lua","/lib/modules/base/09_rootfs.lua","/lib/modules/base/01_gc.lua"},name="pipes",repo="plan9k",dependencies={"openloader-init"}}},["plan9k-corelibs"]={deps={},frontend="MPT",data={checksum="1cb7fa12e1a1a35fc168409b60cfe552",files={"/lib/serialization.lua","/lib/term.lua","/lib/text.lua","/lib/shell.lua","/lib/event.lua"},name="plan9k-corelibs",repo="plan9k",dependencies={}}},["plan9k-data"]={deps={},frontend="MPT",data={checksum="480a898a741b2bf424f9e0e86e5072ba",files={"/usr/bin/base64.lua","/usr/lib/data.lua","/usr/bin/deflate.lua","/usr/bin/inflate.lua","/usr/bin/md5sum.lua","/usr/bin/sha256sum.lua","/usr/bin/gpg.lua"},name="plan9k-data",repo="plan9k",dependencies={}}},["plan9k-network"]={deps={},frontend="MPT",data={checksum="6e06e6cf5028583fe54047ba9e19abc6",files={"/lib/internet.lua","/bin/pastebin.lua","/bin/wget.lua","/lib/modules/base/17_network.lua","/lib/modules/base/19_libnetwork.lua","/bin/arp.lua","/bin/ifconfig.lua","/bin/ping.lua","/bin/route.lua","/lib/modules/network/loopback.lua","/lib/modules/network/modem.lua","/usr/bin/nc.lua","/lib/modules/network/tunnel.lua"},name="plan9k-network",repo="plan9k",dependencies={}}}}} \ No newline at end of file