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

Conflicts:
	build.gradle
	build.properties
	src/main/java/li/cil/oc/api/API.java
	src/main/scala/li/cil/oc/client/Sound.scala
	src/main/scala/li/cil/oc/client/gui/DynamicGuiContainer.scala
	src/main/scala/li/cil/oc/common/EventHandler.scala
	src/main/scala/li/cil/oc/common/asm/ClassTransformer.scala
	src/main/scala/li/cil/oc/common/block/Adapter.scala
	src/main/scala/li/cil/oc/common/block/Assembler.scala
	src/main/scala/li/cil/oc/common/block/Capacitor.scala
	src/main/scala/li/cil/oc/common/block/Case.scala
	src/main/scala/li/cil/oc/common/block/Charger.scala
	src/main/scala/li/cil/oc/common/block/Disassembler.scala
	src/main/scala/li/cil/oc/common/block/DiskDrive.scala
	src/main/scala/li/cil/oc/common/block/Item.scala
	src/main/scala/li/cil/oc/common/block/Keyboard.scala
	src/main/scala/li/cil/oc/common/block/Microcontroller.scala
	src/main/scala/li/cil/oc/common/block/Raid.scala
	src/main/scala/li/cil/oc/common/block/RedstoneAware.scala
	src/main/scala/li/cil/oc/common/block/RobotAfterimage.scala
	src/main/scala/li/cil/oc/common/block/RobotProxy.scala
	src/main/scala/li/cil/oc/common/block/Screen.scala
	src/main/scala/li/cil/oc/common/block/ServerRack.scala
	src/main/scala/li/cil/oc/common/block/SimpleBlock.scala
	src/main/scala/li/cil/oc/common/block/Switch.scala
	src/main/scala/li/cil/oc/common/block/traits/SpecialBlock.scala
	src/main/scala/li/cil/oc/common/component/TextBuffer.scala
	src/main/scala/li/cil/oc/common/entity/Drone.scala
	src/main/scala/li/cil/oc/common/init/Items.scala
	src/main/scala/li/cil/oc/common/item/Tablet.scala
	src/main/scala/li/cil/oc/common/tileentity/Capacitor.scala
	src/main/scala/li/cil/oc/common/tileentity/Microcontroller.scala
	src/main/scala/li/cil/oc/common/tileentity/Redstone.scala
	src/main/scala/li/cil/oc/common/tileentity/Screen.scala
	src/main/scala/li/cil/oc/common/tileentity/ServerRack.scala
	src/main/scala/li/cil/oc/common/tileentity/traits/BundledRedstoneAware.scala
	src/main/scala/li/cil/oc/common/tileentity/traits/Computer.scala
	src/main/scala/li/cil/oc/common/tileentity/traits/RedstoneAware.scala
	src/main/scala/li/cil/oc/common/tileentity/traits/power/Mekanism.scala
	src/main/scala/li/cil/oc/integration/Mods.scala
	src/main/scala/li/cil/oc/integration/opencomputers/DriverBlockEnvironments.scala
	src/main/scala/li/cil/oc/server/component/Redstone.scala
	src/main/scala/li/cil/oc/server/component/RedstoneWireless.scala
	src/main/scala/li/cil/oc/server/component/UpgradeInventoryController.scala
	src/main/scala/li/cil/oc/server/component/robot/Player.scala
	src/main/scala/li/cil/oc/server/network/Network.scala
	src/main/scala/li/cil/oc/util/ItemCosts.scala
	src/main/scala/li/cil/oc/util/ItemUtils.scala
This commit is contained in:
Florian Nücke 2015-01-28 17:59:29 +01:00
commit 19f614a3eb
127 changed files with 2255 additions and 1017 deletions

View File

