Merge branch 'master-MC1.7.10' of github.com:MightyPirates/OpenComputers into OC1.5-MC1.7.10

Conflicts:
	build.properties
This commit is contained in:
Florian Nücke 2015-02-25 12:57:04 +01:00
commit 30f23adf35
30 changed files with 278 additions and 88 deletions

View File

@ -1,7 +1,7 @@
minecraft.version=1.7.10
forge.version=10.13.2.1236
oc.version=1.5.0
oc.version=1.5.1
oc.subversion=
ae2.version=rv1-stable-1

View File

@ -195,7 +195,7 @@ oc:tooltip.Cable=Ein billiger Weg, verschiedene Blöcke miteinander zu verbinden
oc:tooltip.Capacitor=Speichert Energie für spätere Verwendung. Kann extrem schnell befüllt und entleert werden.
oc:tooltip.CardBase=Wie der Name schon sagt, werden alle Erweiterungskarten hieraus hergestellt.
oc:tooltip.Case=Das Computergehäuse ist der essentielle Grundbaustein für einen Computer. §fErweiterungskarten§7, §fRAM§7 und §fFestplatten§7 können in einem Gehäuse installiert werden.[nl] Slots: §f%s§7
oc:tooltip.Charger=Lädt Roboter mit Energie aus Kondensatoren auf. Die Ladegeschwindigkeit hängt vom eingehenden §fRedstonesignal§7 ab, wobei kein Signal "nicht laden" und ein Signal mit maximaler Stärke "schnellstmöglich laden" heißt.
oc:tooltip.Charger=Lädt Roboter mit Energie aus Kondensatoren auf. Die Ladegeschwindigkeit hängt vom eingehenden §fRedstonesignal§7 ab, wobei kein Signal "nicht laden" und ein Signal mit maximaler Stärke "schnellstmöglich laden" heißt. Erlaubt es auch Tablets zu laden, und ermöglicht Zugriff auf Festplatten in Tablets.
oc:tooltip.CircuitBoard=Mühsam ernährt sich das Eichhörnchen. Wenn es groß wird, wird es mal eine gedruckte Leiterplatte.
oc:tooltip.ControlUnit=Klingt wichtig, ist es auch. Man baut daraus immerhin CPUs. Wie könnte es da nicht wichtig sein.
oc:tooltip.ComponentBus=Diese Erweiterung erlaubt es es Servern, mit noch mehr Komponenten gleichzeitig zu kommunizieren, ähnlich wie CPUs.[nl] Supported components: §f%s§7

View File

@ -219,7 +219,7 @@ oc:tooltip.Cable=A cheap way of connecting blocks.
oc:tooltip.Capacitor=Stores energy for later use. Can be filled and emptied very quickly.
oc:tooltip.CardBase=As the name indicates, this is the basic building block for all expansion cards.
oc:tooltip.Case=The Computer Case is the basic building block for computers and houses the computer's §fextension cards§7, §fRAM§7 and §fhard disks§7.[nl] Slots: §f%s§7
oc:tooltip.Charger=Transfers energy from capacitors into adjacent robots and drones. The transfer rate depends on the incoming §fredstone signal§7, where no signal means don't charge devices, and maximum strength means charge at full speed.
oc:tooltip.Charger=Transfers energy from capacitors into adjacent robots and drones. The transfer rate depends on the incoming §fredstone signal§7, where no signal means don't charge devices, and maximum strength means charge at full speed. Can also be used to charge tablets and access hard drives in tablets.
oc:tooltip.CircuitBoard=Now we're getting somewhere. Can be etched to obtain a printed circuit board.
oc:tooltip.ControlUnit=This is the unit that... controls... stuff. You need it to build a CPU. So yeah, totally important.
oc:tooltip.ComponentBus=This expansion allows servers to communicate with more components at the same time, similar to how CPUs do.[nl] Supported components: §f%s§7

View File

@ -1,8 +1,8 @@
local rc = require('rc')
local args = table.pack(...)
if args.n < 2 then
io.write("Usage: rc <service> <command> [args...]")
if args.n < 1 then
io.write("Usage: rc <service> [command] [args...]")
return
end
@ -11,3 +11,4 @@ local result, reason = rc.runCommand(table.unpack(args))
if not result then
io.stderr:write(reason .. "\n")
end

View File

