mirror of
https://github.com/MightyPirates/OpenComputers.git
synced 2025-09-16 02:39:48 -04:00
Merge branch 'master-MC1.11' into master-MC1.12
This commit is contained in:
commit
ac400a5485
@ -1,6 +1,7 @@
|
||||
local process = require("process")
|
||||
local unicode = require("unicode")
|
||||
local event = require("event")
|
||||
local thread = require("thread")
|
||||
local event_mt = getmetatable(event.handlers)
|
||||
|
||||
-- WARNING this code does not use official kernel API and is likely to change
|
||||
@ -42,33 +43,38 @@ local cols =
|
||||
return count == 0 and "-" or tostring(count)
|
||||
end},
|
||||
{"THREADS", function(_,p)
|
||||
-- threads are handles with mt.close
|
||||
-- threads are handles with mt.close == thread.waitForAll
|
||||
local count = 0
|
||||
for _,h in pairs(p.data.handles or {}) do
|
||||
for h in pairs(p.data.handles) do
|
||||
local mt = getmetatable(h)
|
||||
if mt and mt.__index and mt.__index.close then
|
||||
count = count + #h
|
||||
break -- there is only one thread handle manager
|
||||
if mt and mt.__status then
|
||||
count = count + 1
|
||||
end
|
||||
end
|
||||
return count == 0 and "-" or tostring(count)
|
||||
end},
|
||||
{"PARENT", function(_,p)
|
||||
for _,process_info in pairs(process.list) do
|
||||
for _,handle in pairs(process_info.data.handles or {}) do
|
||||
for handle in pairs(process_info.data.handles) do
|
||||
local mt = getmetatable(handle)
|
||||
if mt and mt.__index and mt.__index.close then
|
||||
for _,ht in ipairs(handle) do
|
||||
local ht_mt = getmetatable(ht)
|
||||
if ht_mt.process == p then
|
||||
return thread_id(nil,process_info)
|
||||
end
|
||||
if mt and mt.__status then
|
||||
if mt.process == p then
|
||||
return thread_id(nil, process_info)
|
||||
end
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
return thread_id(nil,p.parent)
|
||||
return thread_id(nil, p.parent)
|
||||
end},
|
||||
{"HANDLES", function(_, p)
|
||||
local count = 0
|
||||
for stream,closure in pairs(p.data.handles) do
|
||||
cprint(string.format("%s %s", stream, closure))
|
||||
if closure then
|
||||
count = count + 1
|
||||
end
|
||||
end
|
||||
return count == 0 and "-" or tostring(count)
|
||||
end},
|
||||
{"CMD", function(_,p) return p.command end},
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
local process = require("process")
|
||||
local fs = require("filesystem")
|
||||
|
||||
--Initialize coroutine library--
|
||||
local _coroutine = coroutine -- real coroutine backend
|
||||
@ -62,8 +63,20 @@ process.list[init_thread] = {
|
||||
data =
|
||||
{
|
||||
vars={},
|
||||
handles={},
|
||||
io={}, --init will populate this
|
||||
coroutine_handler = _coroutine
|
||||
},
|
||||
instances = setmetatable({}, {__mode="v"})
|
||||
}
|
||||
|
||||
-- intercept fs open
|
||||
local fs_open = fs.open
|
||||
fs.open = function(...)
|
||||
local fs_open_result = table.pack(fs_open(...))
|
||||
if fs_open_result[1] then
|
||||
process.closeOnExit(fs_open_result[1])
|
||||
end
|
||||
return table.unpack(fs_open_result, 1, fs_open_result.n)
|
||||
end
|
||||
|
||||
|
@ -17,21 +17,32 @@ function buffer.new(mode, stream)
|
||||
bufferWrite = "",
|
||||
bufferSize = math.max(512, math.min(8 * 1024, computer.freeMemory() / 8)),
|
||||
bufferMode = "full",
|
||||
readTimeout = math.huge
|
||||
readTimeout = math.huge,
|
||||
}
|
||||
mode = mode or "r"
|
||||
for i = 1, unicode.len(mode) do
|
||||
result.mode[unicode.sub(mode, i, i)] = true
|
||||
end
|
||||
-- when stream closes, result should close first
|
||||
-- when result closes, stream should close after
|
||||
-- when stream closes, it is removed from the proc
|
||||
stream.close = setmetatable({close = stream.close,parent = result},{__call = buffer.close})
|
||||
return setmetatable(result, metatable)
|
||||
end
|
||||
|
||||
function buffer:close()
|
||||
if self.mode.w or self.mode.a then
|
||||
self:flush()
|
||||
-- self is either the buffer, or the stream.close callable
|
||||
local meta = getmetatable(self)
|
||||
if meta == metatable.__metatable then
|
||||
return self.stream:close()
|
||||
end
|
||||
self.closed = true
|
||||
return self.stream:close()
|
||||
local parent = self.parent
|
||||
|
||||
if parent.mode.w or parent.mode.a then
|
||||
parent:flush()
|
||||
end
|
||||
parent.closed = true
|
||||
return self.close(parent.stream)
|
||||
end
|
||||
|
||||
function buffer:flush()
|
||||
|
@ -78,7 +78,7 @@ end
|
||||
-- redirects as built by buildCommentRedirects
|
||||
function sh.internal.openCommandRedirects(redirects)
|
||||
local data = process.info().data
|
||||
local ios, handles = data.io, data.handles
|
||||
local ios = data.io
|
||||
|
||||
for _,rjob in ipairs(redirects) do
|
||||
local from_io, to_io, mode = table.unpack(rjob)
|
||||
@ -93,7 +93,6 @@ function sh.internal.openCommandRedirects(redirects)
|
||||
io.stderr:write("could not open '" .. to_io .. "': " .. reason .. "\n")
|
||||
os.exit(1)
|
||||
end
|
||||
table.insert(handles, file)
|
||||
ios[from_io] = file
|
||||
end
|
||||
end
|
||||
|
@ -134,16 +134,16 @@ function pipe.buildPipeChain(progs)
|
||||
-- B needs to be a stack in case any thread in B calls read
|
||||
pipe.createCoroutineStack(thread)
|
||||
chain[i] = thread
|
||||
local data = process.info(thread).data
|
||||
local pio = data.io
|
||||
local proc = process.info(thread)
|
||||
local pio = proc.data.io
|
||||
|
||||
local piped_stream
|
||||
if i < #progs then
|
||||
local handle = setmetatable({redirect = {rawget(pio, 1)},buffer = ""}, {__index = pipe_stream})
|
||||
process.closeOnExit(handle, proc)
|
||||
piped_stream = buffer.new("rw", handle)
|
||||
piped_stream:setvbuf("no", 1024)
|
||||
pio[1] = piped_stream
|
||||
table.insert(data.handles, piped_stream)
|
||||
end
|
||||
|
||||
if prev_piped_stream then
|
||||
@ -194,7 +194,7 @@ function pipe.popen(prog, mode, env)
|
||||
|
||||
local chain = {}
|
||||
-- to simplify the code - shell.execute is run within a function to pass (prog, env)
|
||||
-- if cmd_proc where to come second (mode=="w") then the pipe_proc would have to pass
|
||||
-- if cmd_proc were to come second (mode=="w") then the pipe_proc would have to pass
|
||||
-- the starting args. which is possible, just more complicated
|
||||
local cmd_proc = process.load(function() return shell.execute(prog, env) end, nil, nil, prog)
|
||||
|
||||
|
@ -125,7 +125,11 @@ function process.internal.close(thread, result)
|
||||
checkArg(1,thread,"thread")
|
||||
local pdata = process.info(thread).data
|
||||
pdata.result = result
|
||||
for _,v in pairs(pdata.handles) do
|
||||
local handles = {}
|
||||
for s,_ in pairs(pdata.handles) do
|
||||
table.insert(handles, s)
|
||||
end
|
||||
for _,v in ipairs(handles) do
|
||||
pcall(v.close, v)
|
||||
end
|
||||
process.list[thread] = nil
|
||||
@ -146,6 +150,20 @@ function process.internal.continue(co, ...)
|
||||
return table.unpack(result, 2, result.n)
|
||||
end
|
||||
|
||||
function process.closeOnExit(stream, proc)
|
||||
local handles = (proc or process.info()).data.handles
|
||||
if not handles[stream] then
|
||||
handles[stream] = stream.close
|
||||
stream.close = function(...)
|
||||
local close = handles[stream]
|
||||
handles[stream] = nil
|
||||
if close then
|
||||
return close(...)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function process.running(level) -- kept for backwards compat, prefer process.info
|
||||
local info = process.info(level)
|
||||
if info then
|
||||
|
@ -60,22 +60,6 @@ function thread.waitForAll(threads, timeout)
|
||||
end
|
||||
|
||||
local box_thread = {}
|
||||
local box_thread_list = {close = thread.waitForAll}
|
||||
|
||||
local function get_process_threads(proc, bCreate)
|
||||
local handles = proc.data.handles
|
||||
for _,next_handle in ipairs(handles) do
|
||||
local handle_mt = getmetatable(next_handle)
|
||||
if handle_mt and handle_mt.__index == box_thread_list then
|
||||
return next_handle
|
||||
end
|
||||
end
|
||||
if bCreate then
|
||||
local btm = setmetatable({}, {__index = box_thread_list})
|
||||
table.insert(handles, btm)
|
||||
return btm
|
||||
end
|
||||
end
|
||||
|
||||
function box_thread:resume()
|
||||
local mt = getmetatable(self)
|
||||
@ -120,31 +104,25 @@ function box_thread:detach()
|
||||
end
|
||||
|
||||
function box_thread:attach(parent)
|
||||
checkArg(1, parent, "thread", "number", "nil")
|
||||
local mt = assert(getmetatable(self), "thread panic: no metadata")
|
||||
local proc = process.info(parent)
|
||||
local mt = assert(getmetatable(self), "thread panic: no metadata")
|
||||
if not proc then return nil, "thread failed to attach, process not found" end
|
||||
if mt.attached == proc then return self end -- already attached
|
||||
|
||||
-- remove from old parent
|
||||
local waiting_handler
|
||||
if mt.attached then
|
||||
local prev_threads = assert(get_process_threads(mt.attached), "thread panic: no thread handle")
|
||||
for index,t_in_list in ipairs(prev_threads) do
|
||||
if t_in_list == self then
|
||||
table.remove(prev_threads, index)
|
||||
break
|
||||
end
|
||||
end
|
||||
-- registration happens on the attached proc, unregister before reparenting
|
||||
waiting_handler = mt.unregister()
|
||||
mt.attached.data.handles[self] = nil
|
||||
end
|
||||
|
||||
-- registration happens on the attached proc, unregister before reparenting
|
||||
local waiting_handler = mt.unregister()
|
||||
-- fix close
|
||||
self.close = self.join
|
||||
|
||||
-- attach to parent or the current process
|
||||
mt.attached = proc
|
||||
|
||||
-- this process may not have a box_thread list
|
||||
local threads = get_process_threads(proc, true)
|
||||
table.insert(threads, self)
|
||||
process.closeOnExit(self, proc)
|
||||
|
||||
-- register on the new parent
|
||||
if waiting_handler then -- event-waiting
|
||||
@ -159,9 +137,9 @@ function thread.current()
|
||||
local thread_root
|
||||
while proc do
|
||||
if thread_root then
|
||||
for _,bt in ipairs(get_process_threads(proc) or {}) do
|
||||
if bt.pco.root == thread_root then
|
||||
return bt
|
||||
for handle in pairs(proc.data.handles) do
|
||||
if handle.pco and handle.pco.root == thread_root then
|
||||
return handle
|
||||
end
|
||||
end
|
||||
else
|
||||
@ -174,9 +152,8 @@ end
|
||||
function thread.create(fp, ...)
|
||||
checkArg(1, fp, "function")
|
||||
|
||||
local t = {}
|
||||
local mt = {__status="suspended",__index=box_thread}
|
||||
setmetatable(t, mt)
|
||||
local t = setmetatable({}, mt)
|
||||
t.pco = pipe.createCoroutineStack(function(...)
|
||||
mt.__status = "running"
|
||||
local fp_co = t.pco.create(fp)
|
||||
@ -246,7 +223,7 @@ function thread.create(fp, ...)
|
||||
mt.id = nil
|
||||
mt.reg = nil
|
||||
-- before just removing a handler, make sure it is still ours
|
||||
if id and mt.attached and mt.attached.data.handlers[id] == reg then
|
||||
if id and mt.attached.data.handlers[id] == reg then
|
||||
mt.attached.data.handlers[id] = nil
|
||||
return reg
|
||||
end
|
||||
@ -285,18 +262,12 @@ function thread.create(fp, ...)
|
||||
end
|
||||
|
||||
function mt.close()
|
||||
if t:status() == "dead" then
|
||||
return
|
||||
end
|
||||
local threads = get_process_threads(mt.attached)
|
||||
for index,t_in_list in ipairs(threads) do
|
||||
if t_in_list == t then
|
||||
table.remove(threads, index)
|
||||
break
|
||||
end
|
||||
end
|
||||
local old_status = t:status()
|
||||
mt.__status = "dead"
|
||||
event.push("thread_exit")
|
||||
mt.attached.data.handles[t] = nil
|
||||
if old_status ~= "dead" then
|
||||
event.push("thread_exit")
|
||||
end
|
||||
end
|
||||
|
||||
t:attach() -- the current process
|
||||
@ -321,8 +292,6 @@ do
|
||||
end
|
||||
assert(init_thread, "thread library panic: no init thread")
|
||||
handlers_mt.threaded = true
|
||||
-- handles might be optimized out for memory
|
||||
root_data.handles = root_data.handles or {}
|
||||
-- if we don't separate root handlers from thread handlers we see double dispatch
|
||||
-- because the thread calls dispatch on pull as well
|
||||
root_data.handlers = {} -- root handlers
|
||||
|
@ -938,7 +938,14 @@ sandbox = {
|
||||
}
|
||||
end
|
||||
end,
|
||||
traceback = debug.traceback
|
||||
traceback = debug.traceback,
|
||||
-- using () to wrap the return of debug methods because in Lua doing this
|
||||
-- causes only the first return value to be selected
|
||||
-- e.g. (1, 2) is only (1), the 2 is not returned
|
||||
-- this is critically important here because the 2nd return value from these
|
||||
-- debug methods is the value itself, which opens a door to exploit the sandbox
|
||||
getlocal = function(...) return (debug.getlocal(...)) end,
|
||||
getupvalue = function(...) return (debug.getupvalue(...)) end,
|
||||
},
|
||||
|
||||
-- Lua 5.3.
|
||||
|
@ -51,54 +51,64 @@ abstract class Player(val playerInventory: InventoryPlayer, val otherInventory:
|
||||
ItemStack.EMPTY
|
||||
}
|
||||
|
||||
protected def tryTransferStackInSlot(from: Slot, intoPlayerInventory: Boolean) {
|
||||
// return true if all items have been moved or no more work to do
|
||||
protected def tryMoveAllSlotToSlot(from: Slot, to: Slot): Boolean = {
|
||||
if (to == null)
|
||||
return false // nowhere to move it
|
||||
|
||||
if (from == null ||
|
||||
!from.getHasStack ||
|
||||
from.getStack.isEmpty)
|
||||
return true // all moved because nothing to move
|
||||
|
||||
if (to.inventory == from.inventory)
|
||||
return false // not intended for moving in the same inventory
|
||||
|
||||
// for ghost slots we don't care about stack size
|
||||
val fromStack = from.getStack
|
||||
var somethingChanged = false
|
||||
val toStack = if (to.getHasStack) to.getStack else null
|
||||
val toStackSize = if (!toStack.isEmpty) toStack.getCount else 0
|
||||
|
||||
val step = if (intoPlayerInventory) -1 else 1
|
||||
val (begin, end) =
|
||||
if (intoPlayerInventory) (inventorySlots.size - 1, 0)
|
||||
else (0, inventorySlots.size - 1)
|
||||
val maxStackSize = math.min(fromStack.getMaxStackSize, to.getSlotStackLimit)
|
||||
val itemsMoved = math.min(maxStackSize - toStackSize, fromStack.getCount)
|
||||
|
||||
if (fromStack.getMaxStackSize > 1) for (i <- begin to end by step if i >= 0 && i < inventorySlots.size && from.getHasStack && from.getStack.getCount > 0) {
|
||||
val intoSlot = inventorySlots.get(i)
|
||||
if (intoSlot.inventory != from.inventory && intoSlot.getHasStack) {
|
||||
val intoStack = intoSlot.getStack
|
||||
val itemsAreEqual = fromStack.isItemEqual(intoStack) && ItemStack.areItemStackTagsEqual(fromStack, intoStack)
|
||||
val maxStackSize = math.min(fromStack.getMaxStackSize, intoSlot.getSlotStackLimit)
|
||||
val slotHasCapacity = intoStack.getCount < maxStackSize
|
||||
if (itemsAreEqual && slotHasCapacity) {
|
||||
val itemsMoved = math.min(maxStackSize - intoStack.getCount, fromStack.getCount)
|
||||
if (itemsMoved > 0) {
|
||||
intoStack.grow(from.decrStackSize(itemsMoved).getCount)
|
||||
intoSlot.onSlotChanged()
|
||||
somethingChanged = true
|
||||
}
|
||||
}
|
||||
if (toStack != null) {
|
||||
if (toStackSize < maxStackSize &&
|
||||
fromStack.isItemEqual(toStack) &&
|
||||
ItemStack.areItemStackTagsEqual(fromStack, toStack) &&
|
||||
itemsMoved > 0) {
|
||||
toStack.grow(from.decrStackSize(itemsMoved).getCount)
|
||||
} else return false
|
||||
} else if (to.isItemValid(fromStack)) {
|
||||
to.putStack(from.decrStackSize(itemsMoved))
|
||||
if (maxStackSize == 0) {
|
||||
// Special case: we have an inventory with "phantom/ghost stacks", i.e.
|
||||
// zero size stacks, usually used for configuring machinery. In that
|
||||
// case we stop early if whatever we're shift clicking is already in a
|
||||
// slot of the target inventory. This workaround can be problematic if
|
||||
// an inventory has both real and phantom slots, but we don't have
|
||||
// something like that, yet, so hey.
|
||||
return true
|
||||
}
|
||||
}
|
||||
} else return false
|
||||
|
||||
for (i <- begin to end by step if i >= 0 && i < inventorySlots.size && from.getHasStack && from.getStack.getCount > 0) {
|
||||
val intoSlot = inventorySlots.get(i)
|
||||
if (intoSlot.inventory != from.inventory && !intoSlot.getHasStack && intoSlot.isItemValid(fromStack)) {
|
||||
val maxStackSize = math.min(fromStack.getMaxStackSize, intoSlot.getSlotStackLimit)
|
||||
val itemsMoved = math.min(maxStackSize, fromStack.getCount)
|
||||
intoSlot.putStack(from.decrStackSize(itemsMoved))
|
||||
if (maxStackSize == 0) {
|
||||
// Special case: we have an inventory with "phantom/ghost stacks", i.e.
|
||||
// zero size stacks, usually used for configuring machinery. In that
|
||||
// case we stop early if whatever we're shift clicking is already in a
|
||||
// slot of the target inventory. This workaround can be problematic if
|
||||
// an inventory has both real and phantom slots, but we don't have
|
||||
// something like that, yet, so hey.
|
||||
return
|
||||
}
|
||||
somethingChanged = true
|
||||
}
|
||||
}
|
||||
to.onSlotChanged()
|
||||
from.onSlotChanged()
|
||||
false
|
||||
}
|
||||
|
||||
if (somethingChanged) {
|
||||
from.onSlotChanged()
|
||||
protected def fillOrder(backFill: Boolean): Seq[Int] = {
|
||||
(if (backFill) inventorySlots.indices.reverse else inventorySlots.indices).sortBy(i => inventorySlots(i) match {
|
||||
case s: Slot if s.getHasStack => -1
|
||||
case s: ComponentSlot => s.tier
|
||||
case _ => 99
|
||||
})
|
||||
}
|
||||
|
||||
protected def tryTransferStackInSlot(from: Slot, intoPlayerInventory: Boolean) {
|
||||
for (i <- fillOrder(intoPlayerInventory)) {
|
||||
if (inventorySlots.get(i) match { case slot: Slot => tryMoveAllSlotToSlot(from, slot) case _ => false })
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -249,6 +249,7 @@ object Items extends ItemAPI {
|
||||
data.components = Array(
|
||||
safeGetStack(Constants.BlockName.ScreenTier1),
|
||||
safeGetStack(Constants.BlockName.Keyboard),
|
||||
safeGetStack(Constants.BlockName.Geolyzer),
|
||||
safeGetStack(Constants.ItemName.InventoryUpgrade),
|
||||
safeGetStack(Constants.ItemName.InventoryUpgrade),
|
||||
safeGetStack(Constants.ItemName.InventoryUpgrade),
|
||||
@ -257,6 +258,7 @@ object Items extends ItemAPI {
|
||||
safeGetStack(Constants.ItemName.TankUpgrade),
|
||||
safeGetStack(Constants.ItemName.TankControllerUpgrade),
|
||||
safeGetStack(Constants.ItemName.CraftingUpgrade),
|
||||
safeGetStack(Constants.ItemName.HoverUpgradeTier2),
|
||||
|
||||
safeGetStack(Constants.ItemName.GraphicsCardTier3),
|
||||
safeGetStack(Constants.ItemName.RedstoneCardTier2),
|
||||
|
@ -130,7 +130,7 @@ trait ComponentInventory extends Inventory with network.Environment {
|
||||
|
||||
override def getInventoryStackLimit = 1
|
||||
|
||||
override protected def onItemAdded(slot: Int, stack: ItemStack) = if (isComponentSlot(slot, stack)) {
|
||||
override protected def onItemAdded(slot: Int, stack: ItemStack) = if (slot >= 0 && slot < components.length && isComponentSlot(slot, stack)) {
|
||||
Option(Driver.driverFor(stack)).foreach(driver =>
|
||||
Option(driver.createEnvironment(stack, host)) match {
|
||||
case Some(component) => this.synchronized {
|
||||
@ -154,7 +154,7 @@ trait ComponentInventory extends Inventory with network.Environment {
|
||||
})
|
||||
}
|
||||
|
||||
override protected def onItemRemoved(slot: Int, stack: ItemStack) {
|
||||
override protected def onItemRemoved(slot: Int, stack: ItemStack): Unit = if (slot >= 0 && slot < components.length) {
|
||||
// Uninstall component previously in that slot.
|
||||
components(slot) match {
|
||||
case Some(component) => this.synchronized {
|
||||
|
@ -4,6 +4,7 @@ import li.cil.oc.Settings
|
||||
import li.cil.oc.api
|
||||
import li.cil.oc.api.network.Visibility
|
||||
import li.cil.oc.common.EventHandler
|
||||
import li.cil.oc.common.tileentity.traits.RedstoneChangedEventArgs
|
||||
import li.cil.oc.server.{PacketSender => ServerPacketSender}
|
||||
import net.minecraft.init.SoundEvents
|
||||
import net.minecraft.nbt.NBTTagCompound
|
||||
@ -52,10 +53,10 @@ class NetSplitter extends traits.Environment with traits.OpenSides with traits.R
|
||||
|
||||
// ----------------------------------------------------------------------- //
|
||||
|
||||
override protected def onRedstoneInputChanged(side: EnumFacing, oldMaxValue: Int, newMaxValue: Int): Unit = {
|
||||
super.onRedstoneInputChanged(side, oldMaxValue, newMaxValue)
|
||||
override protected def onRedstoneInputChanged(args: RedstoneChangedEventArgs): Unit = {
|
||||
super.onRedstoneInputChanged(args)
|
||||
val oldIsInverted = isInverted
|
||||
isInverted = newMaxValue > 0
|
||||
isInverted = args.newValue > 0
|
||||
if (isInverted != oldIsInverted) {
|
||||
if (isServer) {
|
||||
node.remove()
|
||||
|
@ -7,6 +7,7 @@ import li.cil.oc.Constants
|
||||
import li.cil.oc.Settings
|
||||
import li.cil.oc.api
|
||||
import li.cil.oc.common.item.data.PrintData
|
||||
import li.cil.oc.common.tileentity.traits.RedstoneChangedEventArgs
|
||||
import li.cil.oc.util.ExtendedAABB
|
||||
import li.cil.oc.util.ExtendedAABB._
|
||||
import li.cil.oc.util.ExtendedNBT._
|
||||
@ -145,9 +146,8 @@ class Print(val canToggle: Option[() => Boolean], val scheduleUpdate: Option[Int
|
||||
}
|
||||
}
|
||||
|
||||
override protected def onRedstoneInputChanged(side: EnumFacing, oldMaxValue: Int, newMaxValue: Int): Unit = {
|
||||
super.onRedstoneInputChanged(side, oldMaxValue, newMaxValue)
|
||||
val newState = newMaxValue > 0
|
||||
override protected def onRedstoneInputChanged(args: RedstoneChangedEventArgs): Unit = {
|
||||
val newState = args.newValue > 0
|
||||
if (!data.emitRedstone && data.hasActiveState && state != newState) {
|
||||
toggleState()
|
||||
}
|
||||
|
@ -16,6 +16,7 @@ import li.cil.oc.api.network.Packet
|
||||
import li.cil.oc.api.network.Visibility
|
||||
import li.cil.oc.api.util.StateAware
|
||||
import li.cil.oc.common.Slot
|
||||
import li.cil.oc.common.tileentity.traits.RedstoneChangedEventArgs
|
||||
import li.cil.oc.integration.opencomputers.DriverRedstoneCard
|
||||
import li.cil.oc.server.{PacketSender => ServerPacketSender}
|
||||
import li.cil.oc.util.ExtendedInventory._
|
||||
@ -290,11 +291,11 @@ class Rack extends traits.PowerAcceptor with traits.Hub with traits.PowerBalance
|
||||
// ----------------------------------------------------------------------- //
|
||||
// RedstoneAware
|
||||
|
||||
override protected def onRedstoneInputChanged(side: EnumFacing, oldMaxValue: Int, newMaxValue: Int) {
|
||||
super.onRedstoneInputChanged(side, oldMaxValue, newMaxValue)
|
||||
override protected def onRedstoneInputChanged(args: RedstoneChangedEventArgs) {
|
||||
super.onRedstoneInputChanged(args)
|
||||
components.collect {
|
||||
case Some(mountable: RackMountable) if mountable.node != null =>
|
||||
mountable.node.sendToNeighbors("redstone.changed", toLocal(side), int2Integer(oldMaxValue), int2Integer(newMaxValue))
|
||||
mountable.node.sendToNeighbors("redstone.changed", args)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5,6 +5,7 @@ import li.cil.oc.api
|
||||
import li.cil.oc.api.network.Component
|
||||
import li.cil.oc.api.network.Node
|
||||
import li.cil.oc.api.network.Visibility
|
||||
import li.cil.oc.common.tileentity.traits.RedstoneChangedEventArgs
|
||||
import li.cil.oc.integration.util.BundledRedstone
|
||||
import li.cil.oc.server.component
|
||||
import li.cil.oc.server.component.RedstoneVanilla
|
||||
@ -43,11 +44,11 @@ class Redstone extends traits.Environment with traits.BundledRedstoneAware with
|
||||
|
||||
// ----------------------------------------------------------------------- //
|
||||
|
||||
override protected def onRedstoneInputChanged(side: EnumFacing, oldMaxValue: Int, newMaxValue: Int) {
|
||||
super.onRedstoneInputChanged(side, oldMaxValue, newMaxValue)
|
||||
override protected def onRedstoneInputChanged(args: RedstoneChangedEventArgs) {
|
||||
super.onRedstoneInputChanged(args)
|
||||
if (node != null && node.network != null) {
|
||||
node.connect(dummyNode)
|
||||
dummyNode.sendToNeighbors("redstone.changed", side, Int.box(oldMaxValue), Int.box(newMaxValue))
|
||||
dummyNode.sendToNeighbors("redstone.changed", args)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ import li.cil.oc.api.network._
|
||||
import li.cil.oc.client.gui
|
||||
import li.cil.oc.common.component.TextBuffer
|
||||
import li.cil.oc.util.BlockPosition
|
||||
import li.cil.oc.common.tileentity.traits.RedstoneChangedEventArgs
|
||||
import li.cil.oc.util.Color
|
||||
import li.cil.oc.util.ExtendedWorld._
|
||||
import net.minecraft.client.Minecraft
|
||||
@ -344,8 +345,8 @@ class Screen(var tier: Int) extends traits.TextBuffer with SidedEnvironment with
|
||||
|
||||
override def onAnalyze(player: EntityPlayer, side: EnumFacing, hitX: Float, hitY: Float, hitZ: Float) = Array(origin.node)
|
||||
|
||||
override protected def onRedstoneInputChanged(side: EnumFacing, oldMaxValue: Int, newMaxValue: Int) {
|
||||
super.onRedstoneInputChanged(side, oldMaxValue, newMaxValue)
|
||||
override protected def onRedstoneInputChanged(args: RedstoneChangedEventArgs) {
|
||||
super.onRedstoneInputChanged(args)
|
||||
val hasRedstoneInput = screens.map(_.maxInput).max > 0
|
||||
if (hasRedstoneInput != hadRedstoneInput) {
|
||||
hadRedstoneInput = hasRedstoneInput
|
||||
|
@ -32,39 +32,31 @@ trait BundledRedstoneAware extends RedstoneAware {
|
||||
super.isOutputEnabled_=(value)
|
||||
}
|
||||
|
||||
def bundledInput(side: EnumFacing, color: Int): Int =
|
||||
math.max(_bundledInput(side.ordinal())(color), _rednetInput(side.ordinal())(color))
|
||||
|
||||
def bundledInput(side: EnumFacing): Array[Int] =
|
||||
(_bundledInput(side.ordinal()), _rednetInput(side.ordinal())).zipped.map(math.max)
|
||||
|
||||
def bundledInput(side: EnumFacing, newBundledInput: Array[Int]): Unit = {
|
||||
val ownBundledInput = _bundledInput(side.ordinal())
|
||||
val oldMaxValue = ownBundledInput.max
|
||||
var changed = false
|
||||
if (newBundledInput != null) for (color <- 0 until 16) {
|
||||
changed = changed || (ownBundledInput(color) >= 0 && ownBundledInput(color) != newBundledInput(color))
|
||||
ownBundledInput(color) = newBundledInput(color)
|
||||
}
|
||||
else for (color <- 0 until 16) {
|
||||
changed = changed || ownBundledInput(color) > 0
|
||||
ownBundledInput(color) = 0
|
||||
}
|
||||
if (changed) {
|
||||
onRedstoneInputChanged(side, oldMaxValue, ownBundledInput.max)
|
||||
for (color <- 0 until 16) {
|
||||
updateInput(_bundledInput, side, color, if (newBundledInput == null) 0 else newBundledInput(color))
|
||||
}
|
||||
}
|
||||
|
||||
def bundledInput(side: EnumFacing, color: Int): Int =
|
||||
math.max(_bundledInput(side.ordinal())(color), _rednetInput(side.ordinal())(color))
|
||||
def rednetInput(side: EnumFacing, color: Int, value: Int): Unit = updateInput(_rednetInput, side, color, value)
|
||||
|
||||
def rednetInput(side: EnumFacing, color: Int, value: Int): Unit = {
|
||||
val oldValue = _rednetInput(side.ordinal())(color)
|
||||
if (oldValue != value) {
|
||||
def updateInput(inputs: Array[Array[Int]], side: EnumFacing, color: Int, newValue: Int): Unit = {
|
||||
val oldValue = inputs(side.ordinal())(color)
|
||||
if (oldValue != newValue) {
|
||||
if (oldValue != -1) {
|
||||
onRedstoneInputChanged(side, oldValue, value)
|
||||
onRedstoneInputChanged(RedstoneChangedEventArgs(side, oldValue, newValue, color))
|
||||
}
|
||||
_rednetInput(side.ordinal())(color) = value
|
||||
inputs(side.ordinal())(color) = newValue
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
def bundledOutput(side: EnumFacing): Array[Int] = _bundledOutput(toLocal(side).ordinal())
|
||||
|
||||
def bundledOutput(side: EnumFacing, color: Int): Int = bundledOutput(side)(color)
|
||||
|
@ -203,9 +203,9 @@ trait Computer extends Environment with ComponentInventory with Rotatable with B
|
||||
checkRedstoneInputChanged()
|
||||
}
|
||||
|
||||
override protected def onRedstoneInputChanged(side: EnumFacing, oldMaxValue: Int, newMaxValue: Int) {
|
||||
super.onRedstoneInputChanged(side, oldMaxValue, newMaxValue)
|
||||
machine.node.sendToNeighbors("redstone.changed", toLocal(side), Int.box(oldMaxValue), Int.box(newMaxValue))
|
||||
override protected def onRedstoneInputChanged(args: RedstoneChangedEventArgs) {
|
||||
super.onRedstoneInputChanged(args)
|
||||
machine.node.sendToNeighbors("redstone.changed", args)
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------- //
|
||||
|
@ -17,7 +17,11 @@ import scala.collection.mutable
|
||||
trait Hub extends traits.Environment with SidedEnvironment with Tickable {
|
||||
override def node: Node = null
|
||||
|
||||
override protected def isConnected = plugs.exists(plug => plug.node.address != null && plug.node.network != null)
|
||||
override protected def isConnected = plugs.exists(plug =>
|
||||
plug != null &&
|
||||
plug.node != null &&
|
||||
plug.node.address != null &&
|
||||
plug.node.network != null)
|
||||
|
||||
protected val plugs = EnumFacing.values.map(side => createPlug(side))
|
||||
|
||||
@ -127,7 +131,8 @@ trait Hub extends traits.Environment with SidedEnvironment with Tickable {
|
||||
if (isServer) {
|
||||
nbt.setNewTagList(PlugsTag, plugs.map(plug => {
|
||||
val plugNbt = new NBTTagCompound()
|
||||
plug.node.save(plugNbt)
|
||||
if (plug.node != null)
|
||||
plug.node.save(plugNbt)
|
||||
plugNbt
|
||||
}))
|
||||
nbt.setNewTagList(QueueTag, queue.map {
|
||||
|
@ -9,6 +9,8 @@ import net.minecraft.util.EnumFacing
|
||||
import net.minecraftforge.fml.relauncher.Side
|
||||
import net.minecraftforge.fml.relauncher.SideOnly
|
||||
|
||||
case class RedstoneChangedEventArgs (side: EnumFacing, oldValue: Int, newValue: Int, color: Int = -1)
|
||||
|
||||
trait RedstoneAware extends RotationAware {
|
||||
protected[tileentity] val _input: Array[Int] = Array.fill(6)(-1)
|
||||
|
||||
@ -39,7 +41,7 @@ trait RedstoneAware extends RotationAware {
|
||||
val oldInput = _input(side.ordinal())
|
||||
_input(side.ordinal()) = newInput
|
||||
if (oldInput >= 0 && newInput != oldInput) {
|
||||
onRedstoneInputChanged(side, oldInput, newInput)
|
||||
onRedstoneInputChanged(RedstoneChangedEventArgs(side, oldInput, newInput))
|
||||
}
|
||||
}
|
||||
|
||||
@ -117,7 +119,7 @@ trait RedstoneAware extends RotationAware {
|
||||
|
||||
// ----------------------------------------------------------------------- //
|
||||
|
||||
protected def onRedstoneInputChanged(side: EnumFacing, oldMaxValue: Int, newMaxValue: Int) {}
|
||||
protected def onRedstoneInputChanged(args: RedstoneChangedEventArgs) {}
|
||||
|
||||
protected def onRedstoneOutputEnabledChanged() {
|
||||
if (getWorld != null) {
|
||||
|
@ -155,6 +155,17 @@ trait Agent extends traits.WorldControl with traits.InventoryControl with traits
|
||||
reason = reason.orElse(Option(what))
|
||||
}
|
||||
|
||||
// all side attempts failed - but there could be a partial block that is hard to "see"
|
||||
val (hasBlock, _) = blockContent(facing)
|
||||
if (hasBlock) {
|
||||
val blockPos = position.offset(facing)
|
||||
val player = rotatedPlayer(facing, facing)
|
||||
player.setSneaking(sneaky)
|
||||
val (ok, why) = click(player, blockPos.toBlockPos, facing)
|
||||
player.setSneaking(false)
|
||||
return result(ok, why)
|
||||
}
|
||||
|
||||
result(false, reason.orNull)
|
||||
}
|
||||
|
||||
|
@ -19,6 +19,9 @@ import li.cil.oc.api.network.Message
|
||||
import li.cil.oc.api.network.Visibility
|
||||
import li.cil.oc.api.prefab
|
||||
import li.cil.oc.api.prefab.AbstractManagedEnvironment
|
||||
import li.cil.oc.common.tileentity.{Robot => EntityRobot, Microcontroller}
|
||||
import li.cil.oc.common.entity.{Drone => EntityDrone}
|
||||
import li.cil.oc.common.item.TabletWrapper
|
||||
import li.cil.oc.util.BlockPosition
|
||||
import li.cil.oc.util.DatabaseAccess
|
||||
import li.cil.oc.util.ExtendedArguments._
|
||||
@ -34,7 +37,7 @@ import scala.collection.convert.WrapAsJava._
|
||||
import scala.collection.convert.WrapAsScala._
|
||||
import scala.language.existentials
|
||||
|
||||
class Geolyzer(val host: EnvironmentHost) extends AbstractManagedEnvironment with DeviceInfo {
|
||||
class Geolyzer(val host: EnvironmentHost) extends AbstractManagedEnvironment with traits.WorldControl with DeviceInfo {
|
||||
override val node = api.Network.newNode(this, Visibility.Network).
|
||||
withComponent("geolyzer").
|
||||
withConnector().
|
||||
@ -52,6 +55,45 @@ class Geolyzer(val host: EnvironmentHost) extends AbstractManagedEnvironment wit
|
||||
|
||||
// ----------------------------------------------------------------------- //
|
||||
|
||||
override protected def checkSideForAction(args: Arguments, n: Int): EnumFacing = {
|
||||
val side = args.checkSideAny(n)
|
||||
val is_uc = host.isInstanceOf[Microcontroller]
|
||||
host match {
|
||||
case robot: EntityRobot => robot.proxy.toGlobal(side)
|
||||
case drone: EntityDrone => drone.toGlobal(side)
|
||||
case uc: Microcontroller => uc.toLocal(side) // not really sure what it is reversed for microcontrollers
|
||||
case tablet: TabletWrapper => tablet.toGlobal(side)
|
||||
case _ => side
|
||||
}
|
||||
}
|
||||
|
||||
override def position: BlockPosition = host match {
|
||||
case robot: EntityRobot => robot.proxy.position
|
||||
case drone: EntityDrone => BlockPosition(drone.getPosition, drone.getEntityWorld)
|
||||
case uc: Microcontroller => uc.position
|
||||
case tablet: TabletWrapper => BlockPosition(tablet.xPosition, tablet.yPosition, tablet.zPosition, tablet.world)
|
||||
case _ => BlockPosition(host)
|
||||
}
|
||||
|
||||
private def canSeeSky: Boolean = {
|
||||
val blockPos = position.offset(EnumFacing.UP)
|
||||
!host.world.provider.isNether && host.world.canBlockSeeSky(blockPos.toBlockPos)
|
||||
}
|
||||
|
||||
@Callback(doc = """function():boolean -- Returns whether there is a clear line of sight to the sky directly above.""")
|
||||
def canSeeSky(computer: Context, args: Arguments): Array[AnyRef] = {
|
||||
result(canSeeSky)
|
||||
}
|
||||
|
||||
@Callback(doc = """function():boolean -- Return whether the sun is currently visible directly above.""")
|
||||
def isSunVisible(computer: Context, args: Arguments): Array[AnyRef] = {
|
||||
val blockPos = BlockPosition(host).offset(EnumFacing.UP)
|
||||
result(
|
||||
host.world.isDaytime &&
|
||||
canSeeSky &&
|
||||
!host.world.getBiome(blockPos.toBlockPos).canRain || (!host.world.isRaining && !host.world.isThundering))
|
||||
}
|
||||
|
||||
@Callback(doc = """function(x:number, z:number[, y:number, w:number, d:number, h:number][, ignoreReplaceable:boolean|options:table]):table -- Analyzes the density of the column at the specified relative coordinates.""")
|
||||
def scan(computer: Context, args: Arguments): Array[AnyRef] = {
|
||||
val (minX, minY, minZ, maxX, maxY, maxZ, optIndex) = getScanArgs(args)
|
||||
|
@ -7,8 +7,11 @@ import li.cil.oc.api.machine.Context
|
||||
import li.cil.oc.api.network.Visibility
|
||||
import li.cil.oc.api.prefab
|
||||
import li.cil.oc.api.prefab.AbstractManagedEnvironment
|
||||
import li.cil.oc.common.tileentity.traits.RedstoneChangedEventArgs
|
||||
import net.minecraft.nbt.NBTTagCompound
|
||||
|
||||
import scala.collection.mutable.ArrayBuffer
|
||||
|
||||
trait RedstoneSignaller extends AbstractManagedEnvironment {
|
||||
override val node = Network.newNode(this, Visibility.Network).
|
||||
withComponent("redstone", Visibility.Neighbors).
|
||||
@ -32,9 +35,13 @@ trait RedstoneSignaller extends AbstractManagedEnvironment {
|
||||
|
||||
// ----------------------------------------------------------------------- //
|
||||
|
||||
def onRedstoneChanged(side: AnyRef, oldMaxValue: Int, newMaxValue: Int): Unit = {
|
||||
node.sendToReachable("computer.signal", "redstone_changed", side, Int.box(oldMaxValue), Int.box(newMaxValue))
|
||||
if (oldMaxValue < wakeThreshold && newMaxValue >= wakeThreshold) {
|
||||
def onRedstoneChanged(args: RedstoneChangedEventArgs): Unit = {
|
||||
val side: AnyRef = if (args.side == null) "wireless" else Int.box(args.side.ordinal)
|
||||
val flatArgs = ArrayBuffer[Object]("redstone_changed", side, Int.box(args.oldValue), Int.box(args.newValue))
|
||||
if (args.color >= 0)
|
||||
flatArgs += Int.box(args.color)
|
||||
node.sendToReachable("computer.signal", flatArgs: _*)
|
||||
if (args.oldValue < wakeThreshold && args.newValue >= wakeThreshold) {
|
||||
if (wakeNeighborsOnly)
|
||||
node.sendToNeighbors("computer.start")
|
||||
else
|
||||
|
@ -12,7 +12,7 @@ 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._
|
||||
import li.cil.oc.common.tileentity.traits.RedstoneAware
|
||||
import li.cil.oc.common.tileentity.traits.{RedstoneAware, RedstoneChangedEventArgs}
|
||||
import li.cil.oc.util.BlockPosition
|
||||
import li.cil.oc.util.ExtendedBlock._
|
||||
import li.cil.oc.util.ExtendedWorld._
|
||||
@ -79,8 +79,8 @@ trait RedstoneVanilla extends RedstoneSignaller with DeviceInfo {
|
||||
override def onMessage(message: Message): Unit = {
|
||||
super.onMessage(message)
|
||||
if (message.name == "redstone.changed") message.data match {
|
||||
case Array(side: EnumFacing, oldMaxValue: Number, newMaxValue: Number) =>
|
||||
onRedstoneChanged(Int.box(side.ordinal()), oldMaxValue.intValue(), newMaxValue.intValue())
|
||||
case Array(args: RedstoneChangedEventArgs) =>
|
||||
onRedstoneChanged(args)
|
||||
case _ =>
|
||||
}
|
||||
}
|
||||
|
163
src/main/scala/li/cil/oc/server/component/RedstoneWireless.scala
Normal file
163
src/main/scala/li/cil/oc/server/component/RedstoneWireless.scala
Normal file
@ -0,0 +1,163 @@
|
||||
package li.cil.oc.server.component
|
||||
|
||||
import codechicken.lib.vec.Vector3
|
||||
import codechicken.wirelessredstone.api.WirelessReceivingDevice
|
||||
import codechicken.wirelessredstone.api.WirelessTransmittingDevice
|
||||
import li.cil.oc.Constants
|
||||
import li.cil.oc.api.driver.DeviceInfo.DeviceAttribute
|
||||
import li.cil.oc.api.driver.DeviceInfo.DeviceClass
|
||||
import li.cil.oc.Settings
|
||||
import li.cil.oc.api.driver.DeviceInfo
|
||||
import li.cil.oc.api.network.EnvironmentHost
|
||||
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._
|
||||
import li.cil.oc.common.EventHandler
|
||||
import li.cil.oc.common.tileentity.traits.RedstoneChangedEventArgs
|
||||
import li.cil.oc.integration.Mods
|
||||
import li.cil.oc.integration.util
|
||||
import net.minecraft.nbt.NBTTagCompound
|
||||
import net.minecraftforge.fml.common.Optional
|
||||
|
||||
import scala.collection.convert.WrapAsJava._
|
||||
|
||||
@Optional.InterfaceList(Array(
|
||||
new Optional.Interface(iface = "codechicken.wirelessredstone.api.WirelessReceivingDevice", modid = Mods.IDs.WirelessRedstoneCBE),
|
||||
new Optional.Interface(iface = "codechicken.wirelessredstone.api.WirelessTransmittingDevice", modid = Mods.IDs.WirelessRedstoneCBE)
|
||||
))
|
||||
trait RedstoneWireless extends RedstoneSignaller with WirelessReceivingDevice with WirelessTransmittingDevice with DeviceInfo {
|
||||
def redstone: EnvironmentHost
|
||||
|
||||
var wirelessFrequency = 0
|
||||
|
||||
var wirelessInput = false
|
||||
|
||||
var wirelessOutput = false
|
||||
|
||||
// ----------------------------------------------------------------------- //
|
||||
|
||||
private final lazy val deviceInfo = Map(
|
||||
DeviceAttribute.Class -> DeviceClass.Communication,
|
||||
DeviceAttribute.Description -> "Wireless redstone controller",
|
||||
DeviceAttribute.Vendor -> Constants.DeviceInfo.DefaultVendor,
|
||||
DeviceAttribute.Product -> "Rw400-M",
|
||||
DeviceAttribute.Capacity -> "1",
|
||||
DeviceAttribute.Width -> "1"
|
||||
)
|
||||
|
||||
override def getDeviceInfo: java.util.Map[String, String] = deviceInfo
|
||||
|
||||
// ----------------------------------------------------------------------- //
|
||||
|
||||
@Callback(doc = """function():number -- Get the wireless redstone input.""")
|
||||
def getWirelessInput(context: Context, args: Arguments): Array[AnyRef] = {
|
||||
wirelessInput = util.WirelessRedstone.getInput(this)
|
||||
result(wirelessInput)
|
||||
}
|
||||
|
||||
@Callback(direct = true, doc = """function():boolean -- Get the wireless redstone output.""")
|
||||
def getWirelessOutput(context: Context, args: Arguments): Array[AnyRef] = result(wirelessOutput)
|
||||
|
||||
@Callback(doc = """function(value:boolean):boolean -- Set the wireless redstone output.""")
|
||||
def setWirelessOutput(context: Context, args: Arguments): Array[AnyRef] = {
|
||||
val oldValue = wirelessOutput
|
||||
val newValue = args.checkBoolean(0)
|
||||
|
||||
if (oldValue != newValue) {
|
||||
wirelessOutput = newValue
|
||||
|
||||
util.WirelessRedstone.updateOutput(this)
|
||||
|
||||
if (Settings.get.redstoneDelay > 0)
|
||||
context.pause(Settings.get.redstoneDelay)
|
||||
}
|
||||
|
||||
result(oldValue)
|
||||
}
|
||||
|
||||
@Callback(direct = true, doc = """function():number -- Get the currently set wireless redstone frequency.""")
|
||||
def getWirelessFrequency(context: Context, args: Arguments): Array[AnyRef] = result(wirelessFrequency)
|
||||
|
||||
@Callback(doc = """function(frequency:number):number -- Set the wireless redstone frequency to use.""")
|
||||
def setWirelessFrequency(context: Context, args: Arguments): Array[AnyRef] = {
|
||||
val oldValue = wirelessFrequency
|
||||
val newValue = args.checkInteger(0)
|
||||
|
||||
if (oldValue != newValue) {
|
||||
util.WirelessRedstone.removeReceiver(this)
|
||||
util.WirelessRedstone.removeTransmitter(this)
|
||||
|
||||
wirelessFrequency = newValue
|
||||
wirelessInput = false
|
||||
wirelessOutput = false
|
||||
|
||||
util.WirelessRedstone.addReceiver(this)
|
||||
|
||||
context.pause(0.5)
|
||||
}
|
||||
|
||||
result(oldValue)
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------- //
|
||||
|
||||
@Optional.Method(modid = Mods.IDs.WirelessRedstoneCBE)
|
||||
override def updateDevice(frequency: Int, on: Boolean) {
|
||||
if (frequency == wirelessFrequency && on != wirelessInput) {
|
||||
wirelessInput = on
|
||||
onRedstoneChanged(RedstoneChangedEventArgs(null, if (on) 0 else 1, if (on) 1 else 0))
|
||||
}
|
||||
}
|
||||
|
||||
@Optional.Method(modid = Mods.IDs.WirelessRedstoneCBE)
|
||||
override def getTransmitPos = new Vector3(redstone.xPosition, redstone.yPosition, redstone.zPosition)
|
||||
|
||||
@Optional.Method(modid = Mods.IDs.WirelessRedstoneCBE)
|
||||
override def getDimension = redstone.world.provider.getDimension
|
||||
|
||||
@Optional.Method(modid = Mods.IDs.WirelessRedstoneCBE)
|
||||
override def getFreq = wirelessFrequency
|
||||
|
||||
@Optional.Method(modid = Mods.IDs.WirelessRedstoneCBE)
|
||||
override def getAttachedEntity = null
|
||||
|
||||
// ----------------------------------------------------------------------- //
|
||||
|
||||
override def onConnect(node: Node) {
|
||||
super.onConnect(node)
|
||||
if (node == this.node) {
|
||||
EventHandler.scheduleWirelessRedstone(this)
|
||||
}
|
||||
}
|
||||
|
||||
override def onDisconnect(node: Node) {
|
||||
super.onDisconnect(node)
|
||||
if (node == this.node) {
|
||||
util.WirelessRedstone.removeReceiver(this)
|
||||
util.WirelessRedstone.removeTransmitter(this)
|
||||
wirelessOutput = false
|
||||
wirelessFrequency = 0
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------- //
|
||||
|
||||
private final val WirelessFrequencyTag = "wirelessFrequency"
|
||||
private final val WirelessInputTag = "wirelessInput"
|
||||
private final val WirelessOutputTag = "wirelessOutput"
|
||||
|
||||
override def load(nbt: NBTTagCompound) {
|
||||
super.load(nbt)
|
||||
wirelessFrequency = nbt.getInteger(WirelessFrequencyTag)
|
||||
wirelessInput = nbt.getBoolean(WirelessInputTag)
|
||||
wirelessOutput = nbt.getBoolean(WirelessOutputTag)
|
||||
}
|
||||
|
||||
override def save(nbt: NBTTagCompound) {
|
||||
super.save(nbt)
|
||||
nbt.setInteger(WirelessFrequencyTag, wirelessFrequency)
|
||||
nbt.setBoolean(WirelessInputTag, wirelessInput)
|
||||
nbt.setBoolean(WirelessOutputTag, wirelessOutput)
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user