Merge branch 'master-MC1.7.10' into master-MC1.12

This commit is contained in:
Adrian Siekierka 2022-08-27 11:16:21 +02:00
commit 0b5de857a7
13 changed files with 99 additions and 42 deletions

View File

@ -55,4 +55,13 @@ public interface MachineHost extends EnvironmentHost {
* @param node the node that was disconnected from the network. * @param node the node that was disconnected from the network.
*/ */
void onMachineDisconnect(Node node); void onMachineDisconnect(Node node);
/** Helper method for printing the machine position in error messages and debug statements. */
default String machinePosition()
{
if (world() != null && world().provider != null)
return String.format("(%g, %g, %g, %d)", xPosition(), yPosition(), zPosition(), world().provider.getDimension());
else
return String.format("(%g, %g, %g)", xPosition(), yPosition(), zPosition());
}
} }

View File

@ -41,5 +41,5 @@ if #args == 0 then
end end
else else
-- execute command. -- execute command.
return sh.execute(...) return sh.execute(_ENV, ...)
end end

View File

@ -10,8 +10,8 @@ function shell.execute(command, env, ...)
if not sh then if not sh then
return false, reason return false, reason
end end
local proc = process.load(sh, nil, nil, command) local proc = process.load(sh, env, nil, command)
local result = table.pack(process.internal.continue(proc, env, command, ...)) local result = table.pack(process.internal.continue(proc, command, ...))
if result.n == 0 then return true end if result.n == 0 then return true end
return table.unpack(result, 1, result.n) return table.unpack(result, 1, result.n)
end end

View File

@ -34,6 +34,7 @@ Claptrap # Borderlands
Codsworth # Fallout 4 Codsworth # Fallout 4
Continuity # Mona Lisa Overdrive Continuity # Mona Lisa Overdrive
Cortana # Halo Cortana # Halo
Crow # Mystery Science Theater 3000
Crypto # Kodos Crypto # Kodos
Curiosity # Mars Rover Curiosity # Mars Rover
Daedalus # Deus Ex Daedalus # Deus Ex
@ -60,6 +61,7 @@ Ghost # I, Robot quote "There have always been ghosts in the machin
GLaDOS # Portal GLaDOS # Portal
Gipsy Danger # Pacific Rim Gipsy Danger # Pacific Rim
G.U.N.T.E.R. # Lost in Space G.U.N.T.E.R. # Lost in Space
Gypsy # Mystery Science Theater 3000
HAL 9000 # Space Odyssey HAL 9000 # Space Odyssey
Harbinger # Mass Effect Harbinger # Mass Effect
Harkness # Fallout 3 Harkness # Fallout 3
@ -117,6 +119,7 @@ T-1000 # Terminator
Tachikoma # Ghost in the Shell Tachikoma # Ghost in the Shell
TARA UH # Perry Rhodan TARA UH # Perry Rhodan
Terminator # Terminator Terminator # Terminator
Tom Servo # Mystery Science Theater 3000
Rinzler # Tron Rinzler # Tron
Twiki # Buck Rodgers Twiki # Buck Rodgers
Uniblab # The Jetsons Uniblab # The Jetsons
@ -132,3 +135,4 @@ Wheatley # Portal
Wintermute # Neuromancer Wintermute # Neuromancer
Wobbo # Contributor Wobbo # Contributor
Yui-MHCP001 # AKA Yui (Mental Health Counseling Program 001) - Sword Art Online Yui-MHCP001 # AKA Yui (Mental Health Counseling Program 001) - Sword Art Online
Zone of Endless # Ace Combat series

View File

@ -131,7 +131,7 @@ trait NetworkControl[AETile >: Null <: TileEntity with IActionHost with IGridHos
case (key, value) => hash += key -> value case (key, value) => hash += key -> value
} }
hash.update("isCraftable", Boolean.box(aeItem.isCraftable)) hash.update("isCraftable", Boolean.box(aeItem.isCraftable))
hash.update("size", Int.box(aeItem.getStackSize.toInt)) hash.update("size", Long.box(aeItem.getStackSize))
hash hash
} }

View File

@ -83,6 +83,14 @@ class DiskDriveMountable(val rack: api.internal.Rack, val slot: Int) extends Abs
else result(false) else result(false)
} }
@Callback(doc = "function(): string -- Return the internal floppy disk address")
def media(context: Context, args: Arguments): Array[AnyRef] = {
if (filesystemNode.isEmpty)
result(Unit, "drive is empty")
else
result(filesystemNode.head.address)
}
// ----------------------------------------------------------------------- // // ----------------------------------------------------------------------- //
// Analyzable // Analyzable

