From f4f6881bdd3b25c2ce855a03acf302959312b587 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Sat, 28 Feb 2015 20:36:04 +0100 Subject: [PATCH 01/10] Trying to prevent NPE in item cost computation. --- src/main/scala/li/cil/oc/util/ItemCosts.scala | 35 ++++++++++--------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/src/main/scala/li/cil/oc/util/ItemCosts.scala b/src/main/scala/li/cil/oc/util/ItemCosts.scala index bb436b667..2a1f4e5e1 100644 --- a/src/main/scala/li/cil/oc/util/ItemCosts.scala +++ b/src/main/scala/li/cil/oc/util/ItemCosts.scala @@ -100,24 +100,27 @@ object ItemCosts { } else { val recipes = CraftingManager.getInstance.getRecipeList.map(_.asInstanceOf[IRecipe]) - val recipe = recipes.find(recipe => recipe.getRecipeOutput != null && fuzzyEquals(stack, recipe.getRecipeOutput)) - val (ingredients, output) = recipe match { - case Some(recipe: ShapedRecipes) => (recipe.recipeItems.flatMap(accumulate(_, path :+ stack)).toIterable, recipe.getRecipeOutput.stackSize) - case Some(recipe: ShapelessRecipes) => (recipe.recipeItems.flatMap(accumulate(_, path :+ stack)).toIterable, recipe.getRecipeOutput.stackSize) - case Some(recipe: ShapedOreRecipe) => (recipe.getInput.flatMap(accumulate(_, path :+ stack)).toIterable, recipe.getRecipeOutput.stackSize) - case Some(recipe: ShapelessOreRecipe) => (recipe.getInput.flatMap(accumulate(_, path :+ stack)).toIterable, recipe.getRecipeOutput.stackSize) - case _ => FurnaceRecipes.smelting.getSmeltingList.asInstanceOf[util.Map[ItemStack, ItemStack]].find { - case (_, value) => fuzzyEquals(stack, value) - } match { - case Some((rein, raus)) => (accumulate(rein, path :+ stack), raus.stackSize) - case _ => (Iterable((stack, 1.0)), 1) + if (recipes == null) Iterable((stack, 1.0)) + else { + val recipe = recipes.filter(_ != null).find(recipe => recipe.getRecipeOutput != null && fuzzyEquals(stack, recipe.getRecipeOutput)) + val (ingredients, output) = recipe match { + case Some(recipe: ShapedRecipes) => (recipe.recipeItems.flatMap(accumulate(_, path :+ stack)).toIterable, recipe.getRecipeOutput.stackSize) + case Some(recipe: ShapelessRecipes) => (recipe.recipeItems.flatMap(accumulate(_, path :+ stack)).toIterable, recipe.getRecipeOutput.stackSize) + case Some(recipe: ShapedOreRecipe) => (recipe.getInput.flatMap(accumulate(_, path :+ stack)).toIterable, recipe.getRecipeOutput.stackSize) + case Some(recipe: ShapelessOreRecipe) => (recipe.getInput.flatMap(accumulate(_, path :+ stack)).toIterable, recipe.getRecipeOutput.stackSize) + case _ => FurnaceRecipes.smelting.getSmeltingList.asInstanceOf[util.Map[ItemStack, ItemStack]].find { + case (_, value) => fuzzyEquals(stack, value) + } match { + case Some((rein, raus)) => (accumulate(rein, path :+ stack), raus.stackSize) + case _ => (Iterable((stack, 1.0)), 1) + } } + val scaled = deflate(ingredients.map { + case (ingredient, count) => (ingredient.copy(), count / output) + }).toArray.sortBy(_._1.getUnlocalizedName) + cache += new ItemStackWrapper(stack.copy()) -> scaled + scaled } - val scaled = deflate(ingredients.map { - case (ingredient, count) => (ingredient.copy(), count / output) - }).toArray.sortBy(_._1.getUnlocalizedName) - cache += new ItemStackWrapper(stack.copy()) -> scaled - scaled } } case list: util.ArrayList[ItemStack]@unchecked if !list.isEmpty => From f498deba26e8130ff5ec965a16781c5750e8fae5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Sun, 1 Mar 2015 19:52:26 +0100 Subject: [PATCH 02/10] Fix potential NPE in directory listing, should close #947. --- src/main/scala/li/cil/oc/common/SaveHandler.scala | 4 ++-- src/main/scala/li/cil/oc/server/fs/Buffered.scala | 2 +- .../scala/li/cil/oc/server/fs/FileInputStreamFileSystem.scala | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/scala/li/cil/oc/common/SaveHandler.scala b/src/main/scala/li/cil/oc/common/SaveHandler.scala index c7fb5b454..2fdc003a8 100644 --- a/src/main/scala/li/cil/oc/common/SaveHandler.scala +++ b/src/main/scala/li/cil/oc/common/SaveHandler.scala @@ -168,7 +168,7 @@ object SaveHandler { val chunk = e.getChunk.getChunkCoordIntPair val dimPath = new io.File(path, dimension.toString) val chunkPath = new io.File(dimPath, s"${chunk.chunkXPos}.${chunk.chunkZPos}") - if (chunkPath.exists && chunkPath.isDirectory) { + if (chunkPath.exists && chunkPath.isDirectory && chunkPath.list() != null) { for (file <- chunkPath.listFiles() if System.currentTimeMillis() - file.lastModified() > TimeToHoldOntoOldSaves) file.delete() } saveData.get(dimension) match { @@ -207,7 +207,7 @@ object SaveHandler { // But that's really not something I'm bothered by, it's a fallback. def recurse(file: File) { file.setLastModified(System.currentTimeMillis()) - if (file.isDirectory) file.listFiles().foreach(recurse) + if (file.exists() && file.isDirectory && file.list() != null) file.listFiles().foreach(recurse) } recurse(statePath) } diff --git a/src/main/scala/li/cil/oc/server/fs/Buffered.scala b/src/main/scala/li/cil/oc/server/fs/Buffered.scala index c09c83d82..f6038e16b 100644 --- a/src/main/scala/li/cil/oc/server/fs/Buffered.scala +++ b/src/main/scala/li/cil/oc/server/fs/Buffered.scala @@ -42,7 +42,7 @@ trait Buffered extends OutputStreamFileSystem { for (child <- directory.listFiles() if isValidFilename(child.getName)) { val childPath = path + child.getName val childFile = new io.File(directory, child.getName) - if (child.isDirectory) { + if (child.exists() && child.isDirectory && child.list() != null) { recurse(childPath + "/", childFile) } else if (!exists(childPath) || !isDirectory(childPath)) { diff --git a/src/main/scala/li/cil/oc/server/fs/FileInputStreamFileSystem.scala b/src/main/scala/li/cil/oc/server/fs/FileInputStreamFileSystem.scala index 56322c7d4..a405bb967 100644 --- a/src/main/scala/li/cil/oc/server/fs/FileInputStreamFileSystem.scala +++ b/src/main/scala/li/cil/oc/server/fs/FileInputStreamFileSystem.scala @@ -3,7 +3,7 @@ package li.cil.oc.server.fs import java.io trait FileInputStreamFileSystem extends InputStreamFileSystem { - protected val root: io.File + protected def root: io.File // ----------------------------------------------------------------------- // @@ -36,7 +36,7 @@ trait FileInputStreamFileSystem extends InputStreamFileSystem { override def list(path: String) = new io.File(root, path) match { case file if file.exists() && file.isFile => Array(file.getName) - case directory if directory.exists() && directory.isDirectory => + case directory if directory.exists() && directory.isDirectory && directory.list() != null => directory.listFiles().map(file => if (file.isDirectory) file.getName + "/" else file.getName) case _ => throw new io.FileNotFoundException("no such file or directory") } From d39ce433eda394311d9817c9f2efdde035113123 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Thu, 5 Mar 2015 19:15:10 +0100 Subject: [PATCH 03/10] Might fix a memory leak. --- .../scala/li/cil/oc/common/EventHandler.scala | 21 +++++++++ .../li/cil/oc/server/component/Keyboard.scala | 43 ------------------- 2 files changed, 21 insertions(+), 43 deletions(-) diff --git a/src/main/scala/li/cil/oc/common/EventHandler.scala b/src/main/scala/li/cil/oc/common/EventHandler.scala index d236182c8..1411e5046 100644 --- a/src/main/scala/li/cil/oc/common/EventHandler.scala +++ b/src/main/scala/li/cil/oc/common/EventHandler.scala @@ -21,6 +21,7 @@ import li.cil.oc.common.tileentity.Robot import li.cil.oc.common.tileentity.traits.power import li.cil.oc.integration.Mods import li.cil.oc.integration.util +import li.cil.oc.server.component.Keyboard import li.cil.oc.server.{PacketSender => ServerPacketSender} import li.cil.oc.util._ import net.minecraft.client.Minecraft @@ -34,6 +35,7 @@ import net.minecraftforge.common.util.ForgeDirection import net.minecraftforge.event.world.BlockEvent import net.minecraftforge.event.world.WorldEvent +import scala.collection.convert.WrapAsScala._ import scala.collection.mutable import scala.concurrent.ExecutionContext.Implicits.global import scala.concurrent.Future @@ -45,10 +47,14 @@ object EventHandler { private val runningRobots = mutable.Set.empty[Robot] + private val keyboards = java.util.Collections.newSetFromMap[Keyboard](new java.util.WeakHashMap[Keyboard, java.lang.Boolean]) + def onRobotStart(robot: Robot): Unit = runningRobots += robot def onRobotStopped(robot: Robot): Unit = runningRobots -= robot + def addKeyboard(keyboard: Keyboard): Unit = keyboards += keyboard + def schedule(tileEntity: TileEntity) { if (SideTracker.isServer) pending.synchronized { pending += (() => Network.joinOrCreateNetwork(tileEntity)) @@ -186,6 +192,21 @@ object EventHandler { } } + @SubscribeEvent + def onPlayerRespawn(e: PlayerRespawnEvent) { + keyboards.foreach(_.releasePressedKeys(e.player)) + } + + @SubscribeEvent + def onPlayerChangedDimension(e: PlayerChangedDimensionEvent) { + keyboards.foreach(_.releasePressedKeys(e.player)) + } + + @SubscribeEvent + def onPlayerLogout(e: PlayerLoggedOutEvent) { + keyboards.foreach(_.releasePressedKeys(e.player)) + } + lazy val drone = api.Items.get("drone") lazy val eeprom = api.Items.get("eeprom") lazy val mcu = api.Items.get("microcontroller") diff --git a/src/main/scala/li/cil/oc/server/component/Keyboard.scala b/src/main/scala/li/cil/oc/server/component/Keyboard.scala index cc1072cc8..6aec2df26 100644 --- a/src/main/scala/li/cil/oc/server/component/Keyboard.scala +++ b/src/main/scala/li/cil/oc/server/component/Keyboard.scala @@ -1,21 +1,14 @@ package li.cil.oc.server.component -import cpw.mods.fml.common.FMLCommonHandler -import cpw.mods.fml.common.eventhandler.SubscribeEvent -import cpw.mods.fml.common.gameevent.PlayerEvent.PlayerChangedDimensionEvent -import cpw.mods.fml.common.gameevent.PlayerEvent.PlayerLoggedOutEvent -import cpw.mods.fml.common.gameevent.PlayerEvent.PlayerRespawnEvent import li.cil.oc.Settings import li.cil.oc.api import li.cil.oc.api.Network import li.cil.oc.api.component.Keyboard.UsabilityChecker import li.cil.oc.api.driver.EnvironmentHost import li.cil.oc.api.network.Message -import li.cil.oc.api.network.Node import li.cil.oc.api.network.Visibility import li.cil.oc.api.prefab import net.minecraft.entity.player.EntityPlayer -import net.minecraftforge.event.world.WorldEvent import scala.collection.mutable @@ -35,21 +28,6 @@ class Keyboard(val host: EnvironmentHost) extends prefab.ManagedEnvironment with // ----------------------------------------------------------------------- // - @SubscribeEvent - def onPlayerRespawn(e: PlayerRespawnEvent) { - releasePressedKeys(e.player) - } - - @SubscribeEvent - def onPlayerChangedDimension(e: PlayerChangedDimensionEvent) { - releasePressedKeys(e.player) - } - - @SubscribeEvent - def onPlayerLogout(e: PlayerLoggedOutEvent) { - releasePressedKeys(e.player) - } - def releasePressedKeys(player: EntityPlayer) { pressedKeys.get(player) match { case Some(keys) => for ((code, char) <- keys) { @@ -65,29 +43,8 @@ class Keyboard(val host: EnvironmentHost) extends prefab.ManagedEnvironment with pressedKeys.remove(player) } - @SubscribeEvent - def onWorldUnload(e: WorldEvent.Unload) { - try FMLCommonHandler.instance.bus.unregister(this) catch { - case ignore: Throwable => - } - } - // ----------------------------------------------------------------------- // - override def onConnect(node: Node) { - if (node == this.node) { - FMLCommonHandler.instance.bus.register(this) - } - } - - override def onDisconnect(node: Node) { - if (node == this.node) { - try FMLCommonHandler.instance.bus.unregister(this) catch { - case ignore: Throwable => - } - } - } - override def onMessage(message: Message) = { message.data match { case Array(p: EntityPlayer, char: Character, code: Integer) if message.name == "keyboard.keyDown" => From 93b7dd63f7e081d5ecb726672913962229b9cbd2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Mon, 9 Mar 2015 03:40:34 +0100 Subject: [PATCH 04/10] Fixes LuaJ fallback, closes #954. --- .../li/cil/oc/server/machine/luaj/LuaJLuaArchitecture.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/scala/li/cil/oc/server/machine/luaj/LuaJLuaArchitecture.scala b/src/main/scala/li/cil/oc/server/machine/luaj/LuaJLuaArchitecture.scala index e4ef87f28..b7667ec53 100644 --- a/src/main/scala/li/cil/oc/server/machine/luaj/LuaJLuaArchitecture.scala +++ b/src/main/scala/li/cil/oc/server/machine/luaj/LuaJLuaArchitecture.scala @@ -102,13 +102,13 @@ class LuaJLuaArchitecture(val machine: api.machine.Machine) extends Architecture memory > 0 } - private def memoryInBytes(components: java.lang.Iterable[ItemStack]) = components.foldLeft(0)((acc, stack) => Option(api.Driver.driverFor(stack)) match { + private def memoryInBytes(components: java.lang.Iterable[ItemStack]) = components.foldLeft(0)((acc, stack) => acc + (Option(api.Driver.driverFor(stack)) match { case Some(driver: Memory) => val sizes = Settings.get.ramSizes val tier = math.round(driver.amount(stack)).toInt - 1 sizes(tier max 0 min (sizes.length - 1)) * 1024 case _ => 0 - }) + })) // ----------------------------------------------------------------------- // From f044c5b96f58c79340cacb7331b0d72d48d1ffbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Mon, 9 Mar 2015 03:40:47 +0100 Subject: [PATCH 05/10] Bump version number. --- build.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.properties b/build.properties index 1e5811b7c..ea984b884 100644 --- a/build.properties +++ b/build.properties @@ -1,7 +1,7 @@ minecraft.version=1.7.10 forge.version=10.13.2.1236 -oc.version=1.5.2 +oc.version=1.5.3 oc.subversion=dev ae2.version=rv1-stable-1 From 5358c8b814acb06e13c35d74281f1d9106099d68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Mon, 9 Mar 2015 16:36:25 +0100 Subject: [PATCH 06/10] Fixed screens potentially preventing chunks to unload. --- src/main/scala/li/cil/oc/common/tileentity/Screen.scala | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/scala/li/cil/oc/common/tileentity/Screen.scala b/src/main/scala/li/cil/oc/common/tileentity/Screen.scala index 669638d93..1caa8a76b 100644 --- a/src/main/scala/li/cil/oc/common/tileentity/Screen.scala +++ b/src/main/scala/li/cil/oc/common/tileentity/Screen.scala @@ -7,6 +7,7 @@ import li.cil.oc.api.network.Analyzable import li.cil.oc.api.network._ import li.cil.oc.common.component.TextBuffer import li.cil.oc.util.Color +import li.cil.oc.util.ExtendedWorld._ import net.minecraft.client.Minecraft import net.minecraft.entity.Entity import net.minecraft.entity.player.EntityPlayer @@ -61,7 +62,7 @@ class Screen(var tier: Int) extends traits.TextBuffer with SidedEnvironment with override def canConnect(side: ForgeDirection) = toLocal(side) != ForgeDirection.SOUTH // Allow connections from front for keyboards, and keyboards only... - override def sidedNode(side: ForgeDirection) = if (toLocal(side) != ForgeDirection.SOUTH || world.getTileEntity(x + side.offsetX, y + side.offsetY, z + side.offsetZ).isInstanceOf[Keyboard]) node else null + override def sidedNode(side: ForgeDirection) = if (toLocal(side) != ForgeDirection.SOUTH || (world.blockExists(position.offset(side)) && world.getTileEntity(position.offset(side)).isInstanceOf[Keyboard])) node else null // ----------------------------------------------------------------------- // From 49c967cdcfc8bb13bbfd17f4ae0734c0d3f31c92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Mon, 9 Mar 2015 16:41:14 +0100 Subject: [PATCH 07/10] Fix sound handler potentially leaking memory by keeping references to tile entities from unloaded worlds. --- src/main/scala/li/cil/oc/client/Sound.scala | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/scala/li/cil/oc/client/Sound.scala b/src/main/scala/li/cil/oc/client/Sound.scala index abb6fa4f4..8350e98fd 100644 --- a/src/main/scala/li/cil/oc/client/Sound.scala +++ b/src/main/scala/li/cil/oc/client/Sound.scala @@ -146,6 +146,7 @@ object Sound { sources.synchronized(try sources.foreach(_._2.stop()) catch { case _: Throwable => // Ignore. }) + sources.clear() } private abstract class Command(val when: Long, val tileEntity: TileEntity) extends Ordered[Command] { From ffd38e59ff373e63a204314475de829383523b56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Wed, 11 Mar 2015 14:37:13 +0100 Subject: [PATCH 08/10] Allow getting array with input / output for all colors for bundled redstone. Closes #958. To get this, do not pass a color value to the corresponding getter method. Note: the returned table is zero indexed to allow treating it the same as the methods, i.e. use the `colors` library to index colors by name e.g. --- .../tileentity/traits/BundledRedstoneAware.scala | 3 +++ .../oc/server/component/RedstoneBundled.scala | 16 ++++++++++------ 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/main/scala/li/cil/oc/common/tileentity/traits/BundledRedstoneAware.scala b/src/main/scala/li/cil/oc/common/tileentity/traits/BundledRedstoneAware.scala index 128ef9a70..cea00a4b3 100644 --- a/src/main/scala/li/cil/oc/common/tileentity/traits/BundledRedstoneAware.scala +++ b/src/main/scala/li/cil/oc/common/tileentity/traits/BundledRedstoneAware.scala @@ -45,6 +45,9 @@ trait BundledRedstoneAware extends RedstoneAware with IBundledEmitter with IBund super.isOutputEnabled_=(value) } + def bundledInput(side: ForgeDirection) = + (_bundledInput(side.ordinal()), _rednetInput(side.ordinal())).zipped.map(math.max) + def bundledInput(side: ForgeDirection, color: Int) = math.max(_bundledInput(side.ordinal())(color), _rednetInput(side.ordinal())(color)) 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 02b3312eb..bfa7120cb 100644 --- a/src/main/scala/li/cil/oc/server/component/RedstoneBundled.scala +++ b/src/main/scala/li/cil/oc/server/component/RedstoneBundled.scala @@ -9,18 +9,22 @@ import li.cil.oc.common.tileentity.traits.BundledRedstoneAware trait RedstoneBundled extends RedstoneVanilla { override def redstone: EnvironmentHost with BundledRedstoneAware - @Callback(direct = true, doc = """function(side:number, color:number):number -- Get the bundled redstone input on the specified side and with the specified color.""") + @Callback(direct = true, doc = """function(side:number[, color:number]):number or table -- Get the bundled redstone input on the specified side and with the specified color.""") def getBundledInput(context: Context, args: Arguments): Array[AnyRef] = { val side = checkSide(args, 0) - val color = checkColor(args, 1) - result(redstone.bundledInput(side, color)) + if (args.optAny(1, null) == null) + result(redstone.bundledInput(side).zipWithIndex.map(_.swap).toMap) + else + result(redstone.bundledInput(side, checkColor(args, 1))) } - @Callback(direct = true, doc = """function(side:number, color:number):number -- Get the bundled redstone output on the specified side and with the specified color.""") + @Callback(direct = true, doc = """function(side:number[, color:number]):number or table -- Get the bundled redstone output on the specified side and with the specified color.""") def getBundledOutput(context: Context, args: Arguments): Array[AnyRef] = { val side = checkSide(args, 0) - val color = checkColor(args, 1) - result(redstone.bundledOutput(side, color)) + if (args.optAny(1, null) == null) + result(redstone.bundledOutput(side).zipWithIndex.map(_.swap).toMap) + else + result(redstone.bundledOutput(side, checkColor(args, 1))) } @Callback(doc = """function(side:number, color:number, value:number):number -- Set the bundled redstone output on the specified side and with the specified color.""") From c0690bb07faa77f66688efcdd9c688b062e12ffc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Wed, 11 Mar 2015 15:45:29 +0100 Subject: [PATCH 09/10] Firing `PlayerInteractEvent` when agents (robots, drones) are interacting with in-world inventories and in the inventory driver. See #900. Hopefully doesn't break anything... --- .../oc/integration/vanilla/DriverInventory.java | 14 +++++++++----- .../component/traits/InventoryWorldControl.scala | 10 ++++++---- .../traits/InventoryWorldControlMk2.scala | 2 +- .../oc/server/component/traits/WorldAware.scala | 8 ++++++++ .../component/traits/WorldInventoryAnalytics.scala | 2 +- 5 files changed, 25 insertions(+), 11 deletions(-) diff --git a/src/main/scala/li/cil/oc/integration/vanilla/DriverInventory.java b/src/main/scala/li/cil/oc/integration/vanilla/DriverInventory.java index 4431fc8b6..cde412eeb 100644 --- a/src/main/scala/li/cil/oc/integration/vanilla/DriverInventory.java +++ b/src/main/scala/li/cil/oc/integration/vanilla/DriverInventory.java @@ -1,5 +1,6 @@ package li.cil.oc.integration.vanilla; +import cpw.mods.fml.common.eventhandler.Event; import li.cil.oc.Settings; import li.cil.oc.api.machine.Arguments; import li.cil.oc.api.machine.Callback; @@ -7,14 +8,16 @@ import li.cil.oc.api.machine.Context; import li.cil.oc.api.network.ManagedEnvironment; import li.cil.oc.api.prefab.DriverTileEntity; import li.cil.oc.integration.ManagedTileEntityEnvironment; +import li.cil.oc.util.BlockPosition; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.inventory.IInventory; import net.minecraft.item.ItemStack; import net.minecraft.tileentity.TileEntity; -import net.minecraft.util.Vec3; import net.minecraft.world.World; import net.minecraft.world.WorldServer; import net.minecraftforge.common.util.FakePlayerFactory; +import net.minecraftforge.event.ForgeEventFactory; +import net.minecraftforge.event.entity.player.PlayerInteractEvent; public final class DriverInventory extends DriverTileEntity { @Override @@ -29,12 +32,12 @@ public final class DriverInventory extends DriverTileEntity { public static final class Environment extends ManagedTileEntityEnvironment { private final EntityPlayer fakePlayer; - private final Vec3 position; + private final BlockPosition position; public Environment(final TileEntity tileEntity, final World world) { super((IInventory) tileEntity, "inventory"); fakePlayer = FakePlayerFactory.get((WorldServer) world, Settings.get().fakePlayerProfile()); - position = Vec3.createVectorHelper(tileEntity.xCoord + 0.5, tileEntity.yCoord + 0.5, tileEntity.zCoord + 0.5); + position = BlockPosition.apply(tileEntity.xCoord, tileEntity.yCoord, tileEntity.zCoord, world); } @Callback(doc = "function():string -- Get the name of this inventory.") @@ -172,8 +175,9 @@ public final class DriverInventory extends DriverTileEntity { private boolean notPermitted() { synchronized (fakePlayer) { - fakePlayer.setPosition(position.xCoord, position.yCoord, position.zCoord); - return !tileEntity.isUseableByPlayer(fakePlayer); + fakePlayer.setPosition(position.toVec3().xCoord, position.toVec3().yCoord, position.toVec3().zCoord); + final PlayerInteractEvent event = ForgeEventFactory.onPlayerInteract(fakePlayer, PlayerInteractEvent.Action.RIGHT_CLICK_BLOCK, position.x(), position.y(), position.z(), 0, fakePlayer.getEntityWorld()); + return !event.isCanceled() && event.useBlock != Event.Result.DENY && !tileEntity.isUseableByPlayer(fakePlayer); } } } 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 c6497f971..3627b8b32 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 @@ -36,8 +36,9 @@ trait InventoryWorldControl extends InventoryAware with WorldAware with SideRest val count = args.optionalItemCount(1) val stack = inventory.getStackInSlot(selectedSlot) if (stack != null && stack.stackSize > 0) { - InventoryUtils.inventoryAt(position.offset(facing)) match { - case Some(inv) if inv.isUseableByPlayer(fakePlayer) => + val blockPos = position.offset(facing) + InventoryUtils.inventoryAt(blockPos) match { + case Some(inv) if inv.isUseableByPlayer(fakePlayer) && mayInteract(blockPos, facing.getOpposite) => if (!InventoryUtils.insertIntoInventory(stack, inv, Option(facing.getOpposite), count)) { // Cannot drop into that inventory. return result(false, "inventory full") @@ -70,8 +71,9 @@ trait InventoryWorldControl extends InventoryAware with WorldAware with SideRest val facing = checkSideForAction(args, 0) val count = args.optionalItemCount(1) - if (InventoryUtils.inventoryAt(position.offset(facing)).exists(inventory => { - inventory.isUseableByPlayer(fakePlayer) && InventoryUtils.extractFromInventory(InventoryUtils.insertIntoInventory(_, this.inventory, slots = Option(insertionSlots)), inventory, facing.getOpposite, count) + val blockPos = position.offset(facing) + if (InventoryUtils.inventoryAt(blockPos).exists(inventory => { + inventory.isUseableByPlayer(fakePlayer) && mayInteract(blockPos, facing.getOpposite) && InventoryUtils.extractFromInventory(InventoryUtils.insertIntoInventory(_, this.inventory, slots = Option(insertionSlots)), inventory, facing.getOpposite, count) })) { context.pause(Settings.get.suckDelay) result(true) 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 55083b348..814ed4706 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 @@ -56,7 +56,7 @@ trait InventoryWorldControlMk2 extends InventoryAware with WorldAware with SideR private def withInventory(side: ForgeDirection, f: IInventory => Array[AnyRef]) = InventoryUtils.inventoryAt(position.offset(side)) match { - case Some(inventory) if inventory.isUseableByPlayer(fakePlayer) => f(inventory) + case Some(inventory) if inventory.isUseableByPlayer(fakePlayer) && mayInteract(position.offset(side), side.getOpposite) => f(inventory) case _ => result(Unit, "no inventory") } } diff --git a/src/main/scala/li/cil/oc/server/component/traits/WorldAware.scala b/src/main/scala/li/cil/oc/server/component/traits/WorldAware.scala index 95df7a722..56bc16711 100644 --- a/src/main/scala/li/cil/oc/server/component/traits/WorldAware.scala +++ b/src/main/scala/li/cil/oc/server/component/traits/WorldAware.scala @@ -1,5 +1,6 @@ package li.cil.oc.server.component.traits +import cpw.mods.fml.common.eventhandler.Event.Result import li.cil.oc.Settings import li.cil.oc.util.BlockPosition import li.cil.oc.util.ExtendedBlock._ @@ -13,6 +14,8 @@ import net.minecraft.world.WorldServer import net.minecraftforge.common.MinecraftForge import net.minecraftforge.common.util.FakePlayerFactory import net.minecraftforge.common.util.ForgeDirection +import net.minecraftforge.event.ForgeEventFactory +import net.minecraftforge.event.entity.player.PlayerInteractEvent.Action import net.minecraftforge.event.world.BlockEvent import net.minecraftforge.fluids.FluidRegistry @@ -33,6 +36,11 @@ trait WorldAware { player } + def mayInteract(blockPos: BlockPosition, face: ForgeDirection): Boolean = { + val event = ForgeEventFactory.onPlayerInteract(fakePlayer, Action.RIGHT_CLICK_BLOCK, blockPos.x, blockPos.y, blockPos.z, face.ordinal(), world) + !event.isCanceled && event.useBlock != Result.DENY + } + def entitiesInBounds[Type <: Entity : ClassTag](bounds: AxisAlignedBB) = { world.getEntitiesWithinAABB(classTag[Type].runtimeClass, bounds).map(_.asInstanceOf[Type]) } diff --git a/src/main/scala/li/cil/oc/server/component/traits/WorldInventoryAnalytics.scala b/src/main/scala/li/cil/oc/server/component/traits/WorldInventoryAnalytics.scala index f03e9ae2d..f59e36129 100644 --- a/src/main/scala/li/cil/oc/server/component/traits/WorldInventoryAnalytics.scala +++ b/src/main/scala/li/cil/oc/server/component/traits/WorldInventoryAnalytics.scala @@ -66,7 +66,7 @@ trait WorldInventoryAnalytics extends WorldAware with SideRestricted with Networ private def withInventory(side: ForgeDirection, f: IInventory => Array[AnyRef]) = InventoryUtils.inventoryAt(position.offset(side)) match { - case Some(inventory) if inventory.isUseableByPlayer(fakePlayer) => f(inventory) + case Some(inventory) if inventory.isUseableByPlayer(fakePlayer) && mayInteract(position.offset(side), side.getOpposite) => f(inventory) case _ => result(null, "no inventory") } } From 3a20897754189a35b834ffaca79fe3bbc97cdabc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Fri, 13 Mar 2015 09:20:00 +0100 Subject: [PATCH 10/10] Fix angel upgrade, closes #960. --- .../scala/li/cil/oc/common/event/AngelUpgradeHandler.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/scala/li/cil/oc/common/event/AngelUpgradeHandler.scala b/src/main/scala/li/cil/oc/common/event/AngelUpgradeHandler.scala index fdc7a9062..40b03b498 100644 --- a/src/main/scala/li/cil/oc/common/event/AngelUpgradeHandler.scala +++ b/src/main/scala/li/cil/oc/common/event/AngelUpgradeHandler.scala @@ -11,10 +11,10 @@ object AngelUpgradeHandler { @SubscribeEvent def onPlaceInAir(e: RobotPlaceInAirEvent) { val machineNode = e.agent.machine.node - machineNode.reachableNodes.exists { + e.setAllowed(machineNode.reachableNodes.exists { case component: Component if component.canBeSeenFrom(machineNode) => component.host.isInstanceOf[UpgradeAngel] case _ => false - } + }) } }