diff --git a/LICENSE b/LICENSE index 68dd6e055..e4a728039 100644 --- a/LICENSE +++ b/LICENSE @@ -21,6 +21,19 @@ THE SOFTWARE. ------------------------------------------------------------------------------- All images / textures and localization strings (resources) are put in the -public domain. More specicially, see CC0 1.0 Universal: +public domain, unless explicitly excluded below. More specicially, see CC0 1.0 +Universal: - http://creativecommons.org/publicdomain/zero/1.0/ \ No newline at end of file + http://creativecommons.org/publicdomain/zero/1.0/ + +Contributions: + PixelToast - Capacitor textures. + asie - Disk drive inject/eject and floppy disk access sound samples. + +Thanks a lot! + +------------------------------------------------------------------------------- + +Assets from other sources: + HDD access samples based on this sample from freesound.org: + https://www.freesound.org/people/artykris/sounds/117401/ diff --git a/README.md b/README.md index 55aa30dcf..27abe14a8 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ If you'd like to contribute code, please have a look at the [code conventions](h If you encounter any bugs, please report them [in the issue tracker](https://github.com/MightyPirates/OpenComputers/issues?state=open), if they have not already been reported. If you report a crash, always provide your log file. -If you wish to discuss or suggest a new feature, the [forums](http://oc.cil.li//index.php?/forum/22-feedback-and-suggestions/) are a good place for that. +If you wish to discuss or suggest a new feature, the [forums](http://oc.cil.li/forums/viewforum.php?f=11) are a good place for that. Extending --------- diff --git a/src/main/java/li/cil/oc/api/FileSystem.java b/src/main/java/li/cil/oc/api/FileSystem.java index d2b8736a8..efe24bece 100644 --- a/src/main/java/li/cil/oc/api/FileSystem.java +++ b/src/main/java/li/cil/oc/api/FileSystem.java @@ -6,6 +6,7 @@ import dan200.computer.api.IWritableMount; import li.cil.oc.api.detail.FileSystemAPI; import li.cil.oc.api.fs.Label; import li.cil.oc.api.network.ManagedEnvironment; +import net.minecraft.tileentity.TileEntity; /** * This class provides factory methods for creating file systems that are @@ -46,7 +47,8 @@ public final class FileSystem { * @return a file system wrapping the specified folder. */ public static li.cil.oc.api.fs.FileSystem fromClass(final Class clazz, final String domain, final String root) { - if (instance != null) return instance.fromClass(clazz, domain, root); + if (instance != null) + return instance.fromClass(clazz, domain, root); return null; } @@ -74,7 +76,8 @@ public final class FileSystem { * @return a file system wrapping the specified folder. */ public static li.cil.oc.api.fs.FileSystem fromSaveDirectory(final String root, final long capacity, final boolean buffered) { - if (instance != null) return instance.fromSaveDirectory(root, capacity, buffered); + if (instance != null) + return instance.fromSaveDirectory(root, capacity, buffered); return null; } @@ -103,7 +106,8 @@ public final class FileSystem { * @return a file system residing in memory. */ public static li.cil.oc.api.fs.FileSystem fromMemory(final long capacity) { - if (instance != null) return instance.fromMemory(capacity); + if (instance != null) + return instance.fromMemory(capacity); return null; } @@ -115,7 +119,8 @@ public final class FileSystem { */ @Optional.Method(modid = "ComputerCraft") public static li.cil.oc.api.fs.FileSystem fromComputerCraft(final IMount mount) { - if (instance != null) return instance.fromComputerCraft(mount); + if (instance != null) + return instance.fromComputerCraft(mount); return null; } @@ -127,7 +132,8 @@ public final class FileSystem { */ @Optional.Method(modid = "ComputerCraft") public static li.cil.oc.api.fs.FileSystem fromComputerCraft(final IWritableMount mount) { - if (instance != null) return instance.fromComputerCraft(mount); + if (instance != null) + return instance.fromComputerCraft(mount); return null; } @@ -140,13 +146,36 @@ public final class FileSystem { * more control over the node, implement your own, and connect this one to * it. In that case you will have to forward any disk driver messages to the * node, though. + *

+ * The container parameter is used to give the file system some physical + * relation to the world, for example this is used by hard drives to send + * the disk event notifications to the client that are used to play disk + * access sounds. + *