View File

@ -44,9 +44,9 @@ trait InventoryWorldControl extends InventoryAware with WorldAware with SideRest
val stack = inventory.getStackInSlot(selectedSlot) val stack = inventory.getStackInSlot(selectedSlot)
if (!stack.isEmpty && stack.getCount > 0) { if (!stack.isEmpty && stack.getCount > 0) {
val blockPos = position.offset(facing) val blockPos = position.offset(facing)
InventoryUtils.inventoryAt(blockPos, facing.getOpposite) match { InventoryUtils.inventorySourceAt(blockPos, facing.getOpposite) match {
case Some(inv) if mayInteract(blockPos, facing.getOpposite, inv) => case Some(inv) if mayInteract(inv) =>
if (!InventoryUtils.insertIntoInventory(stack, inv, count)) { if (!InventoryUtils.insertIntoInventory(stack, inv.inventory, count)) {
// Cannot drop into that inventory. // Cannot drop into that inventory.
return result(false, "inventory full") return result(false, "inventory full")
} }
@ -103,9 +103,9 @@ trait InventoryWorldControl extends InventoryAware with WorldAware with SideRest
val count = args.optItemCount(1) val count = args.optItemCount(1)
val blockPos = position.offset(facing) val blockPos = position.offset(facing)
var extracted: Int = InventoryUtils.inventoryAt(blockPos, facing.getOpposite) match { var extracted: Int = InventoryUtils.inventorySourceAt(blockPos, facing.getOpposite) match {
case Some(inventory) => mayInteract(blockPos, facing.getOpposite) case Some(inventory) => mayInteract(inventory)
InventoryUtils.extractAnyFromInventory((is, sim) => InventoryUtils.insertIntoInventory(is, InventoryUtils.asItemHandler(this.inventory), slots = Option(insertionSlots), simulate = sim), inventory, count) InventoryUtils.extractAnyFromInventory((is, sim) => InventoryUtils.insertIntoInventory(is, InventoryUtils.asItemHandler(this.inventory), slots = Option(insertionSlots), simulate = sim), inventory.inventory, count)
case _ => 0 case _ => 0
} }
if (extracted <= 0) { if (extracted <= 0) {

View File

@ -60,8 +60,8 @@ trait InventoryWorldControlMk2 extends InventoryAware with WorldAware with SideR
} }
private def withInventory(blockPos: BlockPosition, fromSide: EnumFacing, f: IItemHandler => Array[AnyRef]) = private def withInventory(blockPos: BlockPosition, fromSide: EnumFacing, f: IItemHandler => Array[AnyRef]) =
InventoryUtils.inventoryAt(blockPos, fromSide) match { InventoryUtils.inventorySourceAt(blockPos, fromSide) match {
case Some(inventory) if mayInteract(blockPos, fromSide) => f(inventory) case Some(inventory) if mayInteract(inventory) => f(inventory.inventory)
case _ => result(Unit, "no inventory") case _ => result(Unit, "no inventory")
} }
} }

View File

@ -2,15 +2,14 @@ package li.cil.oc.server.component.traits
import li.cil.oc.OpenComputers import li.cil.oc.OpenComputers
import li.cil.oc.Settings import li.cil.oc.Settings
import li.cil.oc.util.BlockPosition import li.cil.oc.util.{BlockInventorySource, BlockPosition, EntityInventorySource, InventorySource}
import li.cil.oc.util.ExtendedBlock._ import li.cil.oc.util.ExtendedBlock._
import li.cil.oc.util.ExtendedWorld._ import li.cil.oc.util.ExtendedWorld._
import net.minecraft.entity.Entity import net.minecraft.entity.Entity
import net.minecraft.entity.EntityLivingBase import net.minecraft.entity.EntityLivingBase
import net.minecraft.entity.item.EntityMinecart import net.minecraft.entity.item.EntityMinecart
import net.minecraft.entity.player.EntityPlayer import net.minecraft.entity.player.EntityPlayer
import net.minecraft.util.EnumFacing import net.minecraft.util.{EnumActionResult, EnumFacing, EnumHand}
import net.minecraft.util.EnumHand
import net.minecraft.util.math.AxisAlignedBB import net.minecraft.util.math.AxisAlignedBB
import net.minecraft.world.WorldServer import net.minecraft.world.WorldServer
import net.minecraftforge.common.MinecraftForge import net.minecraftforge.common.MinecraftForge
@ -35,7 +34,7 @@ trait WorldAware {
player player
} }
def mayInteract(blockPos: BlockPosition, face: EnumFacing): Boolean = { private def mayInteract(blockPos: BlockPosition, face: EnumFacing): Boolean = {
try { try {
val event = new PlayerInteractEvent.RightClickBlock(fakePlayer, EnumHand.MAIN_HAND, blockPos.toBlockPos, face, null) val event = new PlayerInteractEvent.RightClickBlock(fakePlayer, EnumHand.MAIN_HAND, blockPos.toBlockPos, face, null)
MinecraftForge.EVENT_BUS.post(event) MinecraftForge.EVENT_BUS.post(event)
@ -47,9 +46,25 @@ trait WorldAware {
} }
} }
def mayInteract(blockPos: BlockPosition, side: EnumFacing, inventory: IItemHandler): Boolean = mayInteract(blockPos, side) && (inventory match { private def mayInteract(entity: Entity): Boolean = {
try {
val event = new PlayerInteractEvent.EntityInteract(fakePlayer, EnumHand.MAIN_HAND, entity)
MinecraftForge.EVENT_BUS.post(event)
!event.isCanceled
} catch {
case t: Throwable =>
OpenComputers.log.warn("Some event handler threw up while checking for permission to access an entity.", t)
true
}
}
def mayInteract(inv: InventorySource): Boolean = (inv.inventory match {
case inv: InvWrapper if inv.getInv != null => inv.getInv.isUsableByPlayer(fakePlayer) case inv: InvWrapper if inv.getInv != null => inv.getInv.isUsableByPlayer(fakePlayer)
case _ => true case _ => true
}) && (inv match {
case inv: BlockInventorySource => mayInteract(inv.position, inv.side)
case inv: EntityInventorySource => mayInteract(inv.entity)
case _ => true
}) })
def entitiesInBounds[Type <: Entity](clazz: Class[Type], bounds: AxisAlignedBB) = { def entitiesInBounds[Type <: Entity](clazz: Class[Type], bounds: AxisAlignedBB) = {

View File

@ -6,13 +6,13 @@ import li.cil.oc.api.machine.Callback
import li.cil.oc.api.machine.Context import li.cil.oc.api.machine.Context
import li.cil.oc.api.prefab.ItemStackArrayValue import li.cil.oc.api.prefab.ItemStackArrayValue
import li.cil.oc.server.component.result import li.cil.oc.server.component.result
import li.cil.oc.util.{BlockPosition, DatabaseAccess, InventoryUtils} import li.cil.oc.util.{BlockInventorySource, BlockPosition, DatabaseAccess, EntityInventorySource, InventorySource, InventoryUtils, StackOption}
import li.cil.oc.util.ExtendedWorld._ import li.cil.oc.util.ExtendedWorld._
import li.cil.oc.util.ExtendedArguments._ import li.cil.oc.util.ExtendedArguments._
import net.minecraft.block.Block import net.minecraft.block.Block
import li.cil.oc.util.StackOption
import net.minecraft.item.ItemStack import net.minecraft.item.ItemStack
import net.minecraft.util.EnumFacing import net.minecraft.util.EnumFacing
import net.minecraftforge.fml.common.registry.EntityRegistry
import net.minecraftforge.items.IItemHandler import net.minecraftforge.items.IItemHandler
import net.minecraftforge.oredict.OreDictionary import net.minecraftforge.oredict.OreDictionary
@ -102,8 +102,12 @@ trait WorldInventoryAnalytics extends WorldAware with SideRestricted with Networ
} }
case _ => None case _ => None
} }
withInventory(facing, inventory => blockAt(position.offset(facing)) match { withInventorySource(facing, {
case Some(block) => result(block.getRegistryName) case BlockInventorySource(position, _, _) => blockAt(position) match {
case Some(block) => result(block.getRegistryName)
case _ => result(Unit, "Unknown")
}
case EntityInventorySource(entity, _, _) => result(EntityRegistry.getEntry(entity.getClass).getRegistryName)
case _ => result(Unit, "Unknown") case _ => result(Unit, "Unknown")
}) })
} }
@ -122,9 +126,12 @@ trait WorldInventoryAnalytics extends WorldAware with SideRestricted with Networ
withInventory(facing, inventory => store(inventory.getStackInSlot(args.checkSlot(inventory, 1)))) withInventory(facing, inventory => store(inventory.getStackInSlot(args.checkSlot(inventory, 1))))
} }
private def withInventory(side: EnumFacing, f: IItemHandler => Array[AnyRef]) = private def withInventorySource(side: EnumFacing, f: InventorySource => Array[AnyRef]) =
InventoryUtils.inventoryAt(position.offset(side), side.getOpposite) match { InventoryUtils.inventorySourceAt(position.offset(side), side.getOpposite) match {
case Some(inventory) if mayInteract(position.offset(side), side.getOpposite, inventory) => f(inventory) case Some(inventory) if mayInteract(inventory) => f(inventory)
case _ => result(Unit, "no inventory") case _ => result(Unit, "no inventory")
} }
private def withInventory(side: EnumFacing, f: IItemHandler => Array[AnyRef]) =
withInventorySource(side, is => f(is.inventory))
} }

