mirror of
https://github.com/MightyPirates/OpenComputers.git
synced 2025-09-16 18:55:03 -04:00
messed with synchronization of network a bit, mostly removing the synchronizations, meaning using the network in direct lua callbacks is *not safe* anymore. consuming / producing power however should be, that's synchronized (and hopefully won't deadlock, unless I forgot some case); fixed opengl errors when moving screens using RIM by checking if a display list is currently being compiled, and not trying to compile again if so, but simple rendering what we currently have. also reduced the keep-alive time of the cache a bit.
This commit is contained in:
parent
5faedd2525
commit
c8bcc59936
@ -264,7 +264,7 @@ sandbox = {
|
|||||||
(type(timeout) == "number" and timeout or math.huge)
|
(type(timeout) == "number" and timeout or math.huge)
|
||||||
repeat
|
repeat
|
||||||
local signal = table.pack(coroutine.yield(deadline - os.uptime()))
|
local signal = table.pack(coroutine.yield(deadline - os.uptime()))
|
||||||
if signal.n > 0 then -- not a "blind" resume?
|
if signal.n > 0 then
|
||||||
return table.unpack(signal, 1, signal.n)
|
return table.unpack(signal, 1, signal.n)
|
||||||
end
|
end
|
||||||
until os.uptime() >= deadline
|
until os.uptime() >= deadline
|
||||||
@ -295,12 +295,13 @@ sandbox = {
|
|||||||
return nil, reason
|
return nil, reason
|
||||||
end
|
end
|
||||||
local proxy = {address = address, type = type}
|
local proxy = {address = address, type = type}
|
||||||
local methods = component.methods(address)
|
local methods, reason = component.methods(address)
|
||||||
if methods then
|
if not methods then
|
||||||
for method, direct in pairs(methods) do
|
return nil, reason
|
||||||
proxy[method] = function(...)
|
end
|
||||||
return invoke(direct, address, method, ...)
|
for method, direct in pairs(methods) do
|
||||||
end
|
proxy[method] = function(...)
|
||||||
|
return invoke(direct, address, method, ...)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return proxy
|
return proxy
|
||||||
|
BIN
assets/opencomputers/textures/gui/robot.png
Normal file
BIN
assets/opencomputers/textures/gui/robot.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 598 B |
@ -4,32 +4,36 @@ package li.cil.oc.api.driver;
|
|||||||
* List of possible item component types.
|
* List of possible item component types.
|
||||||
* <p/>
|
* <p/>
|
||||||
* This is used to determine which item components may go into which slots in
|
* This is used to determine which item components may go into which slots in
|
||||||
* a computer, since unlike block components, item components must be placed
|
* a computer's inventory.
|
||||||
* inside the computer, not next to it.
|
|
||||||
*/
|
*/
|
||||||
public enum Slot {
|
public enum Slot {
|
||||||
|
/**
|
||||||
|
* Extension cards such as graphics cards or redstone cards.
|
||||||
|
*/
|
||||||
|
Card,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Floppy disks. These can be inserted into the Disk Drive block.
|
||||||
|
*/
|
||||||
|
Disk,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hard disk drives. These can be installed in computers.
|
||||||
|
*/
|
||||||
|
HardDiskDrive,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Memory extension components. Used to increase computer RAM.
|
||||||
|
*/
|
||||||
|
Memory,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Power generating components, such as generators.
|
* Power generating components, such as generators.
|
||||||
*/
|
*/
|
||||||
Power,
|
Power,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Memory extension components.
|
* Tools that can be used by robots.
|
||||||
*/
|
*/
|
||||||
Memory,
|
Tool
|
||||||
|
|
||||||
/**
|
|
||||||
* Hard disk drives.
|
|
||||||
*/
|
|
||||||
HardDiskDrive,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Extension cards such as graphics or redstone cards.
|
|
||||||
*/
|
|
||||||
Card,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Floppy disks.
|
|
||||||
*/
|
|
||||||
Disk
|
|
||||||
}
|
}
|
@ -38,10 +38,9 @@ public @interface LuaCallback {
|
|||||||
* This is mainly intended to allow functions to perform faster than when
|
* This is mainly intended to allow functions to perform faster than when
|
||||||
* called 'synchronously' (where the call takes at least one server tick).
|
* called 'synchronously' (where the call takes at least one server tick).
|
||||||
* <p/>
|
* <p/>
|
||||||
* Note that {@link Network} interaction is mostly synchronized - i.e. the
|
* Keep in mind that the node {@link Network} is <em>not</em> thread safe!
|
||||||
* operations on the network itself are: once you get some result you're
|
* Be sure you know what you're doing if you're working with a node's
|
||||||
* <em>not</em> guaranteed that node you just fetched is still in the
|
* network in a direct callback.
|
||||||
* network, for example!
|
|
||||||
*/
|
*/
|
||||||
boolean direct() default false;
|
boolean direct() default false;
|
||||||
|
|
||||||
@ -63,6 +62,9 @@ public @interface LuaCallback {
|
|||||||
* via a direct call to {@link Component#invoke(String, Context, Object...)}
|
* via a direct call to {@link Component#invoke(String, Context, Object...)}
|
||||||
* from the host side. Also, this limit is per-computer, so the method may
|
* from the host side. Also, this limit is per-computer, so the method may
|
||||||
* be invoked more often than this per tick, if different computers call it.
|
* be invoked more often than this per tick, if different computers call it.
|
||||||
|
* <p/>
|
||||||
|
* An exception to that rule is {@link Connector#changeBuffer(double)},
|
||||||
|
* which is synchronized, so you can consume/produce power in direct calls.
|
||||||
*/
|
*/
|
||||||
int limit() default Integer.MAX_VALUE;
|
int limit() default Integer.MAX_VALUE;
|
||||||
}
|
}
|
||||||
|
@ -33,6 +33,10 @@ package li.cil.oc.api.network;
|
|||||||
* nodes of the other network(s), when a network is split (all pairs).</li>
|
* nodes of the other network(s), when a network is split (all pairs).</li>
|
||||||
* </ul>
|
* </ul>
|
||||||
* <p/>
|
* <p/>
|
||||||
|
* Note that network access is <em>not</em> thread safe! Networks should only
|
||||||
|
* be accessed from the main server thread.
|
||||||
|
*
|
||||||
|
* <p/>
|
||||||
* IMPORTANT: do *not* implement this interface yourself and create
|
* IMPORTANT: do *not* implement this interface yourself and create
|
||||||
* instances of your own network implementation; this will lead to
|
* instances of your own network implementation; this will lead to
|
||||||
* incompatibilities with the built-in network implementation (which can only
|
* incompatibilities with the built-in network implementation (which can only
|
||||||
|
@ -24,9 +24,10 @@ object ScreenRenderer extends TileEntitySpecialRenderer with Callable[Int] with
|
|||||||
|
|
||||||
/** We cache the display lists for the screens we render for performance. */
|
/** We cache the display lists for the screens we render for performance. */
|
||||||
val cache = com.google.common.cache.CacheBuilder.newBuilder().
|
val cache = com.google.common.cache.CacheBuilder.newBuilder().
|
||||||
expireAfterAccess(5, TimeUnit.SECONDS).
|
expireAfterAccess(2, TimeUnit.SECONDS).
|
||||||
removalListener(this).
|
removalListener(this).
|
||||||
asInstanceOf[CacheBuilder[Screen, Int]].build[Screen, Int]()
|
asInstanceOf[CacheBuilder[Screen, Int]].
|
||||||
|
build[Screen, Int]()
|
||||||
|
|
||||||
/** Used to pass the current screen along to call(). */
|
/** Used to pass the current screen along to call(). */
|
||||||
private var screen: Screen = null
|
private var screen: Screen = null
|
||||||
@ -68,19 +69,18 @@ object ScreenRenderer extends TileEntitySpecialRenderer with Callable[Int] with
|
|||||||
|
|
||||||
MonospaceFontRenderer.init(tileEntityRenderer.renderEngine)
|
MonospaceFontRenderer.init(tileEntityRenderer.renderEngine)
|
||||||
val list = cache.get(screen, this)
|
val list = cache.get(screen, this)
|
||||||
compile(list)
|
compileOrDraw(list)
|
||||||
GL11.glCallList(list)
|
|
||||||
|
|
||||||
GL11.glPopMatrix()
|
GL11.glPopMatrix()
|
||||||
GL11.glPopAttrib()
|
GL11.glPopAttrib()
|
||||||
}
|
}
|
||||||
|
|
||||||
private def compile(list: Int) = if (screen.hasChanged) {
|
private def compileOrDraw(list: Int) = if (screen.hasChanged && !RenderState.compilingDisplayList) {
|
||||||
screen.hasChanged = false
|
screen.hasChanged = false
|
||||||
val (sx, sy) = (screen.width, screen.height)
|
val (sx, sy) = (screen.width, screen.height)
|
||||||
val (tw, th) = (sx * 16f, sy * 16f)
|
val (tw, th) = (sx * 16f, sy * 16f)
|
||||||
|
|
||||||
GL11.glNewList(list, GL11.GL_COMPILE)
|
GL11.glNewList(list, GL11.GL_COMPILE_AND_EXECUTE)
|
||||||
|
|
||||||
screen.yaw match {
|
screen.yaw match {
|
||||||
case ForgeDirection.WEST => GL11.glRotatef(-90, 0, 1, 0)
|
case ForgeDirection.WEST => GL11.glRotatef(-90, 0, 1, 0)
|
||||||
@ -137,7 +137,10 @@ object ScreenRenderer extends TileEntitySpecialRenderer with Callable[Int] with
|
|||||||
}
|
}
|
||||||
|
|
||||||
GL11.glEndList()
|
GL11.glEndList()
|
||||||
|
|
||||||
|
true
|
||||||
}
|
}
|
||||||
|
else GL11.glCallList(list)
|
||||||
|
|
||||||
private def playerDistanceSq() = {
|
private def playerDistanceSq() = {
|
||||||
val player = Minecraft.getMinecraft.thePlayer
|
val player = Minecraft.getMinecraft.thePlayer
|
||||||
@ -191,12 +194,12 @@ object ScreenRenderer extends TileEntitySpecialRenderer with Callable[Int] with
|
|||||||
def call = {
|
def call = {
|
||||||
val list = GLAllocation.generateDisplayLists(1)
|
val list = GLAllocation.generateDisplayLists(1)
|
||||||
screen.hasChanged = true // Force compilation.
|
screen.hasChanged = true // Force compilation.
|
||||||
compile(list)
|
|
||||||
list
|
list
|
||||||
}
|
}
|
||||||
|
|
||||||
def onRemoval(e: RemovalNotification[TileEntity, Int]) =
|
def onRemoval(e: RemovalNotification[TileEntity, Int]) {
|
||||||
GLAllocation.deleteDisplayLists(e.getValue)
|
GLAllocation.deleteDisplayLists(e.getValue)
|
||||||
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------- //
|
// ----------------------------------------------------------------------- //
|
||||||
// ITickHandler
|
// ITickHandler
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
package li.cil.oc.common
|
package li.cil.oc.common
|
||||||
|
|
||||||
object GuiType extends Enumeration {
|
object GuiType extends Enumeration {
|
||||||
val Case = Value("Case")
|
val Case, DiskDrive, Screen = Value
|
||||||
val DiskDrive = Value("DiskDrive")
|
|
||||||
val Screen = Value("Screen")
|
|
||||||
}
|
}
|
||||||
|
@ -1,39 +1,21 @@
|
|||||||
package li.cil.oc.common
|
package li.cil.oc.common
|
||||||
|
|
||||||
object PacketType extends Enumeration {
|
object PacketType extends Enumeration {
|
||||||
/**
|
|
||||||
* Computer running / stopped.
|
|
||||||
*
|
|
||||||
* Same as for screen, but for computer running state. The running state is
|
|
||||||
* used on the client side to display different textures based on whether the
|
|
||||||
* computer is running or not.
|
|
||||||
*/
|
|
||||||
val ComputerStateRequest = Value("ComputerStateRequest")
|
val ComputerStateRequest = Value("ComputerStateRequest")
|
||||||
val ComputerStateResponse = Value("ComputerStateResponse")
|
val ComputerStateResponse = Value("ComputerStateResponse")
|
||||||
|
|
||||||
/** Sent by power distributors for client display of average buffer fill. */
|
|
||||||
val PowerStateRequest = Value("PowerStateRequest")
|
val PowerStateRequest = Value("PowerStateRequest")
|
||||||
val PowerStateResponse = Value("PowerStateResponse")
|
val PowerStateResponse = Value("PowerStateResponse")
|
||||||
|
|
||||||
/** Sent by redstone capable blocks (e.g. computers). */
|
|
||||||
val RedstoneStateRequest = Value("RedstoneStateRequest")
|
val RedstoneStateRequest = Value("RedstoneStateRequest")
|
||||||
val RedstoneStateResponse = Value("RedstoneStateResponse")
|
val RedstoneStateResponse = Value("RedstoneStateResponse")
|
||||||
|
|
||||||
/** Sent by rotatable tile entities to notify clients of changes. */
|
|
||||||
val RotatableStateRequest = Value("RotatableStateRequest")
|
val RotatableStateRequest = Value("RotatableStateRequest")
|
||||||
val RotatableStateResponse = Value("RotatableStateResponse")
|
val RotatableStateResponse = Value("RotatableStateResponse")
|
||||||
|
|
||||||
/**
|
|
||||||
* Full buffer request / response.
|
|
||||||
*
|
|
||||||
* This is necessary when a tile entity containing a screen is created for
|
|
||||||
* the first time on the client side, for example, since tile entities are
|
|
||||||
* not automatically synchronized via read/write NBT.
|
|
||||||
*/
|
|
||||||
val ScreenBufferRequest = Value("ScreenBufferRequest")
|
val ScreenBufferRequest = Value("ScreenBufferRequest")
|
||||||
val ScreenBufferResponse = Value("ScreenBufferResponse")
|
val ScreenBufferResponse = Value("ScreenBufferResponse")
|
||||||
|
|
||||||
/** These are sent from the server to the client for partial updates. */
|
|
||||||
val ScreenColorChange = Value("ScreenColorChange")
|
val ScreenColorChange = Value("ScreenColorChange")
|
||||||
val ScreenCopy = Value("ScreenCopy")
|
val ScreenCopy = Value("ScreenCopy")
|
||||||
val ScreenDepthChange = Value("ScreenDepthChange")
|
val ScreenDepthChange = Value("ScreenDepthChange")
|
||||||
@ -42,11 +24,9 @@ object PacketType extends Enumeration {
|
|||||||
val ScreenResolutionChange = Value("ScreenResolutionChange")
|
val ScreenResolutionChange = Value("ScreenResolutionChange")
|
||||||
val ScreenSet = Value("ScreenSet")
|
val ScreenSet = Value("ScreenSet")
|
||||||
|
|
||||||
/** Sent by analyzer tool when used. */
|
|
||||||
val Analyze = Value("Analyze")
|
|
||||||
|
|
||||||
/** Sent by clients on keyboard input for computers. */
|
|
||||||
val KeyDown = Value("KeyDown")
|
val KeyDown = Value("KeyDown")
|
||||||
val KeyUp = Value("KeyUp")
|
val KeyUp = Value("KeyUp")
|
||||||
val Clipboard = Value("Clipboard")
|
val Clipboard = Value("Clipboard")
|
||||||
|
|
||||||
|
val Analyze = Value("Analyze")
|
||||||
}
|
}
|
@ -32,13 +32,8 @@ class Cable(val parent: SpecialDelegator) extends SpecialDelegate {
|
|||||||
|
|
||||||
// ----------------------------------------------------------------------- //
|
// ----------------------------------------------------------------------- //
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
override def setBlockBoundsBasedOnState(world: IBlockAccess, x: Int, y: Int, z: Int) {
|
override def setBlockBoundsBasedOnState(world: IBlockAccess, x: Int, y: Int, z: Int) {
|
||||||
val bounds = Cable.bounds(world, x, y, z)
|
parent.setBlockBounds(Cable.bounds(world, x, y, z))
|
||||||
parent.setBlockBounds(
|
|
||||||
bounds.minX.toFloat, bounds.minY.toFloat, bounds.minZ.toFloat,
|
|
||||||
bounds.maxX.toFloat, bounds.maxY.toFloat, bounds.maxZ.toFloat)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
package li.cil.oc.common.block
|
package li.cil.oc.common.block
|
||||||
|
|
||||||
import li.cil.oc.common.GuiType
|
import li.cil.oc.Config
|
||||||
import li.cil.oc.common.tileentity
|
import li.cil.oc.common.tileentity
|
||||||
import li.cil.oc.{Config, OpenComputers}
|
|
||||||
import net.minecraft.client.renderer.texture.IconRegister
|
import net.minecraft.client.renderer.texture.IconRegister
|
||||||
import net.minecraft.entity.player.EntityPlayer
|
import net.minecraft.entity.player.EntityPlayer
|
||||||
import net.minecraft.util.Icon
|
import net.minecraft.util.Icon
|
||||||
@ -10,7 +9,7 @@ import net.minecraft.world.IBlockAccess
|
|||||||
import net.minecraft.world.World
|
import net.minecraft.world.World
|
||||||
import net.minecraftforge.common.ForgeDirection
|
import net.minecraftforge.common.ForgeDirection
|
||||||
|
|
||||||
class Case(val parent: SimpleDelegator) extends SimpleDelegate {
|
class Case(val parent: SimpleDelegator) extends Computer with SimpleDelegate {
|
||||||
val unlocalizedName = "Case"
|
val unlocalizedName = "Case"
|
||||||
|
|
||||||
// ----------------------------------------------------------------------- //
|
// ----------------------------------------------------------------------- //
|
||||||
@ -52,48 +51,10 @@ class Case(val parent: SimpleDelegator) extends SimpleDelegate {
|
|||||||
|
|
||||||
// ----------------------------------------------------------------------- //
|
// ----------------------------------------------------------------------- //
|
||||||
|
|
||||||
override def hasTileEntity = true
|
|
||||||
|
|
||||||
override def createTileEntity(world: World) = Some(new tileentity.Case(world.isRemote))
|
override def createTileEntity(world: World) = Some(new tileentity.Case(world.isRemote))
|
||||||
|
|
||||||
// ----------------------------------------------------------------------- //
|
// ----------------------------------------------------------------------- //
|
||||||
|
|
||||||
override def canConnectRedstone(world: IBlockAccess, x: Int, y: Int, z: Int, side: ForgeDirection) =
|
|
||||||
world.getBlockTileEntity(x, y, z).asInstanceOf[tileentity.Case].canConnectRedstone(side)
|
|
||||||
|
|
||||||
override def isProvidingStrongPower(world: IBlockAccess, x: Int, y: Int, z: Int, side: ForgeDirection) =
|
|
||||||
isProvidingWeakPower(world, x, y, z, side)
|
|
||||||
|
|
||||||
override def isProvidingWeakPower(world: IBlockAccess, x: Int, y: Int, z: Int, side: ForgeDirection) =
|
|
||||||
world.getBlockTileEntity(x, y, z).asInstanceOf[tileentity.Case].output(side)
|
|
||||||
|
|
||||||
override def onBlockPreDestroy(world: World, x: Int, y: Int, z: Int) =
|
|
||||||
if (!world.isRemote) world.getBlockTileEntity(x, y, z) match {
|
|
||||||
case computer: tileentity.Case =>
|
|
||||||
computer.instance.stop()
|
|
||||||
computer.dropContent(world, x, y, z)
|
|
||||||
case _ => // Ignore.
|
|
||||||
}
|
|
||||||
|
|
||||||
override def onBlockActivated(world: World, x: Int, y: Int, z: Int, player: EntityPlayer,
|
|
||||||
side: ForgeDirection, hitX: Float, hitY: Float, hitZ: Float) = {
|
|
||||||
if (!player.isSneaking) {
|
|
||||||
// Start the computer if it isn't already running and open the GUI.
|
|
||||||
if (!world.isRemote) {
|
|
||||||
world.getBlockTileEntity(x, y, z).asInstanceOf[tileentity.Case].instance.start()
|
|
||||||
}
|
|
||||||
player.openGui(OpenComputers, GuiType.Case.id, world, x, y, z)
|
|
||||||
true
|
|
||||||
}
|
|
||||||
else false
|
|
||||||
}
|
|
||||||
|
|
||||||
override def onNeighborBlockChange(world: World, x: Int, y: Int, z: Int, blockId: Int) =
|
|
||||||
world.getBlockTileEntity(x, y, z) match {
|
|
||||||
case computer: tileentity.Case => computer.checkRedstoneInputChanged()
|
|
||||||
case _ => // Ignore.
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO do we have to manually sync the client since we can only check this on the server side?
|
// TODO do we have to manually sync the client since we can only check this on the server side?
|
||||||
override def onBlockRemovedBy(world: World, x: Int, y: Int, z: Int, player: EntityPlayer) =
|
override def onBlockRemovedBy(world: World, x: Int, y: Int, z: Int, player: EntityPlayer) =
|
||||||
world.getBlockTileEntity(x, y, z) match {
|
world.getBlockTileEntity(x, y, z) match {
|
||||||
|
47
li/cil/oc/common/block/Computer.scala
Normal file
47
li/cil/oc/common/block/Computer.scala
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
package li.cil.oc.common.block
|
||||||
|
|
||||||
|
import li.cil.oc.OpenComputers
|
||||||
|
import li.cil.oc.common.{GuiType, tileentity}
|
||||||
|
import net.minecraft.entity.player.EntityPlayer
|
||||||
|
import net.minecraft.world.{World, IBlockAccess}
|
||||||
|
import net.minecraftforge.common.ForgeDirection
|
||||||
|
|
||||||
|
abstract class Computer extends Delegate {
|
||||||
|
override def hasTileEntity = true
|
||||||
|
|
||||||
|
override def canConnectRedstone(world: IBlockAccess, x: Int, y: Int, z: Int, side: ForgeDirection) =
|
||||||
|
world.getBlockTileEntity(x, y, z).asInstanceOf[tileentity.Computer].isOutputEnabled
|
||||||
|
|
||||||
|
override def isProvidingStrongPower(world: IBlockAccess, x: Int, y: Int, z: Int, side: ForgeDirection) =
|
||||||
|
isProvidingWeakPower(world, x, y, z, side)
|
||||||
|
|
||||||
|
override def isProvidingWeakPower(world: IBlockAccess, x: Int, y: Int, z: Int, side: ForgeDirection) =
|
||||||
|
world.getBlockTileEntity(x, y, z).asInstanceOf[tileentity.Computer].output(side)
|
||||||
|
|
||||||
|
override def onBlockPreDestroy(world: World, x: Int, y: Int, z: Int) =
|
||||||
|
if (!world.isRemote) world.getBlockTileEntity(x, y, z) match {
|
||||||
|
case computer: tileentity.Computer =>
|
||||||
|
computer.instance.stop()
|
||||||
|
computer.dropContent(world, x, y, z)
|
||||||
|
case _ => // Ignore.
|
||||||
|
}
|
||||||
|
|
||||||
|
override def onBlockActivated(world: World, x: Int, y: Int, z: Int, player: EntityPlayer,
|
||||||
|
side: ForgeDirection, hitX: Float, hitY: Float, hitZ: Float) = {
|
||||||
|
if (!player.isSneaking) {
|
||||||
|
// Start the computer if it isn't already running and open the GUI.
|
||||||
|
if (!world.isRemote) {
|
||||||
|
world.getBlockTileEntity(x, y, z).asInstanceOf[tileentity.Computer].instance.start()
|
||||||
|
}
|
||||||
|
player.openGui(OpenComputers, GuiType.Case.id, world, x, y, z)
|
||||||
|
true
|
||||||
|
}
|
||||||
|
else false
|
||||||
|
}
|
||||||
|
|
||||||
|
override def onNeighborBlockChange(world: World, x: Int, y: Int, z: Int, blockId: Int) =
|
||||||
|
world.getBlockTileEntity(x, y, z) match {
|
||||||
|
case computer: tileentity.Computer => computer.checkRedstoneInputChanged()
|
||||||
|
case _ => // Ignore.
|
||||||
|
}
|
||||||
|
}
|
@ -13,6 +13,7 @@ import net.minecraft.entity.player.EntityPlayer
|
|||||||
import net.minecraft.entity.{EnumCreatureType, Entity, EntityLivingBase}
|
import net.minecraft.entity.{EnumCreatureType, Entity, EntityLivingBase}
|
||||||
import net.minecraft.item.ItemStack
|
import net.minecraft.item.ItemStack
|
||||||
import net.minecraft.tileentity.TileEntity
|
import net.minecraft.tileentity.TileEntity
|
||||||
|
import net.minecraft.util.AxisAlignedBB
|
||||||
import net.minecraft.world.IBlockAccess
|
import net.minecraft.world.IBlockAccess
|
||||||
import net.minecraft.world.World
|
import net.minecraft.world.World
|
||||||
import net.minecraftforge.common.ForgeDirection
|
import net.minecraftforge.common.ForgeDirection
|
||||||
@ -284,6 +285,12 @@ class Delegator[Child <: Delegate](id: Int, name: String) extends Block(id, Mate
|
|||||||
case _ => false
|
case _ => false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def setBlockBounds(bounds: AxisAlignedBB) {
|
||||||
|
setBlockBounds(
|
||||||
|
bounds.minX.toFloat, bounds.minY.toFloat, bounds.minZ.toFloat,
|
||||||
|
bounds.maxX.toFloat, bounds.maxY.toFloat, bounds.maxZ.toFloat)
|
||||||
|
}
|
||||||
|
|
||||||
override def setBlockBoundsBasedOnState(world: IBlockAccess, x: Int, y: Int, z: Int) =
|
override def setBlockBoundsBasedOnState(world: IBlockAccess, x: Int, y: Int, z: Int) =
|
||||||
subBlock(world, x, y, z) match {
|
subBlock(world, x, y, z) match {
|
||||||
case Some(subBlock) => subBlock.setBlockBoundsBasedOnState(world, x, y, z)
|
case Some(subBlock) => subBlock.setBlockBoundsBasedOnState(world, x, y, z)
|
||||||
|
@ -1,14 +1,19 @@
|
|||||||
package li.cil.oc.common.block
|
package li.cil.oc.common.block
|
||||||
|
|
||||||
import li.cil.oc.common.tileentity
|
import li.cil.oc.common.tileentity
|
||||||
import net.minecraft.world.World
|
import net.minecraft.world.{IBlockAccess, World}
|
||||||
|
|
||||||
class Robot(val parent: SpecialDelegator) extends SpecialDelegate {
|
class Robot(val parent: SpecialDelegator) extends Computer with SpecialDelegate {
|
||||||
val unlocalizedName = "Robot"
|
val unlocalizedName = "Robot"
|
||||||
|
|
||||||
|
override def createTileEntity(world: World) = Some(new tileentity.Robot)
|
||||||
|
|
||||||
// ----------------------------------------------------------------------- //
|
// ----------------------------------------------------------------------- //
|
||||||
|
|
||||||
override def hasTileEntity = true
|
// override def setBlockBoundsBasedOnState(world: IBlockAccess, x: Int, y: Int, z: Int) {
|
||||||
|
// world.getBlockTileEntity(x, y, z) match {
|
||||||
override def createTileEntity(world: World) = Some(new tileentity.Robot)
|
// case robot: tileentity.Robot => parent.setBlockBounds(robot.bounds)
|
||||||
|
// case _ => super.setBlockBoundsBasedOnState(world, x, y, z)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
@ -2,10 +2,12 @@ package li.cil.oc.common.component
|
|||||||
|
|
||||||
import li.cil.oc.api.network.Visibility
|
import li.cil.oc.api.network.Visibility
|
||||||
import li.cil.oc.common.component
|
import li.cil.oc.common.component
|
||||||
|
import li.cil.oc.common.tileentity
|
||||||
import li.cil.oc.common.tileentity.TileEntity
|
import li.cil.oc.common.tileentity.TileEntity
|
||||||
import li.cil.oc.util.{Persistable, PackedColor, TextBuffer}
|
import li.cil.oc.util.{Persistable, PackedColor, TextBuffer}
|
||||||
import li.cil.oc.{api, Config}
|
import li.cil.oc.{api, Config}
|
||||||
import net.minecraft.nbt.NBTTagCompound
|
import net.minecraft.nbt.NBTTagCompound
|
||||||
|
import scala.collection.convert.WrapAsScala._
|
||||||
|
|
||||||
class Buffer(val owner: Buffer.Environment) extends Persistable {
|
class Buffer(val owner: Buffer.Environment) extends Persistable {
|
||||||
val buffer = new TextBuffer(maxResolution, maxDepth)
|
val buffer = new TextBuffer(maxResolution, maxDepth)
|
||||||
@ -99,6 +101,22 @@ class Buffer(val owner: Buffer.Environment) extends Persistable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override def save(nbt: NBTTagCompound) = {
|
override def save(nbt: NBTTagCompound) = {
|
||||||
|
// Happy thread synchronization hack! Here's the problem: GPUs allow direct
|
||||||
|
// calls for modifying screens to give a more responsive experience. This
|
||||||
|
// causes the following problem: when saving, if the screen is saved first,
|
||||||
|
// then the executor runs in parallel and changes the screen *before* the
|
||||||
|
// server thread begins saving that computer, the saved computer will think
|
||||||
|
// it changed the screen, although the saved screen wasn't. To avoid that we
|
||||||
|
// wait for all computers the screen is connected to to finish their current
|
||||||
|
// execution and pausing them (which will make them resume in the next tick
|
||||||
|
// when their update() runs).
|
||||||
|
if (owner.node.network != null) {
|
||||||
|
for (node <- owner.node.reachableNodes) node.host match {
|
||||||
|
case computer: tileentity.Computer => computer.instance.pause()
|
||||||
|
case _ =>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val screenNbt = new NBTTagCompound
|
val screenNbt = new NBTTagCompound
|
||||||
buffer.save(screenNbt)
|
buffer.save(screenNbt)
|
||||||
nbt.setCompoundTag(Config.namespace + "screen", screenNbt)
|
nbt.setCompoundTag(Config.namespace + "screen", screenNbt)
|
||||||
|
@ -5,7 +5,6 @@ import li.cil.oc.api.driver.Slot
|
|||||||
import li.cil.oc.server.component
|
import li.cil.oc.server.component
|
||||||
import li.cil.oc.server.driver.Registry
|
import li.cil.oc.server.driver.Registry
|
||||||
import net.minecraft.item.ItemStack
|
import net.minecraft.item.ItemStack
|
||||||
import net.minecraftforge.common.ForgeDirection
|
|
||||||
|
|
||||||
class Case(isClient: Boolean) extends Computer {
|
class Case(isClient: Boolean) extends Computer {
|
||||||
def this() = this(false)
|
def this() = this(false)
|
||||||
@ -16,12 +15,6 @@ class Case(isClient: Boolean) extends Computer {
|
|||||||
|
|
||||||
// ----------------------------------------------------------------------- //
|
// ----------------------------------------------------------------------- //
|
||||||
|
|
||||||
override def updateEntity() {
|
|
||||||
super.updateEntity()
|
|
||||||
}
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------- //
|
|
||||||
|
|
||||||
def getInvName = Config.namespace + "container.Case"
|
def getInvName = Config.namespace + "container.Case"
|
||||||
|
|
||||||
def getSizeInventory = 8
|
def getSizeInventory = 8
|
||||||
@ -34,8 +27,4 @@ class Case(isClient: Boolean) extends Computer {
|
|||||||
case (6 | 7, Some(driver)) => driver.slot(item) == Slot.HardDiskDrive
|
case (6 | 7, Some(driver)) => driver.slot(item) == Slot.HardDiskDrive
|
||||||
case _ => false // Invalid slot.
|
case _ => false // Invalid slot.
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------- //
|
|
||||||
|
|
||||||
def canConnectRedstone(side: ForgeDirection) = isOutputEnabled
|
|
||||||
}
|
}
|
@ -54,7 +54,7 @@ trait Inventory extends TileEntity with IInventory with Persistable {
|
|||||||
|
|
||||||
def isUseableByPlayer(player: EntityPlayer) =
|
def isUseableByPlayer(player: EntityPlayer) =
|
||||||
world.getBlockTileEntity(x, y, z) match {
|
world.getBlockTileEntity(x, y, z) match {
|
||||||
case t: TileEntity if t == this => player.getDistanceSq(x + 0.5, y + 0.5, z + 0.5) < 64
|
case t: TileEntity if t == this => player.getDistanceSq(x + 0.5, y + 0.5, z + 0.5) <= 64
|
||||||
case _ => false
|
case _ => false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,7 +73,7 @@ class Keyboard extends Environment with Rotatable {
|
|||||||
|
|
||||||
private def isUseableByPlayer(p: EntityPlayer) =
|
private def isUseableByPlayer(p: EntityPlayer) =
|
||||||
world.getBlockTileEntity(x, y, z) == this &&
|
world.getBlockTileEntity(x, y, z) == this &&
|
||||||
p.getDistanceSq(x + 0.5, y + 0.5, z + 0.5) < 64
|
p.getDistanceSq(x + 0.5, y + 0.5, z + 0.5) <= 64
|
||||||
}
|
}
|
||||||
|
|
||||||
object Keyboard extends IPlayerTracker {
|
object Keyboard extends IPlayerTracker {
|
||||||
|
@ -47,36 +47,42 @@ class PowerDistributor extends Environment with Analyzable {
|
|||||||
// ----------------------------------------------------------------------- //
|
// ----------------------------------------------------------------------- //
|
||||||
|
|
||||||
def changeBuffer(delta: Double): Boolean = {
|
def changeBuffer(delta: Double): Boolean = {
|
||||||
if (delta != 0) {
|
if (delta != 0) this.synchronized {
|
||||||
val oldBuffer = globalBuffer
|
val oldBuffer = globalBuffer
|
||||||
globalBuffer = (globalBuffer + delta) max 0 min globalBufferSize
|
globalBuffer = (globalBuffer + delta) max 0 min globalBufferSize
|
||||||
if (globalBuffer != oldBuffer) {
|
if (globalBuffer != oldBuffer) {
|
||||||
dirty = true
|
dirty = true
|
||||||
if (delta < 0) {
|
if (delta < 0) {
|
||||||
var remaining = -delta
|
var remaining = -delta
|
||||||
for (connector <- buffers if connector.localBuffer > 0) {
|
for (connector <- buffers) {
|
||||||
if (connector.localBuffer < remaining) {
|
connector.synchronized(if (connector.localBuffer > 0) {
|
||||||
remaining -= connector.localBuffer
|
connector.dirty = true
|
||||||
connector.localBuffer = 0
|
if (connector.localBuffer < remaining) {
|
||||||
}
|
remaining -= connector.localBuffer
|
||||||
else {
|
connector.localBuffer = 0
|
||||||
connector.changeBuffer(-remaining)
|
}
|
||||||
return true
|
else {
|
||||||
}
|
connector.localBuffer -= remaining
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (delta > 0) {
|
else if (delta > 0) {
|
||||||
var remaining = delta
|
var remaining = delta
|
||||||
for (connector <- buffers if connector.localBuffer < connector.localBufferSize) {
|
for (connector <- buffers) {
|
||||||
val space = connector.localBufferSize - connector.localBuffer
|
connector.synchronized(if (connector.localBuffer < connector.localBufferSize) {
|
||||||
if (space < remaining) {
|
connector.dirty = true
|
||||||
remaining -= space
|
val space = connector.localBufferSize - connector.localBuffer
|
||||||
connector.localBuffer = connector.localBufferSize
|
if (space < remaining) {
|
||||||
}
|
remaining -= space
|
||||||
else {
|
connector.localBuffer = connector.localBufferSize
|
||||||
connector.changeBuffer(remaining)
|
}
|
||||||
return true
|
else {
|
||||||
}
|
connector.localBuffer += remaining
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -106,10 +112,11 @@ class PowerDistributor extends Environment with Analyzable {
|
|||||||
super.onConnect(node)
|
super.onConnect(node)
|
||||||
if (node == this.node) {
|
if (node == this.node) {
|
||||||
for (node <- node.network.nodes) node match {
|
for (node <- node.network.nodes) node match {
|
||||||
case connector: Connector if connector.localBufferSize > 0 =>
|
case connector: Connector if connector.localBufferSize > 0 => this.synchronized {
|
||||||
buffers += connector
|
buffers += connector
|
||||||
globalBuffer += connector.localBuffer
|
globalBuffer += connector.localBuffer
|
||||||
globalBufferSize += connector.localBufferSize
|
globalBufferSize += connector.localBufferSize
|
||||||
|
}
|
||||||
case _ => node.host match {
|
case _ => node.host match {
|
||||||
case distributor: PowerDistributor => distributors += distributor
|
case distributor: PowerDistributor => distributors += distributor
|
||||||
case _ =>
|
case _ =>
|
||||||
@ -118,11 +125,12 @@ class PowerDistributor extends Environment with Analyzable {
|
|||||||
dirty = true
|
dirty = true
|
||||||
}
|
}
|
||||||
else node match {
|
else node match {
|
||||||
case connector: Connector =>
|
case connector: Connector => this.synchronized {
|
||||||
buffers += connector
|
buffers += connector
|
||||||
globalBuffer += connector.localBuffer
|
globalBuffer += connector.localBuffer
|
||||||
globalBufferSize += connector.localBufferSize
|
globalBufferSize += connector.localBufferSize
|
||||||
dirty = true
|
dirty = true
|
||||||
|
}
|
||||||
case _ => node.host match {
|
case _ => node.host match {
|
||||||
case distributor: PowerDistributor => distributors += distributor
|
case distributor: PowerDistributor => distributors += distributor
|
||||||
case _ =>
|
case _ =>
|
||||||
@ -132,7 +140,7 @@ class PowerDistributor extends Environment with Analyzable {
|
|||||||
|
|
||||||
override def onDisconnect(node: Node) {
|
override def onDisconnect(node: Node) {
|
||||||
super.onDisconnect(node)
|
super.onDisconnect(node)
|
||||||
if (node == this.node) {
|
if (node == this.node) this.synchronized {
|
||||||
buffers.clear()
|
buffers.clear()
|
||||||
distributors.clear()
|
distributors.clear()
|
||||||
globalBuffer = 0
|
globalBuffer = 0
|
||||||
@ -140,11 +148,12 @@ class PowerDistributor extends Environment with Analyzable {
|
|||||||
average = -1
|
average = -1
|
||||||
}
|
}
|
||||||
else node match {
|
else node match {
|
||||||
case connector: Connector =>
|
case connector: Connector => this.synchronized {
|
||||||
buffers -= connector
|
buffers -= connector
|
||||||
globalBuffer -= connector.localBuffer
|
globalBuffer -= connector.localBuffer
|
||||||
globalBufferSize -= connector.localBufferSize
|
globalBufferSize -= connector.localBufferSize
|
||||||
dirty = true
|
dirty = true
|
||||||
|
}
|
||||||
case _ => node.host match {
|
case _ => node.host match {
|
||||||
case distributor: PowerDistributor => distributors -= distributor
|
case distributor: PowerDistributor => distributors -= distributor
|
||||||
case _ =>
|
case _ =>
|
||||||
@ -163,7 +172,7 @@ class PowerDistributor extends Environment with Analyzable {
|
|||||||
})
|
})
|
||||||
average = if (globalBufferSize > 0) globalBuffer / globalBufferSize else 0
|
average = if (globalBufferSize > 0) globalBuffer / globalBufferSize else 0
|
||||||
val shouldSend = (lastSentAverage - average).abs > 0.05
|
val shouldSend = (lastSentAverage - average).abs > 0.05
|
||||||
for (distributor <- distributors) {
|
for (distributor <- distributors) distributor.synchronized {
|
||||||
distributor.dirty = false
|
distributor.dirty = false
|
||||||
distributor.globalBuffer = sumBuffer
|
distributor.globalBuffer = sumBuffer
|
||||||
distributor.globalBufferSize = sumBufferSize
|
distributor.globalBufferSize = sumBufferSize
|
||||||
|
@ -1,15 +1,88 @@
|
|||||||
package li.cil.oc.common.tileentity
|
package li.cil.oc.common.tileentity
|
||||||
|
|
||||||
|
import li.cil.oc.Config
|
||||||
|
import li.cil.oc.api.driver.Slot
|
||||||
|
import li.cil.oc.api.network.{Context, Arguments, LuaCallback}
|
||||||
import li.cil.oc.server.component
|
import li.cil.oc.server.component
|
||||||
|
import li.cil.oc.server.driver.Registry
|
||||||
import net.minecraft.item.ItemStack
|
import net.minecraft.item.ItemStack
|
||||||
|
|
||||||
class Robot extends Computer with ComponentInventory with Rotatable with Redstone {
|
class Robot(isClient: Boolean) extends Computer {
|
||||||
|
def this() = this(false)
|
||||||
|
|
||||||
val instance = if (true) null else new component.Computer(this)
|
// ----------------------------------------------------------------------- //
|
||||||
|
|
||||||
def getInvName = ""
|
val instance = if (isClient) null else new component.Computer(this)
|
||||||
|
|
||||||
def getSizeInventory = 0
|
// ----------------------------------------------------------------------- //
|
||||||
|
|
||||||
def isItemValidForSlot(i: Int, itemstack: ItemStack) = false
|
//def bounds =
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------- //
|
||||||
|
|
||||||
|
@LuaCallback("attack")
|
||||||
|
def attack(context: Context, args: Arguments): Array[AnyRef] = {
|
||||||
|
// Attack with equipped tool.
|
||||||
|
val side = args.checkInteger(0)
|
||||||
|
null
|
||||||
|
}
|
||||||
|
|
||||||
|
@LuaCallback("use")
|
||||||
|
def use(context: Context, args: Arguments): Array[AnyRef] = {
|
||||||
|
// Use equipped tool (e.g. dig, chop, till).
|
||||||
|
val side = args.checkInteger(0)
|
||||||
|
val sneaky = args.checkBoolean(1)
|
||||||
|
null
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------- //
|
||||||
|
|
||||||
|
@LuaCallback("check")
|
||||||
|
def check(context: Context, args: Arguments): Array[AnyRef] = {
|
||||||
|
// Test for blocks or entities.
|
||||||
|
null
|
||||||
|
}
|
||||||
|
|
||||||
|
@LuaCallback("collect")
|
||||||
|
def collect(context: Context, args: Arguments): Array[AnyRef] = {
|
||||||
|
// Pick up items lying around.
|
||||||
|
null
|
||||||
|
}
|
||||||
|
|
||||||
|
@LuaCallback("compare")
|
||||||
|
def compare(context: Context, args: Arguments): Array[AnyRef] = {
|
||||||
|
// Compare block to item selected in inventory.
|
||||||
|
null
|
||||||
|
}
|
||||||
|
|
||||||
|
@LuaCallback("drop")
|
||||||
|
def drop(context: Context, args: Arguments): Array[AnyRef] = {
|
||||||
|
// Drop items from inventory.
|
||||||
|
null
|
||||||
|
}
|
||||||
|
|
||||||
|
@LuaCallback("move")
|
||||||
|
def move(context: Context, args: Arguments): Array[AnyRef] = {
|
||||||
|
// Try to move in the specified direction.
|
||||||
|
null
|
||||||
|
}
|
||||||
|
|
||||||
|
@LuaCallback("place")
|
||||||
|
def place(context: Context, args: Arguments): Array[AnyRef] = {
|
||||||
|
// Place block item selected in inventory.
|
||||||
|
null
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------- //
|
||||||
|
|
||||||
|
def getInvName = Config.namespace + "container.Robot"
|
||||||
|
|
||||||
|
def getSizeInventory = 12
|
||||||
|
|
||||||
|
def isItemValidForSlot(slot: Int, item: ItemStack) = (slot, Registry.driverFor(item)) match {
|
||||||
|
case (0, Some(driver)) => driver.slot(item) == Slot.Tool
|
||||||
|
case (1 | 2, Some(driver)) => driver.slot(item) == Slot.Card
|
||||||
|
case (3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11, _) => true // Normal inventory.
|
||||||
|
case _ => false // Invalid slot.
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,28 +23,28 @@ class Carriage(controller: AnyRef) extends ManagedComponent {
|
|||||||
|
|
||||||
// ----------------------------------------------------------------------- //
|
// ----------------------------------------------------------------------- //
|
||||||
|
|
||||||
@LuaCallback(value = "move", direct = true)
|
@LuaCallback("move")
|
||||||
def move(context: Context, args: Arguments): Array[AnyRef] = this.synchronized {
|
def move(context: Context, args: Arguments): Array[AnyRef] = {
|
||||||
direction = checkDirection(args)
|
direction = checkDirection(args)
|
||||||
simulating = if (args.count > 1) args.checkBoolean(1) else false
|
simulating = if (args.count > 1) args.checkBoolean(1) else false
|
||||||
shouldMove = true
|
shouldMove = true
|
||||||
result(true)
|
result(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
@LuaCallback(value = "simulate", direct = true)
|
@LuaCallback("simulate")
|
||||||
def simulate(context: Context, args: Arguments): Array[AnyRef] = this.synchronized {
|
def simulate(context: Context, args: Arguments): Array[AnyRef] = {
|
||||||
direction = checkDirection(args)
|
direction = checkDirection(args)
|
||||||
simulating = true
|
simulating = true
|
||||||
shouldMove = true
|
shouldMove = true
|
||||||
result(true)
|
result(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
@LuaCallback(value = "getAnchored", direct = true)
|
@LuaCallback("getAnchored")
|
||||||
def getAnchored(context: Context, args: Arguments): Array[AnyRef] =
|
def getAnchored(context: Context, args: Arguments): Array[AnyRef] =
|
||||||
this.synchronized(result(anchored))
|
result(anchored)
|
||||||
|
|
||||||
@LuaCallback(value = "setAnchored", direct = true)
|
@LuaCallback("setAnchored")
|
||||||
def setAnchored(context: Context, args: Arguments): Array[AnyRef] = this.synchronized {
|
def setAnchored(context: Context, args: Arguments): Array[AnyRef] = {
|
||||||
anchored = args.checkBoolean(0)
|
anchored = args.checkBoolean(0)
|
||||||
result(anchored)
|
result(anchored)
|
||||||
}
|
}
|
||||||
@ -72,7 +72,7 @@ class Carriage(controller: AnyRef) extends ManagedComponent {
|
|||||||
|
|
||||||
override def update() {
|
override def update() {
|
||||||
super.update()
|
super.update()
|
||||||
if (shouldMove) this.synchronized {
|
if (shouldMove) {
|
||||||
shouldMove = false
|
shouldMove = false
|
||||||
moving = true
|
moving = true
|
||||||
try {
|
try {
|
||||||
@ -104,7 +104,7 @@ class Carriage(controller: AnyRef) extends ManagedComponent {
|
|||||||
|
|
||||||
// ----------------------------------------------------------------------- //
|
// ----------------------------------------------------------------------- //
|
||||||
|
|
||||||
override def save(nbt: NBTTagCompound) {
|
override def save(nbt: NBTTagCompound) = {
|
||||||
super.save(nbt)
|
super.save(nbt)
|
||||||
nbt.setBoolean("moving", moving)
|
nbt.setBoolean("moving", moving)
|
||||||
nbt.setBoolean("anchored", anchored)
|
nbt.setBoolean("anchored", anchored)
|
||||||
|
@ -97,6 +97,10 @@ class Computer(val owner: tileentity.Computer) extends Persistable with Runnable
|
|||||||
true
|
true
|
||||||
})
|
})
|
||||||
|
|
||||||
|
def pause() = if (state.synchronized(isRunning && !isStopping)) {
|
||||||
|
this.synchronized(if (!isStopping) state.push(Computer.State.Paused))
|
||||||
|
}
|
||||||
|
|
||||||
def stop() = state.synchronized(state.top match {
|
def stop() = state.synchronized(state.top match {
|
||||||
case Computer.State.Stopped | Computer.State.Stopping => false
|
case Computer.State.Stopped | Computer.State.Stopping => false
|
||||||
case _ => state.push(Computer.State.Stopping); true
|
case _ => state.push(Computer.State.Stopping); true
|
||||||
@ -104,6 +108,8 @@ class Computer(val owner: tileentity.Computer) extends Persistable with Runnable
|
|||||||
|
|
||||||
def isRunning = state.synchronized(state.top != Computer.State.Stopped)
|
def isRunning = state.synchronized(state.top != Computer.State.Stopped)
|
||||||
|
|
||||||
|
def isStopping = state.synchronized(state.top == Computer.State.Stopping)
|
||||||
|
|
||||||
// ----------------------------------------------------------------------- //
|
// ----------------------------------------------------------------------- //
|
||||||
|
|
||||||
def isUser(player: String) = !Config.canComputersBeOwned ||
|
def isUser(player: String) = !Config.canComputersBeOwned ||
|
||||||
@ -245,6 +251,11 @@ class Computer(val owner: tileentity.Computer) extends Persistable with Runnable
|
|||||||
assert(lua.getTop == 2)
|
assert(lua.getTop == 2)
|
||||||
assert(lua.isThread(1))
|
assert(lua.isThread(1))
|
||||||
assert(lua.isFunction(2))
|
assert(lua.isFunction(2))
|
||||||
|
// Clear direct call limits again, just to be on the safe side...
|
||||||
|
// Theoretically it'd be possible for the executor to do some direct
|
||||||
|
// calls between the clear and the state check, which could in turn
|
||||||
|
// make this synchronized call fail due the limit still being maxed.
|
||||||
|
callCounts.clear()
|
||||||
// We switch into running state, since we'll behave as though the call
|
// We switch into running state, since we'll behave as though the call
|
||||||
// were performed from our executor thread.
|
// were performed from our executor thread.
|
||||||
switchTo(Computer.State.Running)
|
switchTo(Computer.State.Running)
|
||||||
@ -931,18 +942,8 @@ class Computer(val owner: tileentity.Computer) extends Persistable with Runnable
|
|||||||
|
|
||||||
lua.setGlobal("component")
|
lua.setGlobal("component")
|
||||||
|
|
||||||
// Run the boot script. This sets up the permanent value tables as
|
|
||||||
// well as making the functions used for persisting/unpersisting
|
|
||||||
// available as globals. It also wraps the message sending functions
|
|
||||||
// so that they yield a closure doing the actual call so that that
|
|
||||||
// message call can be performed in a synchronized fashion.
|
|
||||||
// lua.load(classOf[Computer].getResourceAsStream(Config.scriptPath + "boot.lua"), "=boot", "t")
|
|
||||||
// lua.call(0, 0)
|
|
||||||
initPerms()
|
initPerms()
|
||||||
|
|
||||||
// Load the basic kernel which sets up the sandbox, loads the init script
|
|
||||||
// and then runs it in a coroutine with a debug hook checking for
|
|
||||||
// timeouts.
|
|
||||||
lua.load(classOf[Computer].getResourceAsStream(Config.scriptPath + "kernel.lua"), "=kernel", "t")
|
lua.load(classOf[Computer].getResourceAsStream(Config.scriptPath + "kernel.lua"), "=kernel", "t")
|
||||||
lua.newThread() // Left as the first value on the stack.
|
lua.newThread() // Left as the first value on the stack.
|
||||||
|
|
||||||
@ -1066,13 +1067,16 @@ class Computer(val owner: tileentity.Computer) extends Persistable with Runnable
|
|||||||
future = None
|
future = None
|
||||||
|
|
||||||
val enterState = state.synchronized {
|
val enterState = state.synchronized {
|
||||||
|
if (state.top == Computer.State.Stopped ||
|
||||||
|
state.top == Computer.State.Stopping ||
|
||||||
|
state.top == Computer.State.Paused) {
|
||||||
|
return
|
||||||
|
}
|
||||||
// See if the game appears to be paused, in which case we also pause.
|
// See if the game appears to be paused, in which case we also pause.
|
||||||
if (System.currentTimeMillis - lastUpdate > 100) {
|
if (System.currentTimeMillis - lastUpdate > 100) {
|
||||||
state.push(Computer.State.Paused)
|
state.push(Computer.State.Paused)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (state.top == Computer.State.Stopping)
|
|
||||||
return
|
|
||||||
switchTo(Computer.State.Running)
|
switchTo(Computer.State.Running)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,11 +19,10 @@ class FileSystem(val fileSystem: api.fs.FileSystem, var label: Label) extends Ma
|
|||||||
// ----------------------------------------------------------------------- //
|
// ----------------------------------------------------------------------- //
|
||||||
|
|
||||||
@LuaCallback(value = "getLabel", direct = true)
|
@LuaCallback(value = "getLabel", direct = true)
|
||||||
def getLabel(context: Context, args: Arguments): Array[AnyRef] =
|
def getLabel(context: Context, args: Arguments): Array[AnyRef] = result(label.getLabel)
|
||||||
this.synchronized(result(label.getLabel))
|
|
||||||
|
|
||||||
@LuaCallback(value = "setLabel", direct = true)
|
@LuaCallback("setLabel")
|
||||||
def setLabel(context: Context, args: Arguments): Array[AnyRef] = this.synchronized {
|
def setLabel(context: Context, args: Arguments): Array[AnyRef] = {
|
||||||
if (label == null) throw new Exception("filesystem does not support labeling")
|
if (label == null) throw new Exception("filesystem does not support labeling")
|
||||||
if (args.checkAny(0) == null) label.setLabel(null)
|
if (args.checkAny(0) == null) label.setLabel(null)
|
||||||
else label.setLabel(args.checkString(0))
|
else label.setLabel(args.checkString(0))
|
||||||
@ -31,12 +30,12 @@ class FileSystem(val fileSystem: api.fs.FileSystem, var label: Label) extends Ma
|
|||||||
}
|
}
|
||||||
|
|
||||||
@LuaCallback(value = "isReadOnly", direct = true)
|
@LuaCallback(value = "isReadOnly", direct = true)
|
||||||
def isReadOnly(context: Context, args: Arguments): Array[AnyRef] = fileSystem.synchronized {
|
def isReadOnly(context: Context, args: Arguments): Array[AnyRef] = {
|
||||||
result(fileSystem.isReadOnly)
|
result(fileSystem.isReadOnly)
|
||||||
}
|
}
|
||||||
|
|
||||||
@LuaCallback(value = "spaceTotal", direct = true)
|
@LuaCallback(value = "spaceTotal", direct = true)
|
||||||
def spaceTotal(context: Context, args: Arguments): Array[AnyRef] = fileSystem.synchronized {
|
def spaceTotal(context: Context, args: Arguments): Array[AnyRef] = {
|
||||||
val space = fileSystem.spaceTotal
|
val space = fileSystem.spaceTotal
|
||||||
if (space < 0)
|
if (space < 0)
|
||||||
Array("unlimited")
|
Array("unlimited")
|
||||||
@ -45,59 +44,59 @@ class FileSystem(val fileSystem: api.fs.FileSystem, var label: Label) extends Ma
|
|||||||
}
|
}
|
||||||
|
|
||||||
@LuaCallback(value = "spaceUsed", direct = true)
|
@LuaCallback(value = "spaceUsed", direct = true)
|
||||||
def spaceUsed(context: Context, args: Arguments): Array[AnyRef] = fileSystem.synchronized {
|
def spaceUsed(context: Context, args: Arguments): Array[AnyRef] = {
|
||||||
result(fileSystem.spaceUsed)
|
result(fileSystem.spaceUsed)
|
||||||
}
|
}
|
||||||
|
|
||||||
@LuaCallback(value = "exists", direct = true)
|
@LuaCallback(value = "exists", direct = true)
|
||||||
def exists(context: Context, args: Arguments): Array[AnyRef] = fileSystem.synchronized {
|
def exists(context: Context, args: Arguments): Array[AnyRef] = {
|
||||||
result(fileSystem.exists(clean(args.checkString(0))))
|
result(fileSystem.exists(clean(args.checkString(0))))
|
||||||
}
|
}
|
||||||
|
|
||||||
@LuaCallback(value = "size", direct = true)
|
@LuaCallback(value = "size", direct = true)
|
||||||
def size(context: Context, args: Arguments): Array[AnyRef] = fileSystem.synchronized {
|
def size(context: Context, args: Arguments): Array[AnyRef] = {
|
||||||
result(fileSystem.size(clean(args.checkString(0))))
|
result(fileSystem.size(clean(args.checkString(0))))
|
||||||
}
|
}
|
||||||
|
|
||||||
@LuaCallback(value = "isDirectory", direct = true)
|
@LuaCallback(value = "isDirectory", direct = true)
|
||||||
def isDirectory(context: Context, args: Arguments): Array[AnyRef] = fileSystem.synchronized {
|
def isDirectory(context: Context, args: Arguments): Array[AnyRef] = {
|
||||||
result(fileSystem.isDirectory(clean(args.checkString(0))))
|
result(fileSystem.isDirectory(clean(args.checkString(0))))
|
||||||
}
|
}
|
||||||
|
|
||||||
@LuaCallback(value = "lastModified", direct = true)
|
@LuaCallback(value = "lastModified", direct = true)
|
||||||
def lastModified(context: Context, args: Arguments): Array[AnyRef] = fileSystem.synchronized {
|
def lastModified(context: Context, args: Arguments): Array[AnyRef] = {
|
||||||
result(fileSystem.lastModified(clean(args.checkString(0))))
|
result(fileSystem.lastModified(clean(args.checkString(0))))
|
||||||
}
|
}
|
||||||
|
|
||||||
@LuaCallback("list")
|
@LuaCallback("list")
|
||||||
def list(context: Context, args: Arguments): Array[AnyRef] = fileSystem.synchronized {
|
def list(context: Context, args: Arguments): Array[AnyRef] = {
|
||||||
Option(fileSystem.list(clean(args.checkString(0)))) match {
|
Option(fileSystem.list(clean(args.checkString(0)))) match {
|
||||||
case Some(list) => Array(list)
|
case Some(list) => Array(list)
|
||||||
case _ => null
|
case _ => null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@LuaCallback("makeDirectory")
|
@LuaCallback("makeDirectory")
|
||||||
def makeDirectory(context: Context, args: Arguments): Array[AnyRef] = fileSystem.synchronized {
|
def makeDirectory(context: Context, args: Arguments): Array[AnyRef] = {
|
||||||
def recurse(path: String): Boolean = !fileSystem.exists(path) && (fileSystem.makeDirectory(path) ||
|
def recurse(path: String): Boolean = !fileSystem.exists(path) && (fileSystem.makeDirectory(path) ||
|
||||||
(recurse(path.split("/").dropRight(1).mkString("/")) && fileSystem.makeDirectory(path)))
|
(recurse(path.split("/").dropRight(1).mkString("/")) && fileSystem.makeDirectory(path)))
|
||||||
result(recurse(clean(args.checkString(0))))
|
result(recurse(clean(args.checkString(0))))
|
||||||
}
|
}
|
||||||
|
|
||||||
@LuaCallback("remove")
|
@LuaCallback("remove")
|
||||||
def remove(context: Context, args: Arguments): Array[AnyRef] = fileSystem.synchronized {
|
def remove(context: Context, args: Arguments): Array[AnyRef] = {
|
||||||
def recurse(parent: String): Boolean = (!fileSystem.isDirectory(parent) ||
|
def recurse(parent: String): Boolean = (!fileSystem.isDirectory(parent) ||
|
||||||
fileSystem.list(parent).forall(child => recurse(parent + "/" + child))) && fileSystem.delete(parent)
|
fileSystem.list(parent).forall(child => recurse(parent + "/" + child))) && fileSystem.delete(parent)
|
||||||
result(recurse(clean(args.checkString(0))))
|
result(recurse(clean(args.checkString(0))))
|
||||||
}
|
}
|
||||||
|
|
||||||
@LuaCallback("rename")
|
@LuaCallback("rename")
|
||||||
def rename(context: Context, args: Arguments): Array[AnyRef] = fileSystem.synchronized {
|
def rename(context: Context, args: Arguments): Array[AnyRef] = {
|
||||||
result(fileSystem.rename(clean(args.checkString(0)), clean(args.checkString(1))))
|
result(fileSystem.rename(clean(args.checkString(0)), clean(args.checkString(1))))
|
||||||
}
|
}
|
||||||
|
|
||||||
@LuaCallback("close")
|
@LuaCallback("close")
|
||||||
def close(context: Context, args: Arguments): Array[AnyRef] = fileSystem.synchronized {
|
def close(context: Context, args: Arguments): Array[AnyRef] = {
|
||||||
val handle = args.checkInteger(0)
|
val handle = args.checkInteger(0)
|
||||||
Option(fileSystem.getHandle(handle)) match {
|
Option(fileSystem.getHandle(handle)) match {
|
||||||
case Some(file) =>
|
case Some(file) =>
|
||||||
@ -111,8 +110,8 @@ class FileSystem(val fileSystem: api.fs.FileSystem, var label: Label) extends Ma
|
|||||||
}
|
}
|
||||||
|
|
||||||
@LuaCallback("open")
|
@LuaCallback("open")
|
||||||
def open(context: Context, args: Arguments): Array[AnyRef] = fileSystem.synchronized {
|
def open(context: Context, args: Arguments): Array[AnyRef] = {
|
||||||
if (owners.get(context.address).fold(false)(_.size >= Config.maxHandles))
|
if (owners.get(context.address).fold(false)(_.size >= Config.maxHandles))
|
||||||
throw new IOException("too many open handles")
|
throw new IOException("too many open handles")
|
||||||
else {
|
else {
|
||||||
val path = args.checkString(0)
|
val path = args.checkString(0)
|
||||||
@ -126,7 +125,7 @@ class FileSystem(val fileSystem: api.fs.FileSystem, var label: Label) extends Ma
|
|||||||
}
|
}
|
||||||
|
|
||||||
@LuaCallback("read")
|
@LuaCallback("read")
|
||||||
def read(context: Context, args: Arguments): Array[AnyRef] = fileSystem.synchronized {
|
def read(context: Context, args: Arguments): Array[AnyRef] = {
|
||||||
val handle = args.checkInteger(0)
|
val handle = args.checkInteger(0)
|
||||||
val n = args.checkInteger(1)
|
val n = args.checkInteger(1)
|
||||||
checkOwner(context.address, handle)
|
checkOwner(context.address, handle)
|
||||||
@ -157,7 +156,7 @@ class FileSystem(val fileSystem: api.fs.FileSystem, var label: Label) extends Ma
|
|||||||
}
|
}
|
||||||
|
|
||||||
@LuaCallback("seek")
|
@LuaCallback("seek")
|
||||||
def seek(context: Context, args: Arguments): Array[AnyRef] = fileSystem.synchronized {
|
def seek(context: Context, args: Arguments): Array[AnyRef] = {
|
||||||
val handle = args.checkInteger(0)
|
val handle = args.checkInteger(0)
|
||||||
val whence = args.checkString(1)
|
val whence = args.checkString(1)
|
||||||
val offset = args.checkInteger(2)
|
val offset = args.checkInteger(2)
|
||||||
@ -176,7 +175,7 @@ class FileSystem(val fileSystem: api.fs.FileSystem, var label: Label) extends Ma
|
|||||||
}
|
}
|
||||||
|
|
||||||
@LuaCallback("write")
|
@LuaCallback("write")
|
||||||
def write(context: Context, args: Arguments): Array[AnyRef] = fileSystem.synchronized {
|
def write(context: Context, args: Arguments): Array[AnyRef] = {
|
||||||
val handle = args.checkInteger(0)
|
val handle = args.checkInteger(0)
|
||||||
val value = args.checkByteArray(1)
|
val value = args.checkByteArray(1)
|
||||||
if (!node.changeBuffer(-Config.hddWriteCost * value.length)) {
|
if (!node.changeBuffer(-Config.hddWriteCost * value.length)) {
|
||||||
@ -196,7 +195,7 @@ class FileSystem(val fileSystem: api.fs.FileSystem, var label: Label) extends Ma
|
|||||||
message.data match {
|
message.data match {
|
||||||
case Array() if message.name == "computer.stopped" || message.name == "computer.started" =>
|
case Array() if message.name == "computer.stopped" || message.name == "computer.started" =>
|
||||||
owners.get(message.source.address) match {
|
owners.get(message.source.address) match {
|
||||||
case Some(set) => fileSystem.synchronized {
|
case Some(set) => {
|
||||||
set.foreach(handle => Option(fileSystem.getHandle(handle)) match {
|
set.foreach(handle => Option(fileSystem.getHandle(handle)) match {
|
||||||
case Some(file) => file.close()
|
case Some(file) => file.close()
|
||||||
case _ => // Invalid handle... huh.
|
case _ => // Invalid handle... huh.
|
||||||
@ -211,10 +210,10 @@ class FileSystem(val fileSystem: api.fs.FileSystem, var label: Label) extends Ma
|
|||||||
|
|
||||||
override def onDisconnect(node: Node) {
|
override def onDisconnect(node: Node) {
|
||||||
super.onDisconnect(node)
|
super.onDisconnect(node)
|
||||||
if (node == this.node) fileSystem.synchronized {
|
if (node == this.node) {
|
||||||
fileSystem.close()
|
fileSystem.close()
|
||||||
}
|
}
|
||||||
else if (owners.contains(node.address)) fileSystem.synchronized {
|
else if (owners.contains(node.address)) {
|
||||||
for (handle <- owners(node.address)) {
|
for (handle <- owners(node.address)) {
|
||||||
Option(fileSystem.getHandle(handle)) match {
|
Option(fileSystem.getHandle(handle)) match {
|
||||||
case Some(file) => file.close()
|
case Some(file) => file.close()
|
||||||
|
@ -21,7 +21,15 @@ abstract class GraphicsCard extends ManagedComponent {
|
|||||||
|
|
||||||
private var screenInstance: Option[Buffer] = None
|
private var screenInstance: Option[Buffer] = None
|
||||||
|
|
||||||
private def screen(f: (Buffer) => Array[AnyRef]) = this.synchronized {
|
private def screen(f: (Buffer) => Array[AnyRef]) = screenInstance match {
|
||||||
|
case Some(screen) => screen.synchronized(f(screen))
|
||||||
|
case _ => Array(Unit, "no screen")
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------- //
|
||||||
|
|
||||||
|
override def update() {
|
||||||
|
super.update()
|
||||||
if (screenInstance.isEmpty && screenAddress.isDefined) {
|
if (screenInstance.isEmpty && screenAddress.isDefined) {
|
||||||
Option(node.network.node(screenAddress.get)) match {
|
Option(node.network.node(screenAddress.get)) match {
|
||||||
case Some(node: Node) if node.host.isInstanceOf[Buffer.Environment] =>
|
case Some(node: Node) if node.host.isInstanceOf[Buffer.Environment] =>
|
||||||
@ -35,22 +43,16 @@ abstract class GraphicsCard extends ManagedComponent {
|
|||||||
screenAddress = None
|
screenAddress = None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
screenInstance match {
|
|
||||||
case Some(screen) => f(screen)
|
|
||||||
case _ => Array(Unit, "no screen")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------- //
|
|
||||||
|
|
||||||
@LuaCallback("bind")
|
@LuaCallback("bind")
|
||||||
def bind(context: Context, args: Arguments): Array[AnyRef] = this.synchronized {
|
def bind(context: Context, args: Arguments): Array[AnyRef] = {
|
||||||
val address = args.checkString(0)
|
val address = args.checkString(0)
|
||||||
node.network.node(address) match {
|
node.network.node(address) match {
|
||||||
case null => Array(Unit, "invalid address")
|
case null => Array(Unit, "invalid address")
|
||||||
case node: Node if node.host.isInstanceOf[Buffer.Environment] =>
|
case node: Node if node.host.isInstanceOf[Buffer.Environment] => {
|
||||||
screenAddress = Option(address)
|
screenAddress = Option(address)
|
||||||
screenInstance = None
|
screenInstance = Some(node.host.asInstanceOf[Buffer.Environment].instance)
|
||||||
screen(s => {
|
screen(s => {
|
||||||
val (gmw, gmh) = maxResolution
|
val (gmw, gmh) = maxResolution
|
||||||
val (smw, smh) = s.maxResolution
|
val (smw, smh) = s.maxResolution
|
||||||
@ -60,6 +62,7 @@ abstract class GraphicsCard extends ManagedComponent {
|
|||||||
s.background = 0x000000
|
s.background = 0x000000
|
||||||
result(true)
|
result(true)
|
||||||
})
|
})
|
||||||
|
}
|
||||||
case _ => Array(Unit, "not a screen")
|
case _ => Array(Unit, "not a screen")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -220,6 +223,18 @@ abstract class GraphicsCard extends ManagedComponent {
|
|||||||
|
|
||||||
object GraphicsCard {
|
object GraphicsCard {
|
||||||
|
|
||||||
|
// IMPORTANT: usually methods with side effects should *not* be direct
|
||||||
|
// callbacks to avoid the massive headache synchronizing them ensues, in
|
||||||
|
// particular when it comes to world saving. I'm making an exception for
|
||||||
|
// screens, though since they'd be painfully sluggish otherwise. This also
|
||||||
|
// means we have to use a somewhat nasty trick in common.component.Buffer's
|
||||||
|
// save function: we wait for all computers in the same network to finish
|
||||||
|
// their current execution and then pause them, to ensure the state of the
|
||||||
|
// buffer is "clean", meaning the computer has the correct state when it is
|
||||||
|
// saved in turn. If we didn't, a computer might change a screen after it was
|
||||||
|
// saved, but before the computer was saved, leading to mismatching states in
|
||||||
|
// the save file - a Bad Thing (TM).
|
||||||
|
|
||||||
class Tier1 extends GraphicsCard {
|
class Tier1 extends GraphicsCard {
|
||||||
val maxDepth = Config.screenDepthsByTier(0)
|
val maxDepth = Config.screenDepthsByTier(0)
|
||||||
val maxResolution = Config.screenResolutionsByTier(0)
|
val maxResolution = Config.screenResolutionsByTier(0)
|
||||||
|
@ -16,13 +16,13 @@ class NetworkCard extends ManagedComponent {
|
|||||||
// ----------------------------------------------------------------------- //
|
// ----------------------------------------------------------------------- //
|
||||||
|
|
||||||
@LuaCallback("open")
|
@LuaCallback("open")
|
||||||
def open(context: Context, args: Arguments): Array[AnyRef] = this.synchronized {
|
def open(context: Context, args: Arguments): Array[AnyRef] = {
|
||||||
val port = checkPort(args.checkInteger(0))
|
val port = checkPort(args.checkInteger(0))
|
||||||
result(openPorts.add(port))
|
result(openPorts.add(port))
|
||||||
}
|
}
|
||||||
|
|
||||||
@LuaCallback("close")
|
@LuaCallback("close")
|
||||||
def close(context: Context, args: Arguments): Array[AnyRef] = this.synchronized {
|
def close(context: Context, args: Arguments): Array[AnyRef] = {
|
||||||
if (args.count == 0) {
|
if (args.count == 0) {
|
||||||
openPorts.clear()
|
openPorts.clear()
|
||||||
result(true)
|
result(true)
|
||||||
@ -34,7 +34,7 @@ class NetworkCard extends ManagedComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@LuaCallback(value = "isOpen", direct = true)
|
@LuaCallback(value = "isOpen", direct = true)
|
||||||
def isOpen(context: Context, args: Arguments): Array[AnyRef] = this.synchronized {
|
def isOpen(context: Context, args: Arguments): Array[AnyRef] = {
|
||||||
val port = checkPort(args.checkInteger(0))
|
val port = checkPort(args.checkInteger(0))
|
||||||
result(openPorts.contains(port))
|
result(openPorts.contains(port))
|
||||||
}
|
}
|
||||||
@ -66,7 +66,7 @@ class NetworkCard extends ManagedComponent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override def onMessage(message: Message) = this.synchronized {
|
override def onMessage(message: Message) = {
|
||||||
super.onMessage(message)
|
super.onMessage(message)
|
||||||
if ((message.name == "computer.stopped" || message.name == "computer.started") && node.isNeighborOf(message.source))
|
if ((message.name == "computer.stopped" || message.name == "computer.started") && node.isNeighborOf(message.source))
|
||||||
openPorts.clear()
|
openPorts.clear()
|
||||||
|
@ -22,15 +22,15 @@ class WirelessNetworkCard(val owner: TileEntity) extends NetworkCard {
|
|||||||
@LuaCallback(value = "getStrength", direct = true)
|
@LuaCallback(value = "getStrength", direct = true)
|
||||||
def getStrength(context: Context, args: Arguments): Array[AnyRef] = result(strength)
|
def getStrength(context: Context, args: Arguments): Array[AnyRef] = result(strength)
|
||||||
|
|
||||||
@LuaCallback(value = "setStrength", direct = true)
|
@LuaCallback("setStrength")
|
||||||
def setStrength(context: Context, args: Arguments): Array[AnyRef] = this.synchronized {
|
def setStrength(context: Context, args: Arguments): Array[AnyRef] = {
|
||||||
strength = args.checkDouble(0) max 0 min Config.maxWirelessRange
|
strength = args.checkDouble(0) max 0 min Config.maxWirelessRange
|
||||||
result(strength)
|
result(strength)
|
||||||
}
|
}
|
||||||
|
|
||||||
override def isWireless(context: Context, args: Arguments): Array[AnyRef] = result(true)
|
override def isWireless(context: Context, args: Arguments): Array[AnyRef] = result(true)
|
||||||
|
|
||||||
override def send(context: Context, args: Arguments) = this.synchronized {
|
override def send(context: Context, args: Arguments) = {
|
||||||
val address = args.checkString(0)
|
val address = args.checkString(0)
|
||||||
val port = checkPort(args.checkInteger(1))
|
val port = checkPort(args.checkInteger(1))
|
||||||
if (strength > 0) {
|
if (strength > 0) {
|
||||||
@ -44,7 +44,7 @@ class WirelessNetworkCard(val owner: TileEntity) extends NetworkCard {
|
|||||||
super.send(context, args)
|
super.send(context, args)
|
||||||
}
|
}
|
||||||
|
|
||||||
override def broadcast(context: Context, args: Arguments) = this.synchronized {
|
override def broadcast(context: Context, args: Arguments) = {
|
||||||
val port = checkPort(args.checkInteger(0))
|
val port = checkPort(args.checkInteger(0))
|
||||||
if (strength > 0) {
|
if (strength > 0) {
|
||||||
checkPower()
|
checkPower()
|
||||||
|
@ -26,21 +26,24 @@ trait Connector extends Node with network.Connector with Persistable {
|
|||||||
// ----------------------------------------------------------------------- //
|
// ----------------------------------------------------------------------- //
|
||||||
|
|
||||||
def changeBuffer(delta: Double) = if (delta != 0) {
|
def changeBuffer(delta: Double) = if (delta != 0) {
|
||||||
val oldBuffer = localBuffer
|
val remaining = this.synchronized {
|
||||||
localBuffer = localBuffer + delta
|
val oldBuffer = localBuffer
|
||||||
val ok = if (localBuffer < 0) {
|
localBuffer = localBuffer + delta
|
||||||
val remaining = localBuffer
|
val remaining = if (localBuffer < 0) {
|
||||||
localBuffer = 0
|
val remaining = localBuffer
|
||||||
distributor.fold(false)(_.changeBuffer(remaining))
|
localBuffer = 0
|
||||||
|
remaining
|
||||||
|
}
|
||||||
|
else if (localBuffer > localBufferSize) {
|
||||||
|
val remaining = localBuffer - localBufferSize
|
||||||
|
localBuffer = localBufferSize
|
||||||
|
remaining
|
||||||
|
}
|
||||||
|
else 0
|
||||||
|
dirty ||= (localBuffer != oldBuffer)
|
||||||
|
remaining
|
||||||
}
|
}
|
||||||
else if (localBuffer > localBufferSize) {
|
distributor.fold(remaining == 0)(_.changeBuffer(remaining)) || Config.ignorePower
|
||||||
val remaining = localBuffer - localBufferSize
|
|
||||||
localBuffer = localBufferSize
|
|
||||||
distributor.fold(false)(_.changeBuffer(remaining))
|
|
||||||
}
|
|
||||||
else true
|
|
||||||
dirty ||= (localBuffer != oldBuffer)
|
|
||||||
ok || Config.ignorePower
|
|
||||||
} else true
|
} else true
|
||||||
|
|
||||||
// ----------------------------------------------------------------------- //
|
// ----------------------------------------------------------------------- //
|
||||||
@ -59,7 +62,7 @@ trait Connector extends Node with network.Connector with Persistable {
|
|||||||
super.onDisconnect(node)
|
super.onDisconnect(node)
|
||||||
}
|
}
|
||||||
|
|
||||||
private def findDistributor() {
|
private def findDistributor() = {
|
||||||
distributor = reachableNodes.find(_.host.isInstanceOf[PowerDistributor]).fold(None: Option[PowerDistributor])(n => Some(n.host.asInstanceOf[PowerDistributor]))
|
distributor = reachableNodes.find(_.host.isInstanceOf[PowerDistributor]).fold(None: Option[PowerDistributor])(n => Some(n.host.asInstanceOf[PowerDistributor]))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@ import scala.collection.JavaConverters._
|
|||||||
import scala.collection.mutable
|
import scala.collection.mutable
|
||||||
import scala.collection.mutable.ArrayBuffer
|
import scala.collection.mutable.ArrayBuffer
|
||||||
|
|
||||||
class Network private(private val data: mutable.Map[String, Network.Vertex] = mutable.Map.empty) {
|
private class Network private(private val data: mutable.Map[String, Network.Vertex] = mutable.Map.empty) {
|
||||||
def this(node: MutableNode) = {
|
def this(node: MutableNode) = {
|
||||||
this()
|
this()
|
||||||
addNew(node)
|
addNew(node)
|
||||||
@ -25,7 +25,7 @@ class Network private(private val data: mutable.Map[String, Network.Vertex] = mu
|
|||||||
|
|
||||||
// ----------------------------------------------------------------------- //
|
// ----------------------------------------------------------------------- //
|
||||||
|
|
||||||
def connect(nodeA: MutableNode, nodeB: MutableNode) = this.synchronized {
|
def connect(nodeA: MutableNode, nodeB: MutableNode) = {
|
||||||
if (nodeA == nodeB) throw new IllegalArgumentException(
|
if (nodeA == nodeB) throw new IllegalArgumentException(
|
||||||
"Cannot connect a node to itself.")
|
"Cannot connect a node to itself.")
|
||||||
|
|
||||||
@ -59,7 +59,7 @@ class Network private(private val data: mutable.Map[String, Network.Vertex] = mu
|
|||||||
else add(oldNodeB, nodeA)
|
else add(oldNodeB, nodeA)
|
||||||
}
|
}
|
||||||
|
|
||||||
def disconnect(nodeA: MutableNode, nodeB: MutableNode) = this.synchronized {
|
def disconnect(nodeA: MutableNode, nodeB: MutableNode) = {
|
||||||
if (nodeA == nodeB) throw new IllegalArgumentException(
|
if (nodeA == nodeB) throw new IllegalArgumentException(
|
||||||
"Cannot disconnect a node from itself.")
|
"Cannot disconnect a node from itself.")
|
||||||
|
|
||||||
@ -85,7 +85,7 @@ class Network private(private val data: mutable.Map[String, Network.Vertex] = mu
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def remove(node: MutableNode) = this.synchronized {
|
def remove(node: MutableNode) = {
|
||||||
data.remove(node.address) match {
|
data.remove(node.address) match {
|
||||||
case Some(entry) => {
|
case Some(entry) => {
|
||||||
node.network = null
|
node.network = null
|
||||||
@ -105,14 +105,14 @@ class Network private(private val data: mutable.Map[String, Network.Vertex] = mu
|
|||||||
|
|
||||||
// ----------------------------------------------------------------------- //
|
// ----------------------------------------------------------------------- //
|
||||||
|
|
||||||
def node(address: String) = this.synchronized {
|
def node(address: String) = {
|
||||||
data.get(address) match {
|
data.get(address) match {
|
||||||
case Some(node) => node.data
|
case Some(node) => node.data
|
||||||
case _ => null
|
case _ => null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def nodes: Iterable[ImmutableNode] = this.synchronized(data.values.map(_.data))
|
def nodes: Iterable[ImmutableNode] = data.values.map(_.data)
|
||||||
|
|
||||||
def nodes(reference: ImmutableNode): Iterable[ImmutableNode] = {
|
def nodes(reference: ImmutableNode): Iterable[ImmutableNode] = {
|
||||||
val referenceNeighbors = neighbors(reference).toSet
|
val referenceNeighbors = neighbors(reference).toSet
|
||||||
@ -120,7 +120,7 @@ class Network private(private val data: mutable.Map[String, Network.Vertex] = mu
|
|||||||
(node.reachability == Visibility.Neighbors && referenceNeighbors.contains(node))))
|
(node.reachability == Visibility.Neighbors && referenceNeighbors.contains(node))))
|
||||||
}
|
}
|
||||||
|
|
||||||
def neighbors(node: ImmutableNode): Iterable[ImmutableNode] = this.synchronized {
|
def neighbors(node: ImmutableNode): Iterable[ImmutableNode] = {
|
||||||
data.get(node.address) match {
|
data.get(node.address) match {
|
||||||
case Some(n) =>
|
case Some(n) =>
|
||||||
assert(n.data == node)
|
assert(n.data == node)
|
||||||
@ -131,7 +131,7 @@ class Network private(private val data: mutable.Map[String, Network.Vertex] = mu
|
|||||||
|
|
||||||
// ----------------------------------------------------------------------- //
|
// ----------------------------------------------------------------------- //
|
||||||
|
|
||||||
def sendToAddress(source: ImmutableNode, target: String, name: String, args: AnyRef*) = this.synchronized {
|
def sendToAddress(source: ImmutableNode, target: String, name: String, args: AnyRef*) = {
|
||||||
if (source.network != wrapper)
|
if (source.network != wrapper)
|
||||||
throw new IllegalArgumentException("Source node must be in this network.")
|
throw new IllegalArgumentException("Source node must be in this network.")
|
||||||
data.get(target) match {
|
data.get(target) match {
|
||||||
@ -141,13 +141,13 @@ class Network private(private val data: mutable.Map[String, Network.Vertex] = mu
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def sendToNeighbors(source: ImmutableNode, name: String, args: AnyRef*) = this.synchronized {
|
def sendToNeighbors(source: ImmutableNode, name: String, args: AnyRef*) = {
|
||||||
if (source.network != wrapper)
|
if (source.network != wrapper)
|
||||||
throw new IllegalArgumentException("Source node must be in this network.")
|
throw new IllegalArgumentException("Source node must be in this network.")
|
||||||
send(source, neighbors(source).filter(_.reachability != Visibility.None), name, args: _*)
|
send(source, neighbors(source).filter(_.reachability != Visibility.None), name, args: _*)
|
||||||
}
|
}
|
||||||
|
|
||||||
def sendToReachable(source: ImmutableNode, name: String, args: AnyRef*) = this.synchronized {
|
def sendToReachable(source: ImmutableNode, name: String, args: AnyRef*) = {
|
||||||
if (source.network != wrapper)
|
if (source.network != wrapper)
|
||||||
throw new IllegalArgumentException("Source node must be in this network.")
|
throw new IllegalArgumentException("Source node must be in this network.")
|
||||||
send(source, nodes(source), name, args: _*)
|
send(source, nodes(source), name, args: _*)
|
||||||
@ -386,8 +386,7 @@ object Network extends api.detail.NetworkAPI {
|
|||||||
def disconnect(nodeA: ImmutableNode, nodeB: ImmutableNode) =
|
def disconnect(nodeA: ImmutableNode, nodeB: ImmutableNode) =
|
||||||
network.disconnect(nodeA.asInstanceOf[MutableNode], nodeB.asInstanceOf[MutableNode])
|
network.disconnect(nodeA.asInstanceOf[MutableNode], nodeB.asInstanceOf[MutableNode])
|
||||||
|
|
||||||
def remove(node: ImmutableNode) =
|
def remove(node: ImmutableNode) = network.remove(node.asInstanceOf[MutableNode])
|
||||||
network.remove(node.asInstanceOf[MutableNode])
|
|
||||||
|
|
||||||
def node(address: String) = network.node(address)
|
def node(address: String) = network.node(address)
|
||||||
|
|
||||||
|
@ -48,8 +48,7 @@ trait Node extends api.network.Node with Persistable {
|
|||||||
def sendToReachable(name: String, data: AnyRef*) =
|
def sendToReachable(name: String, data: AnyRef*) =
|
||||||
if (network != null) network.sendToReachable(this, name, data: _*)
|
if (network != null) network.sendToReachable(this, name, data: _*)
|
||||||
|
|
||||||
private def isInSameNetwork(other: ImmutableNode) =
|
private def isInSameNetwork(other: ImmutableNode) = network != null && network == other.network
|
||||||
network != null && network == other.network
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------- //
|
// ----------------------------------------------------------------------- //
|
||||||
|
|
||||||
|
@ -1,13 +1,30 @@
|
|||||||
package li.cil.oc.util
|
package li.cil.oc.util
|
||||||
|
|
||||||
|
import li.cil.oc.OpenComputers
|
||||||
import net.minecraft.client.renderer.OpenGlHelper
|
import net.minecraft.client.renderer.OpenGlHelper
|
||||||
import org.lwjgl.opengl._
|
import org.lwjgl.opengl._
|
||||||
|
import org.lwjgl.util.glu.GLU
|
||||||
|
|
||||||
object RenderState {
|
object RenderState {
|
||||||
val arb = GLContext.getCapabilities.GL_ARB_multitexture && !GLContext.getCapabilities.OpenGL13
|
val arb = GLContext.getCapabilities.GL_ARB_multitexture && !GLContext.getCapabilities.OpenGL13
|
||||||
|
|
||||||
private val canUseBlendColor = GLContext.getCapabilities.OpenGL14
|
private val canUseBlendColor = GLContext.getCapabilities.OpenGL14
|
||||||
|
|
||||||
|
def checkError(where: String) {
|
||||||
|
val error = GL11.glGetError
|
||||||
|
if (error != 0) {
|
||||||
|
OpenComputers.log.warning("GL ERROR @ " + where + ": " + GLU.gluErrorString(error))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def compilingDisplayList = {
|
||||||
|
if (GL11.glGetInteger(GL11.GL_LIST_INDEX) != 0) {
|
||||||
|
val mode = GL11.glGetInteger(GL11.GL_LIST_MODE)
|
||||||
|
mode == GL11.GL_COMPILE || mode == GL11.GL_COMPILE_AND_EXECUTE
|
||||||
|
}
|
||||||
|
else false
|
||||||
|
}
|
||||||
|
|
||||||
def disableLighting() {
|
def disableLighting() {
|
||||||
GL11.glDisable(GL11.GL_LIGHTING)
|
GL11.glDisable(GL11.GL_LIGHTING)
|
||||||
if (arb) {
|
if (arb) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user