+ * The container may be null, if no such context can be provided. + * + * @param fileSystem the file system to wrap. + * @param label the label of the file system. + * @param container the tile entity containing the file system. + * @return the network node wrapping the file system. + */ + public static ManagedEnvironment asManagedEnvironment(final li.cil.oc.api.fs.FileSystem fileSystem, final Label label, final TileEntity container) { + if (instance != null) + return instance.asManagedEnvironment(fileSystem, label, container); + return null; + } + + /** + * Like {@link #asManagedEnvironment(li.cil.oc.api.fs.FileSystem, Label, TileEntity)}, + * but does not provide a container. * * @param fileSystem the file system to wrap. * @param label the label of the file system. * @return the network node wrapping the file system. */ public static ManagedEnvironment asManagedEnvironment(final li.cil.oc.api.fs.FileSystem fileSystem, final Label label) { - if (instance != null) return instance.asManagedEnvironment(fileSystem, label); + if (instance != null) + return instance.asManagedEnvironment(fileSystem, label); return null; } @@ -159,7 +188,8 @@ public final class FileSystem { * @return the network node wrapping the file system. */ public static ManagedEnvironment asManagedEnvironment(final li.cil.oc.api.fs.FileSystem fileSystem, final String label) { - if (instance != null) return instance.asManagedEnvironment(fileSystem, label); + if (instance != null) + return instance.asManagedEnvironment(fileSystem, label); return null; } @@ -172,7 +202,8 @@ public final class FileSystem { * @return the network node wrapping the file system. */ public static ManagedEnvironment asManagedEnvironment(final li.cil.oc.api.fs.FileSystem fileSystem) { - if (instance != null) return instance.asManagedEnvironment(fileSystem); + if (instance != null) + return instance.asManagedEnvironment(fileSystem); return null; } diff --git a/src/main/java/li/cil/oc/api/detail/FileSystemAPI.java b/src/main/java/li/cil/oc/api/detail/FileSystemAPI.java index 894e2246e..43264ea33 100644 --- a/src/main/java/li/cil/oc/api/detail/FileSystemAPI.java +++ b/src/main/java/li/cil/oc/api/detail/FileSystemAPI.java @@ -6,6 +6,7 @@ import dan200.computer.api.IWritableMount; import li.cil.oc.api.fs.FileSystem; import li.cil.oc.api.fs.Label; import li.cil.oc.api.network.ManagedEnvironment; +import net.minecraft.tileentity.TileEntity; public interface FileSystemAPI { /** @@ -96,6 +97,24 @@ public interface FileSystemAPI { * more control over the node, implement your own, and connect this one to * it. In that case you will have to forward any disk driver messages to the * node, though. + *

+ * The container parameter is used to give the file system some physical + * relation to the world, for example this is used by hard drives to send + * the disk event notifications to the client that are used to play disk + * access sounds. + *

+ * The container may be null, if no such context can be provided. + * + * @param fileSystem the file system to wrap. + * @param label the label of the file system. + * @param container the tile entity containing the file system. + * @return the network node wrapping the file system. + */ + ManagedEnvironment asManagedEnvironment(FileSystem fileSystem, Label label, TileEntity container); + + /** + * Like {@link #asManagedEnvironment(li.cil.oc.api.fs.FileSystem, Label, TileEntity)}, + * but does not provide a container. * * @param fileSystem the file system to wrap. * @param label the label of the file system. diff --git a/src/main/java/li/cil/oc/api/package-info.java b/src/main/java/li/cil/oc/api/package-info.java index 37c89ceb4..922cb0286 100644 --- a/src/main/java/li/cil/oc/api/package-info.java +++ b/src/main/java/li/cil/oc/api/package-info.java @@ -37,5 +37,5 @@ @cpw.mods.fml.common.API( owner = "OpenComputers|Core", provides = "OpenComputersAPI", - apiVersion = "1.4.4") + apiVersion = "1.4.5") package li.cil.oc.api; \ No newline at end of file diff --git a/src/main/resources/assets/opencomputers/lang/de_DE.lang b/src/main/resources/assets/opencomputers/lang/de_DE.lang index 98aecb463..025f1bfa4 100644 --- a/src/main/resources/assets/opencomputers/lang/de_DE.lang +++ b/src/main/resources/assets/opencomputers/lang/de_DE.lang @@ -173,4 +173,4 @@ oc:tooltip.UpgradeNavigation=Erlaubt es Robotern, ihre Position und Ausrichtung oc:tooltip.UpgradeSign=Erlaubt das Lesen und Schreiben von Text auf Schildern. oc:tooltip.UpgradeSolarGenerator=Kann verwendet werden, um unterwegs Energie aus Sonnenlicht zu generieren. Benötigt eine ungehinderte Sicht zum Himmel über dem Roboter. Generiert Energie mit %s%% der Geschwindigkeit eines Stirlingmotors. oc:tooltip.WirelessNetworkCard=Erlaubt das drahtlose Senden von Netzwerknachrichten, zusätzlich zu normalen. Drahtlose Nachrichten werden nur gesendet, wenn eine §fSignalstärke§7 festgelegt wurde! -oc:tooltip.WirelessRouter=Verhält sich wie ein Switch, aber empfängt zusätzlich Drahtlosnachrichten, und leitet Pakete aus dem Festnetz drahtlos weiter. +oc:tooltip.WirelessRouter=Verhält sich wie ein Switch, aber empfängt zusätzlich Drahtlosnachrichten und leitet Pakete aus dem Festnetz drahtlos weiter. diff --git a/src/main/resources/assets/opencomputers/lua/component/internet/bin/irc.lua b/src/main/resources/assets/opencomputers/lua/component/internet/bin/irc.lua index 5eddd65bb..8c7646908 100644 --- a/src/main/resources/assets/opencomputers/lua/component/internet/bin/irc.lua +++ b/src/main/resources/assets/opencomputers/lua/component/internet/bin/irc.lua @@ -76,6 +76,7 @@ local ignore = { -- command numbers to names. local commands = { +--Replys RPL_WELCOME = "001", RPL_YOURHOST = "002", RPL_CREATED = "003", @@ -102,7 +103,32 @@ local commands = { RPL_ENDOFNAMES = "366", RPL_MOTDSTART = "375", RPL_MOTD = "372", - RPL_ENDOFMOTD = "376" + RPL_ENDOFMOTD = "376", + RPL_WHOISSECURE = "671", + RPL_HELPSTART = "704", + RPL_HELPTXT = "705", + RPL_ENDOFHELP = "706", + RPL_UMODEGMSG = "718", + +--Errors + ERR_BANLISTFULL = "478", + ERR_CHANNELISFULL = "471", + ERR_UNKNOWNMODE = "472", + ERR_INVITEONLYCHAN = "473", + ERR_BANNEDFROMCHAN = "474", + ERR_CHANOPRIVSNEEDED = "482", + ERR_UNIQOPRIVSNEEDED = "485", + ERR_USERNOTINCHANNEL = "441", + ERR_NOTONCHANNEL = "442", + ERR_NICKCOLLISION = "436", + ERR_NICKNAMEINUSE = "433", + ERR_ERRONEUSNICKNAME = "432", + ERR_WASNOSUCHNICK = "406", + ERR_TOOMANYCHANNELS = "405", + ERR_CANNOTSENDTOCHAN = "404", + ERR_NOSUCHCHANNEL = "403", + ERR_NOSUCHNICK = "401", + ERR_MODELOCK = "742" } -- main command handling callback. @@ -116,7 +142,6 @@ local function handleCommand(prefix, command, args, message) --------------------------------------------------- -- General commands - elseif command == "NICK" then print(name(prefix) .. " is now known as " .. tostring(args[1] or message) .. ".") elseif command == "MODE" then @@ -132,6 +157,16 @@ local function handleCommand(prefix, command, args, message) elseif command == "KICK" then print("[" .. args[1] .. "] " .. name(prefix) .. " kicked " .. args[2]) elseif command == "PRIVMSG" then + if string.find(message, "\001TIME\001") then + sock:write("NOTICE " .. name(prefix) .. " :\001TIME " .. os.date() .. "\001\r\n") + sock:flush() + elseif string.find(message, "\001VERSION\001") then + sock:write("NOTICE " .. name(prefix) .. " :\001VERSION Minecraft/OpenComputers Lua 5.2\001\r\n") + sock:flush() + elseif string.find(message, "\001PING") then + sock:write("NOTICE " .. name(prefix) .. " :" .. message .. "\001\r\n") + sock:flush() + end print("[" .. args[1] .. "] " .. name(prefix) .. ": " .. message) elseif command == "NOTICE" then print("[NOTICE] " .. message) @@ -182,6 +217,9 @@ local function handleCommand(prefix, command, args, message) elseif command == commands.RPL_WHOISIDLE then local nick = args[2]:lower() whois[nick].idle = tonumber(args[3]) + elseif command == commands.RPL_WHOISSECURE then + local nick = args[2]:lower() + whois[nick].secureconn = "Is using a secure connection" elseif command == commands.RPL_ENDOFWHOIS then local nick = args[2]:lower() local info = whois[nick] @@ -190,6 +228,7 @@ local function handleCommand(prefix, command, args, message) if info.realName then print("Real name: " .. info.realName) end if info.host then print("Host: " .. info.host) end if info.server then print("Server: " .. info.server .. (info.serverInfo and (" (" .. info.serverInfo .. ")") or "")) end + if info.secureconn then print(info.secureconn) end if info.channels then print("Channels: " .. info.channels) end if info.idle then print("Idle for: " .. info.idle) end whois[nick] = nil @@ -218,6 +257,26 @@ local function handleCommand(prefix, command, args, message) print(message) end elseif command == commands.RPL_ENDOFMOTD then -- ignore + elseif command == commands.RPL_HELPSTART or + command == commands.RPL_HELPTXT or + command == commands.RPL_ENDOFHELP then + print(message) + elseif command == commands.ERR_BANLISTFULL or + command == commands.ERR_BANNEDFROMCHAN or + command == commands.ERR_CANNOTSENDTOCHAN or + command == commands.ERR_CHANNELISFULL or + command == commands.ERR_CHANOPRIVSNEEDED or + command == commands.ERR_ERRONEUSNICKNAME or + command == commands.ERR_INVITEONLYCHAN or + command == commands.ERR_NICKCOLLISION or + command == commands.ERR_NOSUCHNICK or + command == commands.ERR_NOTONCHANNEL or + command == commands.ERR_UNIQOPRIVSNEEDED or + command == commands.ERR_UNKNOWNMODE or + command == commands.ERR_USERNOTINCHANNEL or + command == commands.ERR_WASNOSUCHNICK or + command == commands.ERR_MODELOCK then + print("[ERROR]: " .. message) elseif tonumber(command) and (tonumber(command) >= 200 and tonumber(command) < 400) then print("[Response " .. command .. "] " .. table.concat(args, ", ") .. ": " .. message) @@ -232,7 +291,7 @@ local function handleCommand(prefix, command, args, message) -- Unhandled message. else - print("Unhandled command: " .. command) + print("Unhandled command: " .. command .. ": " .. message) end end @@ -373,4 +432,4 @@ end if not result then error(reason, 0) end -return reason \ No newline at end of file +return reason diff --git a/src/main/resources/assets/opencomputers/robot.names b/src/main/resources/assets/opencomputers/robot.names new file mode 100644 index 000000000..df50afa62 --- /dev/null +++ b/src/main/resources/assets/opencomputers/robot.names @@ -0,0 +1,30 @@ +# This a list of names that robots are randomly named after, unless +# explicitly named using an anvil. +# If your name is on this list and you'd rather it not be, or you'd like a +# different alias, sorry! Please make a pull request with the changed list. +asie +crafteverywhere +LordFokas +Michiyo +mymagadsl +PixelToast +Pyrolusite +SpiritedDusty +Vexatos +Wobbo +YuRaNnNzZZ + +# Names of more or less famous robots, as a bit of filler material. Feel free +# to add more via pull requests. Let's hope this won't get us sued... +Atlas +Bender +C-3PO +Clank +Claptrap +Dog +GLaDOS +KITT +Marvin +P-Body +R2-D2 +Wheatley \ No newline at end of file diff --git a/src/main/resources/assets/opencomputers/sounds.json b/src/main/resources/assets/opencomputers/sounds.json new file mode 100644 index 000000000..8f5e65249 --- /dev/null +++ b/src/main/resources/assets/opencomputers/sounds.json @@ -0,0 +1,33 @@ +{ + "floppy_access": { + "category": "master", + "sounds": [ + {"name": "floppy_access1", "stream": false}, + {"name": "floppy_access2", "stream": false}, + {"name": "floppy_access3", "stream": false}, + {"name": "floppy_access4", "stream": false}, + {"name": "floppy_access5", "stream": false}, + {"name": "floppy_access6", "stream": false} + ] + }, + "floppy_eject": { + "category": "master", + "sounds": [{"name": "floppy_eject", "stream": false}] + }, + "floppy_insert": { + "category": "master", + "sounds": [{"name": "floppy_insert", "stream": false}] + }, + "hdd_access": { + "category": "master", + "sounds": [ + {"name": "hdd_access1", "stream": false}, + {"name": "hdd_access2", "stream": false}, + {"name": "hdd_access3", "stream": false}, + {"name": "hdd_access4", "stream": false}, + {"name": "hdd_access5", "stream": false}, + {"name": "hdd_access6", "stream": false}, + {"name": "hdd_access7", "stream": false} + ] + } +} \ No newline at end of file diff --git a/src/main/resources/assets/opencomputers/sounds/floppy_access1.ogg b/src/main/resources/assets/opencomputers/sounds/floppy_access1.ogg new file mode 100644 index 000000000..ea85f5c15 Binary files /dev/null and b/src/main/resources/assets/opencomputers/sounds/floppy_access1.ogg differ diff --git a/src/main/resources/assets/opencomputers/sounds/floppy_access2.ogg b/src/main/resources/assets/opencomputers/sounds/floppy_access2.ogg new file mode 100644 index 000000000..868c79540 Binary files /dev/null and b/src/main/resources/assets/opencomputers/sounds/floppy_access2.ogg differ diff --git a/src/main/resources/assets/opencomputers/sounds/floppy_access3.ogg b/src/main/resources/assets/opencomputers/sounds/floppy_access3.ogg new file mode 100644 index 000000000..8e3ef45ff Binary files /dev/null and b/src/main/resources/assets/opencomputers/sounds/floppy_access3.ogg differ diff --git a/src/main/resources/assets/opencomputers/sounds/floppy_access4.ogg b/src/main/resources/assets/opencomputers/sounds/floppy_access4.ogg new file mode 100644 index 000000000..b3f6fcd16 Binary files /dev/null and b/src/main/resources/assets/opencomputers/sounds/floppy_access4.ogg differ diff --git a/src/main/resources/assets/opencomputers/sounds/floppy_access5.ogg b/src/main/resources/assets/opencomputers/sounds/floppy_access5.ogg new file mode 100644 index 000000000..44ec4d16e Binary files /dev/null and b/src/main/resources/assets/opencomputers/sounds/floppy_access5.ogg differ diff --git a/src/main/resources/assets/opencomputers/sounds/floppy_access6.ogg b/src/main/resources/assets/opencomputers/sounds/floppy_access6.ogg new file mode 100644 index 000000000..38821e3a7 Binary files /dev/null and b/src/main/resources/assets/opencomputers/sounds/floppy_access6.ogg differ diff --git a/src/main/resources/assets/opencomputers/sounds/floppy_eject.ogg b/src/main/resources/assets/opencomputers/sounds/floppy_eject.ogg new file mode 100644 index 000000000..321cf4bb6 Binary files /dev/null and b/src/main/resources/assets/opencomputers/sounds/floppy_eject.ogg differ diff --git a/src/main/resources/assets/opencomputers/sounds/floppy_insert.ogg b/src/main/resources/assets/opencomputers/sounds/floppy_insert.ogg new file mode 100644 index 000000000..a772b3b51 Binary files /dev/null and b/src/main/resources/assets/opencomputers/sounds/floppy_insert.ogg differ diff --git a/src/main/resources/assets/opencomputers/sounds/hdd_access1.ogg b/src/main/resources/assets/opencomputers/sounds/hdd_access1.ogg new file mode 100644 index 000000000..74be8959e Binary files /dev/null and b/src/main/resources/assets/opencomputers/sounds/hdd_access1.ogg differ diff --git a/src/main/resources/assets/opencomputers/sounds/hdd_access2.ogg b/src/main/resources/assets/opencomputers/sounds/hdd_access2.ogg new file mode 100644 index 000000000..60a52a422 Binary files /dev/null and b/src/main/resources/assets/opencomputers/sounds/hdd_access2.ogg differ diff --git a/src/main/resources/assets/opencomputers/sounds/hdd_access3.ogg b/src/main/resources/assets/opencomputers/sounds/hdd_access3.ogg new file mode 100644 index 000000000..679fe9fec Binary files /dev/null and b/src/main/resources/assets/opencomputers/sounds/hdd_access3.ogg differ diff --git a/src/main/resources/assets/opencomputers/sounds/hdd_access4.ogg b/src/main/resources/assets/opencomputers/sounds/hdd_access4.ogg new file mode 100644 index 000000000..15beb3caa Binary files /dev/null and b/src/main/resources/assets/opencomputers/sounds/hdd_access4.ogg differ diff --git a/src/main/resources/assets/opencomputers/sounds/hdd_access5.ogg b/src/main/resources/assets/opencomputers/sounds/hdd_access5.ogg new file mode 100644 index 000000000..d9c6d9d81 Binary files /dev/null and b/src/main/resources/assets/opencomputers/sounds/hdd_access5.ogg differ diff --git a/src/main/resources/assets/opencomputers/sounds/hdd_access6.ogg b/src/main/resources/assets/opencomputers/sounds/hdd_access6.ogg new file mode 100644 index 000000000..27ec39f62 Binary files /dev/null and b/src/main/resources/assets/opencomputers/sounds/hdd_access6.ogg differ diff --git a/src/main/resources/assets/opencomputers/sounds/hdd_access7.ogg b/src/main/resources/assets/opencomputers/sounds/hdd_access7.ogg new file mode 100644 index 000000000..55c1a396e Binary files /dev/null and b/src/main/resources/assets/opencomputers/sounds/hdd_access7.ogg differ diff --git a/src/main/resources/reference.conf b/src/main/resources/reference.conf index 2fb38606f..558268a71 100644 --- a/src/main/resources/reference.conf +++ b/src/main/resources/reference.conf @@ -39,6 +39,9 @@ opencomputers { # attached to it). For valid key names, please see the following list: # https://github.com/LWJGL/lwjgl/blob/master/src/java/org/lwjgl/input/Keyboard.java#L73 pasteShortcut: [LSHIFT, INSERT] + + # Render robots' names as a label above them when near them + robotLabels: true } # Computer related settings, concerns server performance and security. diff --git a/src/main/scala/li/cil/oc/Settings.scala b/src/main/scala/li/cil/oc/Settings.scala index f99b145dd..efae7169f 100644 --- a/src/main/scala/li/cil/oc/Settings.scala +++ b/src/main/scala/li/cil/oc/Settings.scala @@ -16,6 +16,7 @@ class Settings(config: Config) { val textLinearFiltering = config.getBoolean("client.textLinearFiltering") val textAntiAlias = config.getBoolean("client.textAntiAlias") val pasteShortcut = config.getStringList("client.pasteShortcut").toSet + val robotLabels = config.getBoolean("client.robotLabels") val rTreeDebugRenderer = false // *Not* to be configurable via config file. // ----------------------------------------------------------------------- // diff --git a/src/main/scala/li/cil/oc/client/Proxy.scala b/src/main/scala/li/cil/oc/client/Proxy.scala index 47df2d307..d6885b33f 100644 --- a/src/main/scala/li/cil/oc/client/Proxy.scala +++ b/src/main/scala/li/cil/oc/client/Proxy.scala @@ -9,8 +9,7 @@ import li.cil.oc.client.renderer.block.BlockRenderer import li.cil.oc.client.renderer.item.UpgradeRenderer import li.cil.oc.client.renderer.tileentity._ import li.cil.oc.client.renderer.WirelessNetworkDebugRenderer -import li.cil.oc.common.tileentity -import li.cil.oc.common.{Proxy => CommonProxy} +import li.cil.oc.common.{Proxy => CommonProxy, Sound, tileentity} import li.cil.oc.{Items, Settings, OpenComputers} import net.minecraftforge.client.MinecraftForgeClient import net.minecraftforge.common.MinecraftForge @@ -19,6 +18,7 @@ private[oc] class Proxy extends CommonProxy { override def preInit(e: FMLPreInitializationEvent) { super.preInit(e) + MinecraftForge.EVENT_BUS.register(Sound) MinecraftForge.EVENT_BUS.register(gui.Icons) } diff --git a/src/main/scala/li/cil/oc/client/renderer/tileentity/RobotRenderer.scala b/src/main/scala/li/cil/oc/client/renderer/tileentity/RobotRenderer.scala index dc5bb8718..518b7492a 100644 --- a/src/main/scala/li/cil/oc/client/renderer/tileentity/RobotRenderer.scala +++ b/src/main/scala/li/cil/oc/client/renderer/tileentity/RobotRenderer.scala @@ -1,11 +1,11 @@ package li.cil.oc.client.renderer.tileentity import java.util.logging.Level -import li.cil.oc.OpenComputers +import li.cil.oc.{Settings, OpenComputers} import li.cil.oc.client.Textures import li.cil.oc.common.tileentity import li.cil.oc.util.RenderState -import net.minecraft.client.renderer.entity.RenderManager +import net.minecraft.client.renderer.entity.{RendererLivingEntity, RenderManager} import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer import net.minecraft.client.renderer.{Tessellator, GLAllocation} import net.minecraft.tileentity.TileEntity @@ -175,6 +175,51 @@ object RobotRenderer extends TileEntitySpecialRenderer { GL11.glPushMatrix() GL11.glTranslated(x + 0.5, y + 0.5, z + 0.5) + val name = robot.name + if (Settings.get.robotLabels && name != null && x * x + y * y + z * z < RendererLivingEntity.NAME_TAG_RANGE) { + GL11.glPushMatrix() + + // This is pretty much copy-pasta from the entity's label renderer. + val t = Tessellator.instance + val f = func_147498_b + val scale = 1.6f / 60f + val width = f.getStringWidth(name) + + GL11.glTranslated(0, 0.7, 0) + GL11.glNormal3f(0, 1, 0) + + GL11.glRotatef(-field_147501_a.field_147562_h, 0, 1, 0) + GL11.glRotatef(field_147501_a.field_147563_i, 1, 0, 0) + GL11.glScalef(-scale, -scale, scale) + + GL11.glDisable(GL11.GL_LIGHTING) + GL11.glDepthMask(false) + GL11.glDisable(GL11.GL_DEPTH_TEST) + GL11.glEnable(GL11.GL_BLEND) + GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA) + + GL11.glDisable(GL11.GL_TEXTURE_2D) + t.startDrawingQuads() + val halfWidth = width / 2 + t.setColorRGBA_F(0, 0, 0, 0.25f) + t.addVertex(-halfWidth - 1, -1, 0) + t.addVertex(-halfWidth - 1, 8, 0) + t.addVertex(halfWidth + 1, 8, 0) + t.addVertex(halfWidth + 1, -1, 0) + t.draw + + GL11.glEnable(GL11.GL_TEXTURE_2D) + f.drawString(name, -halfWidth, 0, 0x20FFFFFF) + GL11.glEnable(GL11.GL_DEPTH_TEST) + GL11.glDepthMask(true) + f.drawString(name, -halfWidth, 0, -1) + GL11.glEnable(GL11.GL_LIGHTING) + GL11.glDisable(GL11.GL_BLEND) + GL11.glColor4f(1, 1, 1, 1) + + GL11.glPopMatrix() + } + // If the move started while we were rendering and we have a reference to // the *old* proxy the robot would be rendered at the wrong position, so we // correct for the offset. diff --git a/src/main/scala/li/cil/oc/common/PacketBuilder.scala b/src/main/scala/li/cil/oc/common/PacketBuilder.scala index 80110be45..9d4f69424 100644 --- a/src/main/scala/li/cil/oc/common/PacketBuilder.scala +++ b/src/main/scala/li/cil/oc/common/PacketBuilder.scala @@ -5,11 +5,11 @@ import cpw.mods.fml.common.network.internal.FMLProxyPacket import io.netty.buffer.Unpooled import java.io.{OutputStream, ByteArrayOutputStream, DataOutputStream} import java.util.zip.GZIPOutputStream -import li.cil.oc.common.tileentity.TileEntity import li.cil.oc.OpenComputers import net.minecraft.entity.player.EntityPlayerMP import net.minecraft.item.ItemStack import net.minecraft.nbt.{CompressedStreamTools, NBTTagCompound} +import net.minecraft.tileentity.TileEntity import net.minecraft.world.World import net.minecraftforge.common.util.ForgeDirection import scala.collection.convert.WrapAsScala._ @@ -17,10 +17,10 @@ import scala.collection.convert.WrapAsScala._ // Necessary to keep track of the GZIP stream. abstract class PacketBuilderBase[T <: OutputStream](protected val stream: T) extends DataOutputStream(stream) { def writeTileEntity(t: TileEntity) = { - writeInt(t.world.provider.dimensionId) - writeInt(t.x) - writeInt(t.y) - writeInt(t.z) + writeInt(t.getWorldObj.provider.dimensionId) + writeInt(t.xCoord) + writeInt(t.yCoord) + writeInt(t.zCoord) } def writeDirection(d: ForgeDirection) = writeInt(d.ordinal) @@ -37,7 +37,7 @@ abstract class PacketBuilderBase[T <: OutputStream](protected val stream: T) ext def sendToAllPlayers() = OpenComputers.channel.sendToAll(packet) - def sendToNearbyPlayers(t: TileEntity, range: Double = 1024): Unit = sendToNearbyPlayers(t.world, t.x + 0.5, t.y + 0.5, t.z + 0.5, range) + def sendToNearbyPlayers(t: TileEntity, range: Double = 1024): Unit = sendToNearbyPlayers(t.getWorldObj, t.xCoord + 0.5, t.yCoord + 0.5, t.zCoord + 0.5, range) def sendToNearbyPlayers(world: World, x: Double, y: Double, z: Double, range: Double) { val dimension = world.provider.dimensionId diff --git a/src/main/scala/li/cil/oc/common/Sound.scala b/src/main/scala/li/cil/oc/common/Sound.scala new file mode 100644 index 000000000..08da9ce40 --- /dev/null +++ b/src/main/scala/li/cil/oc/common/Sound.scala @@ -0,0 +1,39 @@ +package li.cil.oc.common + +import cpw.mods.fml.common.eventhandler.SubscribeEvent +import cpw.mods.fml.relauncher.{Side, SideOnly} +import li.cil.oc.Settings +import net.minecraft.tileentity.TileEntity +import net.minecraftforge.client.event.sound.SoundLoadEvent +import scala.collection.mutable + +object Sound { + val lastPlayed = mutable.WeakHashMap.empty[TileEntity, Long] + + def play(t: tileentity.TileEntity, name: String) { + t.world.playSoundEffect(t.x + 0.5, t.y + 0.5, t.z + 0.5, Settings.resourceDomain + ":" + name, 1, 1) + } + + def playDiskInsert(t: tileentity.DiskDrive) { + play(t, "floppy_insert") + } + + def playDiskEject(t: tileentity.DiskDrive) { + play(t, "floppy_eject") + } + + def playDiskActivity(t: TileEntity) = this.synchronized { + lastPlayed.get(t) match { + case Some(time) if time > System.currentTimeMillis() => // Cooldown. + case _ => + t match { + case computer: tileentity.Computer => play(computer, "hdd_access") + case rack: tileentity.Rack => play(rack, "hdd_access") + case drive: tileentity.DiskDrive => play(drive, "floppy_access") + case _ => // Huh? + } + lastPlayed += t -> (System.currentTimeMillis() + 500) + } + } + +} diff --git a/src/main/scala/li/cil/oc/common/block/Hologram.scala b/src/main/scala/li/cil/oc/common/block/Hologram.scala index fe5c5093e..c946213bf 100644 --- a/src/main/scala/li/cil/oc/common/block/Hologram.scala +++ b/src/main/scala/li/cil/oc/common/block/Hologram.scala @@ -10,6 +10,7 @@ import net.minecraft.item.{ItemStack, EnumRarity} import net.minecraft.world.{World, IBlockAccess} import net.minecraft.util.{IIcon, AxisAlignedBB} import net.minecraftforge.common.util.ForgeDirection +import cpw.mods.fml.relauncher.{SideOnly, Side} class Hologram(val parent: SpecialDelegator) extends SpecialDelegate { val unlocalizedName = "Hologram" @@ -28,6 +29,11 @@ class Hologram(val parent: SpecialDelegator) extends SpecialDelegate { override def isSolid(world: IBlockAccess, x: Int, y: Int, z: Int, side: ForgeDirection) = side == ForgeDirection.DOWN + @SideOnly(Side.CLIENT) + override def shouldSideBeRendered(world: IBlockAccess, x: Int, y: Int, z: Int, side: ForgeDirection) = { + super.shouldSideBeRendered(world, x, y, z, side) || side == ForgeDirection.UP + } + override def bounds(world: IBlockAccess, x: Int, y: Int, z: Int) = AxisAlignedBB.getAABBPool.getAABB(0, 0, 0, 1, 3 / 16f, 1) diff --git a/src/main/scala/li/cil/oc/common/tileentity/DiskDrive.scala b/src/main/scala/li/cil/oc/common/tileentity/DiskDrive.scala index 4edfab606..59dc73637 100644 --- a/src/main/scala/li/cil/oc/common/tileentity/DiskDrive.scala +++ b/src/main/scala/li/cil/oc/common/tileentity/DiskDrive.scala @@ -3,6 +3,7 @@ package li.cil.oc.common.tileentity import li.cil.oc.api.driver.Slot import li.cil.oc.api.network.{Analyzable, Component, Visibility} import li.cil.oc.common.EventHandler +import li.cil.oc.common.Sound import li.cil.oc.server.driver.Registry import li.cil.oc.{api, Settings} import net.minecraft.entity.player.EntityPlayer @@ -45,5 +46,11 @@ class DiskDrive extends Environment with ComponentInventory with Rotatable with } case _ => } + Sound.playDiskInsert(this) + } + + override protected def onItemRemoved(slot: Int, stack: ItemStack) { + super.onItemRemoved(slot, stack) + Sound.playDiskEject(this) } } diff --git a/src/main/scala/li/cil/oc/common/tileentity/Robot.scala b/src/main/scala/li/cil/oc/common/tileentity/Robot.scala index a49bf1ffd..c170f3e4d 100644 --- a/src/main/scala/li/cil/oc/common/tileentity/Robot.scala +++ b/src/main/scala/li/cil/oc/common/tileentity/Robot.scala @@ -9,7 +9,7 @@ import li.cil.oc.server.component.robot import li.cil.oc.server.driver.Registry import li.cil.oc.server.{PacketSender => ServerPacketSender, driver, component} import li.cil.oc.util.ExtendedNBT._ -import li.cil.oc.{Blocks, Settings, api, common} +import li.cil.oc._ import net.minecraft.block.Block import net.minecraft.client.Minecraft import net.minecraft.entity.player.EntityPlayer @@ -18,6 +18,9 @@ import net.minecraft.item.ItemStack import net.minecraft.nbt.NBTTagCompound import net.minecraft.util.ChatComponentTranslation import net.minecraftforge.common.util.ForgeDirection +import scala.io.Source +import scala.Some +import java.util.logging.Level // Implementation note: this tile entity is never directly added to the world. // It is always wrapped by a `RobotProxy` tile entity, which forwards any @@ -27,6 +30,7 @@ import net.minecraftforge.common.util.ForgeDirection // old proxy, which will be cleaned up by Minecraft like any other tile entity. class Robot(isRemote: Boolean) extends Computer(isRemote) with ISidedInventory with Buffer with PowerInformation with api.machine.Robot { def this() = this(false) + if (isServer) { computer.setCostPerTick(Settings.get.robotCost) } @@ -42,6 +46,16 @@ class Robot(isRemote: Boolean) extends Computer(isRemote) with ISidedInventory w override def player() = player(facing, facing) + def name: String = { + if (tag != null && tag.hasKey("display")) { + val display = tag.getCompoundTag("display") + if (display != null && display.hasKey("Name")) { + return display.getString("Name") + } + } + null + } + override def saveUpgrade() = this.synchronized { components(3) match { case Some(environment) => @@ -76,6 +90,8 @@ class Robot(isRemote: Boolean) extends Computer(isRemote) with ISidedInventory w var owner = "OpenComputers" + var tag: NBTTagCompound = _ + var xp = 0.0 def xpForNextLevel = xpForLevel(level + 1) @@ -198,24 +214,30 @@ class Robot(isRemote: Boolean) extends Computer(isRemote) with ISidedInventory w def createItemStack() = { val stack = Blocks.robotProxy.createItemStack() - if (globalBuffer > 1 || xp > 0) { - stack.setTagCompound(new NBTTagCompound()) - } + val tag = if (this.tag != null) this.tag.copy.asInstanceOf[NBTTagCompound] else new NBTTagCompound() + stack.setTagCompound(tag) if (xp > 0) { - stack.getTagCompound.setDouble(Settings.namespace + "xp", xp) + tag.setDouble(Settings.namespace + "xp", xp) } if (globalBuffer > 1) { - stack.getTagCompound.setInteger(Settings.namespace + "storedEnergy", globalBuffer.toInt) + tag.setInteger(Settings.namespace + "storedEnergy", globalBuffer.toInt) } stack } def parseItemStack(stack: ItemStack) { if (stack.hasTagCompound) { - xp = stack.getTagCompound.getDouble(Settings.namespace + "xp") + tag = stack.getTagCompound.copy.asInstanceOf[NBTTagCompound] + xp = tag.getDouble(Settings.namespace + "xp") updateXpInfo() bot.node.changeBuffer(stack.getTagCompound.getInteger(Settings.namespace + "storedEnergy")) } + else { + tag = new NBTTagCompound() + } + if (name == null) { + tag.setNewCompoundTag("display", tag => tag.setString("Name", Robot.randomName)) + } } // ----------------------------------------------------------------------- // @@ -332,6 +354,9 @@ class Robot(isRemote: Boolean) extends Computer(isRemote) with ISidedInventory w if (nbt.hasKey(Settings.namespace + "owner")) { owner = nbt.getString(Settings.namespace + "owner") } + if (nbt.hasKey(Settings.namespace + "tag")) { + tag = nbt.getCompoundTag(Settings.namespace + "tag") + } xp = nbt.getDouble(Settings.namespace + "xp") max 0 updateXpInfo() selectedSlot = nbt.getInteger(Settings.namespace + "selectedSlot") max actualSlot(0) min (getSizeInventory - 1) @@ -355,6 +380,9 @@ class Robot(isRemote: Boolean) extends Computer(isRemote) with ISidedInventory w nbt.setNewCompoundTag(Settings.namespace + "keyboard", keyboard.save) nbt.setNewCompoundTag(Settings.namespace + "robot", bot.save) nbt.setString(Settings.namespace + "owner", owner) + if (tag != null) { + nbt.setTag(Settings.namespace + "tag", tag) + } nbt.setDouble(Settings.namespace + "xp", xp) nbt.setInteger(Settings.namespace + "selectedSlot", selectedSlot) if (isAnimatingMove || isAnimatingSwing || isAnimatingTurn) { @@ -371,6 +399,9 @@ class Robot(isRemote: Boolean) extends Computer(isRemote) with ISidedInventory w @SideOnly(Side.CLIENT) override def readFromNBTForClient(nbt: NBTTagCompound) { super.readFromNBTForClient(nbt) + if (nbt.hasKey(Settings.namespace + "tag")) { + tag = nbt.getCompoundTag(Settings.namespace + "tag") + } selectedSlot = nbt.getInteger("selectedSlot") if (nbt.hasKey("equipped")) { equippedItem = Option(ItemStack.loadItemStackFromNBT(nbt.getCompoundTag("equipped"))) @@ -393,6 +424,9 @@ class Robot(isRemote: Boolean) extends Computer(isRemote) with ISidedInventory w override def writeToNBTForClient(nbt: NBTTagCompound) = this.synchronized { super.writeToNBTForClient(nbt) + if (tag != null) { + nbt.setTag(Settings.namespace + "tag", tag) + } nbt.setInteger("selectedSlot", selectedSlot) if (getStackInSlot(0) != null) { nbt.setNewCompoundTag("equipped", getStackInSlot(0).writeToNBT) @@ -566,3 +600,18 @@ class Robot(isRemote: Boolean) extends Computer(isRemote) with ISidedInventory w case _ => (actualSlot(0) until getSizeInventory).toArray } } + +object Robot { + val names = try { + Source.fromInputStream(getClass.getResourceAsStream( + "/assets/" + Settings.resourceDomain + "/robot.names"))("UTF-8"). + getLines().map(_.trim).filter(!_.startsWith("#")).filter(_ != "").toArray + } + catch { + case t: Throwable => + OpenComputers.log.log(Level.WARNING, "Failed loading robot name list.", t) + Array.empty + } + + def randomName = names((math.random * names.length).toInt) +} \ No newline at end of file diff --git a/src/main/scala/li/cil/oc/server/PacketSender.scala b/src/main/scala/li/cil/oc/server/PacketSender.scala index 55395ce48..9bcd1be9e 100644 --- a/src/main/scala/li/cil/oc/server/PacketSender.scala +++ b/src/main/scala/li/cil/oc/server/PacketSender.scala @@ -1,7 +1,7 @@ package li.cil.oc.server import li.cil.oc.common -import li.cil.oc.common.tileentity._ +import li.cil.oc.common.tileentity import li.cil.oc.common.{CompressedPacketBuilder, PacketBuilder, PacketType} import li.cil.oc.util.PackedColor import net.minecraft.entity.player.EntityPlayerMP @@ -9,7 +9,7 @@ import net.minecraft.item.ItemStack import net.minecraftforge.common.util.ForgeDirection object PacketSender { - def sendAbstractBusState(t: AbstractBusAware) { + def sendAbstractBusState(t: tileentity.AbstractBusAware) { val pb = new PacketBuilder(PacketType.AbstractBusState) pb.writeTileEntity(t) @@ -26,7 +26,7 @@ object PacketSender { pb.sendToPlayer(player) } - def sendChargerState(t: Charger) { + def sendChargerState(t: tileentity.Charger) { val pb = new PacketBuilder(PacketType.ChargerState) pb.writeTileEntity(t) @@ -35,7 +35,7 @@ object PacketSender { pb.sendToNearbyPlayers(t) } - def sendComputerState(t: Computer) { + def sendComputerState(t: tileentity.Computer) { val pb = new PacketBuilder(PacketType.ComputerState) pb.writeTileEntity(t) @@ -44,7 +44,7 @@ object PacketSender { pb.sendToNearbyPlayers(t) } - def sendComputerUserList(t: Computer, list: Array[String]) { + def sendComputerUserList(t: tileentity.Computer, list: Array[String]) { val pb = new PacketBuilder(PacketType.ComputerUserList) pb.writeTileEntity(t) @@ -54,7 +54,7 @@ object PacketSender { pb.sendToNearbyPlayers(t) } - def sendHologramClear(t: Hologram) { + def sendHologramClear(t: tileentity.Hologram) { val pb = new PacketBuilder(PacketType.HologramClear) pb.writeTileEntity(t) @@ -62,7 +62,7 @@ object PacketSender { pb.sendToNearbyPlayers(t) } - def sendHologramPowerChange(t: Hologram) { + def sendHologramPowerChange(t: tileentity.Hologram) { val pb = new PacketBuilder(PacketType.HologramPowerChange) pb.writeTileEntity(t) @@ -71,7 +71,7 @@ object PacketSender { pb.sendToNearbyPlayers(t) } - def sendHologramScale(t: Hologram) { + def sendHologramScale(t: tileentity.Hologram) { val pb = new PacketBuilder(PacketType.HologramScale) pb.writeTileEntity(t) @@ -80,7 +80,7 @@ object PacketSender { pb.sendToNearbyPlayers(t) } - def sendHologramSet(t: Hologram) { + def sendHologramSet(t: tileentity.Hologram) { val pb = new CompressedPacketBuilder(PacketType.HologramSet) pb.writeTileEntity(t) @@ -97,7 +97,7 @@ object PacketSender { pb.sendToNearbyPlayers(t) } - def sendPowerState(t: PowerInformation) { + def sendPowerState(t: tileentity.PowerInformation) { val pb = new PacketBuilder(PacketType.PowerState) pb.writeTileEntity(t) @@ -107,7 +107,7 @@ object PacketSender { pb.sendToNearbyPlayers(t) } - def sendRedstoneState(t: RedstoneAware) { + def sendRedstoneState(t: tileentity.RedstoneAware) { val pb = new PacketBuilder(PacketType.RedstoneState) pb.writeTileEntity(t) @@ -119,7 +119,7 @@ object PacketSender { pb.sendToNearbyPlayers(t) } - def sendRobotMove(t: Robot, ox: Int, oy: Int, oz: Int, direction: ForgeDirection) { + def sendRobotMove(t: tileentity.Robot, ox: Int, oy: Int, oz: Int, direction: ForgeDirection) { val pb = new PacketBuilder(PacketType.RobotMove) // Custom pb.writeTileEntity() with fake coordinates (valid for the client). @@ -132,7 +132,7 @@ object PacketSender { pb.sendToNearbyPlayers(t) } - def sendRobotAnimateSwing(t: Robot) { + def sendRobotAnimateSwing(t: tileentity.Robot) { val pb = new PacketBuilder(PacketType.RobotAnimateSwing) pb.writeTileEntity(t.proxy) @@ -141,7 +141,7 @@ object PacketSender { pb.sendToNearbyPlayers(t, 64) } - def sendRobotAnimateTurn(t: Robot) { + def sendRobotAnimateTurn(t: tileentity.Robot) { val pb = new PacketBuilder(PacketType.RobotAnimateTurn) pb.writeTileEntity(t.proxy) @@ -151,7 +151,7 @@ object PacketSender { pb.sendToNearbyPlayers(t, 64) } - def sendRobotEquippedItemChange(t: Robot, stack: ItemStack) { + def sendRobotEquippedItemChange(t: tileentity.Robot, stack: ItemStack) { val pb = new PacketBuilder(PacketType.RobotEquippedItemChange) pb.writeTileEntity(t.proxy) @@ -160,7 +160,7 @@ object PacketSender { pb.sendToNearbyPlayers(t) } - def sendRobotEquippedUpgradeChange(t: Robot, stack: ItemStack) { + def sendRobotEquippedUpgradeChange(t: tileentity.Robot, stack: ItemStack) { val pb = new PacketBuilder(PacketType.RobotEquippedUpgradeChange) pb.writeTileEntity(t.proxy) @@ -169,7 +169,7 @@ object PacketSender { pb.sendToNearbyPlayers(t) } - def sendRobotSelectedSlotChange(t: Robot) { + def sendRobotSelectedSlotChange(t: tileentity.Robot) { val pb = new PacketBuilder(PacketType.RobotSelectedSlotChange) pb.writeTileEntity(t.proxy) @@ -178,7 +178,7 @@ object PacketSender { pb.sendToNearbyPlayers(t, 16) } - def sendRobotXp(t: Robot) { + def sendRobotXp(t: tileentity.Robot) { val pb = new PacketBuilder(PacketType.RobotXp) pb.writeTileEntity(t) @@ -187,7 +187,7 @@ object PacketSender { pb.sendToNearbyPlayers(t) } - def sendRotatableState(t: Rotatable) { + def sendRotatableState(t: tileentity.Rotatable) { val pb = new PacketBuilder(PacketType.RotatableState) pb.writeTileEntity(t) @@ -201,7 +201,7 @@ object PacketSender { val pb = new PacketBuilder(PacketType.ScreenColorChange) val t = b.owner match { - case t: Buffer => + case t: tileentity.Buffer => pb.writeTileEntity(t) t case t: common.component.Terminal => @@ -220,7 +220,7 @@ object PacketSender { val pb = new PacketBuilder(PacketType.ScreenCopy) val t = b.owner match { - case t: Buffer => + case t: tileentity.Buffer => pb.writeTileEntity(t) t case t: common.component.Terminal => @@ -243,7 +243,7 @@ object PacketSender { val pb = new PacketBuilder(PacketType.ScreenDepthChange) val t = b.owner match { - case t: Buffer => + case t: tileentity.Buffer => pb.writeTileEntity(t) t case t: common.component.Terminal => @@ -261,7 +261,7 @@ object PacketSender { val pb = new PacketBuilder(PacketType.ScreenFill) val t = b.owner match { - case t: Buffer => + case t: tileentity.Buffer => pb.writeTileEntity(t) t case t: common.component.Terminal => @@ -279,7 +279,7 @@ object PacketSender { pb.sendToNearbyPlayers(t) } - def sendScreenPowerChange(t: Buffer, hasPower: Boolean) { + def sendScreenPowerChange(t: tileentity.Buffer, hasPower: Boolean) { val pb = new PacketBuilder(PacketType.ScreenPowerChange) pb.writeTileEntity(t) @@ -292,7 +292,7 @@ object PacketSender { val pb = new PacketBuilder(PacketType.ScreenResolutionChange) val t = b.owner match { - case t: Buffer => + case t: tileentity.Buffer => pb.writeTileEntity(t) t case t: common.component.Terminal => @@ -311,7 +311,7 @@ object PacketSender { val pb = new PacketBuilder(PacketType.ScreenSet) val t = b.owner match { - case t: Buffer => + case t: tileentity.Buffer => pb.writeTileEntity(t) t case t: common.component.Terminal => @@ -327,7 +327,7 @@ object PacketSender { pb.sendToNearbyPlayers(t) } - def sendServerPresence(t: Rack) { + def sendServerPresence(t: tileentity.Rack) { val pb = new PacketBuilder(PacketType.ServerPresence) pb.writeTileEntity(t) @@ -342,7 +342,7 @@ object PacketSender { pb.sendToNearbyPlayers(t) } - def sendServerState(t: Rack) { + def sendServerState(t: tileentity.Rack) { val pb = new PacketBuilder(PacketType.ComputerState) pb.writeTileEntity(t) @@ -352,7 +352,7 @@ object PacketSender { pb.sendToNearbyPlayers(t) } - def sendServerState(t: Rack, number: Int, player: Option[EntityPlayerMP] = None) { + def sendServerState(t: tileentity.Rack, number: Int, player: Option[EntityPlayerMP] = None) { val pb = new PacketBuilder(PacketType.ComputerState) pb.writeTileEntity(t) diff --git a/src/main/scala/li/cil/oc/server/component/FileSystem.scala b/src/main/scala/li/cil/oc/server/component/FileSystem.scala index 1e917c526..a5c09143c 100644 --- a/src/main/scala/li/cil/oc/server/component/FileSystem.scala +++ b/src/main/scala/li/cil/oc/server/component/FileSystem.scala @@ -1,16 +1,18 @@ package li.cil.oc.server.component import java.io.{FileNotFoundException, IOException} -import li.cil.oc.Settings -import li.cil.oc.api.Network import li.cil.oc.api.fs.{Label, Mode, FileSystem => IFileSystem} +import li.cil.oc.api.Network import li.cil.oc.api.network._ +import li.cil.oc.common.Sound +import li.cil.oc.Settings import li.cil.oc.util.ExtendedNBT._ import net.minecraft.nbt.{NBTTagIntArray, NBTTagList, NBTTagCompound} import net.minecraftforge.common.util.Constants.NBT +import net.minecraft.tileentity.TileEntity import scala.collection.mutable -class FileSystem(val fileSystem: IFileSystem, var label: Label) extends ManagedComponent { +class FileSystem(val fileSystem: IFileSystem, var label: Label, val container: Option[TileEntity] = None) extends ManagedComponent { val node = Network.newNode(this, Visibility.Network). withComponent("filesystem", Visibility.Neighbors). withConnector(). @@ -75,7 +77,9 @@ class FileSystem(val fileSystem: IFileSystem, var label: Label) extends ManagedC @Callback def list(context: Context, args: Arguments): Array[AnyRef] = fileSystem.synchronized { Option(fileSystem.list(clean(args.checkString(0)))) match { - case Some(list) => Array(list) + case Some(list) => + container.foreach(Sound.playDiskActivity) + Array(list) case _ => null } } @@ -84,19 +88,25 @@ class FileSystem(val fileSystem: IFileSystem, var label: Label) extends ManagedC def makeDirectory(context: Context, args: Arguments): Array[AnyRef] = fileSystem.synchronized { def recurse(path: String): Boolean = !fileSystem.exists(path) && (fileSystem.makeDirectory(path) || (recurse(path.split("/").dropRight(1).mkString("/")) && fileSystem.makeDirectory(path))) - result(recurse(clean(args.checkString(0)))) + val success = recurse(clean(args.checkString(0))) + if (success) container.foreach(Sound.playDiskActivity) + result(success) } @Callback def remove(context: Context, args: Arguments): Array[AnyRef] = fileSystem.synchronized { def recurse(parent: String): Boolean = (!fileSystem.isDirectory(parent) || fileSystem.list(parent).forall(child => recurse(parent + "/" + child))) && fileSystem.delete(parent) - result(recurse(clean(args.checkString(0)))) + val success = recurse(clean(args.checkString(0))) + if (success) container.foreach(Sound.playDiskActivity) + result(success) } @Callback def rename(context: Context, args: Arguments): Array[AnyRef] = fileSystem.synchronized { - result(fileSystem.rename(clean(args.checkString(0)), clean(args.checkString(1)))) + val success = fileSystem.rename(clean(args.checkString(0)), clean(args.checkString(1))) + if (success) container.foreach(Sound.playDiskActivity) + result(success) } @Callback(direct = true) @@ -149,6 +159,7 @@ class FileSystem(val fileSystem: IFileSystem, var label: Label) extends ManagedC if (!node.tryChangeBuffer(-Settings.get.hddReadCost * bytes.length)) { throw new IOException("not enough energy") } + container.foreach(Sound.playDiskActivity) result(bytes) } else { @@ -186,7 +197,10 @@ class FileSystem(val fileSystem: IFileSystem, var label: Label) extends ManagedC } checkOwner(context.node.address, handle) Option(fileSystem.getHandle(handle)) match { - case Some(file) => file.write(value); result(true) + case Some(file) => + file.write(value) + container.foreach(Sound.playDiskActivity) + result(true) case _ => throw new IOException("bad file descriptor") } } diff --git a/src/main/scala/li/cil/oc/server/driver/item/FileSystem.scala b/src/main/scala/li/cil/oc/server/driver/item/FileSystem.scala index 474ab300e..eaabe2aec 100644 --- a/src/main/scala/li/cil/oc/server/driver/item/FileSystem.scala +++ b/src/main/scala/li/cil/oc/server/driver/item/FileSystem.scala @@ -9,24 +9,24 @@ import li.cil.oc.util.mods.ComputerCraft import li.cil.oc.{Settings, Items} import net.minecraft.item.ItemStack import net.minecraft.nbt.NBTTagCompound -import net.minecraft.tileentity.{TileEntity => MCTileEntity} +import net.minecraft.tileentity.TileEntity object FileSystem extends Item { override def worksWith(stack: ItemStack) = isOneOf(stack, Items.hdd1, Items.hdd2, Items.hdd3, Items.floppyDisk) || ComputerCraft.isDisk(stack) - override def createEnvironment(stack: ItemStack, container: MCTileEntity) = + override def createEnvironment(stack: ItemStack, container: TileEntity) = if (ComputerCraft.isDisk(stack) && container != null) { val address = addressFromTag(dataTag(stack)) val mount = ComputerCraft.createDiskMount(stack, container.getWorldObj) - Option(oc.api.FileSystem.asManagedEnvironment(mount, new ComputerCraftLabel(stack))) match { + Option(oc.api.FileSystem.asManagedEnvironment(mount, new ComputerCraftLabel(stack), container)) match { case Some(environment) => environment.node.asInstanceOf[oc.server.network.Node].address = address environment case _ => null } } else Items.multi.subItem(stack) match { - case Some(hdd: HardDiskDrive) => createEnvironment(stack, hdd.kiloBytes * 1024) - case Some(disk: FloppyDisk) => createEnvironment(stack, Settings.get.floppySize * 1024) + case Some(hdd: HardDiskDrive) => createEnvironment(stack, hdd.kiloBytes * 1024, container) + case Some(disk: FloppyDisk) => createEnvironment(stack, Settings.get.floppySize * 1024, container) case _ => null } @@ -44,18 +44,17 @@ object FileSystem extends Item { case _ => 0 } - private def createEnvironment(stack: ItemStack, capacity: Int) = { + private def createEnvironment(stack: ItemStack, capacity: Int, container: TileEntity) = { // We have a bit of a chicken-egg problem here, because we want to use the // node's address as the folder name... so we generate the address here, // if necessary. No one will know, right? Right!? val address = addressFromTag(dataTag(stack)) - Option(oc.api.FileSystem.asManagedEnvironment(oc.api.FileSystem. - fromSaveDirectory(address, capacity, Settings.get.bufferChanges), new ItemLabel(stack))) match { - case Some(environment) => - environment.node.asInstanceOf[oc.server.network.Node].address = address - environment - case _ => null + val fs = oc.api.FileSystem.fromSaveDirectory(address, capacity, Settings.get.bufferChanges) + val environment = oc.api.FileSystem.asManagedEnvironment(fs, new ItemLabel(stack), container) + if (environment != null) { + environment.node.asInstanceOf[oc.server.network.Node].address = address } + environment } private def addressFromTag(tag: NBTTagCompound) = diff --git a/src/main/scala/li/cil/oc/server/fs/FileSystem.scala b/src/main/scala/li/cil/oc/server/fs/FileSystem.scala index 8442a8d3a..141afa8aa 100644 --- a/src/main/scala/li/cil/oc/server/fs/FileSystem.scala +++ b/src/main/scala/li/cil/oc/server/fs/FileSystem.scala @@ -72,6 +72,9 @@ object FileSystem extends api.detail.FileSystemAPI { @Optional.Method(modid = "ComputerCraft") def fromComputerCraft(mount: IWritableMount) = new ComputerCraftWritableFileSystem(mount) + def asManagedEnvironment(fileSystem: api.fs.FileSystem, label: Label, container: net.minecraft.tileentity.TileEntity) = + Option(fileSystem).flatMap(fs => Some(new component.FileSystem(fs, label, Option(container)))).orNull + def asManagedEnvironment(fileSystem: api.fs.FileSystem, label: Label) = Option(fileSystem).flatMap(fs => Some(new component.FileSystem(fs, label))).orNull