View File

@ -799,7 +799,7 @@ class Machine(val host: MachineHost) extends AbstractManagedEnvironment with mac
catch { catch {
case t: Throwable => case t: Throwable =>
OpenComputers.log.error( OpenComputers.log.error(
s"""Unexpected error loading a state of computer at (${host.xPosition}, ${host.yPosition}, ${host.zPosition}). """ + s"""Unexpected error loading a state of computer at ${host.machinePosition()}. """ +
s"""State: ${state.headOption.fold("no state")(_.toString)}. Unless you're upgrading/downgrading across a major version, please report this! Thank you.""", t) s"""State: ${state.headOption.fold("no state")(_.toString)}. Unless you're upgrading/downgrading across a major version, please report this! Thank you.""", t)
close() close()
} }
@ -882,7 +882,7 @@ class Machine(val host: MachineHost) extends AbstractManagedEnvironment with mac
catch { catch {
case t: Throwable => case t: Throwable =>
OpenComputers.log.error( OpenComputers.log.error(
s"""Unexpected error saving a state of computer at (${host.xPosition}, ${host.yPosition}, ${host.zPosition}). """ + s"""Unexpected error saving a state of computer at ${host.machinePosition()}. """ +
s"""State: ${state.headOption.fold("no state")(_.toString)}. Unless you're upgrading/downgrading across a major version, please report this! Thank you.""", t) s"""State: ${state.headOption.fold("no state")(_.toString)}. Unless you're upgrading/downgrading across a major version, please report this! Thank you.""", t)
} }
}) })