@ -1,4 +1,5 @@
local fs = require('filesystem')
local serialization = require('serialization')
-- Keeps track of loaded scripts to retain local values between invocation
-- of their command callbacks.
@ -18,6 +19,19 @@ local function loadConfig()
return nil, reason
end
local function saveConfig(conf)
local file, reason = io.open('/etc/rc.cfg', 'w')
if not file then
return nil, reason
end
for key, value in pairs(conf) do
file:write(tostring(key) .. " = " .. serialization.serialize(value) .. "\n")
end
file:close()
return true
end
function rc.load(name, args)
if loaded[name] then
return loaded[name]
@ -39,14 +53,47 @@ function rc.unload(name)
loaded[name] = nil
end
local function rawRunCommand(name, cmd, args, ...)
local function rawRunCommand(conf, name, cmd, args, ...)
local result, what = rc.load(name, args)
if result then
if type(result[cmd]) == "function" then
result, what = xpcall(result[cmd], debug.traceback, ...)
if result then
if not cmd then
io.output():write("Commands for service " .. name .. "\n")
for command, val in pairs(result) do
if type(val) == "function" then
io.output():write(tostring(command) .. " ")
end
end
return true
elseif type(result[cmd]) == "function" then
res, what = xpcall(result[cmd], debug.traceback, ...)
if res then
return true
end
elseif cmd == "restart" and type(result["stop"]) == "function" and type(result["start"]) == "function" then
res, what = xpcall(result["stop"], debug.traceback, ...)
if res then
res, what = xpcall(result["start"], debug.traceback, ...)
if res then
return true
end
end
elseif cmd == "enable" then
conf.enabled = conf.enabled or {}
for _, _name in ipairs(conf.enabled) do
if name == _name then
return nil, "Service already enabled"
end
end
conf.enabled[#conf.enabled + 1] = name
return saveConfig(conf)
elseif cmd == "disable" then
conf.enabled = conf.enabled or {}
for n, _name in ipairs(conf.enabled) do
if name == _name then
table.remove(conf.enabled, n)
end
end
return saveConfig(conf)
else
what = "Command '" .. cmd .. "' not found in daemon '" .. name .. "'"
end
@ -59,7 +106,7 @@ function rc.runCommand(name, cmd, ...)
if not conf then
return nil, reason
end
return rawRunCommand(name, cmd, conf[name], ...)
return rawRunCommand(conf, name, cmd, conf[name], ...)
end
function rc.allRunCommand(cmd, ...)
@ -69,9 +116,10 @@ function rc.allRunCommand(cmd, ...)
end
local results = {}
for _, name in ipairs(conf.enabled or {}) do
results[name] = table.pack(rawRunCommand(name, cmd, conf[name], ...))
results[name] = table.pack(rawRunCommand(conf, name, cmd, conf[name], ...))
end
return results
end
return rc

View File

@ -5,7 +5,7 @@ SYNOPSIS
df [FILE]...
DESCRIPTION
`cp` allows copying single files on a filesystem and across filesystems.
`df` outputs disk space information for the file systems containing the specified files. If no file names are given it returns the information for all currently mounted file systems.
EXAMPLES
df

View File

@ -6,7 +6,7 @@ SYNOPSIS
primary TYPE ADDRESS
DESCRIPTION
This program allows reading the address of the current primary component of the specified type. It also allows chaning the current primary component for a specified type by providing the (abbreviated) address of the new primary component.
This program allows reading the address of the current primary component of the specified type. It also allows changing the current primary component for a specified type by providing the (abbreviated) address of the new primary component.
EXAMPLES
primary gpu

View File

@ -0,0 +1,36 @@
NAME
rc - Manage services
SYNOPSIS
rc SERVICE COMMAND [ARGS...]
DESCRIPTION
Controls services in /etc/rc.d/
Common commands are start/stop/restart, there are also special commands enable/disable. A command is global function in executable file that is stored in /etc/rc.d/ directory. Service cen define own commands.
COMMANDS
start
This command starts specified service, executed automatically for all enbled services when system boots.
stop
This command stops specified service.
restart
This command restarts specified service. This command doesn't have to be implemented by services when start and stop commands are present.
enable
This command enables specified service. Executing this command won't start the service. It's implemented by the rc library, but can be overridden by service.
disable
This command disables specified service. Executing this command won't stop the service. It's implemented by the rc library, but can be overridden by service.
EXAMPLES
rc example
Lists commands of example service.
rc example start
Starts example setvice.
rc example enable
Makes example start on system boot.

View File

@ -15,6 +15,7 @@ import li.cil.oc.api.detail.ItemInfo
import li.cil.oc.client.renderer.PetRenderer
import li.cil.oc.client.{PacketSender => ClientPacketSender}
import li.cil.oc.common.item.data.MicrocontrollerData
import li.cil.oc.common.tileentity.Robot
import li.cil.oc.common.tileentity.traits.power
import li.cil.oc.integration.Mods
import li.cil.oc.integration.util
@ -40,6 +41,12 @@ object EventHandler {
var totalWorldTicks = 0L
private val runningRobots = mutable.Set.empty[Robot]
def onRobotStart(robot: Robot): Unit = runningRobots += robot
def onRobotStopped(robot: Robot): Unit = runningRobots -= robot
def schedule(tileEntity: TileEntity) {
if (SideTracker.isServer) pending.synchronized {
pending += (() => Network.joinOrCreateNetwork(tileEntity))
@ -108,6 +115,13 @@ object EventHandler {
case t: Throwable => OpenComputers.log.warn("Error in scheduled tick action.", t)
}
})
val invalid = mutable.ArrayBuffer.empty[Robot]
runningRobots.foreach(robot => {
if (robot.isInvalid) invalid += robot
else robot.machine.update()
})
runningRobots --= invalid
}
@SubscribeEvent
@ -207,15 +221,7 @@ object EventHandler {
// Presents!
val present = api.Items.get("present").createItemStack(1)
e.player.worldObj.playSoundAtEntity(e.player, "note.pling", 0.2f, 1f)
if (e.player.inventory.addItemStackToInventory(present)) {
e.player.inventory.markDirty()
if (e.player.openContainer != null) {
e.player.openContainer.detectAndSendChanges()
}
}
else {
e.player.dropPlayerItemWithRandomChoice(present, false)
}
InventoryUtils.addToPlayerInventory(present, e.player)
}
case _ => // Nope.
}
@ -236,9 +242,8 @@ object EventHandler {
for (slot <- 0 until e.craftMatrix.getSizeInventory) {
val stack = e.craftMatrix.getStackInSlot(slot)
if (api.Items.get(stack) == item) {
callback(stack).foreach(extra => if (!e.player.inventory.addItemStackToInventory(extra)) {
e.player.dropPlayerItemWithRandomChoice(extra, false)
})
callback(stack).foreach(extra =>
InventoryUtils.addToPlayerInventory(extra, e.player))
}
}
true

View File

@ -83,11 +83,16 @@ object SaveHandler {
def loadNBT(nbt: NBTTagCompound, name: String): NBTTagCompound = {
val data = load(nbt, name)
if (data.length > 0) {
if (data.length > 0) try {
val bais = new ByteArrayInputStream(data)
val dis = new DataInputStream(bais)
CompressedStreamTools.read(dis)
}
catch {
case t: Throwable =>
OpenComputers.log.warn("There was an error trying to restore a block's state from external data. This indicates that data was somehow corrupted.", t)
new NBTTagCompound()
}
else new NBTTagCompound()
}

View File

@ -3,6 +3,7 @@ package li.cil.oc.common.block
import java.util
import li.cil.oc.Settings
import li.cil.oc.api
import li.cil.oc.client.KeyBindings
import li.cil.oc.common.Tier
import li.cil.oc.common.item.data.MicrocontrollerData
@ -10,6 +11,7 @@ import li.cil.oc.common.tileentity
import li.cil.oc.integration.util.NEI
import li.cil.oc.integration.util.Wrench
import li.cil.oc.util.BlockPosition
import li.cil.oc.util.InventoryUtils
import li.cil.oc.util.Rarity
import net.minecraft.entity.EntityLivingBase
import net.minecraft.entity.player.EntityPlayer
@ -68,16 +70,32 @@ class Microcontroller(protected implicit val tileTag: ClassTag[tileentity.Microc
override def onBlockActivated(world: World, x: Int, y: Int, z: Int, player: EntityPlayer,
side: ForgeDirection, hitX: Float, hitY: Float, hitZ: Float) = {
if (!player.isSneaking && !Wrench.holdsApplicableWrench(player, BlockPosition(x, y, z))) {
if (!world.isRemote) {
world.getTileEntity(x, y, z) match {
case mcu: tileentity.Microcontroller =>
if (mcu.machine.isRunning) mcu.machine.stop()
else mcu.machine.start()
case _ =>
if (!Wrench.holdsApplicableWrench(player, BlockPosition(x, y, z))) {
if (!player.isSneaking) {
if (!world.isRemote) {
world.getTileEntity(x, y, z) match {
case mcu: tileentity.Microcontroller =>
if (mcu.machine.isRunning) mcu.machine.stop()
else mcu.machine.start()
case _ =>
}
}
true
}
true
else if (api.Items.get(player.getHeldItem) == api.Items.get("eeprom")) {
if (!world.isRemote) {
world.getTileEntity(x, y, z) match {
case mcu: tileentity.Microcontroller =>
val newEeprom = player.inventory.decrStackSize(player.inventory.currentItem, 1)
mcu.changeEEPROM(newEeprom) match {
case Some(oldEeprom) => InventoryUtils.addToPlayerInventory(oldEeprom, player)
case _ =>
}
}
}
true
}
else false
}
else false
}

View File

@ -3,6 +3,7 @@ package li.cil.oc.common.container
import li.cil.oc.client.gui.Icons
import li.cil.oc.common
import li.cil.oc.common.InventorySlots.InventorySlot
import li.cil.oc.util.InventoryUtils
import li.cil.oc.util.SideTracker
import net.minecraft.entity.player.EntityPlayer
import net.minecraft.inventory.IInventory
@ -36,8 +37,7 @@ class DynamicComponentSlot(val container: Player, inventory: IInventory, index:
if (SideTracker.isServer && getHasStack && !isItemValid(getStack)) {
val stack = getStack
putStack(null)
player.inventory.addItemStackToInventory(stack)
player.dropPlayerItemWithRandomChoice(stack, false)
InventoryUtils.addToPlayerInventory(stack, player)
}
}
}

View File

@ -31,7 +31,7 @@ object RobotCommonHandler {
val maxFlyingHeight = Settings.get.limitFlightHeight
def isMovingDown = e.direction == ForgeDirection.DOWN
def hasAdjacentBlock(pos: BlockPosition) = ForgeDirection.VALID_DIRECTIONS.exists(side => world.isSideSolid(pos.offset(side), side.getOpposite))
def isWithinFlyingHeight(pos: BlockPosition) = (1 to maxFlyingHeight).exists(n => !world.isAirBlock(pos.offset(e.direction.getOpposite, n)))
def isWithinFlyingHeight(pos: BlockPosition) = (1 to maxFlyingHeight).exists(n => !world.isAirBlock(pos.offset(ForgeDirection.DOWN, n)))
val startPos = BlockPosition(robot)
val targetPos = startPos.offset(e.direction)
// New movement rules as of 1.5:

View File

@ -280,7 +280,7 @@ object Items extends ItemAPI {
def init() {
multi = new item.Delegator() {
lazy val configuredItems = Array(
def configuredItems = Array(
createOpenOS(),
createLuaBios(),
createConfiguredDrone(),

View File

@ -11,6 +11,8 @@ import net.minecraftforge.common.util.Constants.NBT
trait Inventory extends IInventory {
def items: Array[Option[ItemStack]]
def updateItems(slot: Int, stack: ItemStack) = items(slot) = Option(stack)
// ----------------------------------------------------------------------- //
override def getStackInSlot(slot: Int) =
@ -45,7 +47,7 @@ trait Inventory extends IInventory {
}
val oldStack = items(slot)
items(slot) = None
updateItems(slot, null)
if (oldStack.isDefined) {
onItemRemoved(slot, oldStack.get)
}
@ -53,7 +55,7 @@ trait Inventory extends IInventory {
if (stack.stackSize > getInventoryStackLimit) {
stack.stackSize = getInventoryStackLimit
}
items(slot) = Some(stack)
updateItems(slot, stack)
}
if (items(slot).isDefined) {
@ -84,7 +86,7 @@ trait Inventory extends IInventory {
nbt.getTagList(Settings.namespace + "items", NBT.TAG_COMPOUND).foreach((slotNbt: NBTTagCompound) => {
val slot = slotNbt.getByte("slot")
if (slot >= 0 && slot < items.length) {
items(slot) = Option(ItemUtils.loadStack(slotNbt.getCompoundTag("item")))
updateItems(slot, ItemUtils.loadStack(slotNbt.getCompoundTag("item")))
}
})
}

View File

@ -11,7 +11,9 @@ trait ItemStackInventory extends Inventory {
// The item stack that provides the inventory.
def container: ItemStack
lazy val items = Array.fill[Option[ItemStack]](getSizeInventory)(None)
private lazy val inventory = Array.fill[Option[ItemStack]](getSizeInventory)(None)
override def items = inventory
// Initialize the list automatically if we have a container.
if (container != null) {
@ -24,14 +26,14 @@ trait ItemStackInventory extends Inventory {
container.setTagCompound(new NBTTagCompound())
}
for (i <- 0 until items.length) {
items(i) = None
updateItems(i, null)
}
if (container.getTagCompound.hasKey(Settings.namespace + "items")) {
val list = container.getTagCompound.getTagList(Settings.namespace + "items", NBT.TAG_COMPOUND)
for (i <- 0 until (list.tagCount min items.length)) {
val tag = list.getCompoundTagAt(i)
if (!tag.hasNoTags) {
items(i) = Option(ItemUtils.loadStack(tag))
updateItems(i, ItemUtils.loadStack(tag))
}
}
}

View File

@ -1,9 +1,13 @@
package li.cil.oc.common.item
import li.cil.oc.Settings
import net.minecraft.entity.player.EntityPlayer
import net.minecraft.item.ItemStack
import net.minecraft.world.World
class EEPROM extends SimpleItem {
override def doesSneakBypassUse(world: World, x: Int, y: Int, z: Int, player: EntityPlayer): Boolean = true
override def getItemStackDisplayName(stack: ItemStack): String = {
if (stack.hasTagCompound) {
val tag = stack.getTagCompound

View File

@ -4,6 +4,7 @@ import java.util.Random
import li.cil.oc.OpenComputers
import li.cil.oc.api
import li.cil.oc.util.InventoryUtils
import li.cil.oc.util.ItemUtils
import net.minecraft.entity.player.EntityPlayer
import net.minecraft.item.ItemStack
@ -20,15 +21,7 @@ class Present(val parent: Delegator) extends Delegate {
if (!world.isRemote) {
world.playSoundAtEntity(player, "random.levelup", 0.2f, 1f)
val present = Present.nextPresent()
if (player.inventory.addItemStackToInventory(present)) {
player.inventory.markDirty()
if (player.openContainer != null) {
player.openContainer.detectAndSendChanges()
}
}
else {
player.dropPlayerItemWithRandomChoice(present, false)
}
InventoryUtils.addToPlayerInventory(present, player)
}
}
stack

View File

@ -17,20 +17,26 @@ class MicrocontrollerData extends ItemData {
var tier = Tier.One
var components = Array.empty[ItemStack]
var components = Array[ItemStack](null)
var storedEnergy = 0
override def load(nbt: NBTTagCompound) {
tier = nbt.getByte(Settings.namespace + "tier")
components = nbt.getTagList(Settings.namespace + "components", NBT.TAG_COMPOUND).
toArray[NBTTagCompound].map(ItemUtils.loadStack)
toArray[NBTTagCompound].map(ItemUtils.loadStack).filter(_ != null)
storedEnergy = nbt.getInteger(Settings.namespace + "storedEnergy")
// Reserve slot for EEPROM if necessary, avoids having to resize the
// components array in the MCU tile entity, which isn't possible currently.
if (!components.exists(stack => api.Items.get(stack) == api.Items.get("eeprom"))) {
components :+= null
}
}
override def save(nbt: NBTTagCompound) {
nbt.setByte(Settings.namespace + "tier", tier.toByte)
nbt.setNewTagList(Settings.namespace + "components", components.toIterable)
nbt.setNewTagList(Settings.namespace + "components", components.filter(_ != null).toIterable)
nbt.setInteger(Settings.namespace + "storedEnergy", storedEnergy)
}

View File

@ -83,7 +83,7 @@ class Assembler extends traits.Environment with traits.PowerAcceptor with traits
requiredEnergy = totalRequiredEnergy
ServerPacketSender.sendRobotAssembling(this, assembling = true)
for (slot <- 0 until getSizeInventory) items(slot) = None
for (slot <- 0 until getSizeInventory) updateItems(slot, null)
markDirty()
true

View File

@ -221,7 +221,9 @@ class Microcontroller extends traits.PowerAcceptor with traits.Hub with traits.C
nbt.setNewCompoundTag("info", info.save)
}
override lazy val items = info.components.map(Option(_))
override def items = info.components.map(Option(_))
override def updateItems(slot: Int, stack: ItemStack): Unit = info.components(slot) = stack
override def getSizeInventory = info.components.length
@ -232,4 +234,19 @@ class Microcontroller extends traits.PowerAcceptor with traits.Hub with traits.C
// Nope.
override def decrStackSize(slot: Int, amount: Int) = null
// For hotswapping EEPROMs.
def changeEEPROM(newEeprom: ItemStack) = {
val oldEepromIndex = info.components.indexWhere(api.Items.get(_) == api.Items.get("eeprom"))
if (oldEepromIndex >= 0) {
val oldEeprom = info.components(oldEepromIndex)
super.setInventorySlotContents(oldEepromIndex, newEeprom)
Some(oldEeprom)
}
else {
assert(info.components(getSizeInventory - 1) == null)
super.setInventorySlotContents(getSizeInventory - 1, newEeprom)
None
}
}
}

View File

@ -13,6 +13,7 @@ import li.cil.oc.api.event.RobotMoveEvent
import li.cil.oc.api.internal
import li.cil.oc.api.network._
import li.cil.oc.client.gui
import li.cil.oc.common.EventHandler
import li.cil.oc.common.Slot
import li.cil.oc.common.Tier
import li.cil.oc.common.inventory.InventorySelection
@ -402,6 +403,16 @@ class Robot extends traits.Computer with traits.PowerInformation with IFluidHand
}
}
// The robot's machine is updated in a tick handler, to avoid delayed tile
// entity creation when moving, which would screw over all the things...
override protected def updateComputer(): Unit = {}
override protected def onRunningChanged(): Unit = {
super.onRunningChanged()
if (isRunning) EventHandler.onRobotStart(this)
else EventHandler.onRobotStopped(this)
}
override protected def initialize() {
if (isServer) {
// Ensure we have a node address, because the proxy needs this to initialize
@ -419,6 +430,7 @@ class Robot extends traits.Computer with traits.PowerInformation with IFluidHand
case _ =>
}
}
else EventHandler.onRobotStopped(this)
}
// ----------------------------------------------------------------------- //
@ -452,6 +464,7 @@ class Robot extends traits.Computer with traits.PowerInformation with IFluidHand
// robot's proxy instance.
_isOutputEnabled = hasRedstoneCard
_isAbstractBusAvailable = hasAbstractBusCard
if (isRunning) EventHandler.onRobotStart(this)
}
// Side check for Waila (and other mods that may call this client side).

View File

@ -98,19 +98,18 @@ trait Computer extends Environment with ComponentInventory with Rotatable with B
// ----------------------------------------------------------------------- //
override def updateEntity() {
override def updateEntity(): Unit = {
// If we're not yet in a network we might have just been loaded from disk,
// meaning there may be other tile entities that also have not re-joined
// the network. We skip the update this round to allow other tile entities
// to join the network, too, avoiding issues of missing nodes (e.g. in the
// GPU which would otherwise loose track of its screen).
if (isServer && isConnected) {
// If we're not yet in a network we might have just been loaded from disk,
// meaning there may be other tile entities that also have not re-joined
// the network. We skip the update this round to allow other tile entities
// to join the network, too, avoiding issues of missing nodes (e.g. in the
// GPU which would otherwise loose track of its screen).
machine.update()
updateComputer()
if (_isRunning != machine.isRunning) {
_isRunning = machine.isRunning
markDirty()
ServerPacketSender.sendComputerState(this)
onRunningChanged()
}
updateComponents()
@ -119,6 +118,15 @@ trait Computer extends Environment with ComponentInventory with Rotatable with B
super.updateEntity()
}
protected def updateComputer(): Unit = {
machine.update()
}
protected def onRunningChanged(): Unit = {
markDirty()
ServerPacketSender.sendComputerState(this)
}
// ----------------------------------------------------------------------- //
override def readFromNBTForServer(nbt: NBTTagCompound) {

View File

@ -9,7 +9,9 @@ import net.minecraft.nbt.NBTTagCompound
import net.minecraftforge.common.util.ForgeDirection
trait Inventory extends TileEntity with inventory.Inventory {
lazy val items = Array.fill[Option[ItemStack]](getSizeInventory)(None)
private lazy val inventory = Array.fill[Option[ItemStack]](getSizeInventory)(None)
def items = inventory
// ----------------------------------------------------------------------- //

View File

@ -2,12 +2,15 @@ package li.cil.oc.common.tileentity.traits
import cpw.mods.fml.relauncher.Side
import cpw.mods.fml.relauncher.SideOnly
import li.cil.oc.Settings
import li.cil.oc.server.{PacketSender => ServerPacketSender}
import net.minecraft.nbt.NBTTagCompound
trait PowerInformation extends TileEntity {
private var lastSentRatio = -1.0
private var ticksUntilSync = 0
def globalBuffer: Double
def globalBuffer_=(value: Double): Unit
@ -18,12 +21,23 @@ trait PowerInformation extends TileEntity {
protected def updatePowerInformation() {
val ratio = if (globalBufferSize > 0) globalBuffer / globalBufferSize else 0
if (lastSentRatio < 0 || math.abs(lastSentRatio - ratio) > (5.0 / 100.0)) {
if (shouldSync(ratio) || hasChangedSignificantly(ratio)) {
lastSentRatio = ratio
ServerPacketSender.sendPowerState(this)
}
}
private def hasChangedSignificantly(ratio: Double) = lastSentRatio < 0 || math.abs(lastSentRatio - ratio) > (5.0 / 100.0)
private def shouldSync(ratio: Double) = {
ticksUntilSync -= 1
if (ticksUntilSync <= 0) {
ticksUntilSync = (100 / Settings.get.tickFrequency).toInt max 1
lastSentRatio != ratio
}
else false
}
@SideOnly(Side.CLIENT)
override def readFromNBTForClient(nbt: NBTTagCompound) {
super.readFromNBTForClient(nbt)

View File

@ -220,7 +220,7 @@ object PacketSender {
val pb = new SimplePacketBuilder(PacketType.PowerState)
pb.writeTileEntity(t)
pb.writeDouble(t.globalBuffer)
pb.writeDouble(math.round(t.globalBuffer))
pb.writeDouble(t.globalBufferSize)
pb.sendToPlayersNearTileEntity(t)

View File

@ -153,7 +153,7 @@ class Player(val agent: internal.Agent) extends FakePlayer(agent.world.asInstanc
// ----------------------------------------------------------------------- //
override def attackTargetEntityWithCurrentItem(entity: Entity) {
callUsingItemInSlot(0, stack => entity match {
callUsingItemInSlot(agent.equipmentInventory, 0, stack => entity match {
case player: EntityPlayer if !canAttackPlayer(player) => // Avoid player damage.
case _ =>
val event = new RobotAttackEntityEvent.Pre(agent, entity)
@ -173,7 +173,7 @@ class Player(val agent: internal.Agent) extends FakePlayer(agent.world.asInstanc
}
false
}
!cancel && callUsingItemInSlot(0, stack => {
!cancel && callUsingItemInSlot(agent.equipmentInventory, 0, stack => {
val result = isItemUseAllowed(stack) && (entity.interactFirst(this) || (entity match {
case living: EntityLivingBase if getCurrentEquippedItem != null => getCurrentEquippedItem.interactWithEntity(this, living)
case _ => false
@ -186,7 +186,7 @@ class Player(val agent: internal.Agent) extends FakePlayer(agent.world.asInstanc
}
def activateBlockOrUseItem(x: Int, y: Int, z: Int, side: Int, hitX: Float, hitY: Float, hitZ: Float, duration: Double): ActivationType.Value = {
callUsingItemInSlot(0, stack => {
callUsingItemInSlot(agent.equipmentInventory, 0, stack => {
if (shouldCancel(() => ForgeEventFactory.onPlayerInteract(this, Action.RIGHT_CLICK_BLOCK, x, y, z, side, world))) {
return ActivationType.None
}
@ -216,7 +216,7 @@ class Player(val agent: internal.Agent) extends FakePlayer(agent.world.asInstanc
}
def useEquippedItem(duration: Double) = {
callUsingItemInSlot(0, stack => {
callUsingItemInSlot(agent.equipmentInventory, 0, stack => {
if (!shouldCancel(() => ForgeEventFactory.onPlayerInteract(this, Action.RIGHT_CLICK_AIR, 0, 0, 0, 0, world))) {
tryUseItem(stack, duration)
}
@ -260,7 +260,7 @@ class Player(val agent: internal.Agent) extends FakePlayer(agent.world.asInstanc
}
def placeBlock(slot: Int, x: Int, y: Int, z: Int, side: Int, hitX: Float, hitY: Float, hitZ: Float): Boolean = {
callUsingItemInSlot(slot, stack => {
callUsingItemInSlot(agent.mainInventory, slot, stack => {
if (shouldCancel(() => ForgeEventFactory.onPlayerInteract(this, Action.RIGHT_CLICK_BLOCK, x, y, z, side, world))) {
return false
}
@ -270,7 +270,7 @@ class Player(val agent: internal.Agent) extends FakePlayer(agent.world.asInstanc
}
def clickBlock(x: Int, y: Int, z: Int, side: Int): Double = {
callUsingItemInSlot(0, stack => {
callUsingItemInSlot(agent.equipmentInventory, 0, stack => {
if (shouldCancel(() => ForgeEventFactory.onPlayerInteract(this, Action.LEFT_CLICK_BLOCK, x, y, z, side, world))) {
return 0
}
@ -392,7 +392,7 @@ class Player(val agent: internal.Agent) extends FakePlayer(agent.world.asInstanc
}
}
private def callUsingItemInSlot[T](slot: Int, f: (ItemStack) => T, repair: Boolean = true) = {
private def callUsingItemInSlot[T](inventory: IInventory, slot: Int, f: (ItemStack) => T, repair: Boolean = true) = {
val itemsBefore = adjacentItems
val stack = inventory.getStackInSlot(slot)
val oldStack = if (stack != null) stack.copy() else null

View File

@ -11,6 +11,7 @@ import li.cil.oc.server.agent.Player
import li.cil.oc.util.BlockPosition
import li.cil.oc.util.ExtendedArguments._
import li.cil.oc.util.ExtendedWorld._
import li.cil.oc.util.InventoryUtils
import net.minecraft.entity.Entity
import net.minecraft.entity.EntityLivingBase
import net.minecraft.entity.item.EntityMinecart
@ -280,10 +281,7 @@ trait Agent extends traits.WorldControl with traits.InventoryControl with traits
entity.captureDrops = false
for (drop <- entity.capturedDrops) {
val stack = drop.getEntityItem
player.inventory.addItemStackToInventory(stack)
if (stack.stackSize > 0) {
player.dropPlayerItemWithRandomChoice(stack, inPlace = false)
}
InventoryUtils.addToPlayerInventory(stack, player)
}
entity.capturedDrops.clear()
}

View File

@ -9,6 +9,7 @@ import li.cil.oc.api.machine.Callback
import li.cil.oc.api.machine.Context
import li.cil.oc.api.network._
import li.cil.oc.api.prefab
import li.cil.oc.util.InventoryUtils
import net.minecraft.entity.player.EntityPlayer
import net.minecraft.inventory
import net.minecraft.item.ItemStack
@ -67,10 +68,9 @@ class UpgradeCrafting(val host: EnvironmentHost with internal.Robot) extends pre
}
}
save()
val inventory = host.player.inventory
inventory.addItemStackToInventory(result)
InventoryUtils.addToPlayerInventory(result, host.player)
for (stack <- surplus) {
inventory.addItemStackToInventory(stack)
InventoryUtils.addToPlayerInventory(stack, host.player)
}
load()
}
@ -79,7 +79,7 @@ class UpgradeCrafting(val host: EnvironmentHost with internal.Robot) extends pre
}
def load() {
val inventory = host.player.inventory
val inventory = host.mainInventory()
amountPossible = Int.MaxValue
for (slot <- 0 until getSizeInventory) {
val stack = inventory.getStackInSlot(toParentSlot(slot))
@ -91,7 +91,7 @@ class UpgradeCrafting(val host: EnvironmentHost with internal.Robot) extends pre
}
def save() {
val inventory = host.player.inventory
val inventory = host.mainInventory()
for (slot <- 0 until getSizeInventory) {
inventory.setInventorySlotContents(toParentSlot(slot), getStackInSlot(slot))
}
@ -100,7 +100,7 @@ class UpgradeCrafting(val host: EnvironmentHost with internal.Robot) extends pre
private def toParentSlot(slot: Int) = {
val col = slot % 3
val row = slot / 3
row * 4 + col + 4 // first four are always: tool, card, disk, upgrade
row * 4 + col
}
}

View File

@ -3,6 +3,7 @@ package li.cil.oc.util
import li.cil.oc.util.ExtendedWorld._
import net.minecraft.entity.item.EntityItem
import net.minecraft.entity.item.EntityMinecartContainer
import net.minecraft.entity.player.EntityPlayer
import net.minecraft.inventory.IInventory
import net.minecraft.inventory.ISidedInventory
import net.minecraft.item.ItemStack
@ -233,7 +234,7 @@ object InventoryUtils {
/**
* Utility method for dumping all inventory contents into the world.
*/
def dropAllSlots(position: BlockPosition, inventory: IInventory) {
def dropAllSlots(position: BlockPosition, inventory: IInventory): Unit = {
for (slot <- 0 until inventory.getSizeInventory) {
Option(inventory.getStackInSlot(slot)) match {
case Some(stack) if stack.stackSize > 0 =>
@ -244,6 +245,23 @@ object InventoryUtils {
}
}
/**
* Try inserting an item stack into a player inventory. If that fails, drop it into the world.
*/
def addToPlayerInventory(stack: ItemStack, player: EntityPlayer): Unit = {
if (stack != null) {
if (player.inventory.addItemStackToInventory(stack)) {
player.inventory.markDirty()
if (player.openContainer != null) {
player.openContainer.detectAndSendChanges()
}
}
if (stack.stackSize > 0) {
player.dropPlayerItemWithRandomChoice(stack, false)
}
}
}
/**
* Utility method for spawning an item stack in the world.
*/