@ -1,4 +1,4 @@
Copyright (c) 2013-2014 Florian "Sangar" Nücke
Copyright (c) 2013-2015 Florian "Sangar" Nücke
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@ -13,7 +13,7 @@ A few useful links:
You can find experimental builds [on the build server][jenkins]. Expect these to be generally more unstable than builds marked as releases. Use these **at your own risk**, but - when using the latest one - please *do* report bugs you encounter using them. Thanks!
## License / Use in Modpacks
This mod is [licensed under the **MIT license**](https://github.com/MightyPirates/OpenComputers/blob/master/LICENSE). All **assets are public domain**, unless otherwise stated; all are free to be distributed as long as the license / source credits are kept. This means you can use this mod in any mod pack **as you please**. I'd be happy to hear about you using it, though, just out of curiosity.
This mod is [licensed under the **MIT license**](https://github.com/MightyPirates/OpenComputers/blob/master-MC1.7.10/LICENSE). All **assets are public domain**, unless otherwise stated; all are free to be distributed as long as the license / source credits are kept. This means you can use this mod in any mod pack **as you please**. I'd be happy to hear about you using it, though, just out of curiosity.
## Contributing
###Assets and Localizations

View File

@ -17,6 +17,7 @@ buildscript {
apply plugin: 'scala'
apply plugin: 'forge'
apply plugin: 'idea'
apply plugin: 'maven-publish'
file "build.properties" withReader {
@ -136,6 +137,10 @@ repositories {
name 'Railcraft'
artifactPattern "http://addons.cursecdn.com/files/${config.rc.cf}/[module]_[revision].[ext]"
}
ivy {
name 'BloodMagic'
artifactPattern "http://addons.cursecdn.com/files/${config.bloodmagic.cf}/[module]-${config.minecraft.version}-[revision].[ext]"
}
*/
}
@ -173,6 +178,8 @@ dependencies {
provided name: 'ComputerCraft', version: config.cc.version, ext: 'jar'
provided name: 'EnderIO', version: config.eio.version, ext: 'jar'
provided name: 'Railcraft', version: config.rc.version, ext: 'jar'
provided name: 'BloodMagic', version: config.bloodmagic.version, ext: 'jar'
*/
compile 'com.google.code.findbugs:jsr305:1.3.9' // Annotations used by google libs.
@ -317,8 +324,8 @@ publishing {
}
// this is needed for IntelliJ so we don't have to copy over the assets manually every time
sourceSets {
main {
output.resourcesDir = output.classesDir
idea {
module {
outputDir = file('build/classes/main')
}
}

View File

@ -1,17 +1,19 @@
minecraft.version=1.8
forge.version=11.14.0.1280-1.8
oc.version=2.0.0
oc.version=1.4.6
oc.subversion=dev
ae2.version=rv1-stable-1
bc.version=6.2.6
bloodmagic.cf=2223/203
bloodmagic.version=1.3.0a-1
cc.cf=2216/236
cc.version=1.65
ccc.version=1.0.5.34
ccl.version=1.1.2.115
cofhlib.cf=2212/893
cofhlib.version=[1.7.10]1.0.0B6-dev-26
cofhlib.cf=2218/257
cofhlib.version=[1.7.10]1.0.0B7-dev-29
eio.cf=2219/296
eio.version=1.7.10-2.2.1.276
es.version=1.4.5.24

View File

@ -341,6 +341,71 @@ public interface TextBuffer extends ManagedEnvironment, Persistable {
*/
boolean isBackgroundFromPalette(int column, int row);
/**
* Overwrites a portion of the text in raw mode.
* <p/>
* This will copy the given char array into the buffer, starting at the
* specified column and row. The array is expected to be indexed row-
* first, i.e. the first dimension is the vertical axis, the second
* the horizontal.
* <p/>
* <em>Important</em>: this performs no checks as to whether something
* actually changed. It will always send the changed patch to clients.
* It will also not crop the specified array to the actually used range.
* In other words, this is not intended to be exposed as-is to user code,
* it should always be called with validated, and, as necessary, cropped
* values.
*
* @param column the horizontal index.
* @param row the vertical index.
* @param text the text to write.
*/
void rawSetText(int column, int row, char[][] text);
/**
* Overwrites a portion of the foreground color information in raw mode.
* <p/>
* This will convert the specified RGB data (in <tt>0xRRGGBB</tt> format)
* to the internal, packed representation and copy it into the buffer,
* starting at the specified column and row. The array is expected to be
* indexed row-first, i.e. the first dimension is the vertical axis, the
* second the horizontal.
* <p/>
* <em>Important</em>: this performs no checks as to whether something
* actually changed. It will always send the changed patch to clients.
* It will also not crop the specified array to the actually used range.
* In other words, this is not intended to be exposed as-is to user code,
* it should always be called with validated, and, as necessary, cropped
* values.
*
* @param column the horizontal index.
* @param row the vertical index.
* @param color the foreground color data to write.
*/
void rawSetForeground(int column, int row, int[][] color);
/**
* Overwrites a portion of the background color information in raw mode.
* <p/>
* This will convert the specified RGB data (in <tt>0xRRGGBB</tt> format)
* to the internal, packed representation and copy it into the buffer,
* starting at the specified column and row. The array is expected to be
* indexed row-first, i.e. the first dimension is the vertical axis, the
* second the horizontal.
* <p/>
* <em>Important</em>: this performs no checks as to whether something
* actually changed. It will always send the changed patch to clients.
* It will also not crop the specified array to the actually used range.
* In other words, this is not intended to be exposed as-is to user code,
* it should always be called with validated, and, as necessary, cropped
* values.
*
* @param column the horizontal index.
* @param row the vertical index.
* @param color the background color data to write.
*/
void rawSetBackground(int column, int row, int[][] color);
// ----------------------------------------------------------------------- //
/**
@ -452,7 +517,7 @@ public interface TextBuffer extends ManagedEnvironment, Persistable {
* @param button the button of the mouse that was pressed.
* @param player the player that pressed the mouse button. Pass <tt>null</tt> on the client side.
*/
void mouseDown(int x, int y, int button, EntityPlayer player);
void mouseDown(double x, double y, int button, EntityPlayer player);
/**
* Signals a mouse drag event for the buffer.
@ -465,7 +530,7 @@ public interface TextBuffer extends ManagedEnvironment, Persistable {
* @param button the button of the mouse that is pressed.
* @param player the player that moved the mouse. Pass <tt>null</tt> on the client side.
*/
void mouseDrag(int x, int y, int button, EntityPlayer player);
void mouseDrag(double x, double y, int button, EntityPlayer player);
/**
* Signals a mouse button release event for the buffer.
@ -478,7 +543,7 @@ public interface TextBuffer extends ManagedEnvironment, Persistable {
* @param button the button of the mouse that was released.
* @param player the player that released the mouse button. Pass <tt>null</tt> on the client side.
*/
void mouseUp(int x, int y, int button, EntityPlayer player);
void mouseUp(double x, double y, int button, EntityPlayer player);
/**
* Signals a mouse wheel scroll event for the buffer.
@ -491,7 +556,7 @@ public interface TextBuffer extends ManagedEnvironment, Persistable {
* @param delta indicates the direction of the mouse scroll.
* @param player the player that scrolled the mouse wheel. Pass <tt>null</tt> on the client side.
*/
void mouseScroll(int x, int y, int delta, EntityPlayer player);
void mouseScroll(double x, double y, int delta, EntityPlayer player);
// ----------------------------------------------------------------------- //

View File

@ -6,7 +6,7 @@ import li.cil.oc.api.machine.Context;
/**
* This interface can be used with an {@link li.cil.oc.api.network.Environment}
* and is intended to be used for environments wrapping a ComputerCraft
* peripheral. Tt could be used for other purposes as well, though. It allows
* peripheral. It could be used for other purposes as well, though. It allows
* providing method names in addition to those defined via the
* {@link li.cil.oc.api.machine.Callback} annotation, and invoking said methods.
*/

View File

@ -0,0 +1,26 @@
package li.cil.oc.api.network;
import net.minecraft.util.EnumFacing;
/**
* This is an extended version of {@link li.cil.oc.api.network.SimpleComponent}
* which allows controlling connectivity on a side-by-side basis.
* <p/>
* Like the <tt>SimpleComponent</tt> interface, this is intended to be used
* with tile entities that should act as OC components. Please see the
* <tt>SimpleComponent</tt> interface for more information.
*/
public interface SidedComponent {
/**
* Whether this component can connect to a node on the specified side.
* <p/>
* The provided side is relative to the component, i.e. when the tile
* entity sits at (0, 0, 0) and is asked for its southern node (positive
* Z axis) it has to return the connectivity for the face between it and
* the block at (0, 0, 1).
*
* @param side the side to check for.
* @return whether the component may be connected to from the specified side.
*/
boolean canConnectNode(EnumFacing side);
}

View File

@ -1,4 +1,4 @@
Copyright (c) 2013-2014 Florian "Sangar" Nücke
Copyright (c) 2013-2015 Florian "Sangar" Nücke
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@ -105,6 +105,18 @@ opencomputers {
# importantly, can only render code page 437 (as opposed to...
# a *lot* of unicode).
fontRenderer: "unifont"
# The sample rate used for generating beeps of computers' internal
# speakers. Use custom values at your own responsibility here; if it
# breaks OC you'll get no support. Some potentially reasonable
# lower values are 16000 or even 8000 (which was the old default, but
# leads to artifacting on certain frequencies).
beepSampleRate: 44100
# The base volume of beeps generated by computers. This may be in a
# range of [0, 127], where 0 means mute (the sound will not even be
# generated), and 127 means maximum amplitude / volume.
beepVolume: 32
}
# Computer related settings, concerns server performance and security.
@ -675,11 +687,11 @@ opencomputers {
# each point of complexity.
tabletAssemblyComplexity: 5000
# The base energy cost for assembling a microcontroller.
# The base energy cost for assembling a drone.
droneAssemblyBase: 25000
# The additional amount of energy required to assemble a
# microcontroller for each point of complexity.
# drone for each point of complexity.
droneAssemblyComplexity: 15000
# The amount of energy it takes to extract one ingredient from an

View File

@ -298,7 +298,7 @@ oc:tooltip.UpgradePiston=This upgrade is very pushy. It allows moving blocks, si
oc:tooltip.UpgradeSign=Allows reading text on and writing text to signs.
oc:tooltip.UpgradeSolarGenerator=Can be used to generate energy from sunlight on the go. Requires a clear line of sight to the sky above the device. Generates energy at %s%% of the speed of a Stirling Engine.
oc:tooltip.UpgradeTank=This upgrade provides a tank for fluid storage for robots and drones. Without one of these, they will not be able to store fluids internally.
oc:tooltip.UpgradeTankController=This upgrade allows the robots and drones more control in how they interacts with external tanks, and allows them to transfer fluids into and out of fluid tank items in their inventory.
oc:tooltip.UpgradeTankController=This upgrade allows robots and drones more control in how they interacts with external tanks, and allows them to transfer fluids into and out of fluid tank items in their inventory.
oc:tooltip.UpgradeTractorBeam=Equips a device with extremely advanced technology, nicknamed the "Item Magnet". Allows the device to pick up items anywhere within 3 blocks of its location.
oc:tooltip.WirelessNetworkCard=Allows wireless sending of network messages in addition to normal ones. You can adjust the §fsignal strength§7 to control how far messages are sent. Higher signal strength results in higher energy consumption.
oc:tooltip.WorldSensorCard=Allows reading out information about the world, such as its gravity and whether it has a breathable atmosphere. Use results at own risk. The manufacturer takes no responsibility for bodily or material harm caused by decisions made upon the cards' outputs. We have lawyers. And money. Don't even try.
@ -308,7 +308,7 @@ item.oc.AbstractBusCard.usage=This card allows computers, servers and robots to
item.oc.Analyzer.usage=The §oAnalyzer§r is a handy tool for getting some information about OpenComputers-related blocks in the world. Simply (sneak-)activate a block to get some information printed to the chat. This ranges from basic things like the address of components, to power levels in the subnetwork the block is in, and information on the error lead to a computer to crash, for example.[nl][nl]Another useful functionality is that when using the using the analyzer on a block while holding down [Ctrl] the address of the block component will be copied to the clipboard.
item.oc.ComponentBus.usage=A §oComponent Bus§r is a server-specific upgrade that allows the server to communicate with more components at the same time, without shutting down. Like with CPUs, higher tier buses provide higher component limits.
item.oc.CPU.usage=The §oCentral Processing Unit§r is a core part for each computer. It defines the architecture of the computer, and the number of components that can be connected to the computer before it stops working. Higher tier CPUs also provide a higher per-tick direct call limit to the computer - in simpler terms: better CPUs run faster.
item.oc.DebugCard.usage=The §oDebug Card§r is a non-craftable item that was originally only intended to make debugging things easier, by automating some processes. It has since gotten a bunch more functionality, making it quite useful for custom map-making.
item.oc.DebugCard.usage=The §oDebug Card§r is a non-craftable item that was originally only intended to make debugging things easier, by automating some processes. It has since gotten a bunch more functionality, making it quite useful for custom map-making.[nl][nl]Note that you can use shift-rightclick while holding the card to bind it to you / unbind it, meaning §orunCommand§r will be performed using your permission levels instead of the default OpenComputers ones.
item.oc.DroneCase.usage=The §oDrone Case§r is used to build Drones in the Assembler. Drones are light-weight, fast and very mobile machines with limited functionality. Unlike Robots they cannot use tools, and can interact with the world only in a relatively limited manner.[nl][nl]They make up for their limitations with speed and lower running energy costs. They are well suited for transport of small amounts of items, and ideal for reconnaissance. Pairing a Drone with a Robot can be quite powerful, with the Robot doing the "hard work", and the Drone providing information about the environment and transporting items to and from a central hub, for example.[nl][nl]Like microcontrollers, Drones can only be programmed using their EEPROM. Accordingly, the EEPROM can be changed by recrafting the Drone with another EEPROM.
item.oc.eeprom.usage=The §oEEPROM§r is what contains the code used to initialize a computer when it is being booted. This data is stored as a plain byte array, and may mean different things to different CPU architectures. For example, for Lua it is usually a small script that searches for file systems with an init script, for other architectures it may be actual machine code.
item.oc.FloppyDisk.usage=The §oFloppy Disk§r is the cheapest and smallest type of storage medium in OpenComputers. It is a handy early game way of storing data and transferring it between computers and robots. You may also find floppy disks with useful programs on them in dungeon chests.[nl][nl]Beware: shift-rightclicking while holding a floppy disk in your hand will wipe the floppy disk!

View File

@ -17,13 +17,17 @@ local text = require("text")
local args, options = shell.parse(...)
if #args < 1 then
print("Usage: irc <nickname> [server:port]")
print("Usage: irc <nickname> [server[:port]]")
return
end
local nick = args[1]
local host = args[2] or "irc.esper.net:6667"
if not host:find(":") then
host = host .. ":6667"
end
-- try to connect to server.
local sock, reason = internet.open(host)
if not sock then

View File

@ -27,7 +27,7 @@ end
function component.isAvailable(componentType)
checkArg(1, componentType, "string")
if not primaries[componentType] then
if not primaries[componentType] and not adding[componentType] then
-- This is mostly to avoid out of memory errors preventing proxy
-- creation cause confusion by trying to create the proxy again,
-- causing the oom error to be thrown again.

View File

@ -351,8 +351,8 @@ function filesystem.list(path)
table.remove(result, i)
else
f = result[i]
i = i + 1
end
i = i + 1
end
local i = 0
return function()
@ -376,22 +376,31 @@ function filesystem.makeDirectory(path)
end
function filesystem.remove(path)
local node, rest, vnode, vrest = findNode(filesystem.path(path))
local name = filesystem.name(path)
if vnode.children[name] then
vnode.children[name] = nil
removeEmptyNodes(vnode)
return true
elseif vnode.links[name] then
vnode.links[name] = nil
removeEmptyNodes(vnode)
return true
else
local function removeVirtual()
local node, rest, vnode, vrest = findNode(filesystem.path(path))
local name = filesystem.name(path)
if vnode.children[name] then
vnode.children[name] = nil
removeEmptyNodes(vnode)
return true
elseif vnode.links[name] then
vnode.links[name] = nil
removeEmptyNodes(vnode)
return true
end
return false
end
local function removePhysical()
node, rest = findNode(path)
if node.fs and rest then
return component.proxy(node.fs).remove(rest)
end
return nil, "no such file or directory"
return false
end
local success = removeVirtual()
success = removePhysical() or success -- Always run.
if success then return true
else return nil, "no such file or directory"
end
end

View File

@ -108,10 +108,11 @@ function term.isAvailable()
return component.isAvailable("gpu") and component.isAvailable("screen")
end
function term.read(history, dobreak, hint, pwchar)
function term.read(history, dobreak, hint, pwchar, filter)
checkArg(1, history, "table", "nil")
checkArg(3, hint, "function", "table", "nil")
checkArg(4, pwchar, "string", "nil")
checkArg(5, filter, "string", "function", "nil")
history = history or {}
table.insert(history, "")
local offset = term.getCursor() - 1
@ -130,6 +131,13 @@ function term.read(history, dobreak, hint, pwchar)
pwchar = unicode.sub(pwchar, 1, 1)
end
if type(filter) == "string" then
local pattern = filter
filter = function(line)
return line:match(pattern)
end
end
local function masktext(str)
return pwchar and pwchar:rep(unicode.len(str)) or str
end
@ -327,12 +335,16 @@ function term.read(history, dobreak, hint, pwchar)
elseif code == keyboard.keys.tab and hint then
tab(keyboard.isShiftDown() and -1 or 1)
elseif code == keyboard.keys.enter then
local cbx, cby = getCursor()
if cby ~= #history then -- bring entry to front
history[#history] = line()
table.remove(history, cby)
if not filter or filter(line() or "") then
local cbx, cby = getCursor()
if cby ~= #history then -- bring entry to front
history[#history] = line()
table.remove(history, cby)
end
return true, history[#history] .. "\n"
else
computer.beep(2000, 0.1)
end
return true, history[#history] .. "\n"
elseif keyboard.isControlDown() and code == keyboard.keys.d then
if line() == "" then
history[#history] = ""

View File

@ -9,7 +9,7 @@ DESCRIPTION
EXAMPLES
echo test
Print `test` to the terminal.
Print `test` to the standard output (which is usually the terminal).
echo "a b" > test
Writes the string `a b` to the standard output, which is redirected into file `test`.
echo "a b"
Writes the string `a b`.

View File

@ -0,0 +1,16 @@
assets/opencomputers/sounds/computer_running.ogg
assets/opencomputers/sounds/floppy_access1.ogg
assets/opencomputers/sounds/floppy_access2.ogg
assets/opencomputers/sounds/floppy_access3.ogg
assets/opencomputers/sounds/floppy_access4.ogg
assets/opencomputers/sounds/floppy_access5.ogg
assets/opencomputers/sounds/floppy_access6.ogg
assets/opencomputers/sounds/floppy_eject.ogg
assets/opencomputers/sounds/floppy_insert.ogg
assets/opencomputers/sounds/hdd_access1.ogg
assets/opencomputers/sounds/hdd_access2.ogg
assets/opencomputers/sounds/hdd_access3.ogg
assets/opencomputers/sounds/hdd_access4.ogg
assets/opencomputers/sounds/hdd_access5.ogg
assets/opencomputers/sounds/hdd_access6.ogg
assets/opencomputers/sounds/hdd_access7.ogg

View File

@ -49,6 +49,8 @@ class Settings(val config: Config) {
}
val monochromeColor = Integer.decode(config.getString("client.monochromeColor"))
val fontRenderer = config.getString("client.fontRenderer")
val beepSampleRate = config.getInt("client.beepSampleRate")
val beepAmplitude = config.getInt("client.beepVolume") max 0 min Byte.MaxValue
// ----------------------------------------------------------------------- //
// computer

View File

@ -5,9 +5,13 @@ import net.minecraftforge.fml.client.FMLClientHandler
import org.lwjgl.input.Keyboard
object KeyBindings {
def showExtendedTooltips = Keyboard.isCreated && Keyboard.isKeyDown(extendedTooltip.getKeyCode)
def showExtendedTooltips = Keyboard.isCreated && (try Keyboard.isKeyDown(extendedTooltip.getKeyCode) catch {
case _: Throwable => false // Don't ask me, sometimes things can apparently screw up LWJGL's keyboard handling.
})
def showMaterialCosts = Keyboard.isCreated && Keyboard.isKeyDown(materialCosts.getKeyCode)
def showMaterialCosts = Keyboard.isCreated && (try Keyboard.isKeyDown(materialCosts.getKeyCode) catch {
case _: Throwable => false // Don't ask me, sometimes things can apparently screw up LWJGL's keyboard handling.
})
def extendedTooltip = FMLClientHandler.instance.getClient.gameSettings.keyBindSneak

View File

@ -355,6 +355,9 @@ object PacketHandler extends CommonPacketHandler {
case PacketType.TextBufferMultiResolutionChange => onTextBufferMultiResolutionChange(p, buffer)
case PacketType.TextBufferMultiMaxResolutionChange => onTextBufferMultiMaxResolutionChange(p, buffer)
case PacketType.TextBufferMultiSet => onTextBufferMultiSet(p, buffer)
case PacketType.TextBufferMultiRawSetText => onTextBufferMultiRawSetText(p, buffer)
case PacketType.TextBufferMultiRawSetBackground => onTextBufferMultiRawSetBackground(p, buffer)
case PacketType.TextBufferMultiRawSetForeground => onTextBufferMultiRawSetForeground(p, buffer)
case _ => // Invalid packet.
}
}
@ -426,6 +429,60 @@ object PacketHandler extends CommonPacketHandler {
buffer.set(col, row, s, vertical)
}
def onTextBufferMultiRawSetText(p: PacketParser, buffer: component.TextBuffer) {
val col = p.readInt()
val row = p.readInt()
val rows = p.readShort()
val text = new Array[Array[Char]](rows)
for (y <- 0 until rows) {
val cols = p.readShort()
val line = new Array[Char](cols)
for (x <- 0 until cols) {
line(x) = p.readChar()
}
text(y) = line
}
buffer.rawSetText(col, row, text)
}
def onTextBufferMultiRawSetBackground(p: PacketParser, buffer: component.TextBuffer) {
val col = p.readInt()
val row = p.readInt()
val rows = p.readShort()
val color = new Array[Array[Int]](rows)
for (y <- 0 until rows) {
val cols = p.readShort()
val line = new Array[Int](cols)
for (x <- 0 until cols) {
line(x) = p.readInt()
}
color(y) = line
}
buffer.rawSetBackground(col, row, color)
}
def onTextBufferMultiRawSetForeground(p: PacketParser, buffer: component.TextBuffer) {
val col = p.readInt()
val row = p.readInt()
val rows = p.readShort()
val color = new Array[Array[Int]](rows)
for (y <- 0 until rows) {
val cols = p.readShort()
val line = new Array[Int](cols)
for (x <- 0 until cols) {
line(x) = p.readInt()
}
color(y) = line
}
buffer.rawSetForeground(col, row, color)
}
def onScreenTouchMode(p: PacketParser) =
p.readTileEntity[Screen]() match {
case Some(t) => t.invertTouchMode = p.readBoolean()

View File

@ -76,35 +76,35 @@ object PacketSender {
}
}
def sendMouseClick(address: String, x: Int, y: Int, drag: Boolean, button: Int) {
def sendMouseClick(address: String, x: Double, y: Double, drag: Boolean, button: Int) {
val pb = new SimplePacketBuilder(PacketType.MouseClickOrDrag)
pb.writeUTF(address)
pb.writeShort(x)
pb.writeShort(y)
pb.writeFloat(x.toFloat)
pb.writeFloat(y.toFloat)
pb.writeBoolean(drag)
pb.writeByte(button.toByte)
pb.sendToServer()
}
def sendMouseScroll(address: String, x: Int, y: Int, scroll: Int) {
def sendMouseScroll(address: String, x: Double, y: Double, scroll: Int) {
val pb = new SimplePacketBuilder(PacketType.MouseScroll)
pb.writeUTF(address)
pb.writeShort(x)
pb.writeShort(y)
pb.writeFloat(x.toFloat)
pb.writeFloat(y.toFloat)
pb.writeByte(scroll)
pb.sendToServer()
}
def sendMouseUp(address: String, x: Int, y: Int, button: Int) {
def sendMouseUp(address: String, x: Double, y: Double, button: Int) {
val pb = new SimplePacketBuilder(PacketType.MouseUp)
pb.writeUTF(address)
pb.writeShort(x)
pb.writeShort(y)
pb.writeFloat(x.toFloat)
pb.writeFloat(y.toFloat)
pb.writeByte(button.toByte)
pb.sendToServer()

View File

@ -8,6 +8,7 @@ import java.util.Timer
import java.util.TimerTask
import java.util.UUID
import com.google.common.base.Charsets
import li.cil.oc.OpenComputers
import li.cil.oc.Settings
import net.minecraft.client.Minecraft
@ -19,11 +20,13 @@ import net.minecraftforge.client.event.sound.SoundLoadEvent
import net.minecraftforge.event.world.WorldEvent
import net.minecraftforge.fml.client.FMLClientHandler
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
import net.minecraftforge.fml.common.gameevent.TickEvent.ClientTickEvent
import net.minecraftforge.fml.relauncher.ReflectionHelper
import paulscode.sound.SoundSystem
import paulscode.sound.SoundSystemConfig
import scala.collection.mutable
import scala.io.Source
object Sound {
private val sources = mutable.Map.empty[TileEntity, PseudoLoopingStream]
@ -100,6 +103,33 @@ object Sound {
manager = event.manager
}
private var hasPreloaded = Settings.get.soundVolume <= 0
@SubscribeEvent
def onTick(e: ClientTickEvent) {
if (!hasPreloaded && soundSystem != null) {
hasPreloaded = true
new Thread(new Runnable() {
override def run(): Unit = {
val preloadConfigLocation = new ResourceLocation(Settings.resourceDomain, "sounds/preload.cfg")
val preloadConfigResource = Minecraft.getMinecraft.getResourceManager.getResource(preloadConfigLocation)
for (location <- Source.fromInputStream(preloadConfigResource.getInputStream)(Charsets.UTF_8).getLines()) {
val url = getClass.getClassLoader.getResource(location)
if (url != null) try {
val sourceName = "preload_" + location
soundSystem.newSource(false, sourceName, url, location, true, 0, 0, 0, SoundSystemConfig.ATTENUATION_NONE, 16)
soundSystem.activate(sourceName)
soundSystem.removeSource(sourceName)
} catch {
case _: Throwable => // Meh.
}
else OpenComputers.log.warn(s"Couldn't preload sound $location!")
}
}
})
}
}
@SubscribeEvent
def onWorldUnload(event: WorldEvent.Unload) {
commandQueue.synchronized(commandQueue.clear())

View File

@ -6,8 +6,8 @@ import li.cil.oc.common.tileentity
import net.minecraft.entity.player.InventoryPlayer
class Adapter(playerInventory: InventoryPlayer, val adapter: tileentity.Adapter) extends DynamicGuiContainer(new container.Adapter(playerInventory, adapter)) {
override def drawGuiContainerForegroundLayer(mouseX: Int, mouseY: Int) = {
super.drawGuiContainerForegroundLayer(mouseX, mouseY)
override def drawSecondaryForegroundLayer(mouseX: Int, mouseY: Int) = {
super.drawSecondaryForegroundLayer(mouseX, mouseY)
fontRendererObj.drawString(
Localization.localizeImmediately(adapter.getName),
8, 6, 0x404040)

View File

@ -60,7 +60,7 @@ class Assembler(playerInventory: InventoryPlayer, val assembler: tileentity.Asse
add(buttonList, runButton)
}
override def drawGuiContainerForegroundLayer(mouseX: Int, mouseY: Int) = {
override def drawSecondaryForegroundLayer(mouseX: Int, mouseY: Int) = {
GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS) // Me lazy... prevents NEI render glitch.
if (!assemblerContainer.isAssembling) {
val message =

View File

@ -33,9 +33,8 @@ class Case(playerInventory: InventoryPlayer, val computer: tileentity.Case) exte
add(buttonList, powerButton)
}
override def drawGuiContainerForegroundLayer(mouseX: Int, mouseY: Int) = {
super.drawGuiContainerForegroundLayer(mouseX, mouseY)
GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS) // Me lazy... prevents NEI render glitch.
override protected def drawSecondaryForegroundLayer(mouseX: Int, mouseY: Int) = {
super.drawSecondaryForegroundLayer(mouseX, mouseY)
fontRendererObj.drawString(
Localization.localizeImmediately(computer.getName),
8, 6, 0x404040)
@ -44,7 +43,6 @@ class Case(playerInventory: InventoryPlayer, val computer: tileentity.Case) exte
tooltip.add(if (computer.isRunning) Localization.Computer.TurnOff else Localization.Computer.TurnOn)
copiedDrawHoveringText(tooltip, mouseX - guiLeft, mouseY - guiTop, fontRendererObj)
}
GL11.glPopAttrib()
}
override def drawSecondaryBackgroundLayer() {

View File

@ -6,8 +6,8 @@ import li.cil.oc.common.tileentity
import net.minecraft.entity.player.InventoryPlayer
class Charger(playerInventory: InventoryPlayer, val charger: tileentity.Charger) extends DynamicGuiContainer(new container.Charger(playerInventory, charger)) {
override def drawGuiContainerForegroundLayer(mouseX: Int, mouseY: Int) = {
super.drawGuiContainerForegroundLayer(mouseX, mouseY)
override def drawSecondaryForegroundLayer(mouseX: Int, mouseY: Int) = {
super.drawSecondaryForegroundLayer(mouseX, mouseY)
fontRendererObj.drawString(
Localization.localizeImmediately(charger.getName),
8, 6, 0x404040)

View File

@ -11,7 +11,7 @@ import org.lwjgl.opengl.GL11
class Database(playerInventory: InventoryPlayer, val databaseInventory: DatabaseInventory) extends DynamicGuiContainer(new container.Database(playerInventory, databaseInventory)) {
ySize = 256
override def drawGuiContainerForegroundLayer(mouseX: Int, mouseY: Int) {}
override def drawSecondaryForegroundLayer(mouseX: Int, mouseY: Int) {}
override protected def drawGuiContainerBackgroundLayer(dt: Float, mouseX: Int, mouseY: Int) {
GL11.glColor4f(1, 1, 1, 1)

View File

@ -13,7 +13,7 @@ class Disassembler(playerInventory: InventoryPlayer, val disassembler: tileentit
val progress = addWidget(new ProgressBar(18, 65))
override def drawGuiContainerForegroundLayer(mouseX: Int, mouseY: Int) = {
override def drawSecondaryForegroundLayer(mouseX: Int, mouseY: Int) = {
fontRendererObj.drawString(
Localization.localizeImmediately(disassembler.getName),
8, 6, 0x404040)

View File

@ -6,8 +6,8 @@ import li.cil.oc.common.tileentity
import net.minecraft.entity.player.InventoryPlayer
class DiskDrive(playerInventory: InventoryPlayer, val drive: tileentity.DiskDrive) extends DynamicGuiContainer(new container.DiskDrive(playerInventory, drive)) {
override def drawGuiContainerForegroundLayer(mouseX: Int, mouseY: Int) = {
super.drawGuiContainerForegroundLayer(mouseX, mouseY)
override def drawSecondaryForegroundLayer(mouseX: Int, mouseY: Int) = {
super.drawSecondaryForegroundLayer(mouseX, mouseY)
fontRendererObj.drawString(
Localization.localizeImmediately(drive.getName),
8, 6, 0x404040)

View File

@ -87,7 +87,7 @@ class Drone(playerInventory: InventoryPlayer, val drone: entity.Drone) extends D
override protected def changeSize(w: Double, h: Double, recompile: Boolean) = 2.0
override protected def drawGuiContainerForegroundLayer(mouseX: Int, mouseY: Int) {
override protected def drawSecondaryForegroundLayer(mouseX: Int, mouseY: Int) {
drawBufferLayer()
GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS) // Me lazy... prevents NEI render glitch.
if (isPointInRegion(power.x, power.y, power.width, power.height, mouseX, mouseY)) {

View File

@ -1,18 +1,21 @@
package li.cil.oc.client.gui
import codechicken.nei.ItemPanel
import codechicken.nei.LayoutManager
import li.cil.oc.Localization
import li.cil.oc.client.Textures
import li.cil.oc.common
import li.cil.oc.common.container.ComponentSlot
import li.cil.oc.common.container.Player
import li.cil.oc.integration.Mods
import li.cil.oc.integration.util.NEI
import li.cil.oc.util.RenderState
import net.minecraft.client.gui.Gui
import net.minecraft.client.renderer.GlStateManager
import net.minecraft.client.renderer.Tessellator
import net.minecraft.inventory.Container
import net.minecraft.inventory.Slot
import net.minecraft.item.ItemStack
import net.minecraftforge.fml.common.Optional
import org.lwjgl.opengl.GL11
import scala.collection.convert.WrapAsScala._
@ -22,12 +25,24 @@ abstract class DynamicGuiContainer(container: Container) extends CustomGuiContai
protected var hoveredStackNEI: Option[ItemStack] = None
override protected def drawGuiContainerForegroundLayer(mouseX: Int, mouseY: Int) {
protected def drawSecondaryForegroundLayer(mouseX: Int, mouseY: Int) {
fontRendererObj.drawString(
Localization.localizeImmediately("container.inventory"),
8, ySize - 96 + 2, 0x404040)
}
override protected def drawGuiContainerForegroundLayer(mouseX: Int, mouseY: Int) {
GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS)
drawSecondaryForegroundLayer(mouseX, mouseY)
for (slot <- 0 until inventorySlots.inventorySlots.size()) {
drawSlotHighlight(inventorySlots.inventorySlots.get(slot).asInstanceOf[Slot])
}
GL11.glPopAttrib()
}
protected def drawSecondaryBackgroundLayer() {}
override protected def drawGuiContainerBackgroundLayer(dt: Float, mouseX: Int, mouseY: Int) {
@ -41,9 +56,11 @@ abstract class DynamicGuiContainer(container: Container) extends CustomGuiContai
GL11.glPushMatrix()
GL11.glTranslatef(guiLeft, guiTop, 0)
GL11.glDisable(GL11.GL_DEPTH_TEST)
for (slot <- 0 until inventorySlots.inventorySlots.size()) {
drawSlotInventory(inventorySlots.inventorySlots.get(slot).asInstanceOf[Slot])
}
GL11.glEnable(GL11.GL_DEPTH_TEST)
GL11.glPopMatrix()
}
@ -55,12 +72,11 @@ abstract class DynamicGuiContainer(container: Container) extends CustomGuiContai
super.drawScreen(mouseX, mouseY, dt)
GL11.glPushMatrix()
GL11.glTranslatef(guiLeft, guiTop, 0)
for (slot <- 0 until inventorySlots.inventorySlots.size()) {
drawSlotHighlight(inventorySlots.inventorySlots.get(slot).asInstanceOf[Slot])
if (Mods.NotEnoughItems.isAvailable) {
GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS)
drawNEIHighlights()
GL11.glPopAttrib()
}
GL11.glPopMatrix()
}
protected def drawSlotInventory(slot: Slot) {
@ -70,13 +86,13 @@ abstract class DynamicGuiContainer(container: Container) extends CustomGuiContai
drawDisabledSlot(component)
}
case _ =>
zLevel += 1
if (!isInPlayerInventory(slot)) {
drawSlotBackground(slot.xDisplayPosition - 1, slot.yDisplayPosition - 1)
}
if (!slot.getHasStack) {
slot match {
case component: ComponentSlot =>
GL11.glDisable(GL11.GL_DEPTH_TEST)
if (component.tierIcon != null) {
mc.getTextureManager.bindTexture(component.tierIcon)
Gui.drawModalRectWithCustomSizedTexture(slot.xDisplayPosition, slot.yDisplayPosition, 0, 0, 16, 16, 16, 16)
@ -85,38 +101,37 @@ abstract class DynamicGuiContainer(container: Container) extends CustomGuiContai
mc.getTextureManager.bindTexture(slot.getBackgroundLocation)
Gui.drawModalRectWithCustomSizedTexture(slot.xDisplayPosition, slot.yDisplayPosition, 0, 0, 16, 16, 16, 16)
}
GL11.glEnable(GL11.GL_DEPTH_TEST)
case _ =>
}
zLevel -= 1
}
}
}
protected def drawSlotHighlight(slot: Slot) {
slot match {
if (mc.thePlayer.inventory.getItemStack == null) slot match {
case component: ComponentSlot if component.slot == common.Slot.None || component.tier == common.Tier.None => // Ignore.
case _ =>
if (mc.thePlayer.inventory.getItemStack == null) {
val currentIsInPlayerInventory = isInPlayerInventory(slot)
val drawHighlight = hoveredSlot match {
case Some(hovered) =>
val hoveredIsInPlayerInventory = isInPlayerInventory(hovered)
(currentIsInPlayerInventory != hoveredIsInPlayerInventory) &&
((currentIsInPlayerInventory && slot.getHasStack && isSelectiveSlot(hovered) && hovered.isItemValid(slot.getStack)) ||
(hoveredIsInPlayerInventory && hovered.getHasStack && isSelectiveSlot(slot) && slot.isItemValid(hovered.getStack)))
case _ => hoveredStackNEI match {
case Some(stack) => !currentIsInPlayerInventory && isSelectiveSlot(slot) && slot.isItemValid(stack)
case _ => false
}
}
if (drawHighlight) {
GlStateManager.disableLighting()
GL11.glDisable(GL11.GL_DEPTH_TEST)
drawGradientRect(slot.xDisplayPosition, slot.yDisplayPosition, slot.xDisplayPosition + 16, slot.yDisplayPosition + 16, 0x80FFFFFF, 0x80FFFFFF)
GlStateManager.enableLighting()
GL11.glEnable(GL11.GL_DEPTH_TEST)
val currentIsInPlayerInventory = isInPlayerInventory(slot)
val drawHighlight = hoveredSlot match {
case Some(hovered) =>
val hoveredIsInPlayerInventory = isInPlayerInventory(hovered)
(currentIsInPlayerInventory != hoveredIsInPlayerInventory) &&
((currentIsInPlayerInventory && slot.getHasStack && isSelectiveSlot(hovered) && hovered.isItemValid(slot.getStack)) ||
(hoveredIsInPlayerInventory && hovered.getHasStack && isSelectiveSlot(slot) && slot.isItemValid(hovered.getStack)))
case _ => hoveredStackNEI match {
case Some(stack) => !currentIsInPlayerInventory && isSelectiveSlot(slot) && slot.isItemValid(stack)
case _ => false
}
}
if (drawHighlight) {
zLevel += 100
drawGradientRect(
slot.xDisplayPosition, slot.yDisplayPosition,
slot.xDisplayPosition + 16, slot.yDisplayPosition + 16,
0x80FFFFFF, 0x80FFFFFF)
zLevel -= 100
}
}
}
@ -128,11 +143,7 @@ abstract class DynamicGuiContainer(container: Container) extends CustomGuiContai
protected def drawDisabledSlot(slot: ComponentSlot) {
GL11.glColor4f(1, 1, 1, 1)
mc.getTextureManager.bindTexture(slot.tierIcon)
GL11.glDisable(GL11.GL_DEPTH_TEST)
GL11.glDisable(GL11.GL_LIGHTING)
Gui.drawModalRectWithCustomSizedTexture(slot.xDisplayPosition, slot.yDisplayPosition, 0, 0, 16, 16, 16, 16)
GL11.glEnable(GL11.GL_LIGHTING)
GL11.glEnable(GL11.GL_DEPTH_TEST)
}
protected def drawSlotBackground(x: Int, y: Int) {
@ -152,4 +163,26 @@ abstract class DynamicGuiContainer(container: Container) extends CustomGuiContai
case player: Player => slot.inventory == player.playerInventory
case _ => false
}
@Optional.Method(modid = Mods.IDs.NotEnoughItems)
private def drawNEIHighlights(): Unit = {
val panel = LayoutManager.itemPanel
if (panel == null) return
zLevel += 350
for (index <- 0 until ItemPanel.items.size()) {
val rect = panel.getSlotRect(index)
val slot = panel.getSlotMouseOver(rect.x, rect.y)
if (slot != null) hoveredSlot match {
case Some(hovered) =>
if (!isInPlayerInventory(hovered) && isSelectiveSlot(hovered) && hovered.isItemValid(slot.item)) {
drawGradientRect(
rect.x1 + 1, rect.y1 + 1,
rect.x2, rect.y2,
0x40FFFFFF, 0x40FFFFFF)
}
case _ =>
}
}
zLevel -= 350
}
}

View File

@ -8,8 +8,8 @@ import net.minecraft.entity.player.InventoryPlayer
import org.lwjgl.opengl.GL11
class Raid(playerInventory: InventoryPlayer, val raid: tileentity.Raid) extends DynamicGuiContainer(new container.Raid(playerInventory, raid)) {
override def drawGuiContainerForegroundLayer(mouseX: Int, mouseY: Int) = {
super.drawGuiContainerForegroundLayer(mouseX, mouseY)
override def drawSecondaryForegroundLayer(mouseX: Int, mouseY: Int) = {
super.drawSecondaryForegroundLayer(mouseX, mouseY)
fontRendererObj.drawString(
Localization.localizeImmediately(raid.getName),
8, 6, 0x404040)

View File

@ -128,7 +128,7 @@ class Robot(playerInventory: InventoryPlayer, val robot: tileentity.Robot) exten
}
}
override protected def drawGuiContainerForegroundLayer(mouseX: Int, mouseY: Int) {
override protected def drawSecondaryForegroundLayer(mouseX: Int, mouseY: Int) {
drawBufferLayer()
GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS) // Me lazy... prevents NEI render glitch.
if (isPointInRegion(power.x, power.y, power.width, power.height, mouseX, mouseY)) {

View File

@ -20,18 +20,18 @@ class Screen(val buffer: api.component.TextBuffer, val hasMouse: Boolean, val ha
private var x, y = 0
private var mx, my = 0
private var mx, my = -1
override def handleMouseInput() {
super.handleMouseInput()
if (hasMouse && Mouse.hasWheel && Mouse.getEventDWheel != 0) {
val mouseX = Mouse.getEventX * width / mc.displayWidth
val mouseY = height - Mouse.getEventY * height / mc.displayHeight - 1
val bx = (mouseX - x - bufferMargin) / TextBufferRenderCache.renderer.charRenderWidth + 1
val by = (mouseY - y - bufferMargin) / TextBufferRenderCache.renderer.charRenderHeight + 1
val bx = (mouseX - x - bufferMargin) / TextBufferRenderCache.renderer.charRenderWidth.toDouble
val by = (mouseY - y - bufferMargin) / TextBufferRenderCache.renderer.charRenderHeight.toDouble
val bw = buffer.getWidth
val bh = buffer.getHeight
if (bx > 0 && by > 0 && bx <= bw && by <= bh) {
if (bx >= 0 && by >= 0 && bx < bw && by < bh) {
val scroll = math.signum(Mouse.getEventDWheel)
buffer.mouseScroll(bx, by, scroll, null)
}
@ -60,35 +60,35 @@ class Screen(val buffer: api.component.TextBuffer, val hasMouse: Boolean, val ha
super.mouseReleased(mouseX, mouseY, button)
if (hasMouse && button >= 0) {
if (didDrag) {
val bx = ((mouseX - x - bufferMargin) / scale / TextBufferRenderCache.renderer.charRenderWidth).toInt + 1
val by = ((mouseY - y - bufferMargin) / scale / TextBufferRenderCache.renderer.charRenderHeight).toInt + 1
val bx = (mouseX - x - bufferMargin) / scale / TextBufferRenderCache.renderer.charRenderWidth
val by = (mouseY - y - bufferMargin) / scale / TextBufferRenderCache.renderer.charRenderHeight
val bw = buffer.getWidth
val bh = buffer.getHeight
if (bx > 0 && by > 0 && bx <= bw && by <= bh) {
if (bx >= 0 && by >= 0 && bx < bw && by < bh) {
buffer.mouseUp(bx, by, button, null)
}
else {
buffer.mouseUp(-1, -1, button, null)
buffer.mouseUp(-1.0, -1.0, button, null)
}
}
didDrag = false
mx = 0
my = 0
mx = -1
my = -1
}
}
private def clickOrDrag(mouseX: Int, mouseY: Int, button: Int) {
val bx = ((mouseX - x - bufferMargin) / scale / TextBufferRenderCache.renderer.charRenderWidth).toInt + 1
val by = ((mouseY - y - bufferMargin) / scale / TextBufferRenderCache.renderer.charRenderHeight).toInt + 1
val bx = (mouseX - x - bufferMargin) / scale / TextBufferRenderCache.renderer.charRenderWidth
val by = (mouseY - y - bufferMargin) / scale / TextBufferRenderCache.renderer.charRenderHeight
val bw = buffer.getWidth
val bh = buffer.getHeight
if (bx > 0 && by > 0 && bx <= bw && by <= bh) {
if (bx != mx || by != my) {
if (mx > 0 && my > 0) buffer.mouseDrag(bx, by, button, null)
if (bx >= 0 && by >= 0 && bx < bw && by < bh) {
if (bx.toInt != mx || by.toInt != my) {
if (mx >= 0 && my >= 0) buffer.mouseDrag(bx, by, button, null)
else buffer.mouseDown(bx, by, button, null)
didDrag = mx > 0 && my > 0
mx = bx
my = by
didDrag = mx >= 0 && my >= 0
mx = bx.toInt
my = by.toInt
}
}
}

View File

@ -9,8 +9,8 @@ import net.minecraft.inventory.Slot
import org.lwjgl.opengl.GL11
class Server(playerInventory: InventoryPlayer, serverInventory: ServerInventory) extends DynamicGuiContainer(new container.Server(playerInventory, serverInventory)) {
override def drawGuiContainerForegroundLayer(mouseX: Int, mouseY: Int) {
super.drawGuiContainerForegroundLayer(mouseX, mouseY)
override def drawSecondaryForegroundLayer(mouseX: Int, mouseY: Int) {
super.drawSecondaryForegroundLayer(mouseX, mouseY)
fontRendererObj.drawString(
Localization.localizeImmediately(serverInventory.getName),
8, 6, 0x404040)

View File

@ -73,8 +73,8 @@ class ServerRack(playerInventory: InventoryPlayer, val rack: tileentity.ServerRa
add(buttonList, switchButton)
}
override def drawGuiContainerForegroundLayer(mouseX: Int, mouseY: Int) = {
super.drawGuiContainerForegroundLayer(mouseX, mouseY)
override def drawSecondaryForegroundLayer(mouseX: Int, mouseY: Int) = {
super.drawSecondaryForegroundLayer(mouseX, mouseY)
GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS) // Prevents NEI render glitch.
fontRendererObj.drawString(

View File

@ -11,8 +11,8 @@ class Switch(playerInventory: InventoryPlayer, val switch: tileentity.Switch) ex
private val switchContainer = inventorySlots.asInstanceOf[container.Switch]
private val format = new DecimalFormat("#.##hz")
override def drawGuiContainerForegroundLayer(mouseX: Int, mouseY: Int) = {
super.drawGuiContainerForegroundLayer(mouseX, mouseY)
override def drawSecondaryForegroundLayer(mouseX: Int, mouseY: Int) = {
super.drawSecondaryForegroundLayer(mouseX, mouseY)
fontRendererObj.drawString(
Localization.localizeImmediately(switch.getName),
8, 6, 0x404040)

View File

@ -7,6 +7,7 @@ import li.cil.oc.api.Network
import li.cil.oc.api.detail.ItemInfo
import li.cil.oc.client.renderer.PetRenderer
import li.cil.oc.client.{PacketSender => ClientPacketSender}
import li.cil.oc.common.item.data.MicrocontrollerData
import li.cil.oc.integration.Mods
import li.cil.oc.integration.util
import li.cil.oc.server.{PacketSender => ServerPacketSender}
@ -45,7 +46,7 @@ object EventHandler {
def scheduleWirelessRedstone(rs: server.component.RedstoneWireless) {
if (SideTracker.isServer) pending.synchronized {
pending += (() => if (!rs.owner.isInvalid) {
pending += (() => if (rs.node.network != null) {
util.WirelessRedstone.addReceiver(rs)
util.WirelessRedstone.updateOutput(rs)
})
@ -90,11 +91,18 @@ object EventHandler {
@SubscribeEvent
def clientLoggedIn(e: ClientConnectedToServerEvent) {
PetRenderer.hidden.clear()
if (Settings.get.hideOwnPet) {
PetRenderer.hidden += Minecraft.getMinecraft.thePlayer.getName
try {
PetRenderer.hidden.clear()
if (Settings.get.hideOwnPet) {
PetRenderer.hidden += Minecraft.getMinecraft.thePlayer.getName
}
ClientPacketSender.sendPetVisibility()
}
catch {
case _: Throwable =>
// Reportedly, things can derp if this is called at inopportune moments,
// such as the server shutting down.
}
ClientPacketSender.sendPetVisibility()
}
lazy val drone = api.Items.get("drone")
@ -116,12 +124,12 @@ object EventHandler {
didRecraft = recraft(e, mcu, stack => {
// Restore EEPROM currently used in microcontroller.
new ItemUtils.MicrocontrollerData(stack).components.find(api.Items.get(_) == eeprom)
new MicrocontrollerData(stack).components.find(api.Items.get(_) == eeprom)
}) || didRecraft
didRecraft = recraft(e, drone, stack => {
// Restore EEPROM currently used in drone.
new ItemUtils.MicrocontrollerData(stack).components.find(api.Items.get(_) == eeprom)
new MicrocontrollerData(stack).components.find(api.Items.get(_) == eeprom)
}) || didRecraft
// Presents?

View File

@ -40,6 +40,9 @@ object PacketType extends Enumeration {
TextBufferMultiResolutionChange,
TextBufferMultiMaxResolutionChange,
TextBufferMultiSet,
TextBufferMultiRawSetText,
TextBufferMultiRawSetBackground,
TextBufferMultiRawSetForeground,
TextBufferPowerChange,
ScreenTouchMode,
ServerPresence,

View File

@ -1,33 +1,23 @@
package li.cil.oc.common.block
import li.cil.oc.OpenComputers
import li.cil.oc.common.GuiType
import li.cil.oc.common.tileentity
import net.minecraft.block.Block
import net.minecraft.block.state.IBlockState
import net.minecraft.entity.player.EntityPlayer
import net.minecraft.util.BlockPos
import net.minecraft.util.EnumFacing
import net.minecraft.world.IBlockAccess
import net.minecraft.world.World
class Adapter extends SimpleBlock {
class Adapter extends SimpleBlock with traits.GUI {
override def guiType = GuiType.Adapter
override def hasTileEntity(state: IBlockState) = true
override def createNewTileEntity(world: World, metadata: Int) = new tileentity.Adapter()
// ----------------------------------------------------------------------- //
override def localOnBlockActivated(world: World, pos: BlockPos, player: EntityPlayer, side: EnumFacing, hitX: Float, hitY: Float, hitZ: Float) = {
if (!player.isSneaking) {
if (!world.isRemote) {
player.openGui(OpenComputers, GuiType.Adapter.id, world, pos.getX, pos.getY, pos.getZ)
}
true
}
else false
}
override def onNeighborBlockChange(world: World, pos: BlockPos, state: IBlockState, neighborBlock: Block) =
world.getTileEntity(pos) match {
case adapter: tileentity.Adapter => adapter.neighborChanged()

View File

@ -1,17 +1,15 @@
package li.cil.oc.common.block
import li.cil.oc.OpenComputers
import li.cil.oc.Settings
import li.cil.oc.common.GuiType
import li.cil.oc.common.tileentity
import net.minecraft.block.state.IBlockState
import net.minecraft.entity.player.EntityPlayer
import net.minecraft.util.BlockPos
import net.minecraft.util.EnumFacing
import net.minecraft.world.IBlockAccess
import net.minecraft.world.World
class Assembler extends SimpleBlock with traits.PowerAcceptor with traits.StateAware {
class Assembler extends SimpleBlock with traits.PowerAcceptor with traits.StateAware with traits.GUI {
setLightLevel(0.34f)
override def isOpaqueCube = false
@ -20,23 +18,15 @@ class Assembler extends SimpleBlock with traits.PowerAcceptor with traits.StateA
override def isBlockSolid(world: IBlockAccess, pos: BlockPos, side: EnumFacing) = side == EnumFacing.DOWN || side == EnumFacing.UP
override def isSideSolid(world: IBlockAccess, pos: BlockPos, side: EnumFacing) = side == EnumFacing.DOWN || side == EnumFacing.UP
// ----------------------------------------------------------------------- //
override def energyThroughput = Settings.get.assemblerRate
override def guiType = GuiType.Assembler
override def hasTileEntity(state: IBlockState) = true
override def createNewTileEntity(world: World, metadata: Int) = new tileentity.Assembler()
// ----------------------------------------------------------------------- //
override def localOnBlockActivated(world: World, pos: BlockPos, player: EntityPlayer, side: EnumFacing, hitX: Float, hitY: Float, hitZ: Float) = {
if (!player.isSneaking) {
if (!world.isRemote) {
player.openGui(OpenComputers, GuiType.Assembler.id, world, pos.getX, pos.getY, pos.getZ)
}
true
}
else false
}
}

View File

@ -8,7 +8,9 @@ import codechicken.multipart.TFacePart
import codechicken.multipart.TileMultipart
import li.cil.oc.integration.fmp.CablePart
*/
import li.cil.oc.api.network.Environment
import li.cil.oc.api.network.SidedComponent
import li.cil.oc.api.network.SidedEnvironment
import li.cil.oc.common.tileentity
import li.cil.oc.integration.Mods
@ -65,6 +67,8 @@ class Cable extends SimpleBlock with traits.Extended {
override def shouldSideBeRendered(world: IBlockAccess, pos: BlockPos, side: EnumFacing) = true
override def isSideSolid(world: IBlockAccess, pos: BlockPos, side: EnumFacing) = false
// ----------------------------------------------------------------------- //
override def hasTileEntity(state: IBlockState) = true
@ -142,12 +146,15 @@ object Cable {
case host: SidedEnvironment =>
if (host.getWorld.isRemote) host.canConnect(side)
else host.sidedNode(side) != null
case host: Environment with SidedComponent =>
host.canConnectNode(side)
case host: Environment => true
case host if Mods.ForgeMultipart.isAvailable => hasMultiPartNode(tileEntity)
case _ => false
}
private def hasMultiPartNode(tileEntity: TileEntity) = false
/* TODO FMP
tileEntity match {
case host: TileMultipart => host.partList.exists(_.isInstanceOf[CablePart])
@ -164,6 +171,7 @@ object Cable {
}
private def cableColorFMP(tileEntity: TileEntity) = EnumDyeColor.SILVER
/* TODO FMP
tileEntity match {
case host: TileMultipart => (host.partList collect {
@ -179,6 +187,7 @@ object Cable {
}
private def canConnectFromSideFMP(tileEntity: TileEntity, side: EnumFacing) = true
/* TODO FMP
tileEntity match {
case host: TileMultipart =>

View File

@ -1,5 +1,7 @@
package li.cil.oc.common.block
import java.util.Random
import li.cil.oc.common.tileentity
import net.minecraft.block.Block
import net.minecraft.block.state.IBlockState
@ -8,6 +10,7 @@ import net.minecraft.world.World
class Capacitor extends SimpleBlock {
setLightLevel(0.34f)
setTickRandomly(true)
// ----------------------------------------------------------------------- //
@ -17,6 +20,21 @@ class Capacitor extends SimpleBlock {
// ----------------------------------------------------------------------- //
override def hasComparatorInputOverride = true
override def getComparatorInputOverride(world: World, pos: BlockPos): Int =
world.getTileEntity(pos) match {
case capacitor: tileentity.Capacitor if !world.isRemote =>
math.round(15 * capacitor.node.localBuffer / capacitor.node.localBufferSize).toInt
case _ => 0
}
override def updateTick(world: World, pos: BlockPos, state: IBlockState, rand: Random): Unit = {
world.notifyNeighborsOfStateChange(pos, this)
}
override def tickRate(world: World) = 1
override def onNeighborBlockChange(world: World, pos: BlockPos, state: IBlockState, neighborBlock: Block) =
world.getTileEntity(pos) match {
case capacitor: tileentity.Capacitor => capacitor.recomputeCapacity()

View File

@ -2,11 +2,9 @@ package li.cil.oc.common.block
import java.util
import li.cil.oc.OpenComputers
import li.cil.oc.Settings
import li.cil.oc.common.GuiType
import li.cil.oc.common.tileentity
import li.cil.oc.integration.util.Wrench
import li.cil.oc.util.Color
import li.cil.oc.util.Rarity
import li.cil.oc.util.Tooltip
@ -28,7 +26,7 @@ object Case {
final val Running = PropertyBool.create("running")
}
class Case(val tier: Int) extends RedstoneAware with traits.PowerAcceptor with traits.Rotatable with traits.StateAware {
class Case(val tier: Int) extends RedstoneAware with traits.PowerAcceptor with traits.Rotatable with traits.StateAware with traits.GUI {
def getRunning(state: IBlockState) =
if (state.getBlock == this)
state.getValue(Case.Running).asInstanceOf[Boolean]
@ -69,27 +67,21 @@ class Case(val tier: Int) extends RedstoneAware with traits.PowerAcceptor with t
override def energyThroughput = Settings.get.caseRate(tier)
override def guiType = GuiType.Case
override def createNewTileEntity(world: World, metadata: Int) = new tileentity.Case(tier)
// ----------------------------------------------------------------------- //
override def localOnBlockActivated(world: World, pos: BlockPos, player: EntityPlayer, side: EnumFacing, hitX: Float, hitY: Float, hitZ: Float) = {
if (!player.isSneaking && !Wrench.holdsApplicableWrench(player, pos)) {
if (!world.isRemote) {
player.openGui(OpenComputers, GuiType.Case.id, world, pos.getX, pos.getY, pos.getZ)
if (player.isSneaking) {
if (!world.isRemote) world.getTileEntity(pos) match {
case computer: tileentity.Case if !computer.machine.isRunning => computer.machine.start()
case _ =>
}
true
}
else if (player.getCurrentEquippedItem == null) {
if (!world.isRemote) {
world.getTileEntity(pos) match {
case computer: tileentity.Case if !computer.machine.isRunning => computer.machine.start()
case _ =>
}
}
true
}
else false
else super.localOnBlockActivated(world, pos, player, side, hitX, hitY, hitZ)
}
override def removedByPlayer(world: World, pos: BlockPos, player: EntityPlayer, willHarvest: Boolean) =

View File

@ -1,6 +1,5 @@
package li.cil.oc.common.block
import li.cil.oc.OpenComputers
import li.cil.oc.Settings
import li.cil.oc.common.GuiType
import li.cil.oc.common.tileentity
@ -14,11 +13,13 @@ import net.minecraft.util.EnumFacing
import net.minecraft.world.IBlockAccess
import net.minecraft.world.World
class Charger extends RedstoneAware with traits.PowerAcceptor with traits.Rotatable with traits.StateAware {
class Charger extends RedstoneAware with traits.PowerAcceptor with traits.Rotatable with traits.StateAware with traits.GUI {
override protected def setDefaultExtendedState(state: IBlockState) = setDefaultState(state)
override def energyThroughput = Settings.get.chargerRate
override def guiType = GuiType.Charger
override def createNewTileEntity(world: World, metadata: Int) = new tileentity.Charger()
// ----------------------------------------------------------------------- //
@ -28,26 +29,18 @@ class Charger extends RedstoneAware with traits.PowerAcceptor with traits.Rotata
// ----------------------------------------------------------------------- //
override def localOnBlockActivated(world: World, pos: BlockPos, player: EntityPlayer, side: EnumFacing, hitX: Float, hitY: Float, hitZ: Float) =
world.getTileEntity(pos) match {
if (Wrench.holdsApplicableWrench(player, pos)) world.getTileEntity(pos) match {
case charger: tileentity.Charger =>
if (Wrench.holdsApplicableWrench(player, pos)) {
if (!world.isRemote) {
charger.invertSignal = !charger.invertSignal
charger.chargeSpeed = 1.0 - charger.chargeSpeed
PacketSender.sendChargerState(charger)
Wrench.wrenchUsed(player, pos)
}
true
if (!world.isRemote) {
charger.invertSignal = !charger.invertSignal
charger.chargeSpeed = 1.0 - charger.chargeSpeed
PacketSender.sendChargerState(charger)
Wrench.wrenchUsed(player, pos)
}
else if (!player.isSneaking) {
if (!world.isRemote) {
player.openGui(OpenComputers, GuiType.Charger.id, world, pos.getX, pos.getY, pos.getZ)
}
true
}
else false
case _ => super.localOnBlockActivated(world, pos, player, side, hitX, hitY, hitZ)
true
case _ => false
}
else super.localOnBlockActivated(world, pos, player, side, hitX, hitY, hitZ)
override def onNeighborBlockChange(world: World, pos: BlockPos, state: IBlockState, neighborBlock: Block) {
world.getTileEntity(pos) match {

View File

@ -1,6 +1,5 @@
package li.cil.oc.common.block
import li.cil.oc.OpenComputers
import li.cil.oc.Settings
import li.cil.oc.common.GuiType
import li.cil.oc.common.tileentity
@ -8,11 +7,9 @@ import li.cil.oc.util.Tooltip
import net.minecraft.block.state.IBlockState
import net.minecraft.entity.player.EntityPlayer
import net.minecraft.item.ItemStack
import net.minecraft.util.BlockPos
import net.minecraft.util.EnumFacing
import net.minecraft.world.World
class Disassembler extends SimpleBlock with traits.PowerAcceptor with traits.StateAware {
class Disassembler extends SimpleBlock with traits.PowerAcceptor with traits.StateAware with traits.GUI {
override protected def tooltipBody(metadata: Int, stack: ItemStack, player: EntityPlayer, tooltip: java.util.List[String], advanced: Boolean) {
tooltip.addAll(Tooltip.get(getClass.getSimpleName, (Settings.get.disassemblerBreakChance * 100).toInt.toString))
}
@ -21,19 +18,9 @@ class Disassembler extends SimpleBlock with traits.PowerAcceptor with traits.Sta
override def energyThroughput = Settings.get.disassemblerRate
override def guiType = GuiType.Disassembler
override def hasTileEntity(state: IBlockState) = true
override def createNewTileEntity(world: World, metadata: Int) = new tileentity.Disassembler()
// ----------------------------------------------------------------------- //
override def localOnBlockActivated(world: World, pos: BlockPos, player: EntityPlayer, side: EnumFacing, hitX: Float, hitY: Float, hitZ: Float) = {
if (!player.isSneaking) {
if (!world.isRemote) {
player.openGui(OpenComputers, GuiType.Disassembler.id, world, pos.getX, pos.getY, pos.getZ)
}
true
}
else false
}
}

View File

@ -1,6 +1,5 @@
package li.cil.oc.common.block
import li.cil.oc.OpenComputers
import li.cil.oc.common.GuiType
import li.cil.oc.common.tileentity
import li.cil.oc.integration.Mods
@ -12,7 +11,7 @@ import net.minecraft.util.BlockPos
import net.minecraft.util.EnumFacing
import net.minecraft.world.World
class DiskDrive extends SimpleBlock with traits.Rotatable {
class DiskDrive extends SimpleBlock with traits.Rotatable with traits.GUI {
override protected def setDefaultExtendedState(state: IBlockState) = setDefaultState(state)
override protected def tooltipTail(metadata: Int, stack: ItemStack, player: EntityPlayer, tooltip: java.util.List[String], advanced: Boolean) {
@ -24,6 +23,8 @@ class DiskDrive extends SimpleBlock with traits.Rotatable {
// ----------------------------------------------------------------------- //
override def guiType = GuiType.DiskDrive
override def hasTileEntity(state: IBlockState) = true
override def createNewTileEntity(world: World, metadata: Int) = new tileentity.DiskDrive()
@ -41,30 +42,23 @@ class DiskDrive extends SimpleBlock with traits.Rotatable {
// ----------------------------------------------------------------------- //
override def localOnBlockActivated(world: World, pos: BlockPos, player: EntityPlayer, side: EnumFacing, hitX: Float, hitY: Float, hitZ: Float) = {
world.getTileEntity(pos) match {
// Behavior: sneaking -> Insert[+Eject], not sneaking -> GUI.
if (player.isSneaking) world.getTileEntity(pos) match {
case drive: tileentity.DiskDrive =>
// Behavior: sneaking -> Insert[+Eject], not sneaking -> GUI.
if (!player.isSneaking) {
val isDiskInDrive = drive.getStackInSlot(0) != null
val isHoldingDisk = drive.isItemValidForSlot(0, player.getCurrentEquippedItem)
if (isDiskInDrive) {
if (!world.isRemote) {
player.openGui(OpenComputers, GuiType.DiskDrive.id, world, pos.getX, pos.getY, pos.getZ)
drive.dropSlot(0, 1, Option(drive.facing))
}
true
}
else {
val isDiskInDrive = drive.getStackInSlot(0) != null
val isHoldingDisk = drive.isItemValidForSlot(0, player.getCurrentEquippedItem)
if (isDiskInDrive) {
if (!world.isRemote) {
drive.dropSlot(0, 1, Option(drive.facing))
}
}
if (isHoldingDisk) {
// Insert the disk.
drive.setInventorySlotContents(0, player.inventory.decrStackSize(player.inventory.currentItem, 1))
}
isDiskInDrive || isHoldingDisk
if (isHoldingDisk) {
// Insert the disk.
drive.setInventorySlotContents(0, player.inventory.decrStackSize(player.inventory.currentItem, 1))
}
isDiskInDrive || isHoldingDisk
case _ => false
}
else super.localOnBlockActivated(world, pos, player, side, hitX, hitY, hitZ)
}
}

View File

@ -32,6 +32,8 @@ class Hologram(val tier: Int) extends SimpleBlock {
super.shouldSideBeRendered(world, pos, side) || side == EnumFacing.UP
}
override def isSideSolid(world: IBlockAccess, pos: BlockPos, side: EnumFacing) = side == EnumFacing.DOWN
// ----------------------------------------------------------------------- //
override def rarity(stack: ItemStack) = Rarity.byTier(tier)

View File

@ -5,6 +5,7 @@ import java.util
import li.cil.oc.Settings
import li.cil.oc.api
import li.cil.oc.client.KeyBindings
import li.cil.oc.common.item.data.RobotData
import li.cil.oc.common.tileentity
import li.cil.oc.util.Color
import li.cil.oc.util.ItemCosts
@ -83,7 +84,7 @@ class Item(value: Block) extends ItemBlock(value) {
// manually before it's placed to ensure different component addresses
// in the different robots, to avoid interference of screens e.g.
val needsCopying = player.capabilities.isCreativeMode && api.Items.get(stack) == api.Items.get("robot")
val stackToUse = if (needsCopying) new ItemUtils.RobotData(stack).copyItemStack() else stack
val stackToUse = if (needsCopying) new RobotData(stack).copyItemStack() else stack
if (super.placeBlockAt(stackToUse, player, world, pos, side, hitX, hitY, hitZ, newState)) {
// If it's a rotatable block try to make it face the player.
world.getTileEntity(pos) match {

View File

@ -5,13 +5,12 @@ import java.util
import li.cil.oc.Settings
import li.cil.oc.client.KeyBindings
import li.cil.oc.common.Tier
import li.cil.oc.common.item.data.MicrocontrollerData
import li.cil.oc.common.tileentity
import li.cil.oc.integration.util.NEI
import li.cil.oc.integration.util.Wrench
import li.cil.oc.util.BlockPosition
import li.cil.oc.util.InventoryUtils
import li.cil.oc.util.ItemUtils
import li.cil.oc.util.Rarity
import net.minecraft.block.Block
import net.minecraft.block.state.IBlockState
import net.minecraft.entity.EntityLivingBase
import net.minecraft.entity.player.EntityPlayer
@ -19,10 +18,11 @@ import net.minecraft.item.ItemStack
import net.minecraft.util.BlockPos
import net.minecraft.util.EnumFacing
import net.minecraft.util.MovingObjectPosition
import net.minecraft.world.IBlockAccess
import net.minecraft.world.World
class Microcontroller extends RedstoneAware with traits.PowerAcceptor with traits.Rotatable with traits.StateAware {
import scala.reflect.ClassTag
class Microcontroller(protected implicit val tileTag: ClassTag[tileentity.Microcontroller]) extends RedstoneAware with traits.PowerAcceptor with traits.Rotatable with traits.StateAware with traits.CustomDrops[tileentity.Microcontroller] {
setCreativeTab(null)
NEI.hide(this)
@ -36,17 +36,12 @@ class Microcontroller extends RedstoneAware with traits.PowerAcceptor with trait
case _ => null
}
// Custom drop logic for NBT tagged item stack.
override def getDrops(world: IBlockAccess, pos: BlockPos, state: IBlockState, fortune: Int) = new java.util.ArrayList[ItemStack]()
override def onBlockHarvested(worldIn: World, pos: BlockPos, state: IBlockState, player: EntityPlayer) {}
// ----------------------------------------------------------------------- //
override protected def tooltipTail(metadata: Int, stack: ItemStack, player: EntityPlayer, tooltip: util.List[String], advanced: Boolean) {
super.tooltipTail(metadata, stack, player, tooltip, advanced)
if (KeyBindings.showExtendedTooltips) {
val info = new ItemUtils.MicrocontrollerData(stack)
val info = new MicrocontrollerData(stack)
for (component <- info.components) {
tooltip.add("- " + component.getDisplayName)
}
@ -54,7 +49,7 @@ class Microcontroller extends RedstoneAware with traits.PowerAcceptor with trait
}
override def rarity(stack: ItemStack) = {
val data = new ItemUtils.MicrocontrollerData(stack)
val data = new MicrocontrollerData(stack)
Rarity.byTier(data.tier)
}
@ -81,26 +76,16 @@ class Microcontroller extends RedstoneAware with traits.PowerAcceptor with trait
else false
}
override def onBlockPlacedBy(world: World, pos: BlockPos, state: IBlockState, placer: EntityLivingBase, stack: ItemStack) {
super.onBlockPlacedBy(world, pos, state, placer, stack)
if (!world.isRemote) world.getTileEntity(pos) match {
case mcu: tileentity.Microcontroller =>
mcu.info.load(stack)
mcu.snooperNode.changeBuffer(mcu.info.storedEnergy - mcu.snooperNode.localBuffer)
case _ =>
}
override protected def doCustomInit(tileEntity: tileentity.Microcontroller, player: EntityLivingBase, stack: ItemStack): Unit = {
super.doCustomInit(tileEntity, player, stack)
tileEntity.info.load(stack)
tileEntity.snooperNode.changeBuffer(tileEntity.info.storedEnergy - tileEntity.snooperNode.localBuffer)
}
override def removedByPlayer(world: World, pos: BlockPos, player: EntityPlayer, willHarvest: Boolean) = {
if (!world.isRemote) {
world.getTileEntity(pos) match {
case mcu: tileentity.Microcontroller =>
mcu.saveComponents()
mcu.info.storedEnergy = mcu.snooperNode.localBuffer.toInt
InventoryUtils.spawnStackInWorld(BlockPosition(pos, world), mcu.info.createItemStack())
case _ =>
}
}
super.removedByPlayer(world, pos, player, willHarvest)
override protected def doCustomDrops(tileEntity: tileentity.Microcontroller, player: EntityPlayer, willHarvest: Boolean): Unit = {
super.doCustomDrops(tileEntity, player, willHarvest)
tileEntity.saveComponents()
tileEntity.info.storedEnergy = tileEntity.snooperNode.localBuffer.toInt
Block.spawnAsEntity(tileEntity.world, tileEntity.getPos, tileEntity.info.createItemStack())
}
}

View File

@ -1,19 +1,40 @@
package li.cil.oc.common.block
import li.cil.oc.OpenComputers
import java.util
import li.cil.oc.client.KeyBindings
import li.cil.oc.common.GuiType
import li.cil.oc.common.item.data.RaidData
import li.cil.oc.common.tileentity
import net.minecraft.block.Block
import net.minecraft.block.state.IBlockState
import net.minecraft.entity.EntityLivingBase
import net.minecraft.entity.player.EntityPlayer
import net.minecraft.item.ItemStack
import net.minecraft.util.BlockPos
import net.minecraft.util.EnumFacing
import net.minecraft.world.World
class Raid extends SimpleBlock with traits.Rotatable {
import scala.reflect.ClassTag
class Raid(protected implicit val tileTag: ClassTag[tileentity.Raid]) extends SimpleBlock with traits.Rotatable with traits.GUI with traits.CustomDrops[tileentity.Raid] {
override protected def setDefaultExtendedState(state: IBlockState) = setDefaultState(state)
override def hasTileEntity(state: IBlockState) = true
override protected def tooltipTail(metadata: Int, stack: ItemStack, player: EntityPlayer, tooltip: util.List[String], advanced: Boolean) {
super.tooltipTail(metadata, stack, player, tooltip, advanced)
if (KeyBindings.showExtendedTooltips) {
val data = new RaidData(stack)
for (disk <- data.disks) {
tooltip.add("- " + disk.getDisplayName)
}
}
}
// ----------------------------------------------------------------------- //
override def guiType = GuiType.Raid
override def createNewTileEntity(world: World, metadata: Int) = new tileentity.Raid()
// ----------------------------------------------------------------------- //
@ -26,16 +47,27 @@ class Raid extends SimpleBlock with traits.Rotatable {
case _ => 0
}
// ----------------------------------------------------------------------- //
override def localOnBlockActivated(world: World, pos: BlockPos, player: EntityPlayer, side: EnumFacing, hitX: Float, hitY: Float, hitZ: Float) = {
world.getTileEntity(pos) match {
case drive: tileentity.Raid if !player.isSneaking =>
if (!world.isRemote) {
player.openGui(OpenComputers, GuiType.Raid.id, world, pos.getX, pos.getY, pos.getZ)
}
true
case _ => false
override protected def doCustomInit(tileEntity: tileentity.Raid, player: EntityLivingBase, stack: ItemStack): Unit = {
super.doCustomInit(tileEntity, player, stack)
val data = new RaidData(stack)
for (i <- 0 until math.min(data.disks.length, tileEntity.getSizeInventory)) {
tileEntity.setInventorySlotContents(i, data.disks(i))
}
data.label.foreach(tileEntity.label.setLabel)
if (!data.filesystem.hasNoTags) {
tileEntity.tryCreateRaid(data.filesystem.getCompoundTag("node").getString("address"))
tileEntity.filesystem.foreach(_.load(data.filesystem))
}
}
override protected def doCustomDrops(tileEntity: tileentity.Raid, player: EntityPlayer, willHarvest: Boolean): Unit = {
super.doCustomDrops(tileEntity, player, willHarvest)
val stack = createItemStack()
val data = new RaidData()
data.disks = tileEntity.items.map(_.orNull)
tileEntity.filesystem.foreach(_.save(data.filesystem))
data.label = Option(tileEntity.label.getLabel)
data.save(stack)
Block.spawnAsEntity(tileEntity.world, tileEntity.getPos, stack)
}
}

View File

@ -4,9 +4,9 @@ import java.util.Random
import li.cil.oc.Settings
import li.cil.oc.api
import li.cil.oc.common.item.data.RobotData
import li.cil.oc.common.tileentity
import li.cil.oc.integration.util.NEI
import li.cil.oc.util.ItemUtils
import li.cil.oc.util.Rarity
import net.minecraft.block.state.IBlockState
import net.minecraft.entity.player.EntityPlayer
@ -30,6 +30,8 @@ class RobotAfterimage extends SimpleBlock {
override def isBlockSolid(world: IBlockAccess, pos: BlockPos, side: EnumFacing) = false
override def isSideSolid(world: IBlockAccess, pos: BlockPos, side: EnumFacing) = false
override def getPickBlock(target: MovingObjectPosition, world: World, pos: BlockPos) =
findMovingRobot(world, pos) match {
case Some(robot) => robot.info.createItemStack()
@ -43,7 +45,7 @@ class RobotAfterimage extends SimpleBlock {
// ----------------------------------------------------------------------- //
override def rarity(stack: ItemStack) = {
val data = new ItemUtils.RobotData(stack)
val data = new RobotData(stack)
Rarity.byTier(data.tier)
}

View File

@ -7,13 +7,13 @@ import li.cil.oc.Settings
import li.cil.oc.api
import li.cil.oc.client.KeyBindings
import li.cil.oc.common.GuiType
import li.cil.oc.common.item.data.RobotData
import li.cil.oc.common.tileentity
import li.cil.oc.integration.util.NEI
import li.cil.oc.server.PacketSender
import li.cil.oc.server.component.robot
import li.cil.oc.util.BlockPosition
import li.cil.oc.util.InventoryUtils
import li.cil.oc.util.ItemUtils
import li.cil.oc.util.Rarity
import li.cil.oc.util.Tooltip
import net.minecraft.block.state.IBlockState
@ -46,6 +46,8 @@ class RobotProxy extends RedstoneAware with traits.StateAware {
override def isBlockSolid(world: IBlockAccess, pos: BlockPos, side: EnumFacing) = false
override def isSideSolid(world: IBlockAccess, pos: BlockPos, side: EnumFacing) = false
override def getPickBlock(target: MovingObjectPosition, world: World, pos: BlockPos) =
world.getTileEntity(pos) match {
case proxy: tileentity.RobotProxy => proxy.robot.info.copyItemStack()
@ -55,7 +57,7 @@ class RobotProxy extends RedstoneAware with traits.StateAware {
// ----------------------------------------------------------------------- //
override def rarity(stack: ItemStack) = {
val data = new ItemUtils.RobotData(stack)
val data = new RobotData(stack)
Rarity.byTier(data.tier)
}
@ -71,7 +73,7 @@ class RobotProxy extends RedstoneAware with traits.StateAware {
override protected def tooltipTail(metadata: Int, stack: ItemStack, player: EntityPlayer, tooltip: util.List[String], advanced: Boolean) {
super.tooltipTail(metadata, stack, player, tooltip, advanced)
if (KeyBindings.showExtendedTooltips) {
val info = new ItemUtils.RobotData(stack)
val info = new RobotData(stack)
val components = info.containers ++ info.components
if (components.length > 0) {
tooltip.addAll(Tooltip.get("Server.Components"))

View File

@ -36,6 +36,8 @@ object Screen {
class Screen(val tier: Int) extends RedstoneAware with traits.OmniRotatable {
setLightLevel(0.34f)
override def isSideSolid(world: IBlockAccess, pos: BlockPos, side: EnumFacing) = toLocal(world, pos, side) != EnumFacing.SOUTH
override protected def setDefaultExtendedState(state: IBlockState) = setDefaultState(state)
override protected def addExtendedState(state: IBlockState, world: IBlockAccess, pos: BlockPos) =
@ -83,8 +85,9 @@ class Screen(val tier: Int) extends RedstoneAware with traits.OmniRotatable {
override def localOnBlockActivated(world: World, pos: BlockPos, player: EntityPlayer, side: EnumFacing, hitX: Float, hitY: Float, hitZ: Float) = rightClick(world, pos, player, side, hitX, hitY, hitZ, force = false)
def rightClick(world: World, pos: BlockPos, player: EntityPlayer, side: EnumFacing, hitX: Float, hitY: Float, hitZ: Float, force: Boolean) =
if (Wrench.holdsApplicableWrench(player, pos)) false
def rightClick(world: World, pos: BlockPos, player: EntityPlayer,
side: EnumFacing, hitX: Float, hitY: Float, hitZ: Float, force: Boolean) = {
if (Wrench.holdsApplicableWrench(player, pos) && getValidRotations(world, pos).contains(side) && !force) false
else world.getTileEntity(pos) match {
case screen: tileentity.Screen if screen.hasKeyboard && (force || player.isSneaking == screen.invertTouchMode) =>
// Yep, this GUI is actually purely client side. We could skip this
@ -98,6 +101,7 @@ class Screen(val tier: Int) extends RedstoneAware with traits.OmniRotatable {
screen.click(player, hitX, hitY, hitZ)
case _ => false
}
}
override def onEntityCollidedWithBlock(world: World, pos: BlockPos, entity: Entity) =
if (world.isRemote) (entity, world.getTileEntity(pos)) match {

View File

@ -1,11 +1,9 @@
package li.cil.oc.common.block
import li.cil.oc.OpenComputers
import li.cil.oc.Settings
import li.cil.oc.common.GuiType
import li.cil.oc.common.tileentity
import net.minecraft.block.state.IBlockState
import net.minecraft.entity.player.EntityPlayer
import net.minecraft.util.BlockPos
import net.minecraft.util.EnumFacing
import net.minecraft.world.IBlockAccess
@ -13,7 +11,7 @@ import net.minecraft.world.World
import net.minecraftforge.fml.relauncher.Side
import net.minecraftforge.fml.relauncher.SideOnly
class ServerRack extends RedstoneAware with traits.PowerAcceptor with traits.Rotatable with traits.StateAware {
class ServerRack extends RedstoneAware with traits.PowerAcceptor with traits.Rotatable with traits.StateAware with traits.GUI {
override protected def setDefaultExtendedState(state: IBlockState) = setDefaultState(state)
@SideOnly(Side.CLIENT)
@ -31,23 +29,15 @@ class ServerRack extends RedstoneAware with traits.PowerAcceptor with traits.Rot
override def isBlockSolid(world: IBlockAccess, pos: BlockPos, side: EnumFacing) = side == EnumFacing.SOUTH
override def isSideSolid(world: IBlockAccess, pos: BlockPos, side: EnumFacing) = toLocal(world, pos, side) != EnumFacing.SOUTH
// ----------------------------------------------------------------------- //
override def energyThroughput = Settings.get.serverRackRate
override def guiType = GuiType.Rack
override def hasTileEntity(state: IBlockState) = true
override def createNewTileEntity(world: World, metadata: Int) = new tileentity.ServerRack()
// ----------------------------------------------------------------------- //
override def localOnBlockActivated(world: World, pos: BlockPos, player: EntityPlayer, side: EnumFacing, hitX: Float, hitY: Float, hitZ: Float) = {
if (!player.isSneaking) {
if (!world.isRemote) {
player.openGui(OpenComputers, GuiType.Rack.id, world, pos.getX, pos.getY, pos.getZ)
}
true
}
else false
}
}

View File

@ -156,7 +156,7 @@ abstract class SimpleBlock(material: Material = Material.iron) extends BlockCont
// Block
// ----------------------------------------------------------------------- //
override def isNormalCube(world: IBlockAccess, pos: BlockPos) = true
override def isSideSolid(world: IBlockAccess, pos: BlockPos, side: EnumFacing) = true
override def canHarvestBlock(world: IBlockAccess, pos: BlockPos, player: EntityPlayer) = true

View File

@ -1,31 +1,14 @@
package li.cil.oc.common.block
import li.cil.oc.OpenComputers
import li.cil.oc.common.GuiType
import li.cil.oc.common.tileentity
import net.minecraft.block.state.IBlockState
import net.minecraft.entity.player.EntityPlayer
import net.minecraft.util.BlockPos
import net.minecraft.util.EnumFacing
import net.minecraft.world.World
class Switch extends SimpleBlock {
class Switch extends SimpleBlock with traits.GUI {
override def guiType = GuiType.Switch
override def hasTileEntity(state: IBlockState) = true
override def createNewTileEntity(world: World, metadata: Int) = new tileentity.Switch()
// ----------------------------------------------------------------------- //
override def localOnBlockActivated(world: World, pos: BlockPos, player: EntityPlayer, side: EnumFacing, hitX: Float, hitY: Float, hitZ: Float) = {
world.getTileEntity(pos) match {
case switch: tileentity.Switch =>
if (!player.isSneaking) {
if (!world.isRemote) {
player.openGui(OpenComputers, GuiType.Switch.id, world, pos.getX, pos.getY, pos.getZ)
}
true
}
else false
}
}
}

View File

@ -0,0 +1,50 @@
package li.cil.oc.common.block.traits
import java.util
import li.cil.oc.common.block.SimpleBlock
import net.minecraft.block.state.IBlockState
import net.minecraft.entity.EntityLivingBase
import net.minecraft.entity.player.EntityPlayer
import net.minecraft.item.ItemStack
import net.minecraft.tileentity.TileEntity
import net.minecraft.util.BlockPos
import net.minecraft.world.IBlockAccess
import net.minecraft.world.World
import scala.reflect.ClassTag
trait CustomDrops[Tile <: TileEntity] extends SimpleBlock {
protected def tileTag: ClassTag[Tile]
override def getDrops(world: IBlockAccess, pos: BlockPos, state: IBlockState, fortune: Int): util.List[ItemStack] = new java.util.ArrayList[ItemStack]()
override def breakBlock(world: World, pos: BlockPos, state: IBlockState): Unit = {}
override def removedByPlayer(world: World, pos: BlockPos, player: EntityPlayer, willHarvest: Boolean): Boolean = {
if (!world.isRemote) {
val matcher = tileTag
world.getTileEntity(pos) match {
case matcher(tileEntity) => doCustomDrops(tileEntity, player, willHarvest)
case _ =>
}
}
super.removedByPlayer(world, pos, player, willHarvest)
}
override def onBlockPlacedBy(world: World, pos: BlockPos, state: IBlockState, placer: EntityLivingBase, stack: ItemStack): Unit = {
super.onBlockPlacedBy(world, pos, state, placer, stack)
if (!world.isRemote) {
val matcher = tileTag
world.getTileEntity(pos) match {
case matcher(tileEntity) => doCustomInit(tileEntity, placer, stack)
case _ =>
}
}
}
protected def doCustomInit(tileEntity: Tile, player: EntityLivingBase, stack: ItemStack): Unit = {}
protected def doCustomDrops(tileEntity: Tile, player: EntityPlayer, willHarvest: Boolean): Unit = {}
}

View File

@ -0,0 +1,24 @@
package li.cil.oc.common.block.traits
import li.cil.oc.OpenComputers
import li.cil.oc.common.GuiType
import li.cil.oc.common.block.SimpleBlock
import net.minecraft.block.state.IBlockState
import net.minecraft.entity.player.EntityPlayer
import net.minecraft.util.BlockPos
import net.minecraft.util.EnumFacing
import net.minecraft.world.World
trait GUI extends SimpleBlock {
def guiType: GuiType.EnumVal
override def localOnBlockActivated(world: World, pos: BlockPos, player: EntityPlayer, side: EnumFacing, hitX: Float, hitY: Float, hitZ: Float): Boolean = {
if (!player.isSneaking) {
if (!world.isRemote) {
player.openGui(OpenComputers, guiType.id, world, pos.getX, pos.getY, pos.getZ)
}
true
}
else super.localOnBlockActivated(world, pos, player, side, hitX, hitY, hitZ)
}
}

View File

@ -41,14 +41,16 @@ class TextBuffer(val host: EnvironmentHost) extends prefab.ManagedEnvironment wi
withConnector().
create()
private var maxResolution = Settings.screenResolutionsByTier(0)
private var maxResolution = Settings.screenResolutionsByTier(Tier.One)
private var maxDepth = Settings.screenDepthsByTier(0)
private var maxDepth = Settings.screenDepthsByTier(Tier.One)
private var aspectRatio = (1.0, 1.0)
private var powerConsumptionPerTick = Settings.get.screenCost
private var precisionMode = false
// For client side only.
private var isRendering = true
@ -162,6 +164,21 @@ class TextBuffer(val host: EnvironmentHost) extends prefab.ManagedEnvironment wi
}
}
@Callback(direct = true, doc = """function():boolean -- Returns whether the screen is in high precision mode (sub-pixel mouse event positions).""")
def isPrecise(computer: Context, args: Arguments): Array[AnyRef] = result(precisionMode)
@Callback(doc = """function(enabled:boolean):boolean -- Set whether to use high precision mode (sub-pixel mouse event positions).""")
def setPrecise(computer: Context, args: Arguments): Array[AnyRef] = {
// Available for T3 screens only... easiest way to check for us is to
// base it off of the maximum color depth.
if (maxDepth == Settings.screenDepthsByTier(Tier.Three)) {
val oldValue = precisionMode
precisionMode = args.checkBoolean(0)
result(oldValue)
}
else result(Unit, "unsupported operation")
}
// ----------------------------------------------------------------------- //
override def setEnergyCostPerTick(value: Double) {
@ -189,7 +206,7 @@ class TextBuffer(val host: EnvironmentHost) extends prefab.ManagedEnvironment wi
if (height < 1) throw new IllegalArgumentException("height must be larger or equal to one")
maxResolution = (width, height)
fullyLitCost = computeFullyLitCost()
proxy.onScreenMaxResolutionChange(width, width)
proxy.onBufferMaxResolutionChange(width, width)
}
override def getMaximumWidth = maxResolution._1
@ -205,7 +222,7 @@ class TextBuffer(val host: EnvironmentHost) extends prefab.ManagedEnvironment wi
if (w < 1 || h < 1 || w > mw || h > mw || h * w > mw * mh)
throw new IllegalArgumentException("unsupported resolution")
// Always send to clients, their state might be dirty.
proxy.onScreenResolutionChange(w, h)
proxy.onBufferResolutionChange(w, h)
if (data.size = (w, h)) {
if (node != null) {
node.sendToReachable("computer.signal", "screen_resized", Int.box(w), Int.box(h))
@ -227,7 +244,7 @@ class TextBuffer(val host: EnvironmentHost) extends prefab.ManagedEnvironment wi
if (depth.ordinal > maxDepth.ordinal)
throw new IllegalArgumentException("unsupported depth")
// Always send to clients, their state might be dirty.
proxy.onScreenDepthChange(depth)
proxy.onBufferDepthChange(depth)
data.format = PackedColor.Depth.format(depth)
}
@ -236,7 +253,7 @@ class TextBuffer(val host: EnvironmentHost) extends prefab.ManagedEnvironment wi
override def setPaletteColor(index: Int, color: Int) = data.format match {
case palette: PackedColor.MutablePaletteFormat =>
palette(index) = color
proxy.onScreenPaletteChange(index)
proxy.onBufferPaletteChange(index)
case _ => throw new Exception("palette not available")
}
@ -251,7 +268,7 @@ class TextBuffer(val host: EnvironmentHost) extends prefab.ManagedEnvironment wi
val value = PackedColor.Color(color, isFromPalette)
if (data.foreground != value) {
data.foreground = value
proxy.onScreenColorChange()
proxy.onBufferColorChange()
}
}
@ -265,7 +282,7 @@ class TextBuffer(val host: EnvironmentHost) extends prefab.ManagedEnvironment wi
val value = PackedColor.Color(color, isFromPalette)
if (data.background != value) {
data.background = value
proxy.onScreenColorChange()
proxy.onBufferColorChange()
}
}
@ -275,27 +292,28 @@ class TextBuffer(val host: EnvironmentHost) extends prefab.ManagedEnvironment wi
def copy(col: Int, row: Int, w: Int, h: Int, tx: Int, ty: Int) =
if (data.copy(col, row, w, h, tx, ty))
proxy.onScreenCopy(col, row, w, h, tx, ty)
proxy.onBufferCopy(col, row, w, h, tx, ty)
def fill(col: Int, row: Int, w: Int, h: Int, c: Char) =
if (data.fill(col, row, w, h, c))
proxy.onScreenFill(col, row, w, h, c)
proxy.onBufferFill(col, row, w, h, c)
def set(col: Int, row: Int, s: String, vertical: Boolean) = if (col < data.width && (col >= 0 || -col < s.length)) {
// Make sure the string isn't longer than it needs to be, in particular to
// avoid sending too much data to our clients.
val (x, y, truncated) =
if (vertical) {
if (row < 0) (col, 0, s.substring(-row))
else (col, row, s.substring(0, math.min(s.length, data.height - row)))
}
else {
if (col < 0) (0, row, s.substring(-col))
else (col, row, s.substring(0, math.min(s.length, data.width - col)))
}
if (data.set(x, y, truncated, vertical))
proxy.onScreenSet(x, row, truncated, vertical)
}
def set(col: Int, row: Int, s: String, vertical: Boolean): Unit =
if (col < data.width && (col >= 0 || -col < s.length)) {
// Make sure the string isn't longer than it needs to be, in particular to
// avoid sending too much data to our clients.
val (x, y, truncated) =
if (vertical) {
if (row < 0) (col, 0, s.substring(-row))
else (col, row, s.substring(0, math.min(s.length, data.height - row)))
}
else {
if (col < 0) (0, row, s.substring(-col))
else (col, row, s.substring(0, math.min(s.length, data.width - col)))
}
if (data.set(x, y, truncated, vertical))
proxy.onBufferSet(x, row, truncated, vertical)
}
def get(col: Int, row: Int) = data.get(col, row)
@ -321,6 +339,40 @@ class TextBuffer(val host: EnvironmentHost) extends prefab.ManagedEnvironment wi
override def isBackgroundFromPalette(column: Int, row: Int) =
data.format.isFromPalette(PackedColor.extractBackground(color(column, row)))
override def rawSetText(col: Int, row: Int, text: Array[Array[Char]]): Unit = {
for (y <- row until ((row + text.length) min data.height)) {
val line = text(y - row)
Array.copy(line, 0, data.buffer(y), col, line.length min data.width)
}
proxy.onBufferRawSetText(col, row, text)
}
override def rawSetBackground(col: Int, row: Int, color: Array[Array[Int]]): Unit = {
for (y <- row until ((row + color.length) min data.height)) {
val line = color(y - row)
for (x <- col until ((col + line.length) min data.width)) {
val packedBackground = data.color(row)(col) & 0x00FF
val packedForeground = (data.format.deflate(PackedColor.Color(line(x - col))) << PackedColor.ForegroundShift) & 0xFF00
data.color(row)(col) = (packedForeground | packedBackground).toShort
}
}
// TODO Better for bandwidth to send packed shorts here. Would need a special case for handling on client, though...
proxy.onBufferRawSetBackground(col, row, color)
}
override def rawSetForeground(col: Int, row: Int, color: Array[Array[Int]]): Unit = {
for (y <- row until ((row + color.length) min data.height)) {
val line = color(y - row)
for (x <- col until ((col + line.length) min data.width)) {
val packedBackground = data.format.deflate(PackedColor.Color(line(x - col))) & 0x00FF
val packedForeground = data.color(row)(col) & 0xFF00
data.color(row)(col) = (packedForeground | packedBackground).toShort
}
}
// TODO Better for bandwidth to send packed shorts here. Would need a special case for handling on client, though...
proxy.onBufferRawSetForeground(col, row, color)
}
private def color(column: Int, row: Int) = {
if (column < 0 || column >= getWidth || row < 0 || row >= getHeight)
throw new IndexOutOfBoundsException()
@ -351,16 +403,16 @@ class TextBuffer(val host: EnvironmentHost) extends prefab.ManagedEnvironment wi
override def clipboard(value: String, player: EntityPlayer) =
proxy.clipboard(value, player)
override def mouseDown(x: Int, y: Int, button: Int, player: EntityPlayer) =
override def mouseDown(x: Double, y: Double, button: Int, player: EntityPlayer) =
proxy.mouseDown(x, y, button, player)
override def mouseDrag(x: Int, y: Int, button: Int, player: EntityPlayer) =
override def mouseDrag(x: Double, y: Double, button: Int, player: EntityPlayer) =
proxy.mouseDrag(x, y, button, player)
override def mouseUp(x: Int, y: Int, button: Int, player: EntityPlayer) =
override def mouseUp(x: Double, y: Double, button: Int, player: EntityPlayer) =
proxy.mouseUp(x, y, button, player)
override def mouseScroll(x: Int, y: Int, delta: Int, player: EntityPlayer) =
override def mouseScroll(x: Double, y: Double, delta: Int, player: EntityPlayer) =
proxy.mouseScroll(x, y, delta, player)
// ----------------------------------------------------------------------- //
@ -403,6 +455,12 @@ class TextBuffer(val host: EnvironmentHost) extends prefab.ManagedEnvironment wi
if (nbt.hasKey(Settings.namespace + "hasPower")) {
hasPower = nbt.getBoolean(Settings.namespace + "hasPower")
}
if (nbt.hasKey(Settings.namespace + "maxWidth") && nbt.hasKey(Settings.namespace + "maxHeight")) {
val maxWidth = nbt.getInteger(Settings.namespace + "maxWidth")
val maxHeight = nbt.getInteger(Settings.namespace + "maxHeight")
maxResolution = (maxWidth, maxHeight)
}
precisionMode = nbt.getBoolean(Settings.namespace + "precise")
}
// Null check for Waila (and other mods that may call this client side).
@ -428,6 +486,9 @@ class TextBuffer(val host: EnvironmentHost) extends prefab.ManagedEnvironment wi
SaveHandler.scheduleSave(host, nbt, node.address + "_buffer", data.save _)
nbt.setBoolean(Settings.namespace + "isOn", isDisplaying)
nbt.setBoolean(Settings.namespace + "hasPower", hasPower)
nbt.setInteger(Settings.namespace + "maxWidth", maxResolution._1)
nbt.setInteger(Settings.namespace + "maxHeight", maxResolution._2)
nbt.setBoolean(Settings.namespace + "precise", precisionMode)
}
}
@ -477,28 +538,40 @@ object TextBuffer {
def render() = false
def onScreenColorChange(): Unit
def onBufferColorChange(): Unit
def onScreenCopy(col: Int, row: Int, w: Int, h: Int, tx: Int, ty: Int) {
def onBufferCopy(col: Int, row: Int, w: Int, h: Int, tx: Int, ty: Int) {
owner.relativeLitArea = -1
}
def onScreenDepthChange(depth: ColorDepth): Unit
def onBufferDepthChange(depth: ColorDepth): Unit
def onScreenFill(col: Int, row: Int, w: Int, h: Int, c: Char) {
def onBufferFill(col: Int, row: Int, w: Int, h: Int, c: Char) {
owner.relativeLitArea = -1
}
def onScreenPaletteChange(index: Int): Unit
def onBufferPaletteChange(index: Int): Unit
def onScreenResolutionChange(w: Int, h: Int) {
def onBufferResolutionChange(w: Int, h: Int) {
owner.relativeLitArea = -1
}
def onScreenMaxResolutionChange(w: Int, h: Int) {
def onBufferMaxResolutionChange(w: Int, h: Int) {
}
def onScreenSet(col: Int, row: Int, s: String, vertical: Boolean) {
def onBufferSet(col: Int, row: Int, s: String, vertical: Boolean) {
owner.relativeLitArea = -1
}
def onBufferRawSetText(col: Int, row: Int, text: Array[Array[Char]]) {
owner.relativeLitArea = -1
}
def onBufferRawSetBackground(col: Int, row: Int, color: Array[Array[Int]]) {
owner.relativeLitArea = -1
}
def onBufferRawSetForeground(col: Int, row: Int, color: Array[Array[Int]]) {
owner.relativeLitArea = -1
}
@ -508,13 +581,13 @@ object TextBuffer {
def clipboard(value: String, player: EntityPlayer): Unit
def mouseDown(x: Int, y: Int, button: Int, player: EntityPlayer): Unit
def mouseDown(x: Double, y: Double, button: Int, player: EntityPlayer): Unit
def mouseDrag(x: Int, y: Int, button: Int, player: EntityPlayer): Unit
def mouseDrag(x: Double, y: Double, button: Int, player: EntityPlayer): Unit
def mouseUp(x: Int, y: Int, button: Int, player: EntityPlayer): Unit
def mouseUp(x: Double, y: Double, button: Int, player: EntityPlayer): Unit
def mouseScroll(x: Int, y: Int, delta: Int, player: EntityPlayer): Unit
def mouseScroll(x: Double, y: Double, delta: Int, player: EntityPlayer): Unit
}
class ClientProxy(val owner: TextBuffer) extends Proxy {
@ -532,35 +605,35 @@ object TextBuffer {
wasDirty
}
override def onScreenColorChange() {
override def onBufferColorChange() {
markDirty()
}
override def onScreenCopy(col: Int, row: Int, w: Int, h: Int, tx: Int, ty: Int) {
super.onScreenCopy(col, row, w, h, tx, ty)
override def onBufferCopy(col: Int, row: Int, w: Int, h: Int, tx: Int, ty: Int) {
super.onBufferCopy(col, row, w, h, tx, ty)
markDirty()
}
override def onScreenDepthChange(depth: ColorDepth) {
override def onBufferDepthChange(depth: ColorDepth) {
markDirty()
}
override def onScreenFill(col: Int, row: Int, w: Int, h: Int, c: Char) {
super.onScreenFill(col, row, w, h, c)
override def onBufferFill(col: Int, row: Int, w: Int, h: Int, c: Char) {
super.onBufferFill(col, row, w, h, c)
markDirty()
}
override def onScreenPaletteChange(index: Int) {
override def onBufferPaletteChange(index: Int) {
markDirty()
}
override def onScreenResolutionChange(w: Int, h: Int) {
super.onScreenResolutionChange(w, h)
override def onBufferResolutionChange(w: Int, h: Int) {
super.onBufferResolutionChange(w, h)
markDirty()
}
override def onScreenSet(col: Int, row: Int, s: String, vertical: Boolean) {
super.onScreenSet(col, row, s, vertical)
override def onBufferSet(col: Int, row: Int, s: String, vertical: Boolean) {
super.onBufferSet(col, row, s, vertical)
dirty = true
}
@ -579,22 +652,22 @@ object TextBuffer {
ClientPacketSender.sendClipboard(nodeAddress, value)
}
override def mouseDown(x: Int, y: Int, button: Int, player: EntityPlayer) {
override def mouseDown(x: Double, y: Double, button: Int, player: EntityPlayer) {
debug(s"{type = mouseDown, x = $x, y = $y, button = $button}")
ClientPacketSender.sendMouseClick(nodeAddress, x, y, drag = false, button)
}
override def mouseDrag(x: Int, y: Int, button: Int, player: EntityPlayer) {
override def mouseDrag(x: Double, y: Double, button: Int, player: EntityPlayer) {
debug(s"{type = mouseDrag, x = $x, y = $y, button = $button}")
ClientPacketSender.sendMouseClick(nodeAddress, x, y, drag = true, button)
}
override def mouseUp(x: Int, y: Int, button: Int, player: EntityPlayer) {
override def mouseUp(x: Double, y: Double, button: Int, player: EntityPlayer) {
debug(s"{type = mouseUp, x = $x, y = $y, button = $button}")
ClientPacketSender.sendMouseUp(nodeAddress, x, y, button)
}
override def mouseScroll(x: Int, y: Int, delta: Int, player: EntityPlayer) {
override def mouseScroll(x: Double, y: Double, delta: Int, player: EntityPlayer) {
debug(s"{type = mouseScroll, x = $x, y = $y, delta = $delta}")
ClientPacketSender.sendMouseScroll(nodeAddress, x, y, delta)
}
@ -609,53 +682,71 @@ object TextBuffer {
}
class ServerProxy(val owner: TextBuffer) extends Proxy {
override def onScreenColorChange() {
override def onBufferColorChange() {
owner.host.markChanged()
owner.synchronized(ServerPacketSender.appendTextBufferColorChange(owner.pendingCommands, owner.data.foreground, owner.data.background))
}
override def onScreenCopy(col: Int, row: Int, w: Int, h: Int, tx: Int, ty: Int) {
super.onScreenCopy(col, row, w, h, tx, ty)
override def onBufferCopy(col: Int, row: Int, w: Int, h: Int, tx: Int, ty: Int) {
super.onBufferCopy(col, row, w, h, tx, ty)
owner.host.markChanged()
owner.synchronized(ServerPacketSender.appendTextBufferCopy(owner.pendingCommands, col, row, w, h, tx, ty))
}
override def onScreenDepthChange(depth: ColorDepth) {
override def onBufferDepthChange(depth: ColorDepth) {
owner.host.markChanged()
owner.synchronized(ServerPacketSender.appendTextBufferDepthChange(owner.pendingCommands, depth))
}
override def onScreenFill(col: Int, row: Int, w: Int, h: Int, c: Char) {
super.onScreenFill(col, row, w, h, c)
override def onBufferFill(col: Int, row: Int, w: Int, h: Int, c: Char) {
super.onBufferFill(col, row, w, h, c)
owner.host.markChanged()
owner.synchronized(ServerPacketSender.appendTextBufferFill(owner.pendingCommands, col, row, w, h, c))
}
override def onScreenPaletteChange(index: Int) {
override def onBufferPaletteChange(index: Int) {
owner.host.markChanged()
owner.synchronized(ServerPacketSender.appendTextBufferPaletteChange(owner.pendingCommands, index, owner.getPaletteColor(index)))
}
override def onScreenResolutionChange(w: Int, h: Int) {
super.onScreenResolutionChange(w, h)
override def onBufferResolutionChange(w: Int, h: Int) {
super.onBufferResolutionChange(w, h)
owner.host.markChanged()
owner.synchronized(ServerPacketSender.appendTextBufferResolutionChange(owner.pendingCommands, w, h))
}
override def onScreenMaxResolutionChange(w: Int, h: Int) {
override def onBufferMaxResolutionChange(w: Int, h: Int) {
if (owner.node.network != null) {
super.onScreenMaxResolutionChange(w, h)
super.onBufferMaxResolutionChange(w, h)
owner.host.markChanged()
owner.synchronized(ServerPacketSender.appendTextBufferMaxResolutionChange(owner.pendingCommands, w, h))
}
}
override def onScreenSet(col: Int, row: Int, s: String, vertical: Boolean) {
super.onScreenSet(col, row, s, vertical)
override def onBufferSet(col: Int, row: Int, s: String, vertical: Boolean) {
super.onBufferSet(col, row, s, vertical)
owner.host.markChanged()
owner.synchronized(ServerPacketSender.appendTextBufferSet(owner.pendingCommands, col, row, s, vertical))
}
override def onBufferRawSetText(col: Int, row: Int, text: Array[Array[Char]]) {
super.onBufferRawSetText(col, row, text)
owner.host.markChanged()
owner.synchronized(ServerPacketSender.appendTextBufferRawSetText(owner.pendingCommands, col, row, text))
}
override def onBufferRawSetBackground(col: Int, row: Int, color: Array[Array[Int]]) {
super.onBufferRawSetBackground(col, row, color)
owner.host.markChanged()
owner.synchronized(ServerPacketSender.appendTextBufferRawSetBackground(owner.pendingCommands, col, row, color))
}
override def onBufferRawSetForeground(col: Int, row: Int, color: Array[Array[Int]]) {
super.onBufferRawSetForeground(col, row, color)
owner.host.markChanged()
owner.synchronized(ServerPacketSender.appendTextBufferRawSetForeground(owner.pendingCommands, col, row, color))
}
override def keyDown(character: Char, code: Int, player: EntityPlayer) {
sendToKeyboards("keyboard.keyDown", player, Char.box(character), Int.box(code))
}
@ -668,24 +759,41 @@ object TextBuffer {
sendToKeyboards("keyboard.clipboard", player, value)
}
override def mouseDown(x: Int, y: Int, button: Int, player: EntityPlayer) {
if (Settings.get.inputUsername) owner.node.sendToReachable("computer.checked_signal", player, "touch", Int.box(x), Int.box(y), Int.box(button), player.getName)
else owner.node.sendToReachable("computer.checked_signal", player, "touch", Int.box(x), Int.box(y), Int.box(button))
override def mouseDown(x: Double, y: Double, button: Int, player: EntityPlayer) {
sendMouseEvent(player, "touch", x, y, button)
}
override def mouseDrag(x: Int, y: Int, button: Int, player: EntityPlayer) {
if (Settings.get.inputUsername) owner.node.sendToReachable("computer.checked_signal", player, "drag", Int.box(x), Int.box(y), Int.box(button), player.getName)
else owner.node.sendToReachable("computer.checked_signal", player, "drag", Int.box(x), Int.box(y), Int.box(button))
override def mouseDrag(x: Double, y: Double, button: Int, player: EntityPlayer) {
sendMouseEvent(player, "drag", x, y, button)
}
override def mouseUp(x: Int, y: Int, button: Int, player: EntityPlayer) {
if (Settings.get.inputUsername) owner.node.sendToReachable("computer.checked_signal", player, "drop", Int.box(x), Int.box(y), Int.box(button), player.getName)
else owner.node.sendToReachable("computer.checked_signal", player, "drop", Int.box(x), Int.box(y), Int.box(button))
override def mouseUp(x: Double, y: Double, button: Int, player: EntityPlayer) {
sendMouseEvent(player, "drop", x, y, button)
}
override def mouseScroll(x: Int, y: Int, delta: Int, player: EntityPlayer) {
if (Settings.get.inputUsername) owner.node.sendToReachable("computer.checked_signal", player, "scroll", Int.box(x), Int.box(y), Int.box(delta), player.getName)
else owner.node.sendToReachable("computer.checked_signal", player, "scroll", Int.box(x), Int.box(y), Int.box(delta))
override def mouseScroll(x: Double, y: Double, delta: Int, player: EntityPlayer) {
sendMouseEvent(player, "scroll", x, y, delta)
}
private def sendMouseEvent(player: EntityPlayer, name: String, x: Double, y: Double, data: Int) = {
val args = mutable.ArrayBuffer.empty[AnyRef]
args += player
args += name
if (owner.precisionMode) {
args += double2Double(x)
args += double2Double(y)
}
else {
args += int2Integer(x.toInt + 1)
args += int2Integer(y.toInt + 1)
}
args += int2Integer(data)
if (Settings.get.inputUsername) {
args += player.getName
}
owner.node.sendToReachable("computer.checked_signal", args: _*)
}
private def sendToKeyboards(name: String, values: AnyRef*) {

View File

@ -39,6 +39,15 @@ abstract class ComponentSlot(inventory: IInventory, index: Int, x: Int, y: Int)
}
}
override def putStack(stack: ItemStack): Unit = {
super.putStack(stack)
inventory match {
case playerAware: common.tileentity.traits.PlayerInputAware =>
playerAware.onSetInventorySlotContents(container.playerInventory.player, getSlotIndex, stack)
case _ =>
}
}
override def onSlotChanged() {
super.onSlotChanged()
for (slot <- container.inventorySlots) slot match {

View File

@ -18,12 +18,12 @@ import li.cil.oc.common.Slot
import li.cil.oc.common.inventory.ComponentInventory
import li.cil.oc.common.inventory.Inventory
import li.cil.oc.common.inventory.MultiTank
import li.cil.oc.common.item.data.MicrocontrollerData
import li.cil.oc.server.component
import li.cil.oc.util.BlockPosition
import li.cil.oc.util.ExtendedNBT._
import li.cil.oc.util.ExtendedWorld._
import li.cil.oc.util.InventoryUtils
import li.cil.oc.util.ItemUtils
import net.minecraft.block.material.Material
import net.minecraft.entity.Entity
import net.minecraft.entity.item.EntityItem
@ -61,7 +61,7 @@ class Drone(val world: World) extends Entity(world) with MachineHost with intern
var lastEnergyUpdate = 0
// Logic stuff, components, machine and such.
val info = new ItemUtils.MicrocontrollerData()
val info = new MicrocontrollerData()
val machine = if (!world.isRemote) {
val m = Machine.create(this)
m.node.asInstanceOf[Connector].setLocalBufferSize(0)
@ -296,6 +296,7 @@ class Drone(val world: World) extends Entity(world) with MachineHost with intern
def setRunning(value: Boolean) = dataWatcher.updateObject(5, byte2Byte(if (value) 1: Byte else 0: Byte))
// Round target values to low accuracy to avoid floating point errors accumulating.
def targetX_=(value: Float): Unit = dataWatcher.updateObject(6, float2Float(math.round(value * 4) / 4f))

View File

@ -13,10 +13,12 @@ import li.cil.oc.common.block.SimpleBlock
import li.cil.oc.common.item
import li.cil.oc.common.item.Delegator
import li.cil.oc.common.item.SimpleItem
import li.cil.oc.common.item.data.MicrocontrollerData
import li.cil.oc.common.item.data.RobotData
import li.cil.oc.common.item.data.TabletData
import li.cil.oc.common.recipe.Recipes
import li.cil.oc.integration.Mods
import li.cil.oc.util.Color
import li.cil.oc.util.ItemUtils
import net.minecraft.block.Block
import net.minecraft.creativetab.CreativeTabs
import net.minecraft.item.Item
@ -149,7 +151,7 @@ object Items extends ItemAPI {
}
def createConfiguredDrone() = {
val data = new ItemUtils.MicrocontrollerData()
val data = new MicrocontrollerData()
data.tier = Tier.Four
data.storedEnergy = Settings.get.bufferDrone.toInt
@ -175,7 +177,7 @@ object Items extends ItemAPI {
}
def createConfiguredMicrocontroller() = {
val data = new ItemUtils.MicrocontrollerData()
val data = new MicrocontrollerData()
data.tier = Tier.Four
data.storedEnergy = Settings.get.bufferMicrocontroller.toInt
@ -198,7 +200,7 @@ object Items extends ItemAPI {
}
def createConfiguredRobot() = {
val data = new ItemUtils.RobotData()
val data = new RobotData()
data.name = "Creatix"
data.tier = Tier.Four
@ -241,6 +243,37 @@ object Items extends ItemAPI {
stack
}
def createConfiguredTablet() = {
val data = new TabletData()
data.energy = Settings.get.bufferTablet
data.maxEnergy = data.energy
data.items = Array(
Option(get("screen1").createItemStack(1)),
Option(get("keyboard").createItemStack(1)),
Option(get("signUpgrade").createItemStack(1)),
Option(get("pistonUpgrade").createItemStack(1)),
Option(get("graphicsCard2").createItemStack(1)),
Option(get("redstoneCard2").createItemStack(1)),
Option(get("wlanCard").createItemStack(1)),
Option(get("cpu3").createItemStack(1)),
Option(get("ram6").createItemStack(1)),
Option(get("ram6").createItemStack(1)),
Option(createLuaBios()),
Option(createOpenOS()),
Option(get("hdd3").createItemStack(1))
)
val stack = get("tablet").createItemStack(1)
data.save(stack)
stack
}
// ----------------------------------------------------------------------- //
def init() {
@ -397,7 +430,8 @@ object Items extends ItemAPI {
Items.createLuaBios(),
Items.createConfiguredDrone(),
Items.createConfiguredMicrocontroller(),
Items.createConfiguredRobot()
Items.createConfiguredRobot(),
Items.createConfiguredTablet()
)
override def getSubItems(item: Item, tab: CreativeTabs, list: util.List[_]): Unit = {

View File

@ -1,3 +1,27 @@
package li.cil.oc.common.item
class DebugCard(val parent: Delegator) extends Delegate
import java.util
import li.cil.oc.common.item.data.DebugCardData
import net.minecraft.entity.player.EntityPlayer
import net.minecraft.item.ItemStack
import net.minecraft.world.World
class DebugCard(val parent: Delegator) extends Delegate {
override protected def tooltipExtended(stack: ItemStack, tooltip: util.List[String]): Unit = {
super.tooltipExtended(stack, tooltip)
val data = new DebugCardData(stack)
data.player.foreach(name => tooltip.add(s"§8$name§r"))
}
override def onItemRightClick(stack: ItemStack, world: World, player: EntityPlayer): ItemStack = {
if (player.isSneaking) {
val data = new DebugCardData(stack)
if (data.player.contains(player.getName)) data.player = None
else data.player = Option(player.getName)
data.save(stack)
player.swingItem()
}
stack
}
}

View File

@ -25,10 +25,11 @@ import scala.collection.mutable
object Delegator {
def subItem(stack: ItemStack) =
stack.getItem match {
if (stack != null) stack.getItem match {
case delegator: Delegator => delegator.subItem(stack.getItemDamage)
case _ => None
}
else None
}
class Delegator extends Item {

View File

@ -4,9 +4,9 @@ import java.util
import li.cil.oc.client.KeyBindings
import li.cil.oc.common.entity
import li.cil.oc.common.item.data.MicrocontrollerData
import li.cil.oc.integration.util.NEI
import li.cil.oc.util.BlockPosition
import li.cil.oc.util.ItemUtils
import li.cil.oc.util.Rarity
import net.minecraft.entity.player.EntityPlayer
import net.minecraft.item.ItemStack
@ -19,15 +19,15 @@ class Drone(val parent: Delegator) extends Delegate {
override protected def tooltipExtended(stack: ItemStack, tooltip: util.List[String]): Unit = {
if (KeyBindings.showExtendedTooltips) {
val info = new ItemUtils.MicrocontrollerData(stack)
for (component <- info.components) {
val info = new MicrocontrollerData(stack)
for (component <- info.components if component != null) {
tooltip.add("- " + component.getDisplayName)
}
}
}
override def rarity(stack: ItemStack) = {
val data = new ItemUtils.MicrocontrollerData(stack)
val data = new MicrocontrollerData(stack)
Rarity.byTier(data.tier)
}

View File

@ -24,10 +24,9 @@ import li.cil.oc.client.KeyBindings
import li.cil.oc.common.GuiType
import li.cil.oc.common.Slot
import li.cil.oc.common.inventory.ComponentInventory
import li.cil.oc.common.item.data.TabletData
import li.cil.oc.server.component
import li.cil.oc.util.ExtendedNBT._
import li.cil.oc.util.ItemUtils
import li.cil.oc.util.ItemUtils.TabletData
import li.cil.oc.util.RotationHelper
import li.cil.oc.util.Tooltip
import net.minecraft.entity.Entity
@ -54,7 +53,7 @@ class Tablet(val parent: Delegator) extends Delegate {
override protected def tooltipExtended(stack: ItemStack, tooltip: util.List[String]): Unit = {
if (KeyBindings.showExtendedTooltips) {
val info = new ItemUtils.TabletData(stack)
val info = new TabletData(stack)
// Ignore/hide the screen.
val components = info.items.drop(1)
if (components.length > 1) {
@ -70,7 +69,7 @@ class Tablet(val parent: Delegator) extends Delegate {
override def durability(stack: ItemStack) = {
if (stack.hasTagCompound) {
val data = new ItemUtils.TabletData()
val data = new TabletData()
data.load(stack.getTagCompound)
data.energy / data.maxEnergy
}

View File

@ -0,0 +1,34 @@
package li.cil.oc.common.item.data
import li.cil.oc.Settings
import net.minecraft.item.ItemStack
import net.minecraft.nbt.NBTTagCompound
class DebugCardData extends ItemData {
def this(stack: ItemStack) {
this()
load(stack)
}
var player: Option[String] = None
override def load(nbt: NBTTagCompound) {
val tag = dataTag(nbt)
if (tag.hasKey(Settings.namespace + "player")) {
player = Option(tag.getString(Settings.namespace + "player"))
}
}
override def save(nbt: NBTTagCompound) {
val tag = dataTag(nbt)
tag.removeTag(Settings.namespace + "player")
player.foreach(tag.setString(Settings.namespace + "player", _))
}
private def dataTag(nbt: NBTTagCompound) = {
if (!nbt.hasKey(Settings.namespace + "data")) {
nbt.setTag(Settings.namespace + "data", new NBTTagCompound())
}
nbt.getCompoundTag(Settings.namespace + "data")
}
}

View File

@ -0,0 +1,26 @@
package li.cil.oc.common.item.data
import li.cil.oc.api.Persistable
import net.minecraft.item.ItemStack
import net.minecraft.nbt.NBTTagCompound
object ItemData {
}
abstract class ItemData extends Persistable {
def load(stack: ItemStack) {
if (stack.hasTagCompound) {
// Because ItemStack's load function doesn't copy the compound tag,
// but keeps it as is, leading to oh so fun bugs!
load(stack.getTagCompound.copy().asInstanceOf[NBTTagCompound])
}
}
def save(stack: ItemStack) {
if (!stack.hasTagCompound) {
stack.setTagCompound(new NBTTagCompound())
}
save(stack.getTagCompound)
}
}

View File

@ -0,0 +1,49 @@
package li.cil.oc.common.item.data
import li.cil.oc.Settings
import li.cil.oc.api
import li.cil.oc.common.Tier
import li.cil.oc.util.ExtendedNBT._
import li.cil.oc.util.ItemUtils
import net.minecraft.item.ItemStack
import net.minecraft.nbt.NBTTagCompound
import net.minecraftforge.common.util.Constants.NBT
class MicrocontrollerData extends ItemData {
def this(stack: ItemStack) {
this()
load(stack)
}
var tier = Tier.One
var components = Array.empty[ItemStack]
var storedEnergy = 0
override def load(nbt: NBTTagCompound) {
tier = nbt.getByte(Settings.namespace + "tier")
components = nbt.getTagList(Settings.namespace + "components", NBT.TAG_COMPOUND).
toArray[NBTTagCompound].map(ItemUtils.loadStack)
storedEnergy = nbt.getInteger(Settings.namespace + "storedEnergy")
}
override def save(nbt: NBTTagCompound) {
nbt.setByte(Settings.namespace + "tier", tier.toByte)
nbt.setNewTagList(Settings.namespace + "components", components.toIterable)
nbt.setInteger(Settings.namespace + "storedEnergy", storedEnergy)
}
def createItemStack() = {
val stack = api.Items.get("microcontroller").createItemStack(1)
save(stack)
stack
}
def copyItemStack() = {
val stack = createItemStack()
val newInfo = new MicrocontrollerData(stack)
newInfo.save(stack)
stack
}
}

View File

@ -0,0 +1,47 @@
package li.cil.oc.common.item.data
import li.cil.oc.Settings
import li.cil.oc.util.ExtendedNBT._
import li.cil.oc.util.ItemUtils
import net.minecraft.item.ItemMap
import net.minecraft.item.ItemStack
import net.minecraft.nbt.NBTTagCompound
import net.minecraft.world.World
class NavigationUpgradeData extends ItemData {
def this(stack: ItemStack) {
this()
load(stack)
}
var map = new ItemStack(net.minecraft.init.Items.filled_map)
def mapData(world: World) = try map.getItem.asInstanceOf[ItemMap].getMapData(map, world) catch {
case _: Throwable => throw new Exception("invalid map")
}
override def load(stack: ItemStack) {
if (stack.hasTagCompound) {
load(stack.getTagCompound.getCompoundTag(Settings.namespace + "data"))
}
}
override def save(stack: ItemStack) {
if (!stack.hasTagCompound) {
stack.setTagCompound(new NBTTagCompound())
}
save(stack.getCompoundTag(Settings.namespace + "data"))
}
override def load(nbt: NBTTagCompound) {
if (nbt.hasKey(Settings.namespace + "map")) {
map = ItemUtils.loadStack(nbt.getCompoundTag(Settings.namespace + "map"))
}
}
override def save(nbt: NBTTagCompound) {
if (map != null) {
nbt.setNewCompoundTag(Settings.namespace + "map", map.writeToNBT)
}
}
}

View File

@ -0,0 +1,43 @@
package li.cil.oc.common.item.data
import li.cil.oc.Settings
import li.cil.oc.api
import li.cil.oc.util.ExtendedNBT._
import li.cil.oc.util.ItemUtils
import net.minecraft.item.ItemStack
import net.minecraft.nbt.NBTTagCompound
import net.minecraftforge.common.util.Constants.NBT
class RaidData extends ItemData {
def this(stack: ItemStack) {
this()
load(stack)
}
var disks = Array.empty[ItemStack]
var filesystem = new NBTTagCompound()
var label: Option[String] = None
override def load(nbt: NBTTagCompound): Unit = {
disks = nbt.getTagList(Settings.namespace + "disks", NBT.TAG_COMPOUND).
toArray[NBTTagCompound].map(ItemUtils.loadStack)
filesystem = nbt.getCompoundTag(Settings.namespace + "filesystem")
if (nbt.hasKey(Settings.namespace + "label")) {
label = Option(nbt.getString(Settings.namespace + "label"))
}
}
override def save(nbt: NBTTagCompound): Unit = {
nbt.setNewTagList(Settings.namespace + "disks", disks.toIterable)
nbt.setTag(Settings.namespace + "filesystem", filesystem)
label.foreach(nbt.setString(Settings.namespace + "label", _))
}
def createItemStack() = {
val stack = api.Items.get("raid").createItemStack(1)
save(stack)
stack
}
}

View File

@ -0,0 +1,114 @@
package li.cil.oc.common.item.data
import com.google.common.base.Charsets
import com.google.common.base.Strings
import li.cil.oc.OpenComputers
import li.cil.oc.Settings
import li.cil.oc.api
import li.cil.oc.integration.opencomputers.DriverScreen
import li.cil.oc.util.ExtendedNBT._
import li.cil.oc.util.ItemUtils
import net.minecraft.item.ItemStack
import net.minecraft.nbt.NBTTagCompound
import net.minecraftforge.common.util.Constants.NBT
import scala.io.Source
object RobotData {
val names = try {
Source.fromInputStream(getClass.getResourceAsStream(
"/assets/" + Settings.resourceDomain + "/robot.names"))(Charsets.UTF_8).
getLines().map(_.takeWhile(_ != '#').trim()).filter(_ != "").toArray
}
catch {
case t: Throwable =>
OpenComputers.log.warn("Failed loading robot name list.", t)
Array.empty[String]
}
def randomName = if (names.length > 0) names((math.random * names.length).toInt) else "Robot"
}
class RobotData extends ItemData {
def this(stack: ItemStack) {
this()
load(stack)
}
var name = ""
// Overall energy including components.
var totalEnergy = 0
// Energy purely stored in robot component - this is what we have to restore manually.
var robotEnergy = 0
var tier = 0
var components = Array.empty[ItemStack]
var containers = Array.empty[ItemStack]
var lightColor = 0xF23030
override def load(nbt: NBTTagCompound) {
if (nbt.hasKey("display") && nbt.getCompoundTag("display").hasKey("Name")) {
name = nbt.getCompoundTag("display").getString("Name")
}
if (Strings.isNullOrEmpty(name)) {
name = RobotData.randomName
}
totalEnergy = nbt.getInteger(Settings.namespace + "storedEnergy")
robotEnergy = nbt.getInteger(Settings.namespace + "robotEnergy")
tier = nbt.getInteger(Settings.namespace + "tier")
components = nbt.getTagList(Settings.namespace + "components", NBT.TAG_COMPOUND).
toArray[NBTTagCompound].map(ItemUtils.loadStack)
containers = nbt.getTagList(Settings.namespace + "containers", NBT.TAG_COMPOUND).
toArray[NBTTagCompound].map(ItemUtils.loadStack)
if (nbt.hasKey(Settings.namespace + "lightColor")) {
lightColor = nbt.getInteger(Settings.namespace + "lightColor")
}
}
override def save(nbt: NBTTagCompound) {
if (!Strings.isNullOrEmpty(name)) {
if (!nbt.hasKey("display")) {
nbt.setTag("display", new NBTTagCompound())
}
nbt.getCompoundTag("display").setString("Name", name)
}
nbt.setInteger(Settings.namespace + "storedEnergy", totalEnergy)
nbt.setInteger(Settings.namespace + "robotEnergy", robotEnergy)
nbt.setInteger(Settings.namespace + "tier", tier)
nbt.setNewTagList(Settings.namespace + "components", components.toIterable)
nbt.setNewTagList(Settings.namespace + "containers", containers.toIterable)
nbt.setInteger(Settings.namespace + "lightColor", lightColor)
}
def createItemStack() = {
val stack = api.Items.get("robot").createItemStack(1)
save(stack)
stack
}
def copyItemStack() = {
val stack = createItemStack()
// Forget all node addresses and so on. This is used when 'picking' a
// robot in creative mode.
val newInfo = new RobotData(stack)
newInfo.components.foreach(cs => Option(api.Driver.driverFor(cs)) match {
case Some(driver) if driver == DriverScreen =>
val nbt = driver.dataTag(cs)
for (tagName <- nbt.getKeySet.toArray) {
nbt.removeTag(tagName.asInstanceOf[String])
}
case _ =>
})
// Don't show energy info (because it's unreliable) but fill up the
// internal buffer. This is for creative use only, anyway.
newInfo.totalEnergy = 0
newInfo.robotEnergy = 50000
newInfo.save(stack)
stack
}
}

View File

@ -0,0 +1,47 @@
package li.cil.oc.common.item.data
import li.cil.oc.Settings
import li.cil.oc.util.ExtendedNBT._
import li.cil.oc.util.ItemUtils
import net.minecraft.item.ItemStack
import net.minecraft.nbt.NBTTagCompound
import net.minecraftforge.common.util.Constants.NBT
class TabletData extends ItemData {
def this(stack: ItemStack) {
this()
load(stack)
}
var items = Array.fill[Option[ItemStack]](32)(None)
var isRunning = false
var energy = 0.0
var maxEnergy = 0.0
override def load(nbt: NBTTagCompound) {
nbt.getTagList(Settings.namespace + "items", NBT.TAG_COMPOUND).foreach((slotNbt: NBTTagCompound) => {
val slot = slotNbt.getByte("slot")
if (slot >= 0 && slot < items.length) {
items(slot) = Option(ItemUtils.loadStack(slotNbt.getCompoundTag("item")))
}
})
isRunning = nbt.getBoolean(Settings.namespace + "isRunning")
energy = nbt.getDouble(Settings.namespace + "energy")
maxEnergy = nbt.getDouble(Settings.namespace + "maxEnergy")
}
override def save(nbt: NBTTagCompound) {
nbt.setNewTagList(Settings.namespace + "items",
items.zipWithIndex collect {
case (Some(stack), slot) => (stack, slot)
} map {
case (stack, slot) =>
val slotNbt = new NBTTagCompound()
slotNbt.setByte("slot", slot.toByte)
slotNbt.setNewCompoundTag("item", stack.writeToNBT)
})
nbt.setBoolean(Settings.namespace + "isRunning", isRunning)
nbt.setDouble(Settings.namespace + "energy", energy)
nbt.setDouble(Settings.namespace + "maxEnergy", maxEnergy)
}
}

View File

@ -5,9 +5,10 @@ import java.util.UUID
import li.cil.oc.Settings
import li.cil.oc.api
import li.cil.oc.api.detail.ItemInfo
import li.cil.oc.common.init.Items
import li.cil.oc.common.item.data.MicrocontrollerData
import li.cil.oc.integration.Mods
import li.cil.oc.util.ExtendedNBT._
import li.cil.oc.util.ItemUtils
import li.cil.oc.util.SideTracker
import net.minecraft.init.Blocks
import net.minecraft.inventory.InventoryCrafting
@ -20,6 +21,7 @@ import scala.util.control.Breaks._
object ExtendedRecipe {
private lazy val drone = api.Items.get("drone")
private lazy val eeprom = api.Items.get("eeprom")
private lazy val luaBios = Items.createLuaBios()
private lazy val mcu = api.Items.get("microcontroller")
private lazy val navigationUpgrade = api.Items.get("navigationUpgrade")
private lazy val linkedCard = api.Items.get("linkedCard")
@ -71,7 +73,7 @@ object ExtendedRecipe {
}
}
if (api.Items.get(craftedStack) == eeprom) breakable {
if (api.Items.get(craftedStack) == eeprom && !ItemStack.areItemStackTagsEqual(craftedStack, luaBios)) breakable {
for (slot <- 0 until inventory.getSizeInventory) {
val stack = inventory.getStackInSlot(slot)
if (stack != null && api.Items.get(stack) == eeprom && stack.hasTagCompound) {
@ -95,7 +97,7 @@ object ExtendedRecipe {
// Find old Microcontroller.
(0 until inventory.getSizeInventory).map(inventory.getStackInSlot).find(api.Items.get(_) == descriptor) match {
case Some(oldMcu) =>
val data = new ItemUtils.MicrocontrollerData(oldMcu)
val data = new MicrocontrollerData(oldMcu)
// Remove old EEPROM.
val oldRom = data.components.filter(api.Items.get(_) == eeprom)

View File

@ -5,6 +5,7 @@ import li.cil.oc.api
import li.cil.oc.api.internal
import li.cil.oc.common.Slot
import li.cil.oc.common.Tier
import li.cil.oc.common.item.data.MicrocontrollerData
import li.cil.oc.util.ExtendedNBT._
import li.cil.oc.util.ItemUtils
import net.minecraft.inventory.IInventory
@ -29,7 +30,7 @@ object DroneTemplate extends Template {
def assemble(inventory: IInventory) = {
val items = (0 until inventory.getSizeInventory).map(inventory.getStackInSlot)
val data = new ItemUtils.MicrocontrollerData()
val data = new MicrocontrollerData()
data.tier = caseTier(inventory)
data.components = items.drop(1).filter(_ != null).toArray
data.storedEnergy = Settings.get.bufferDrone.toInt
@ -43,7 +44,7 @@ object DroneTemplate extends Template {
def selectDisassembler(stack: ItemStack) = api.Items.get(stack) == api.Items.get("drone")
def disassemble(stack: ItemStack, ingredients: Array[ItemStack]) = {
val info = new ItemUtils.MicrocontrollerData(stack)
val info = new MicrocontrollerData(stack)
val itemName = ItemUtils.caseNameWithTierSuffix("droneCase", info.tier)
Array(api.Items.get(itemName).createItemStack(1)) ++ info.components

View File

@ -5,6 +5,7 @@ import li.cil.oc.api
import li.cil.oc.api.internal
import li.cil.oc.common.Slot
import li.cil.oc.common.Tier
import li.cil.oc.common.item.data.MicrocontrollerData
import li.cil.oc.util.ExtendedNBT._
import li.cil.oc.util.ItemUtils
import net.minecraft.inventory.IInventory
@ -29,7 +30,7 @@ object MicrocontrollerTemplate extends Template {
def assemble(inventory: IInventory) = {
val items = (0 until inventory.getSizeInventory).map(inventory.getStackInSlot)
val data = new ItemUtils.MicrocontrollerData()
val data = new MicrocontrollerData()
data.tier = caseTier(inventory)
data.components = items.drop(1).filter(_ != null).toArray
data.storedEnergy = Settings.get.bufferMicrocontroller.toInt
@ -43,7 +44,7 @@ object MicrocontrollerTemplate extends Template {
def selectDisassembler(stack: ItemStack) = api.Items.get(stack) == api.Items.get("microcontroller")
def disassemble(stack: ItemStack, ingredients: Array[ItemStack]) = {
val info = new ItemUtils.MicrocontrollerData(stack)
val info = new MicrocontrollerData(stack)
val itemName = ItemUtils.caseNameWithTierSuffix("microcontrollerCase", info.tier)
Array(api.Items.get(itemName).createItemStack(1)) ++ info.components

View File

@ -1,7 +1,7 @@
package li.cil.oc.common.template
import li.cil.oc.api
import li.cil.oc.util.ItemUtils
import li.cil.oc.common.item.data.NavigationUpgradeData
import net.minecraft.item.ItemStack
import net.minecraft.nbt.NBTTagCompound
import net.minecraftforge.fml.common.event.FMLInterModComms
@ -12,7 +12,7 @@ object NavigationUpgradeTemplate {
def selectDisassembler(stack: ItemStack) = api.Items.get(stack) == api.Items.get("navigationUpgrade")
def disassemble(stack: ItemStack, ingredients: Array[ItemStack]) = {
val info = new ItemUtils.NavigationUpgradeData(stack)
val info = new NavigationUpgradeData(stack)
ingredients.map {
case part if part.getItem == net.minecraft.init.Items.filled_map => info.map
case part => part

View File

@ -5,6 +5,7 @@ import li.cil.oc.api
import li.cil.oc.api.internal
import li.cil.oc.common.Slot
import li.cil.oc.common.Tier
import li.cil.oc.common.item.data.RobotData
import li.cil.oc.util.ExtendedNBT._
import li.cil.oc.util.ItemUtils
import net.minecraft.inventory.IInventory
@ -16,21 +17,21 @@ import net.minecraftforge.fml.common.event.FMLInterModComms
object RobotTemplate extends Template {
override protected def hostClass = classOf[internal.Robot]
def selectTier1(stack: ItemStack) = ItemUtils.caseTier(stack) == Tier.One
def selectTier1(stack: ItemStack) = api.Items.get(stack) == api.Items.get("case1")
def selectTier2(stack: ItemStack) = ItemUtils.caseTier(stack) == Tier.Two
def selectTier2(stack: ItemStack) = api.Items.get(stack) == api.Items.get("case2")
def selectTier3(stack: ItemStack) = ItemUtils.caseTier(stack) == Tier.Three
def selectTier3(stack: ItemStack) = api.Items.get(stack) == api.Items.get("case3")
def selectCreative(stack: ItemStack) = ItemUtils.caseTier(stack) == Tier.Four
def selectCreative(stack: ItemStack) = api.Items.get(stack) == api.Items.get("caseCreative")
def validate(inventory: IInventory): Array[AnyRef] = validateComputer(inventory)
def assemble(inventory: IInventory) = {
val items = (0 until inventory.getSizeInventory).map(inventory.getStackInSlot)
val data = new ItemUtils.RobotData()
val data = new RobotData()
data.tier = ItemUtils.caseTier(inventory.getStackInSlot(0))
data.name = ItemUtils.RobotData.randomName
data.name = RobotData.randomName
data.robotEnergy = Settings.get.bufferRobot.toInt
data.totalEnergy = data.robotEnergy
data.containers = items.slice(1, 4).filter(_ != null).toArray
@ -45,7 +46,7 @@ object RobotTemplate extends Template {
def selectDisassembler(stack: ItemStack) = api.Items.get(stack) == api.Items.get("robot")
def disassemble(stack: ItemStack, ingredients: Array[ItemStack]) = {
val info = new ItemUtils.RobotData(stack)
val info = new RobotData(stack)
val itemName = ItemUtils.caseNameWithTierSuffix("case", info.tier)
Array(api.Items.get(itemName).createItemStack(1)) ++ info.containers ++ info.components

View File

@ -5,8 +5,8 @@ import li.cil.oc.api
import li.cil.oc.api.internal
import li.cil.oc.common.Slot
import li.cil.oc.common.Tier
import li.cil.oc.common.item.data.TabletData
import li.cil.oc.util.ExtendedNBT._
import li.cil.oc.util.ItemUtils
import net.minecraft.inventory.IInventory
import net.minecraft.item.ItemStack
import net.minecraft.nbt.NBTTagCompound
@ -32,7 +32,7 @@ object TabletTemplate extends Template {
val items = mutable.ArrayBuffer(
Option(api.Items.get("screen1").createItemStack(1))
) ++ (1 until inventory.getSizeInventory).map(slot => Option(inventory.getStackInSlot(slot)))
val data = new ItemUtils.TabletData()
val data = new TabletData()
data.items = items.filter(_.isDefined).toArray
data.energy = Settings.get.bufferTablet
data.maxEnergy = data.energy
@ -46,7 +46,7 @@ object TabletTemplate extends Template {
def selectDisassembler(stack: ItemStack) = api.Items.get(stack) == api.Items.get("tablet")
def disassemble(stack: ItemStack, ingredients: Array[ItemStack]) = {
val info = new ItemUtils.TabletData(stack)
val info = new TabletData(stack)
Array(api.Items.get("tabletCase").createItemStack(1)) ++ info.items.collect {
case Some(item) => item
}.drop(1) // Screen.

View File

@ -10,10 +10,10 @@ import li.cil.oc.api.network._
import li.cil.oc.common.Slot
import li.cil.oc.common.entity.Drone
import li.cil.oc.common.item.Tablet
import li.cil.oc.common.item.data.TabletData
import li.cil.oc.server.{PacketSender => ServerPacketSender}
import li.cil.oc.util.BlockPosition
import li.cil.oc.util.ExtendedWorld._
import li.cil.oc.util.ItemUtils
import net.minecraft.entity.player.EntityPlayer
import net.minecraft.item.ItemStack
import net.minecraft.nbt.NBTTagCompound
@ -101,7 +101,7 @@ class Charger extends traits.Environment with traits.PowerAcceptor with traits.R
handler(itemCharge)
}
}
val data = new ItemUtils.TabletData(stack)
val data = new TabletData(stack)
tryCharge(data.energy, data.maxEnergy, (amount) => {
data.energy = math.min(data.maxEnergy, data.energy + amount)
data.save(stack)

View File

@ -11,6 +11,7 @@ import li.cil.oc.util.BlockPosition
import li.cil.oc.util.ExtendedNBT._
import li.cil.oc.util.InventoryUtils
import li.cil.oc.util.ItemUtils
import net.minecraft.entity.player.EntityPlayer
import net.minecraft.item.ItemStack
import net.minecraft.nbt.NBTTagCompound
import net.minecraft.util.EnumFacing
@ -20,7 +21,7 @@ import net.minecraftforge.fml.relauncher.SideOnly
import scala.collection.mutable
class Disassembler extends traits.Environment with traits.PowerAcceptor with traits.Inventory with traits.StateAware {
class Disassembler extends traits.Environment with traits.PowerAcceptor with traits.Inventory with traits.StateAware with traits.PlayerInputAware {
val node = api.Network.newNode(this, Visibility.None).
withConnector(Settings.get.bufferConverter).
create()
@ -33,6 +34,8 @@ class Disassembler extends traits.Environment with traits.PowerAcceptor with tra
var buffer = 0.0
var disassembleNextInstantly = false
def progress = if (queue.isEmpty) 0 else (1 - (queue.size * Settings.get.disassemblerItemCost - buffer) / totalRequiredEnergy) * 100
private def setActive(value: Boolean) = if (value != isActive) {
@ -64,7 +67,8 @@ class Disassembler extends traits.Environment with traits.PowerAcceptor with tra
super.updateEntity()
if (world.getTotalWorldTime % Settings.get.tickFrequency == 0) {
if (queue.isEmpty) {
disassemble(decrStackSize(0, 1))
val instant = disassembleNextInstantly // Is reset via decrStackSize
disassemble(decrStackSize(0, 1), instant)
setActive(queue.nonEmpty)
}
else {
@ -76,10 +80,10 @@ class Disassembler extends traits.Environment with traits.PowerAcceptor with tra
buffer += want
}
}
if (buffer >= Settings.get.disassemblerItemCost) {
while (buffer >= Settings.get.disassemblerItemCost && queue.nonEmpty) {
buffer -= Settings.get.disassemblerItemCost
val stack = queue.remove(0)
if (world.rand.nextDouble > Settings.get.disassemblerBreakChance) {
if (world.rand.nextDouble >= Settings.get.disassemblerBreakChance) {
drop(stack)
}
}
@ -87,7 +91,7 @@ class Disassembler extends traits.Environment with traits.PowerAcceptor with tra
}
}
def disassemble(stack: ItemStack) {
def disassemble(stack: ItemStack, instant: Boolean = false) {
// Validate the item, never trust Minecraft / other Mods on anything!
if (stack != null && isItemValidForSlot(0, stack)) {
val ingredients = ItemUtils.getIngredients(stack)
@ -99,6 +103,10 @@ class Disassembler extends traits.Environment with traits.PowerAcceptor with tra
case _ => queue ++= ingredients
}
totalRequiredEnergy = queue.size * Settings.get.disassemblerItemCost
if (instant) {
buffer = totalRequiredEnergy
disassembleNextInstantly = false // Just to be sure...
}
}
}
@ -152,4 +160,17 @@ class Disassembler extends traits.Environment with traits.PowerAcceptor with tra
override def isItemValidForSlot(i: Int, stack: ItemStack) =
((Settings.get.disassembleAllTheThings || api.Items.get(stack) != null) && ItemUtils.getIngredients(stack).nonEmpty) ||
DisassemblerTemplates.select(stack) != None
override def setInventorySlotContents(slot: Int, stack: ItemStack): Unit = {
super.setInventorySlotContents(slot, stack)
if (!world.isRemote) {
disassembleNextInstantly = false
}
}
override def onSetInventorySlotContents(player: EntityPlayer, slot: Int, stack: ItemStack): Unit = {
if (!world.isRemote) {
disassembleNextInstantly = stack != null && slot == 0 && player.capabilities.isCreativeMode
}
}
}

View File

@ -12,8 +12,8 @@ import li.cil.oc.api.machine.Context
import li.cil.oc.api.network._
import li.cil.oc.common.Slot
import li.cil.oc.common.Tier
import li.cil.oc.common.item.data.MicrocontrollerData
import li.cil.oc.util.ExtendedNBT._
import li.cil.oc.util.ItemUtils
import net.minecraft.item.ItemStack
import net.minecraft.nbt.NBTTagCompound
import net.minecraft.util.EnumFacing
@ -21,7 +21,7 @@ import net.minecraftforge.fml.relauncher.Side
import net.minecraftforge.fml.relauncher.SideOnly
class Microcontroller extends traits.PowerAcceptor with traits.Computer with SidedEnvironment with internal.Microcontroller {
val info = new ItemUtils.MicrocontrollerData()
val info = new MicrocontrollerData()
override val node = api.Network.newNode(this, Visibility.Network).
withComponent("microcontroller").

View File

@ -77,7 +77,7 @@ class Raid extends traits.Environment with traits.Inventory with traits.Rotatabl
}
}
private def tryCreateRaid(id: String) {
def tryCreateRaid(id: String) {
if (items.count(_.isDefined) == items.length) {
val fs = api.FileSystem.asManagedEnvironment(
api.FileSystem.fromSaveDirectory(id, wipeDisksAndComputeSpace, Settings.get.bufferChanges),

View File

@ -1,6 +1,7 @@
package li.cil.oc.common.tileentity
import li.cil.oc.Settings
import li.cil.oc.api
import li.cil.oc.api.network.Visibility
import li.cil.oc.common.tileentity.traits.BundledRedstoneAware
import li.cil.oc.common.tileentity.traits.Environment
@ -11,12 +12,18 @@ import net.minecraft.nbt.NBTTagCompound
import net.minecraft.util.EnumFacing
class Redstone extends Environment with BundledRedstoneAware {
val instance = if (BundledRedstone.isAvailable) new component.Redstone[BundledRedstoneAware](this) with component.RedstoneBundled else new component.Redstone(this)
val instance =
if (BundledRedstone.isAvailable)
new component.Redstone.Bundled(this)
else
new component.Redstone.Vanilla(this)
val node = instance.node
if (node != null) {
val dummyNode = if (node != null) {
node.setVisibility(Visibility.Network)
_isOutputEnabled = true
api.Network.newNode(this, Visibility.None).create()
}
else null
override def canUpdate = isServer
@ -34,8 +41,11 @@ class Redstone extends Environment with BundledRedstoneAware {
// ----------------------------------------------------------------------- //
override protected def onRedstoneInputChanged(side: EnumFacing) {
super.onRedstoneInputChanged(side)
node.sendToReachable("computer.signal", "redstone_changed", Int.box(side.ordinal()))
override protected def onRedstoneInputChanged(side: EnumFacing, oldMaxValue: Int, newMaxValue: Int) {
super.onRedstoneInputChanged(side, oldMaxValue, newMaxValue)
if (node != null && node.network != null) {
node.connect(dummyNode)
dummyNode.sendToNeighbors("redstone.changed", side, int2Integer(oldMaxValue), int2Integer(newMaxValue))
}
}
}

View File

@ -18,6 +18,7 @@ import li.cil.oc.common.Tier
import li.cil.oc.common.inventory.InventorySelection
import li.cil.oc.common.inventory.MultiTank
import li.cil.oc.common.inventory.TankSelection
import li.cil.oc.common.item.data.RobotData
import li.cil.oc.integration.opencomputers.DriverKeyboard
import li.cil.oc.integration.opencomputers.DriverRedstoneCard
import li.cil.oc.integration.opencomputers.DriverScreen
@ -28,7 +29,6 @@ import li.cil.oc.util.BlockPosition
import li.cil.oc.util.ExtendedNBT._
import li.cil.oc.util.ExtendedWorld._
import li.cil.oc.util.InventoryUtils
import li.cil.oc.util.ItemUtils
import net.minecraft.block.Block
import net.minecraft.block.BlockLiquid
import net.minecraft.client.Minecraft
@ -37,7 +37,6 @@ import net.minecraft.init.Blocks
import net.minecraft.inventory.IInventory
import net.minecraft.item.ItemStack
import net.minecraft.nbt.NBTTagCompound
import net.minecraft.tileentity.TileEntity
import net.minecraft.util.BlockPos
import net.minecraft.util.EnumFacing
import net.minecraftforge.common.MinecraftForge
@ -56,7 +55,7 @@ import scala.collection.mutable
class Robot extends traits.Computer with traits.PowerInformation with IFluidHandler with internal.Robot with MultiTank with InventorySelection with TankSelection {
var proxy: RobotProxy = _
val info = new ItemUtils.RobotData()
val info = new RobotData()
val bot = if (isServer) new robot.Robot(this) else null
@ -244,7 +243,7 @@ class Robot extends traits.Computer with traits.PowerInformation with IFluidHand
// worked before the client is notified so that we can use the same trick on
// the client by sending a corresponding packet. This also saves us from
// having to send the complete state again (e.g. screen buffer) each move.
// world.setBlockToAir(newPosition)
// world.setBlockToAir(newPosition)
// In some cases (though I couldn't quite figure out which one) setBlock
// will return true, even though the block was not created / adjusted.
val created = world.setBlockState(newPosition, blockRobotProxy.getDefaultState, 1)
@ -751,8 +750,13 @@ class Robot extends traits.Computer with traits.PowerInformation with IFluidHand
override def dropSlot(slot: Int, count: Int, direction: Option[EnumFacing]) =
InventoryUtils.dropSlot(BlockPosition(x, y, z, world), dynamicInventory, slot, count, direction)
override def dropAllSlots() =
override def dropAllSlots() = {
InventoryUtils.dropSlot(BlockPosition(x, y, z, world), this, 0, Int.MaxValue)
for (slot <- containerSlots) {
InventoryUtils.dropSlot(BlockPosition(x, y, z, world), this, slot, Int.MaxValue)
}
InventoryUtils.dropAllSlots(BlockPosition(x, y, z, world), dynamicInventory)
}
// ----------------------------------------------------------------------- //

View File

@ -139,7 +139,7 @@ class Screen(var tier: Int) extends traits.TextBuffer with SidedEnvironment with
}
// Convert to absolute coordinates and send the packet to the server.
origin.buffer.mouseDown((brx * bw).toInt + 1, (bry * bh).toInt + 1, 0, null)
origin.buffer.mouseDown(brx * bw, bry * bh, 0, null)
true
}
@ -319,8 +319,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) {
super.onRedstoneInputChanged(side)
override protected def onRedstoneInputChanged(side: EnumFacing, oldMaxValue: Int, newMaxValue: Int) {
super.onRedstoneInputChanged(side, oldMaxValue, newMaxValue)
val hasRedstoneInput = screens.map(_.maxInput).max > 0
if (hasRedstoneInput != hadRedstoneInput) {
hadRedstoneInput = hasRedstoneInput

View File

@ -207,7 +207,7 @@ class ServerRack extends traits.PowerAcceptor with traits.Hub with traits.PowerB
val l = 2 / 16.0
val h = 14 / 16.0
val slot = (((1 - hitY) - l) / (h - l) * 4).toInt
Some(math.max(0, math.min(servers.length, slot)))
Some(math.max(0, math.min(servers.length - 1, slot)))
}
else None
}
@ -409,10 +409,10 @@ class ServerRack extends traits.PowerAcceptor with traits.Hub with traits.PowerB
checkRedstoneInputChanged()
}
override protected def onRedstoneInputChanged(side: EnumFacing) {
super.onRedstoneInputChanged(side)
override protected def onRedstoneInputChanged(side: EnumFacing, oldMaxValue: Int, newMaxValue: Int) {
super.onRedstoneInputChanged(side, oldMaxValue, newMaxValue)
servers collect {
case Some(server) => server.machine.signal("redstone_changed", server.machine.node.address, Int.box(toLocal(side).ordinal()))
case Some(server) => server.machine.node.sendToNeighbors("redstone.changed", toLocal(side), int2Integer(oldMaxValue), int2Integer(newMaxValue))
}
}

View File

@ -55,13 +55,15 @@ trait BundledRedstoneAware extends RedstoneAware /* with IBundledEmitter with IB
def bundledInput(side: EnumFacing, color: Int) =
math.max(_bundledInput(side.ordinal())(color), _rednetInput(side.ordinal())(color))
def rednetInput(side: EnumFacing, color: Int, value: Int) =
if (_rednetInput(side.ordinal())(color) != value) {
if (_rednetInput(side.ordinal())(color) != -1) {
onRedstoneInputChanged(side)
def rednetInput(side: EnumFacing, color: Int, value: Int): Unit = {
val oldValue = _rednetInput(side.ordinal())(color)
if (oldValue != value) {
if (oldValue != -1) {
onRedstoneInputChanged(side, oldValue, value)
}
_rednetInput(side.ordinal())(color) = value
}
}
def bundledOutput(side: EnumFacing) = _bundledOutput(toLocal(side).ordinal())
@ -87,19 +89,20 @@ trait BundledRedstoneAware extends RedstoneAware /* with IBundledEmitter with IB
override protected def updateRedstoneInput(side: EnumFacing) {
super.updateRedstoneInput(side)
val oldBundledInput = _bundledInput(side.ordinal())
val ownBundledInput = _bundledInput(side.ordinal())
val newBundledInput = computeBundledInput(side)
val oldMaxValue = ownBundledInput.max
var changed = false
if (newBundledInput != null) for (color <- 0 until 16) {
changed = changed || (oldBundledInput(color) >= 0 && oldBundledInput(color) != newBundledInput(color))
oldBundledInput(color) = newBundledInput(color)
changed = changed || (ownBundledInput(color) >= 0 && ownBundledInput(color) != newBundledInput(color))
ownBundledInput(color) = newBundledInput(color)
}
else for (color <- 0 until 16) {
changed = changed || oldBundledInput(color) > 0
oldBundledInput(color) = 0
changed = changed || ownBundledInput(color) > 0
ownBundledInput(color) = 0
}
if (changed) {
onRedstoneInputChanged(side)
onRedstoneInputChanged(side, oldMaxValue, ownBundledInput.max)
}
}

View File

@ -180,9 +180,9 @@ trait Computer extends Environment with ComponentInventory with Rotatable with B
checkRedstoneInputChanged()
}
override protected def onRedstoneInputChanged(side: EnumFacing) {
super.onRedstoneInputChanged(side)
machine.signal("redstone_changed", machine.node.address, Int.box(toLocal(side).ordinal()))
override protected def onRedstoneInputChanged(side: EnumFacing, oldMaxValue: Int, newMaxValue: Int) {
super.onRedstoneInputChanged(side, oldMaxValue, newMaxValue)
machine.node.sendToNeighbors("redstone.changed", toLocal(side), int2Integer(oldMaxValue), int2Integer(newMaxValue))
}
// ----------------------------------------------------------------------- //

View File

@ -0,0 +1,14 @@
package li.cil.oc.common.tileentity.traits
import net.minecraft.entity.player.EntityPlayer
import net.minecraft.inventory.IInventory
import net.minecraft.item.ItemStack
// Used to get notifications from containers when a player changes a slot in
// this inventory. Normally the player causing a setInventorySlotContents is
// unavailable. Using this we gain access to the causing player, allowing for
// some player-specific logic, such as the disassembler working instantaneously
// when used by a player in creative mode.
trait PlayerInputAware extends IInventory {
def onSetInventorySlotContents(player: EntityPlayer, slot: Int, stack: ItemStack): Unit
}

View File

@ -84,8 +84,8 @@ trait RedstoneAware extends RotationAware /* with IConnectable with IRedstoneEmi
val oldInput = _input(side.ordinal())
val newInput = computeInput(side)
_input(side.ordinal()) = newInput
if (oldInput >= 0 && input(side) != oldInput) {
onRedstoneInputChanged(side)
if (oldInput >= 0 && newInput != oldInput) {
onRedstoneInputChanged(side, oldInput, newInput)
}
}
@ -148,7 +148,7 @@ trait RedstoneAware extends RotationAware /* with IConnectable with IRedstoneEmi
}
}
protected def onRedstoneInputChanged(side: EnumFacing) {}
protected def onRedstoneInputChanged(side: EnumFacing, oldMaxValue: Int, newMaxValue: Int) {}
protected def onRedstoneOutputEnabledChanged() {
world.notifyNeighborsOfStateChange(getPos, getBlockType)

View File

@ -14,7 +14,7 @@
// @Optional.Method(modid = Mods.IDs.Mekanism)
// def transferEnergyToAcceptor(side: EnumFacing, amount: Double) =
// if (!Mods.Mekanism.isAvailable) 0
// else amount - tryChangeBuffer(side, amount * Settings.get.ratioMekanism) / Settings.get.ratioMekanism
// else tryChangeBuffer(side, amount * Settings.get.ratioMekanism) / Settings.get.ratioMekanism
//
// @Optional.Method(modid = Mods.IDs.Mekanism)
// def getMaxEnergy = EnumFacing.values.map(globalBufferSize).max / Settings.get.ratioMekanism

View File

@ -21,6 +21,7 @@ object Mods {
val AppliedEnergistics2 = new SimpleMod(IDs.AppliedEnergistics2, version = "@[rv1,)", providesPower = true)
val BattleGear2 = new SimpleMod(IDs.BattleGear2)
val BloodMagic = new SimpleMod(IDs.BloodMagic)
val BuildCraft = new SimpleMod(IDs.BuildCraft)
val BuildCraftTiles = new SimpleMod(IDs.BuildCraftTiles)
val BuildCraftTools = new SimpleMod(IDs.BuildCraftTools)
@ -71,37 +72,38 @@ object Mods {
// ----------------------------------------------------------------------- //
val Proxies = Array(
// integration.appeng.ModAppEng,
// integration.buildcraft.tools.ModBuildCraftAPITools,
// integration.buildcraft.tiles.ModBuildCraftAPITiles,
// integration.buildcraft.transport.ModBuildCraftAPITransport,
// integration.cofh.energy.ModCoFHEnergy,
// integration.cofh.item.ModCoFHItem,
// integration.cofh.tileentity.ModCoFHTileEntity,
// integration.cofh.transport.ModCoFHTransport,
// integration.enderstorage.ModEnderStorage,
// integration.forestry.ModForestry,
// integration.fmp.ModForgeMultipart,
// integration.gc.ModGalacticraft,
// integration.gregtech.ModGregtech,
// integration.ic2.ModIndustrialCraft2,
// integration.mfr.ModMineFactoryReloaded,
// integration.mystcraft.ModMystcraft,
// integration.railcraft.ModRailcraft,
// integration.stargatetech2.ModStargateTech2,
// integration.thaumcraft.ModThaumcraft,
// integration.thermalexpansion.ModThermalExpansion,
// integration.tcon.ModTinkersConstruct,
// integration.tmechworks.ModTMechworks,
// integration.appeng.ModAppEng,
// integration.bloodmagic.ModBloodMagic,
// integration.buildcraft.tools.ModBuildCraftAPITools,
// integration.buildcraft.tiles.ModBuildCraftAPITiles,
// integration.buildcraft.transport.ModBuildCraftAPITransport,
// integration.cofh.energy.ModCoFHEnergy,
// integration.cofh.item.ModCoFHItem,
// integration.cofh.tileentity.ModCoFHTileEntity,
// integration.cofh.transport.ModCoFHTransport,
// integration.enderstorage.ModEnderStorage,
// integration.forestry.ModForestry,
// integration.fmp.ModForgeMultipart,
// integration.gc.ModGalacticraft,
// integration.gregtech.ModGregtech,
// integration.ic2.ModIndustrialCraft2,
// integration.mfr.ModMineFactoryReloaded,
// integration.mystcraft.ModMystcraft,
// integration.railcraft.ModRailcraft,
// integration.stargatetech2.ModStargateTech2,
// integration.thaumcraft.ModThaumcraft,
// integration.thermalexpansion.ModThermalExpansion,
// integration.tcon.ModTinkersConstruct,
// integration.tmechworks.ModTMechworks,
integration.vanilla.ModVanilla,
// integration.versionchecker.ModVersionChecker,
// integration.waila.ModWaila,
// integration.wrcbe.ModWRCBE,
// integration.wrsve.ModWRSVE,
// integration.versionchecker.ModVersionChecker,
// integration.waila.ModWaila,
// integration.wrcbe.ModWRCBE,
// integration.wrsve.ModWRSVE,
// // Register the general IPeripheral driver last, if at all, to avoid it
// // being used rather than other more concrete implementations.
// integration.computercraft.ModComputerCraft,
// // Register the general IPeripheral driver last, if at all, to avoid it
// // being used rather than other more concrete implementations.
// integration.computercraft.ModComputerCraft,
// We go last to ensure all other mod integration is done, e.g. to
// allow properly checking if wireless redstone is present.
@ -111,7 +113,7 @@ object Mods {
def init(): Unit = {
for (proxy <- Proxies) {
tryInit(proxy)
}
}
}
private def tryInit(mod: ModProxy) {
@ -131,6 +133,7 @@ object Mods {
object IDs {
final val AppliedEnergistics2 = "appliedenergistics2"
final val BattleGear2 = "battlegear2"
final val BloodMagic = "AWWayofTime"
final val BuildCraft = "BuildCraft|Core"
final val BuildCraftPower = "BuildCraftAPI|power"
final val BuildCraftTiles = "BuildCraftAPI|tiles"

View File

@ -1,11 +1,15 @@
package li.cil.oc.integration.appeng
import appeng.api.AEApi
import appeng.api.config.Actionable
import appeng.api.networking.crafting.ICraftingLink
import appeng.api.networking.crafting.ICraftingRequester
import appeng.api.networking.security.IActionHost
import appeng.api.networking.security.MachineSource
import appeng.api.storage.data.IAEItemStack
import appeng.core.Api
import appeng.me.helpers.IGridProxyable
import appeng.tile.misc.TileInterface
import appeng.tile.networking.TileController
import appeng.util.item.AEItemStack
import com.google.common.collect.ImmutableSet
@ -25,6 +29,7 @@ import li.cil.oc.util.ResultWrapper._
import net.minecraft.block.Block
import net.minecraft.item.ItemStack
import net.minecraft.nbt.NBTTagCompound
import net.minecraft.tileentity.TileEntity
import net.minecraft.world.World
import net.minecraftforge.common.DimensionManager
import net.minecraftforge.common.util.Constants.NBT
@ -37,19 +42,30 @@ import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future
object DriverController extends DriverTileEntity with EnvironmentAware {
def getTileEntityClass = classOf[TileController]
private type AETile = TileEntity with IGridProxyable with IActionHost
def getTileEntityClass = {
if (AEApi.instance != null && AEApi.instance.blocks != null) {
if (AEApi.instance.blocks.blockController != null && AEApi.instance.blocks.blockController.item != null)
classOf[TileController]
else
classOf[TileInterface]
}
else null
}
def createEnvironment(world: World, x: Int, y: Int, z: Int): ManagedEnvironment =
new Environment(world.getTileEntity(x, y, z).asInstanceOf[TileController])
new Environment(world.getTileEntity(x, y, z).asInstanceOf[AETile])
override def providedEnvironment(stack: ItemStack) =
if (stack != null &&
Api.instance != null &&
Api.instance.blocks != null &&
Api.instance.blocks.blockController != null &&
Block.getBlockFromItem(stack.getItem) == Api.instance.blocks.blockController.block) classOf[Environment] else null
AEApi.instance != null &&
AEApi.instance.blocks != null &&
AEApi.instance.blocks.blockController != null &&
Block.getBlockFromItem(stack.getItem) == AEApi.instance.blocks.blockController.block) classOf[Environment]
else null
class Environment(tileEntity: TileController) extends ManagedTileEntityEnvironment[TileController](tileEntity, "me_controller") with NamedBlock {
class Environment(tileEntity: AETile) extends ManagedTileEntityEnvironment[AETile](tileEntity, "me_controller") with NamedBlock {
override def preferredName = "me_controller"
override def priority = 0
@ -63,9 +79,17 @@ object DriverController extends DriverTileEntity with EnvironmentAware {
"busy" -> cpu.isBusy)))
@Callback(doc = "function():table -- Get a list of known item recipes. These can be used to issue crafting requests.")
def getCraftables(context: Context, args: Arguments): Array[AnyRef] =
def getCraftables(context: Context, args: Arguments): Array[AnyRef] = {
result(tileEntity.getProxy.getStorage.getItemInventory.getStorageList.
filter(_.isCraftable).map(new Craftable(tileEntity, _)).toArray)
filter(_.isCraftable).map(stack => {
val patterns = tileEntity.getProxy.getCrafting.getCraftingFor(stack, null, 0, tileEntity.getWorldObj)
val result = patterns.find(pattern => pattern.getOutputs.exists(_.isSameType(stack))) match {
case Some(pattern) => pattern.getOutputs.find(_.isSameType(stack)).get
case _ => stack.copy.setStackSize(0) // Should not be possible, but hey...
}
new Craftable(tileEntity, result)
}).toArray)
}
@Callback(doc = "function():table -- Get a list of the stored items in the network.")
def getItemsInNetwork(context: Context, args: Arguments): Array[AnyRef] =
@ -96,7 +120,7 @@ object DriverController extends DriverTileEntity with EnvironmentAware {
result(tileEntity.getProxy.getEnergy.getStoredPower)
}
class Craftable(var controller: TileController, var stack: IAEItemStack) extends AbstractValue with ICraftingRequester {
class Craftable(var controller: AETile, var stack: IAEItemStack) extends AbstractValue with ICraftingRequester {
def this() = this(null, null)
private val links = mutable.Set.empty[ICraftingLink]
@ -180,8 +204,8 @@ object DriverController extends DriverTileEntity with EnvironmentAware {
EventHandler.schedule(() => {
val world = DimensionManager.getWorld(dimension)
val tileEntity = world.getTileEntity(x, y, z)
if (tileEntity != null && tileEntity.isInstanceOf[TileController]) {
controller = tileEntity.asInstanceOf[TileController]
if (tileEntity != null && tileEntity.isInstanceOf[AETile]) {
controller = tileEntity.asInstanceOf[AETile]
}
})
}

View File

@ -0,0 +1,30 @@
package li.cil.oc.integration.bloodmagic;
import WayofTime.alchemicalWizardry.api.items.interfaces.IBloodOrb;
import WayofTime.alchemicalWizardry.api.soulNetwork.SoulNetworkHandler;
import li.cil.oc.api.driver.Converter;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import java.util.Map;
public class ConverterBloodOrb implements Converter {
@Override
public void convert(Object value, Map<Object, Object> output) {
if (value instanceof ItemStack) {
final ItemStack stack = (ItemStack) value;
final Item item = stack.getItem();
if (item instanceof IBloodOrb) {
final IBloodOrb bloodOrb = (IBloodOrb) item;
final String ownerName = stack.stackTagCompound.getString("ownerName");
final int maxOrbTier = SoulNetworkHandler.getCurrentMaxOrb(ownerName);
output.put("ownerName", ownerName);
output.put("networkOrbTier", maxOrbTier);
output.put("networkEssence", SoulNetworkHandler.getCurrentEssence(ownerName));
output.put("maxNetworkEssence", SoulNetworkHandler.getMaximumForOrbTier(maxOrbTier));
output.put("maxEssence", bloodOrb.getMaxEssence());
output.put("orbTier", bloodOrb.getOrbLevel());
}
}
}
}

View File

@ -0,0 +1,79 @@
package li.cil.oc.integration.bloodmagic;
import li.cil.oc.api.driver.NamedBlock;
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.ManagedEnvironment;
import li.cil.oc.api.prefab.DriverTileEntity;
import li.cil.oc.integration.ManagedTileEntityEnvironment;
import net.minecraft.world.World;
import WayofTime.alchemicalWizardry.api.tile.IBloodAltar;
public class DriverBloodAltar extends DriverTileEntity {
@Override
public Class<?> getTileEntityClass() {
return IBloodAltar.class;
}
@Override
public ManagedEnvironment createEnvironment(World world, int x, int y, int z) {
return new Environment((IBloodAltar) world.getTileEntity(x, y, z));
}
public static final class Environment extends ManagedTileEntityEnvironment<IBloodAltar> implements NamedBlock {
public Environment(final IBloodAltar tileEntity) {
super(tileEntity, "blood_altar");
}
@Override
public String preferredName() {
return "blood_altar";
}
@Override
public int priority() {
return 0;
}
@Callback(doc = "function():number -- Get the capacity.")
public Object[] getCapacity(final Context context, final Arguments arguments) {
return new Object[]{tileEntity.getCapacity()};
}
@Callback(doc = "function():number -- Get the amount of blood currently contained by this altar.")
public Object[] getCurrentBlood(final Context context, final Arguments arguments) {
return new Object[]{tileEntity.getCurrentBlood()};
}
@Callback(doc = "function():number -- Get the current tier.")
public Object[] getTier(final Context context, final Arguments arguments) {
return new Object[]{tileEntity.getTier()};
}
@Callback(doc = "function():number -- Get the progress.")
public Object[] getProgress(final Context context, final Arguments arguments) {
return new Object[]{tileEntity.getProgress()};
}
@Callback(doc = "function():number -- Get the sacrifice multiplier.")
public Object[] getSacrificeMultiplier(final Context context, final Arguments arguments) {
return new Object[]{tileEntity.getCapacity()};
}
@Callback(doc = "function():number -- Get the self sacrifice multiplier.")
public Object[] getSelfSacrificeMultiplier(final Context context, final Arguments arguments) {
return new Object[]{tileEntity.getSelfSacrificeMultiplier()};
}
@Callback(doc = "function():number -- Get the orb multiplier.")
public Object[] getOrbMultiplier(final Context context, final Arguments arguments) {
return new Object[]{tileEntity.getOrbMultiplier()};
}
@Callback(doc = "function():number -- Get the dislocation multiplier.")
public Object[] getDislocationMultiplier(final Context context, final Arguments arguments) {
return new Object[]{tileEntity.getDislocationMultiplier()};
}
}
}

View File

@ -0,0 +1,69 @@
package li.cil.oc.integration.bloodmagic;
import WayofTime.alchemicalWizardry.api.rituals.IMasterRitualStone;
import WayofTime.alchemicalWizardry.common.tileEntity.TEMasterStone;
import li.cil.oc.api.driver.NamedBlock;
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.ManagedEnvironment;
import li.cil.oc.api.prefab.DriverTileEntity;
import li.cil.oc.integration.ManagedTileEntityEnvironment;
import net.minecraft.world.World;
public class DriverMasterRitualStone extends DriverTileEntity {
@Override
public Class<?> getTileEntityClass() {
return IMasterRitualStone.class;
}
@Override
public ManagedEnvironment createEnvironment(World world, int x, int y, int z) {
return new Environment((IMasterRitualStone) world.getTileEntity(x, y, z));
}
public static class Environment extends ManagedTileEntityEnvironment<IMasterRitualStone> implements NamedBlock {
public Environment(IMasterRitualStone tileEntity) {
super(tileEntity, "master_ritual_stone");
}
@Override
public String preferredName() {
return "master_ritual_stone";
}
@Override
public int priority() {
return 0;
}
@Callback(doc = "function():string -- Get the name of the player owning this master ritual stone.")
public Object[] getOwner(final Context context, final Arguments arguments) {
return new Object[]{tileEntity.getOwner()};
}
@Callback(doc = "function():string -- Get the current ritual.")
public Object[] getCurrentRitual(final Context context, final Arguments arguments) {
if (tileEntity instanceof TEMasterStone) {
TEMasterStone masterStone = (TEMasterStone) tileEntity;
return new Object[]{masterStone.getCurrentRitual()};
}
return new Object[]{"internal error"};
}
@Callback(doc = "function():number -- Get the remaining cooldown.")
public Object[] getCooldown(final Context context, final Arguments arguments) {
return new Object[]{tileEntity.getCooldown()};
}
@Callback(doc = "function():number -- Get the running time.")
public Object[] getRunningTime(final Context context, final Arguments arguments) {
return new Object[]{tileEntity.getRunningTime()};
}
@Callback(doc = "function():boolean -- Get whether the tanks are empty.")
public Object[] areTanksEmpty(final Context context, final Arguments arguments) {
return new Object[]{tileEntity.areTanksEmpty()};
}
}
}

View File

@ -0,0 +1,15 @@
package li.cil.oc.integration.bloodmagic
import li.cil.oc.api.Driver
import li.cil.oc.integration.{Mods, ModProxy}
object ModBloodMagic extends ModProxy {
override def getMod = Mods.BloodMagic
override def initialize() {
Driver.add(new DriverBloodAltar)
Driver.add(new DriverMasterRitualStone)
Driver.add(new ConverterBloodOrb)
}
}

View File

@ -5,13 +5,90 @@ import dan200.computercraft.api.peripheral.IComputerAccess
import dan200.computercraft.api.peripheral.IPeripheral
import li.cil.oc.Settings
import li.cil.oc.api
import li.cil.oc.api.machine.Context
import li.cil.oc.api.network.Component
import li.cil.oc.common.tileentity.AccessPoint
import li.cil.oc.common.tileentity.Switch
import li.cil.oc.util.ResultWrapper._
import net.minecraftforge.common.util.ForgeDirection
import scala.collection.convert.WrapAsJava._
import scala.collection.convert.WrapAsScala._
import scala.collection.mutable
class SwitchPeripheral(val switch: Switch) extends IPeripheral {
private val methods = Map[String, (IComputerAccess, ILuaContext, Array[AnyRef]) => Array[AnyRef]](
// Generic modem methods.
"open" -> ((computer, context, arguments) => {
val port = checkPort(arguments, 0)
if (switch.openPorts(computer).size >= 128)
throw new IllegalArgumentException("too many open channels")
result(switch.openPorts(computer).add(port))
}),
"isOpen" -> ((computer, context, arguments) => {
val port = checkPort(arguments, 0)
result(switch.openPorts(computer).contains(port))
}),
"close" -> ((computer, context, arguments) => {
val port = checkPort(arguments, 0)
result(switch.openPorts(computer).remove(port))
}),
"closeAll" -> ((computer, context, arguments) => {
switch.openPorts(computer).clear()
null
}),
"transmit" -> ((computer, context, arguments) => {
val sendPort = checkPort(arguments, 0)
val answerPort = checkPort(arguments, 1)
val data = Seq(Int.box(answerPort)) ++ arguments.drop(2)
val packet = api.Network.newPacket(s"cc${computer.getID}_${computer.getAttachmentName}", null, sendPort, data.toArray)
result(switch.tryEnqueuePacket(None, packet))
}),
"isWireless" -> ((computer, context, arguments) => {
result(switch.isInstanceOf[AccessPoint])
}),
// Undocumented modem messages.
"callRemote" -> ((computer, context, arguments) => {
val address = checkString(arguments, 0)
visibleComponents.find(_.address == address) match {
case Some(component) =>
val method = checkString(arguments, 1)
val fakeContext = new CCContext(computer, context)
component.invoke(method, fakeContext, arguments.drop(2): _*)
case _ => null
}
}),
"getMethodsRemote" -> ((computer, context, arguments) => {
val address = checkString(arguments, 0)
visibleComponents.find(_.address == address) match {
case Some(component) => result(mapAsJavaMap(component.methods.zipWithIndex.map(t => (t._2 + 1, t._1)).toMap))
case _ => null
}
}),
"getNamesRemote" -> ((computer, context, arguments) => {
result(mapAsJavaMap(visibleComponents.map(_.address).zipWithIndex.map(t => (t._2 + 1, t._1)).toMap))
}),
"getTypeRemote" -> ((computer, context, arguments) => {
val address = checkString(arguments, 0)
visibleComponents.find(_.address == address) match {
case Some(component) => result(component.name)
case _ => null
}
}),
"isPresentRemote" -> ((computer, context, arguments) => {
val address = checkString(arguments, 0)
result(visibleComponents.exists(_.address == address))
}),
// OC specific.
"maxPacketSize" -> ((computer, context, arguments) => {
result(Settings.get.maxNetworkPacketSize)
})
)
private val methodNames = methods.keys.toArray.sorted
override def getType = "modem"
override def attach(computer: IComputerAccess) {
@ -24,34 +101,9 @@ class SwitchPeripheral(val switch: Switch) extends IPeripheral {
switch.openPorts -= computer
}
override def getMethodNames = Array("open", "isOpen", "close", "closeAll", "maxPacketSize", "transmit", "isWireless")
override def getMethodNames = methodNames
override def callMethod(computer: IComputerAccess, context: ILuaContext, method: Int, arguments: Array[AnyRef]) = getMethodNames()(method) match {
case "open" =>
val port = checkPort(arguments, 0)
if (switch.openPorts(computer).size >= 128)
throw new IllegalArgumentException("too many open channels")
result(switch.openPorts(computer).add(port))
case "isOpen" =>
val port = checkPort(arguments, 0)
result(switch.openPorts(computer).contains(port))
case "close" =>
val port = checkPort(arguments, 0)
result(switch.openPorts(computer).remove(port))
case "closeAll" =>
switch.openPorts(computer).clear()
null
case "maxPacketSize" =>
result(Settings.get.maxNetworkPacketSize)
case "transmit" =>
val sendPort = checkPort(arguments, 0)
val answerPort = checkPort(arguments, 1)
val data = Seq(Int.box(answerPort)) ++ arguments.drop(2)
val packet = api.Network.newPacket(s"cc${computer.getID}_${computer.getAttachmentName}", null, sendPort, data.toArray)
result(switch.tryEnqueuePacket(None, packet))
case "isWireless" => result(switch.isInstanceOf[AccessPoint])
case _ => null
}
override def callMethod(computer: IComputerAccess, context: ILuaContext, method: Int, arguments: Array[AnyRef]) = methods(methodNames(method))(computer, context, arguments)
override def equals(other: IPeripheral) = other match {
case peripheral: SwitchPeripheral => peripheral.switch == switch
@ -66,4 +118,41 @@ class SwitchPeripheral(val switch: Switch) extends IPeripheral {
throw new IllegalArgumentException(s"bad argument #${index + 1} (number in [1, 65535] expected)")
port
}
private def checkString(args: Array[AnyRef], index: Int) = {
if (args.length < index - 1 || !args(index).isInstanceOf[String])
throw new IllegalArgumentException(s"bad argument #${index + 1} (string expected)")
args(index).asInstanceOf[String]
}
private def visibleComponents = {
ForgeDirection.VALID_DIRECTIONS.flatMap(side => {
val node = switch.sidedNode(side)
node.reachableNodes.collect {
case component: Component if component.canBeSeenFrom(node) => component
}
})
}
class CCContext(val computer: IComputerAccess, val context: ILuaContext) extends Context {
override def node() = switch.node
override def isPaused = false
override def stop() = false
override def canInteract(player: String) = true
override def signal(name: String, args: AnyRef*) = {
computer.queueEvent(name, args.toArray)
true
}
override def pause(seconds: Double) = false
override def isRunning = true
override def start() = false
}
}

View File

@ -33,7 +33,7 @@ object DriverBlockEnvironments extends driver.Block with EnvironmentAware {
else if (isOneOf(block.getBlock, "case1", "case2", "case3", "caseCreative", "microcontroller")) classOf[Machine]
else if (isOneOf(block.getBlock, "hologram1", "hologram2")) classOf[tileentity.Hologram]
else if (isOneOf(block.getBlock, "motionSensor")) classOf[tileentity.MotionSensor]
else if (isOneOf(block.getBlock, "redstone")) if (BundledRedstone.isAvailable) classOf[component.Redstone.Bundled] else classOf[component.Redstone.Simple]
else if (isOneOf(block.getBlock, "redstone")) if (BundledRedstone.isAvailable) classOf[component.Redstone.Bundled] else classOf[component.Redstone.Vanilla]
else if (isOneOf(block.getBlock, "screen1")) classOf[common.component.TextBuffer].asInstanceOf[Class[_ <: Environment]]
else if (isOneOf(block.getBlock, "screen2", "screen3")) classOf[common.component.Screen]
else if (isOneOf(block.getBlock, "robot")) classOf[component.robot.Robot].asInstanceOf[Class[_ <: Environment]]

Some files were not shown because too many files have changed in this diff Show More