View File

@ -376,7 +376,7 @@ abstract class NativeLuaArchitecture(val machine: api.machine.Machine) extends A
try lua.gc(LuaState.GcAction.COLLECT, 0) catch { try lua.gc(LuaState.GcAction.COLLECT, 0) catch {
case t: Throwable => case t: Throwable =>
OpenComputers.log.warn(s"Error cleaning up loaded computer @ (${machine.host.xPosition}, ${machine.host.yPosition}, ${machine.host.zPosition}). This either means the server is badly overloaded or a user created an evil __gc method, accidentally or not.") OpenComputers.log.warn(s"Error cleaning up loaded computer @ ${machine.host().machinePosition()}. This either means the server is badly overloaded or a user created an evil __gc method, accidentally or not.")
machine.crash("error in garbage collector, most likely __gc method timed out") machine.crash("error in garbage collector, most likely __gc method timed out")
} }
} catch { } catch {
@ -414,15 +414,15 @@ abstract class NativeLuaArchitecture(val machine: api.machine.Machine) extends A
try lua.gc(LuaState.GcAction.COLLECT, 0) catch { try lua.gc(LuaState.GcAction.COLLECT, 0) catch {
case t: Throwable => case t: Throwable =>
OpenComputers.log.warn(s"Error cleaning up loaded computer @ (${machine.host.xPosition}, ${machine.host.yPosition}, ${machine.host.zPosition}). This either means the server is badly overloaded or a user created an evil __gc method, accidentally or not.") OpenComputers.log.warn(s"Error cleaning up loaded computer @ ${machine.host().machinePosition()}. This either means the server is badly overloaded or a user created an evil __gc method, accidentally or not.")
machine.crash("error in garbage collector, most likely __gc method timed out") machine.crash("error in garbage collector, most likely __gc method timed out")
} }
} catch { } catch {
case e: LuaRuntimeException => case e: LuaRuntimeException =>
OpenComputers.log.warn(s"Could not persist computer @ (${machine.host.xPosition}, ${machine.host.yPosition}, ${machine.host.zPosition}).\n${e.toString}" + (if (e.getLuaStackTrace.isEmpty) "" else "\tat " + e.getLuaStackTrace.mkString("\n\tat "))) OpenComputers.log.warn(s"Could not persist computer @ ${machine.host().machinePosition()}.\n${e.toString}" + (if (e.getLuaStackTrace.isEmpty) "" else "\tat " + e.getLuaStackTrace.mkString("\n\tat ")))
nbt.removeTag("state") nbt.removeTag("state")
case e: LuaGcMetamethodException => case e: LuaGcMetamethodException =>
OpenComputers.log.warn(s"Could not persist computer @ (${machine.host.xPosition}, ${machine.host.yPosition}, ${machine.host.zPosition}).\n${e.toString}") OpenComputers.log.warn(s"Could not persist computer @ ${machine.host().machinePosition()}.\n${e.toString}")
nbt.removeTag("state") nbt.removeTag("state")
} }

View File

@ -40,33 +40,40 @@ object InventoryUtils {
(!checkNBT || ItemStack.areItemStackTagsEqual(stackA, stackB)) (!checkNBT || ItemStack.areItemStackTagsEqual(stackA, stackB))
/** /**
* Retrieves an actual inventory implementation for a specified world coordinate. * Retrieves an actual inventory implementation for a specified world coordinate,
* <br> * complete with a reference to the source of said implementation.
* This performs special handling for (double-)chests and also checks for
* mine carts with chests.
*/ */
def inventoryAt(position: BlockPosition, side: EnumFacing): Option[IItemHandler] = position.world match { def inventorySourceAt(position: BlockPosition, side: EnumFacing): Option[InventorySource] = position.world match {
case Some(world) if world.blockExists(position) => world.getTileEntity(position) match { case Some(world) if world.blockExists(position) => world.getTileEntity(position) match {
case tile: TileEntity if tile.hasCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, side) => Option(tile.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, side)) case tile: TileEntity if tile.hasCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, side) => Option(BlockInventorySource(position, side, tile.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, side)))
case tile: IInventory => Option(asItemHandler(tile, side)) case tile: IInventory => Option(BlockInventorySource(position, side, asItemHandler(tile, side)))
case _ => world.getEntitiesWithinAABB(classOf[Entity], position.bounds) case _ => world.getEntitiesWithinAABB(classOf[Entity], position.bounds)
.filter(e => !e.isDead && e.hasCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, side)) .filter(e => !e.isDead && e.hasCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, side))
.map(_.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, side)) .map(a => EntityInventorySource(a, side, a.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, side)))
.find(_ != null) .find(a => a != null && a.inventory != null)
} }
case _ => None case _ => None
} }
def anyInventoryAt(position: BlockPosition): Option[IItemHandler] = { /**
* Retrieves an actual inventory implementation for a specified world coordinate.
*/
def inventoryAt(position: BlockPosition, side: EnumFacing): Option[IItemHandler] = inventorySourceAt(position, side)
.map(a => a.inventory)
def anyInventorySourceAt(position: BlockPosition): Option[InventorySource] = {
for(side <- null :: EnumFacing.VALUES.toList) { for(side <- null :: EnumFacing.VALUES.toList) {
inventoryAt(position, side) match { inventorySourceAt(position, side) match {
case inv: Some[IItemHandler] => return inv case inv: Some[InventorySource] => return inv
case _ => case _ =>
} }
} }
None None
} }
def anyInventoryAt(position: BlockPosition): Option[IItemHandler] = anyInventorySourceAt(position)
.map(a => a.inventory)
/** /**
* Inserts a stack into an inventory. * Inserts a stack into an inventory.
* <br> * <br>
@ -397,3 +404,10 @@ object InventoryUtils {
case _ => null case _ => null
} }
} }
sealed trait InventorySource {
def side: EnumFacing
def inventory: IItemHandler
}
final case class BlockInventorySource(position: BlockPosition, side: EnumFacing, inventory: IItemHandler) extends InventorySource
final case class EntityInventorySource(entity: Entity, side: EnumFacing, inventory: IItemHandler) extends InventorySource