diff --git a/assets/blocks.psd b/assets/blocks.psd index e1c7f8ea9..950f8f813 100644 Binary files a/assets/blocks.psd and b/assets/blocks.psd differ diff --git a/build.gradle b/build.gradle index 3731bd8d1..bac7ab7e3 100644 --- a/build.gradle +++ b/build.gradle @@ -78,6 +78,10 @@ repositories { name = "mobius" url = "http://mobiusstrip.eu/maven" } + maven { + name = "fallback" + url = "http://maven.cil.li/" + } /* maven { name = "BluePower" @@ -115,7 +119,14 @@ repositories { name 'DVS1 Maven FS' url 'http://dvs1.progwml6.com/files/maven' } - + maven { + name 'ProjectRed' + url 'http://files.projectredwiki.com/maven/' + } + maven { + name 'ColoredLightCore' + url "http://coloredlightscore.us.to/maven/clc/" + } ivy { name "BuildCraft" artifactPattern "http://www.mod-buildcraft.com/releases/BuildCraft/[revision]/[module]-[revision]-[classifier].[ext]" @@ -128,19 +139,18 @@ repositories { name 'Mekanism' artifactPattern "http://ci.cil.li/job/Mekanism/${config.mekanism.build}/artifact/output/[module]-${config.minecraft.version}-[revision].${config.mekanism.build}.[ext]" } - ivy { - name 'ProjectRed' - artifactPattern "http://projectredwiki.com/maven/mrtjp/[module]/${config.minecraft.version}-[revision]/[module]-${config.minecraft.version}-[revision]-dev.[ext]" - } ivy { name 'immibis' artifactPattern "https://dl.dropboxusercontent.com/u/2944265/mods/autobuilt/files/[module]-[revision].[ext]" } - ivy { name 'CoFHLib' artifactPattern "http://addons-origin.cursecdn.com/files/${config.cofhlib.cf}/[module]-[revision].[ext]" } + ivy { + name 'CoFHCore' + artifactPattern "http://addons-origin.cursecdn.com/files/${config.cofhcore.cf}/[module]-[revision].[ext]" + } ivy { name 'MineFactoryReloaded' artifactPattern "http://addons-origin.cursecdn.com/files/${config.mfr.cf}/[module]-[revision].[ext]" @@ -181,7 +191,9 @@ dependencies { provided "mcp.mobius.waila:Waila:${config.waila.version}:dev" /* provided "appeng:RotaryCraft:${config.rotc.version}:api" - provided "appeng:appliedenergistics2:${config.ae2.version}:dev" + provided ("appeng:appliedenergistics2:${config.ae2.version}:dev") { + exclude module: 'buildcraft' + } provided "codechicken:EnderStorage:${config.minecraft.version}-${config.es.version}:dev" provided "codechicken:ForgeMultipart:${config.minecraft.version}-${config.fmp.version}:dev" provided "codechicken:WR-CBE:${config.minecraft.version}-${config.wrcbe.version}:dev" @@ -195,22 +207,27 @@ dependencies { provided "notenoughkeys:NeK:${config.minecraft.version}-${config.nek.version}:deobf-dev" provided "qmunity:QmunityLib:${config.qmunitylib.version}:deobf" provided "tmech:TMechworks:${config.minecraft.version}-${config.tmech.version}:deobf" + provided ("mrtjp:ProjectRed:${config.projred.version}:dev") { + exclude module: 'CoFHCore' + } + provided "coloredlightscore:ColoredLightsCore:${config.coloredlights.version}:api" - provided name: "buildcraft", version: "${config.bc.version}", classifier: "dev", ext: 'jar' + provided name: 'buildcraft', version: config.bc.version, classifier: "dev", ext: 'jar' provided name: 'GalacticraftCoreAll', version: config.gc.version, ext: 'jar' provided name: 'MekanismAll', version: config.mekanism.version, ext: 'jar' - provided name: 'ProjectRed', version: config.projred.version, ext: 'jar' provided name: 'redlogic', version: config.redlogic.version, ext: 'jar' - provided name: 'CoFHLib', version: URLEncoder.encode(config.cofhlib.version, "UTF-8"), ext: 'jar' - provided name: 'MineFactoryReloaded', version: URLEncoder.encode(config.mfr.version, "UTF-8"), ext: 'jar' + provided name: 'CoFHLib', version: config.cofhlib.version, ext: 'jar' + provided name: 'CoFHCore', version: config.cofhcore.version, ext: 'jar' + provided name: 'MineFactoryReloaded', version: config.mfr.version, ext: 'jar' 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' provided name: 'ExtraCells', version: config.ec.version, ext: 'jar' - */ + provided "cyano.poweradvantage:PowerAdvantage-API:${config.poweradvantage.version}" + compile 'com.google.code.findbugs:jsr305:1.3.9' // Annotations used by google libs. embedded files('libs/OpenComputers-JNLua.jar', 'libs/OpenComputers-LuaJ.jar') diff --git a/build.properties b/build.properties index 298bd58da..ff4431e13 100644 --- a/build.properties +++ b/build.properties @@ -1,7 +1,7 @@ minecraft.version=1.8 forge.version=11.14.3.1450 -oc.version=1.5.13 +oc.version=1.5.14 oc.subversion= ae2.version=rv2-beta-26 @@ -15,6 +15,7 @@ ccc.version=1.0.5.34 ccl.version=1.1.2.115 cofhlib.cf=2230/207 cofhlib.version=[1.7.10]1.0.0RC7-127 +coloredlights.version=1.3.7.35 ec.cf=2242/839 ec.version=deobf-1.7.10-2.2.73b129 eio.cf=2219/296 @@ -33,7 +34,8 @@ mfr.cf=2229/626 mfr.version=[1.7.10]2.8.0RC8-86 nei.version=1.0.5.82 nek.version=1.0.0b35dev -projred.version=4.7.0pre2.87 +poweradvantage.version=1.2.0 +projred.version=1.7.10-4.6.2.82 qmunitylib.version=0.1.105 rc.cf=2219/321 rc.version=1.7.10-9.4.0.0 @@ -43,5 +45,7 @@ tmech.version=75.0afb56c re.version=3.0.0.342 waila.version=1.6.0_B1_1.8.1 wrcbe.version=1.4.1.2 +cofhcore.cf=2246/697 +cofhcore.version=[1.7.10]3.0.3B4-302-dev maven.url=file:///home/www/maven.cil.li/web \ No newline at end of file diff --git a/src/main/java/li/cil/oc/api/API.java b/src/main/java/li/cil/oc/api/API.java index 0623789c7..051bcb5d8 100644 --- a/src/main/java/li/cil/oc/api/API.java +++ b/src/main/java/li/cil/oc/api/API.java @@ -12,7 +12,7 @@ import li.cil.oc.api.detail.*; */ public class API { public static final String ID_OWNER = "OpenComputers|Core"; - public static final String VERSION = "5.5.2"; + public static final String VERSION = "5.5.3"; public static DriverAPI driver = null; public static FileSystemAPI fileSystem = null; diff --git a/src/main/java/li/cil/oc/api/FileSystem.java b/src/main/java/li/cil/oc/api/FileSystem.java index d4663d5d2..2d457c921 100644 --- a/src/main/java/li/cil/oc/api/FileSystem.java +++ b/src/main/java/li/cil/oc/api/FileSystem.java @@ -107,6 +107,19 @@ public final class FileSystem { return null; } + /** + * Wrap a file system retrieved via one of the from??? methods to + * make it read-only. + * + * @param fileSystem the file system to wrap. + * @return the specified file system wrapped to be read-only. + */ + public static li.cil.oc.api.fs.FileSystem asReadOnly(final li.cil.oc.api.fs.FileSystem fileSystem) { + if (API.fileSystem != null) + return API.fileSystem.asReadOnly(fileSystem); + return null; + } + /** * Creates a network node that makes the specified file system available via * the common file system driver. 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 312884f22..b413adc86 100644 --- a/src/main/java/li/cil/oc/api/detail/FileSystemAPI.java +++ b/src/main/java/li/cil/oc/api/detail/FileSystemAPI.java @@ -67,6 +67,15 @@ public interface FileSystemAPI { */ FileSystem fromMemory(long capacity); + /** + * Wrap a file system retrieved via one of the from??? methods to + * make it read-only. + * + * @param fileSystem the file system to wrap. + * @return the specified file system wrapped to be read-only. + */ + FileSystem asReadOnly(final FileSystem fileSystem); + /** * Creates a network node that makes the specified file system available via * the common file system driver. diff --git a/src/main/resources/application.conf b/src/main/resources/application.conf index 97aa94738..02775cf50 100644 --- a/src/main/resources/application.conf +++ b/src/main/resources/application.conf @@ -780,6 +780,7 @@ opencomputers { Galacticraft: 48.0 IndustrialCraft2: 400.0 Mekanism: 1333.33 + PowerAdvantage: 31.25 RedstoneFlux: 100.0 } } diff --git a/src/main/resources/assets/opencomputers/doc/en_US/block/index.md b/src/main/resources/assets/opencomputers/doc/en_US/block/index.md index 1275d7a48..a33f40557 100644 --- a/src/main/resources/assets/opencomputers/doc/en_US/block/index.md +++ b/src/main/resources/assets/opencomputers/doc/en_US/block/index.md @@ -23,7 +23,6 @@ Keep in mind that some of these may not be available, depending on the recipe se ### Extensions * [Adapter](adapter.md) -* [Cable](cable.md) * [Geolyzer](geolyzer.md) * [Motion Sensor](motionSensor.md) * [Redstone I/O](redstone.md) @@ -38,6 +37,8 @@ Keep in mind that some of these may not be available, depending on the recipe se ## Networking * [Access Point](accessPoint.md) +* [Cable](cable.md) +* [Net Splitter](netSplitter.md) * [Switch](switch.md) ## Power management diff --git a/src/main/resources/assets/opencomputers/doc/en_US/block/netSplitter.md b/src/main/resources/assets/opencomputers/doc/en_US/block/netSplitter.md new file mode 100644 index 000000000..230e4484f --- /dev/null +++ b/src/main/resources/assets/opencomputers/doc/en_US/block/netSplitter.md @@ -0,0 +1,7 @@ +# Net Splitter + +![*.net *.split](oredict:oc:netSplitter) + +The net splitter is a device that allows controlling connectivity between subnetworks. Unlike the [switch](switch.md) or [power converter](powerConverter.md) it directly connects adjacent subnetworks, i.e. components can be accessed. Each side's connectivity can be toggled using a wrench (e.g. the [scrench](../item/wrench.md)). When a redstone signal is applied to the net splitter, all sides' connectivity is inverted. + +This block can therefore be used to toggle connectivity to certain parts of a component network. Use a [redstone I/O block](redstone.md) or [redstone cards](../item/redstoneCard1.md) to automate the net splitter. diff --git a/src/main/resources/assets/opencomputers/doc/en_US/general/quickstart.md b/src/main/resources/assets/opencomputers/doc/en_US/general/quickstart.md index b880cbdc6..fe5d77675 100644 --- a/src/main/resources/assets/opencomputers/doc/en_US/general/quickstart.md +++ b/src/main/resources/assets/opencomputers/doc/en_US/general/quickstart.md @@ -4,13 +4,13 @@ Also know as "how to build your first computer". To get your first [computer](co **Disclaimer**: this will be step-by-step, and also provide some information on how to look for issues yourself later on, so this is quite long. If you have never built a computer in real life, and/or are completely new to the mod, it is highly recommended you read through it all. -First off, you will need a [computer case](../block/case1.md). This is the block which will contain of the components, defining the behavior of the computer you are building. +First off, you will need a [computer case](../block/case1.md). This is the block which will contain all of the components, defining the behavior of the computer you are building. ![A tier two computer case.](oredict:oc:case2) For example, you will need to choose what tier of [graphics card](../item/graphicsCard1.md) you wish to use, if you need a [network card](../item/lanCard.md), a [redstone card](../item/redstoneCard1.md) or, if you're just playing around in creative mode, maybe even a [debug card](../item/debugCard.md). -When you open the [computer case](../block/case1.md)'s GUI you will see a few slots to the right. The number of slots, and what tier of component can be placed into them (indicated by the small roman numeral in the slot) depends on the tier of the case itself. +When you open the [computer case](../block/case1.md)'s GUI, you will see a few slots to the right. The number of slots, and what tier of component can be placed into them (indicated by the small roman numeral in the slot) depends on the tier of the case itself. ![GUI of a tier two computer case.](opencomputers:doc/img/configuration_case1.png) In their empty state, [computer cases](../block/case1.md) are pretty useless. You can try to power up your [computer](computer.md) now, but it'll immediately print an error message to your chat log, and make its dissatisfaction heard by beeping at you. Good thing the error message is telling you what you can do to fix this situation: it requires energy. Connect your [computer](computer.md) to some power, either directly or via a [power converter](../block/powerConverter.md). diff --git a/src/main/resources/assets/opencomputers/doc/ru_RU/block/index.md b/src/main/resources/assets/opencomputers/doc/ru_RU/block/index.md index 0a412c466..5a8833c46 100644 --- a/src/main/resources/assets/opencomputers/doc/ru_RU/block/index.md +++ b/src/main/resources/assets/opencomputers/doc/ru_RU/block/index.md @@ -23,7 +23,6 @@ ### Расширения * [Адаптер](adapter.md) -* [Кабель](cable.md) * [Геоанализатор](geolyzer.md) * [Датчик движения](motionSensor.md) * [Редстоун I/O](redstone.md) @@ -38,6 +37,8 @@ ## Сеть * [Точка доступа](accessPoint.md) +* [Кабель](cable.md) +* [Сетевой переключатель](netSplitter.md) * [Коммутатор](switch.md) ## Управление питанием diff --git a/src/main/resources/assets/opencomputers/doc/ru_RU/block/netSplitter.md b/src/main/resources/assets/opencomputers/doc/ru_RU/block/netSplitter.md new file mode 100644 index 000000000..78a3ed03a --- /dev/null +++ b/src/main/resources/assets/opencomputers/doc/ru_RU/block/netSplitter.md @@ -0,0 +1,7 @@ +# Сетевой переключатель + +![*.net *.split](oredict:oc:netSplitter) + +Сетевой переключатель позволяет контролировать соединение между подсетями. В отличие от [коммутатора](switch.md) или [конвертера энергии](powerConverter.md) позволяет непосредственно соединить подсети, делая при этом доступными все компоненты. Соединение каждой стороны переключается [ключем](../item/wrench.md). При подаче сигнала красного камня все соединения инвертируются. + +Таким образом, этот блок может быть использован для переключения соединения определенных компонентов сети. Используйте [редстоун I/O](redstone.md) или [редстоун карты](../item/redstoneCard1.md) для автоматизации сетевого переключателя. \ No newline at end of file diff --git a/src/main/resources/assets/opencomputers/lang/en_US.lang b/src/main/resources/assets/opencomputers/lang/en_US.lang index a017ac1e4..dedec1602 100644 --- a/src/main/resources/assets/opencomputers/lang/en_US.lang +++ b/src/main/resources/assets/opencomputers/lang/en_US.lang @@ -36,6 +36,7 @@ tile.oc.screen2.name=Screen (Tier 2) tile.oc.screen3.name=Screen (Tier 3) tile.oc.serverRack.name=Server Rack tile.oc.switch.name=Switch +tile.oc.netSplitter.name=Net Splitter tile.oc.waypoint.name=Waypoint # Items @@ -155,6 +156,7 @@ oc:gui.Analyzer.AddressCopied=Address copied to clipboard. oc:gui.Analyzer.ChargerSpeed=§6Charge speed§f: %s oc:gui.Analyzer.ComponentName=§6Component name§f: %s oc:gui.Analyzer.Components=§6Number of connected components§f: %s +oc:gui.Analyzer.CopyToClipboard=Click to copy to clipboard. oc:gui.Analyzer.LastError=§6Last error§f: %s oc:gui.Analyzer.RobotName=§6Name§f: %s oc:gui.Analyzer.RobotOwner=§6Owner§f: %s @@ -330,6 +332,7 @@ oc:tooltip.TabletCase=Basic case for tablets. Place it into the assembler to add oc:tooltip.Terminal=Allows controlling a server remotely, as long as you are in range of it. Acts like a portable screen and keyboard. Shift-right-click a server in a server rack to bind the terminal to it. oc:tooltip.TexturePicker=This tool allows showing a string describing a block's surface, for use in 3D printer shape definitions. Totally not texture names, nope. No sir. oc:tooltip.Tier=§8Tier %s +oc:tooltip.NetSplitter=Acts as a dynamic connector. Connectivity of each side can be toggled by hitting it with a wrench. Connectivity of all sides can be inverted by applying a redstone signal. oc:tooltip.TooLong=Hold [§f%s§7] for a detailed tooltip. oc:tooltip.Transistor=A basic element in most other computer parts. It's a bit twisted, but it does the job. oc:tooltip.UpgradeAngel=Allows robots to place blocks in thin air, even if there is no point of reference. diff --git a/src/main/resources/assets/opencomputers/lang/ru_RU.lang b/src/main/resources/assets/opencomputers/lang/ru_RU.lang index 3f9adc63c..658abedaf 100644 --- a/src/main/resources/assets/opencomputers/lang/ru_RU.lang +++ b/src/main/resources/assets/opencomputers/lang/ru_RU.lang @@ -36,6 +36,7 @@ tile.oc.screen2.name=Монитор (2-ой уровень) tile.oc.screen3.name=Монитор (3-ий уровень) tile.oc.serverRack.name=Серверная стойка tile.oc.switch.name=Коммутатор +tile.oc.netSplitter.name=Сетевой переключатель tile.oc.waypoint.name=Путевая точка # Items @@ -154,6 +155,7 @@ oc:gui.Analyzer.AddressCopied=Адрес скопирован в буфер об oc:gui.Analyzer.ChargerSpeed=§6Скорость зарядки§f: %s oc:gui.Analyzer.ComponentName=§6Имя компонента§f: %s oc:gui.Analyzer.Components=§6Количество подключенных компонентов§f: %s +oc:gui.Analyzer.CopyToClipboard=Кликните для копирования в буфер обмена. oc:gui.Analyzer.LastError=§6Последняя ошибка§f: %s oc:gui.Analyzer.RobotName=§6Имя§f: %s oc:gui.Analyzer.RobotOwner=§6Владелец§f: %s @@ -329,6 +331,7 @@ oc:tooltip.TabletCase=Простой корпус для планшета. По oc:tooltip.Terminal=Позволяет дистанционно управлять сервером, пока вы находитесь в радиусе его действия. Действует как портативный дисплей с клавиатурой.[nl] Shift+ПКМ по серверу в стойке для привязки к нему терминала. oc:tooltip.TexturePicker=Простой инструмент, позволяющий узнать название текстуры блока, которое можно использовать в 3D печати. oc:tooltip.Tier=§8Уровень %s +oc:tooltip.NetSplitter=Работает как переключатель. Соединение каждой стороны переключается ключем. При подаче сигнала красного камня все соединения инвертируются. oc:tooltip.TooLong=Удерживайте [§f%s§7], чтобы отобразить описание. oc:tooltip.Transistor=Базовый элемент для других частей компьютера. Он немного деформирован, но отлично выполняет свою работу. oc:tooltip.UpgradeAngel=Позволяет роботам размещать блоки в воздухе, даже если отсутствует точка опоры. diff --git a/src/main/resources/assets/opencomputers/loot/OpenOS/bin/install.lua b/src/main/resources/assets/opencomputers/loot/OpenOS/bin/install.lua index 25367c286..b147bcc1e 100644 --- a/src/main/resources/assets/opencomputers/loot/OpenOS/bin/install.lua +++ b/src/main/resources/assets/opencomputers/loot/OpenOS/bin/install.lua @@ -9,7 +9,7 @@ local args, options = shell.parse(...) local fromAddress = options.from and component.get(options.from) or filesystem.get(os.getenv("_")).address local candidates = {} -for address in component.list("filesystem") do +for address in component.list("filesystem", true) do local dev = component.proxy(address) if not dev.isReadOnly() and dev.address ~= computer.tmpAddress() and dev.address ~= fromAddress then table.insert(candidates, dev) diff --git a/src/main/resources/assets/opencomputers/loot/OpenOS/bin/sh.lua b/src/main/resources/assets/opencomputers/loot/OpenOS/bin/sh.lua index ffb31dba3..cfd9a5656 100644 --- a/src/main/resources/assets/opencomputers/loot/OpenOS/bin/sh.lua +++ b/src/main/resources/assets/opencomputers/loot/OpenOS/bin/sh.lua @@ -38,7 +38,11 @@ end function memoryStream:write(value) if not self.redirect.write and self.closed then - error("attempt to use a closed stream") + -- if next is dead, ignore all writes + if coroutine.status(self.next) ~= "dead" then + error("attempt to use a closed stream") + end + return true end if self.redirect.write then self.redirect.write:write(value) @@ -306,6 +310,7 @@ local function execute(env, command, ...) elseif pipes[i] then io.output(pipes[i]) end + io.write('') end, command) if not threads[i] then return false, reason diff --git a/src/main/resources/assets/opencomputers/loot/OpenOS/boot/04_component.lua b/src/main/resources/assets/opencomputers/loot/OpenOS/boot/04_component.lua index 5c084a5ca..a961a9aa5 100644 --- a/src/main/resources/assets/opencomputers/loot/OpenOS/boot/04_component.lua +++ b/src/main/resources/assets/opencomputers/loot/OpenOS/boot/04_component.lua @@ -116,7 +116,7 @@ end ------------------------------------------------------------------------------- -for address in component.list('screen') do +for address in component.list('screen', true) do if #component.invoke(address,'getKeyboards') > 0 then component.setPrimary('screen',address) end diff --git a/src/main/resources/assets/opencomputers/loot/OpenOS/init.lua b/src/main/resources/assets/opencomputers/loot/OpenOS/init.lua index 4edad2a25..cadfa551c 100644 --- a/src/main/resources/assets/opencomputers/loot/OpenOS/init.lua +++ b/src/main/resources/assets/opencomputers/loot/OpenOS/init.lua @@ -28,8 +28,8 @@ do function rom.inits() return ipairs(rom.invoke("list", "boot")) end function rom.isDirectory(path) return rom.invoke("isDirectory", path) end - local screen = component.list('screen')() - for address in component.list('screen') do + local screen = component.list('screen', true)() + for address in component.list('screen', true) do if #component.invoke(address, 'getKeyboards') > 0 then screen = address end diff --git a/src/main/resources/assets/opencomputers/loot/OpenOS/lib/filesystem.lua b/src/main/resources/assets/opencomputers/loot/OpenOS/lib/filesystem.lua index 7edda653b..dcbeb1d15 100644 --- a/src/main/resources/assets/opencomputers/loot/OpenOS/lib/filesystem.lua +++ b/src/main/resources/assets/opencomputers/loot/OpenOS/lib/filesystem.lua @@ -242,7 +242,7 @@ end function filesystem.proxy(filter) checkArg(1, filter, "string") local address - for c in component.list("filesystem") do + for c in component.list("filesystem", true) do if component.invoke(c, "getLabel") == filter then address = c break diff --git a/src/main/resources/assets/opencomputers/lua/component/data/bin/md5sum.lua b/src/main/resources/assets/opencomputers/lua/component/data/bin/md5sum.lua index 6a8a874af..ebdb3ba2c 100644 --- a/src/main/resources/assets/opencomputers/lua/component/data/bin/md5sum.lua +++ b/src/main/resources/assets/opencomputers/lua/component/data/bin/md5sum.lua @@ -22,6 +22,6 @@ else read = read .. current until current ~= "" file:close() - io.write(data.toHex(data.md5(read)) .. "\t".. args[i]) + io.write(data.toHex(data.md5(read)) .. "\t".. args[i] .. "\n") end end diff --git a/src/main/resources/assets/opencomputers/lua/component/data/bin/sha256sum.lua b/src/main/resources/assets/opencomputers/lua/component/data/bin/sha256sum.lua index 777e2b67c..5e63c7c61 100644 --- a/src/main/resources/assets/opencomputers/lua/component/data/bin/sha256sum.lua +++ b/src/main/resources/assets/opencomputers/lua/component/data/bin/sha256sum.lua @@ -22,6 +22,6 @@ else read = read .. current until current ~= "" file:close() - io.write(data.toHex(data.sha256(read)) .. "\t".. args[i]) + io.write(data.toHex(data.sha256(read)) .. "\t".. args[i] .. "\n") end end diff --git a/src/main/resources/assets/opencomputers/lua/machine.lua b/src/main/resources/assets/opencomputers/lua/machine.lua index 8a08680c9..56e79e3c0 100644 --- a/src/main/resources/assets/opencomputers/lua/machine.lua +++ b/src/main/resources/assets/opencomputers/lua/machine.lua @@ -732,7 +732,7 @@ sandbox = { tonumber = tonumber, tostring = tostring, type = type, - _VERSION = _VERSION:match("5.3") and "Lua 5.3.0" or "Lua 5.2.4", + _VERSION = _VERSION:match("5.3") and "Lua 5.3" or "Lua 5.2", xpcall = function(f, msgh, ...) local handled = false local result = table.pack(xpcall(f, function(...) diff --git a/src/main/resources/assets/opencomputers/recipes/default.recipes b/src/main/resources/assets/opencomputers/recipes/default.recipes index 137f32e65..69dc8b668 100644 --- a/src/main/resources/assets/opencomputers/recipes/default.recipes +++ b/src/main/resources/assets/opencomputers/recipes/default.recipes @@ -576,6 +576,11 @@ motionSensor { [daylightDetector, "oc:cpu2", daylightDetector] [ingotGold, "oc:materialCircuitBoardPrinted", ingotGold]] } +netSplitter { + input: [[ingotIron, "oc:cable", ingotIron] + ["oc:cable", craftingPiston, "oc:cable"] + [ingotIron, "oc:materialCircuitBoardPrinted", ingotIron]] +} printer { input: [[ingotIron, hopper, ingotIron] [craftingPiston, "oc:circuitChip3", craftingPiston] diff --git a/src/main/resources/assets/opencomputers/robot.names b/src/main/resources/assets/opencomputers/robot.names index 53d76de29..9165e1cc9 100644 --- a/src/main/resources/assets/opencomputers/robot.names +++ b/src/main/resources/assets/opencomputers/robot.names @@ -30,6 +30,7 @@ Crypto # Kodos Curiosity # Mars Rover Daedalus # Deus Ex Dalek Sec # Doctor Who +David # A.I. (the movie) Death Trap # Borderlands 2's Mechromancer Deputy ANDY # Eureka Dog # Half-Life diff --git a/src/main/resources/assets/opencomputers/textures/blocks/netSplitter_side.png b/src/main/resources/assets/opencomputers/textures/blocks/netSplitter_side.png new file mode 100644 index 000000000..fcf2787f0 Binary files /dev/null and b/src/main/resources/assets/opencomputers/textures/blocks/netSplitter_side.png differ diff --git a/src/main/resources/assets/opencomputers/textures/blocks/netSplitter_top.png b/src/main/resources/assets/opencomputers/textures/blocks/netSplitter_top.png new file mode 100644 index 000000000..d2dc29f3e Binary files /dev/null and b/src/main/resources/assets/opencomputers/textures/blocks/netSplitter_top.png differ diff --git a/src/main/resources/assets/opencomputers/textures/blocks/overlay/netSplitter_on.png b/src/main/resources/assets/opencomputers/textures/blocks/overlay/netSplitter_on.png new file mode 100644 index 000000000..9c61d7643 Binary files /dev/null and b/src/main/resources/assets/opencomputers/textures/blocks/overlay/netSplitter_on.png differ diff --git a/src/main/scala/li/cil/oc/Constants.scala b/src/main/scala/li/cil/oc/Constants.scala index 852112341..13d869f5c 100644 --- a/src/main/scala/li/cil/oc/Constants.scala +++ b/src/main/scala/li/cil/oc/Constants.scala @@ -38,6 +38,7 @@ object Constants { final val ScreenTier3 = "screen3" final val ServerRack = "serverRack" final val Switch = "switch" + final val NetSplitter = "netSplitter" final val Waypoint = "waypoint" def Case(tier: Int) = ItemUtils.caseNameWithTierSuffix("case", tier) diff --git a/src/main/scala/li/cil/oc/Localization.scala b/src/main/scala/li/cil/oc/Localization.scala index 8073b2799..d44efb544 100644 --- a/src/main/scala/li/cil/oc/Localization.scala +++ b/src/main/scala/li/cil/oc/Localization.scala @@ -1,5 +1,8 @@ package li.cil.oc +import li.cil.oc.client.CommandHandler.SetClipboardCommand +import net.minecraft.event.ClickEvent +import net.minecraft.event.HoverEvent import net.minecraft.util.ChatComponentText import net.minecraft.util.ChatComponentTranslation import net.minecraft.util.StatCollector @@ -23,7 +26,12 @@ object Localization { def localizeImmediately(key: String) = StatCollector.translateToLocal(resolveKey(key)).split(nl).map(_.trim).mkString("\n") object Analyzer { - def Address(value: String) = localizeLater("gui.Analyzer.Address", value) + def Address(value: String) = { + val result = localizeLater("gui.Analyzer.Address", value) + result.getChatStyle.setChatClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, s"/${SetClipboardCommand.name} $value")) + result.getChatStyle.setChatHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, localizeLater("gui.Analyzer.CopyToClipboard"))) + result + } def AddressCopied = localizeLater("gui.Analyzer.AddressCopied") diff --git a/src/main/scala/li/cil/oc/OpenComputers.scala b/src/main/scala/li/cil/oc/OpenComputers.scala index 2eda7f8f7..55367417d 100644 --- a/src/main/scala/li/cil/oc/OpenComputers.scala +++ b/src/main/scala/li/cil/oc/OpenComputers.scala @@ -2,7 +2,7 @@ package li.cil.oc import li.cil.oc.common.IMC import li.cil.oc.common.Proxy -import li.cil.oc.server.CommandHandler +import li.cil.oc.server.command.CommandHandler import net.minecraftforge.fml.common.Mod import net.minecraftforge.fml.common.Mod.EventHandler import net.minecraftforge.fml.common.SidedProxy diff --git a/src/main/scala/li/cil/oc/Settings.scala b/src/main/scala/li/cil/oc/Settings.scala index d4e8bf8ba..14d025294 100644 --- a/src/main/scala/li/cil/oc/Settings.scala +++ b/src/main/scala/li/cil/oc/Settings.scala @@ -218,6 +218,7 @@ class Settings(val config: Config) { private val valueGalacticraft = config.getDouble("power.value.Galacticraft") private val valueIndustrialCraft2 = config.getDouble("power.value.IndustrialCraft2") private val valueMekanism = config.getDouble("power.value.Mekanism") + private val valuePowerAdvantage = config.getDouble("power.value.PowerAdvantage") private val valueRedstoneFlux = config.getDouble("power.value.RedstoneFlux") private val valueInternal = 1000 @@ -227,6 +228,7 @@ class Settings(val config: Config) { val ratioGalacticraft = valueGalacticraft / valueInternal val ratioIndustrialCraft2 = valueIndustrialCraft2 / valueInternal val ratioMekanism = valueMekanism / valueInternal + val ratioPowerAdvantage = valuePowerAdvantage / valueInternal val ratioRedstoneFlux = valueRedstoneFlux / valueInternal // ----------------------------------------------------------------------- // diff --git a/src/main/scala/li/cil/oc/client/CommandHandler.scala b/src/main/scala/li/cil/oc/client/CommandHandler.scala new file mode 100644 index 000000000..c196c934e --- /dev/null +++ b/src/main/scala/li/cil/oc/client/CommandHandler.scala @@ -0,0 +1,31 @@ +package li.cil.oc.client + +import li.cil.oc.common.command.SimpleCommand +import net.minecraft.client.gui.GuiScreen +import net.minecraft.command.ICommandSender +import net.minecraftforge.client.ClientCommandHandler + +object CommandHandler { + def register(): Unit = { + ClientCommandHandler.instance.registerCommand(SetClipboardCommand) + } + + object SetClipboardCommand extends SimpleCommand("oc_setclipboard") { + override def getCommandUsage(source: ICommandSender): String = name + " " + + override def execute(source: ICommandSender, command: Array[String]): Unit = { + if (source.getEntityWorld.isRemote && command != null && command.length > 0) { + GuiScreen.setClipboardString(command(0)) + } + } + + // OP levels for reference: + // 1 - Ops can bypass spawn protection. + // 2 - Ops can use /clear, /difficulty, /effect, /gamemode, /gamerule, /give, /summon, /setblock and /tp, and can edit command blocks. + // 3 - Ops can use /ban, /deop, /kick, and /op. + // 4 - Ops can use /stop. + + override def getRequiredPermissionLevel = 0 + } + +} diff --git a/src/main/scala/li/cil/oc/client/PacketHandler.scala b/src/main/scala/li/cil/oc/client/PacketHandler.scala index 0d28a81b4..bb4cb64d5 100644 --- a/src/main/scala/li/cil/oc/client/PacketHandler.scala +++ b/src/main/scala/li/cil/oc/client/PacketHandler.scala @@ -58,6 +58,7 @@ object PacketHandler extends CommonPacketHandler { case PacketType.HologramTranslation => onHologramPositionOffsetY(p) case PacketType.HologramValues => onHologramValues(p) case PacketType.LootDisk => onLootDisk(p) + case PacketType.NetSplitterState => onNetSplitterState(p) case PacketType.ParticleEffect => onParticleEffect(p) case PacketType.PetVisibility => onPetVisibility(p) case PacketType.PowerState => onPowerState(p) @@ -442,6 +443,7 @@ object PacketHandler extends CommonPacketHandler { } buffer.data.load(nbt) buffer.proxy.markDirty() + buffer.markInitialized() case _ => // Invalid packet. } } @@ -587,6 +589,15 @@ object PacketHandler extends CommonPacketHandler { buffer.rawSetForeground(col, row, color) } + def onNetSplitterState(p: PacketParser) = + p.readTileEntity[NetSplitter]() match { + case Some(t) => + t.isInverted = p.readBoolean() + t.openSides = t.uncompressSides(p.readByte()) + t.world.markBlockForUpdate(t.getPos) + case _ => // Invalid packet. + } + def onScreenTouchMode(p: PacketParser) = p.readTileEntity[Screen]() match { case Some(t) => t.invertTouchMode = p.readBoolean() diff --git a/src/main/scala/li/cil/oc/client/Proxy.scala b/src/main/scala/li/cil/oc/client/Proxy.scala index 6f3541607..62138a839 100644 --- a/src/main/scala/li/cil/oc/client/Proxy.scala +++ b/src/main/scala/li/cil/oc/client/Proxy.scala @@ -34,6 +34,8 @@ private[oc] class Proxy extends CommonProxy { api.API.manual = client.Manual + CommandHandler.register() + MinecraftForge.EVENT_BUS.register(Textures) ModelInitialization.preInit() @@ -67,6 +69,7 @@ private[oc] class Proxy extends CommonProxy { ClientRegistry.bindTileEntitySpecialRenderer(classOf[tileentity.AccessPoint], SwitchRenderer) ClientRegistry.bindTileEntitySpecialRenderer(classOf[tileentity.RobotProxy], RobotRenderer) ClientRegistry.bindTileEntitySpecialRenderer(classOf[tileentity.Screen], ScreenRenderer) + ClientRegistry.bindTileEntitySpecialRenderer(classOf[tileentity.NetSplitter], NetSplitterRenderer) ClientRegistry.registerKeyBinding(KeyBindings.materialCosts) ClientRegistry.registerKeyBinding(KeyBindings.clipboardPaste) diff --git a/src/main/scala/li/cil/oc/client/Textures.scala b/src/main/scala/li/cil/oc/client/Textures.scala index 036330018..624df6b7e 100644 --- a/src/main/scala/li/cil/oc/client/Textures.scala +++ b/src/main/scala/li/cil/oc/client/Textures.scala @@ -131,6 +131,7 @@ object Textures { val GeolyzerTopOn = L("overlay/geolyzer_top_on") val MicrocontrollerFrontLight = L("overlay/microcontroller_front_light") val MicrocontrollerFrontOn = L("overlay/microcontroller_front_on") + val NetSplitterOn = L("overlay/netSplitter_on") val PowerDistributorSideOn = L("overlay/powerDistributor_side_on") val PowerDistributorTopOn = L("overlay/powerDistributor_top_on") val RackFrontActivity = L("overlay/serverRack_front_activity") @@ -143,6 +144,8 @@ object Textures { val Cable = L("cable") val CableCap = L("cableCap") val GenericTop = L("generic_top", load = false) + val NetSplitterSide = L("netSplitter_side") + val NetSplitterTop = L("netSplitter_top") val RackFront = L("serverRack_front", load = false) val RackSide = L("serverRack_side", load = false) diff --git a/src/main/scala/li/cil/oc/client/renderer/PetRenderer.scala b/src/main/scala/li/cil/oc/client/renderer/PetRenderer.scala index 73a1543e7..8ebdc0ec1 100644 --- a/src/main/scala/li/cil/oc/client/renderer/PetRenderer.scala +++ b/src/main/scala/li/cil/oc/client/renderer/PetRenderer.scala @@ -31,7 +31,10 @@ object PetRenderer { "DaKaTotal" ->(0.5, 0.7, 1.0), "MichiyoRavencroft" ->(1.0, 0.0, 0.0), "Vexatos" ->(0.18, 0.95, 0.922), - "StoneNomad" ->(0.8, 0.77, 0.75) + "StoneNomad" ->(0.8, 0.77, 0.75), + "LizzyTheSiren" ->(0.3, 0.3, 1.0), + "vifino" ->(0.2, 1.0, 0.1), + "Izaya" ->(0.0, 0.2, 0.6) ) private val petLocations = com.google.common.cache.CacheBuilder.newBuilder(). diff --git a/src/main/scala/li/cil/oc/client/renderer/block/CableModel.scala b/src/main/scala/li/cil/oc/client/renderer/block/CableModel.scala index 765c33483..bf5e15a70 100644 --- a/src/main/scala/li/cil/oc/client/renderer/block/CableModel.scala +++ b/src/main/scala/li/cil/oc/client/renderer/block/CableModel.scala @@ -83,17 +83,17 @@ object CableModel extends SmartBlockModelBase with ISmartItemModel { class BlockModel(val state: IExtendedBlockState) extends SmartBlockModelBase { override def getGeneralQuads = state.getValue(block.property.PropertyTile.Tile) match { - case cable: tileentity.Cable => + case t: tileentity.Cable => val faces = mutable.ArrayBuffer.empty[BakedQuad] - val color = Some(cable.color) - val mask = Cable.neighbors(cable.world, cable.getPos) + val color = Some(t.color) + val mask = Cable.neighbors(t.world, t.getPos) faces ++= bakeQuads(Middle, cableTexture, color) for (side <- EnumFacing.values) { val connected = (mask & (1 << side.getIndex)) != 0 val (plug, shortBody, longBody) = Connected(side.getIndex) if (connected) { - if (isCable(cable.position.offset(side))) { + if (isCable(t.position.offset(side))) { faces ++= bakeQuads(longBody, cableTexture, color) } else { diff --git a/src/main/scala/li/cil/oc/client/renderer/block/ModelInitialization.scala b/src/main/scala/li/cil/oc/client/renderer/block/ModelInitialization.scala index 3766b7f99..463682427 100644 --- a/src/main/scala/li/cil/oc/client/renderer/block/ModelInitialization.scala +++ b/src/main/scala/li/cil/oc/client/renderer/block/ModelInitialization.scala @@ -29,6 +29,8 @@ import scala.collection.mutable object ModelInitialization { final val CableBlockLocation = new ModelResourceLocation(Settings.resourceDomain + ":" + Constants.BlockName.Cable, "normal") final val CableItemLocation = new ModelResourceLocation(Settings.resourceDomain + ":" + Constants.BlockName.Cable, "inventory") + final val NetSplitterBlockLocation = new ModelResourceLocation(Settings.resourceDomain + ":" + Constants.BlockName.NetSplitter, "normal") + final val NetSplitterItemLocation = new ModelResourceLocation(Settings.resourceDomain + ":" + Constants.BlockName.NetSplitter, "inventory") final val PrintBlockLocation = new ModelResourceLocation(Settings.resourceDomain + ":" + Constants.BlockName.Print, "normal") final val PrintItemLocation = new ModelResourceLocation(Settings.resourceDomain + ":" + Constants.BlockName.Print, "inventory") final val RobotBlockLocation = new ModelResourceLocation(Settings.resourceDomain + ":" + Constants.BlockName.Robot, "normal") @@ -45,6 +47,7 @@ object ModelInitialization { MinecraftForge.EVENT_BUS.register(this) registerModel(Constants.BlockName.Cable, CableBlockLocation, CableItemLocation) + registerModel(Constants.BlockName.NetSplitter, NetSplitterBlockLocation, NetSplitterItemLocation) registerModel(Constants.BlockName.Print, PrintBlockLocation, PrintItemLocation) registerModel(Constants.BlockName.Robot, RobotBlockLocation, RobotItemLocation) registerModel(Constants.BlockName.RobotAfterimage, RobotAfterimageBlockLocation, RobotAfterimageItemLocation) @@ -137,6 +140,8 @@ object ModelInitialization { registry.putObject(CableBlockLocation, CableModel) registry.putObject(CableItemLocation, CableModel) + registry.putObject(NetSplitterBlockLocation, NetSplitterModel) + registry.putObject(NetSplitterItemLocation, NetSplitterModel) registry.putObject(PrintBlockLocation, PrintModel) registry.putObject(PrintItemLocation, PrintModel) registry.putObject(RobotBlockLocation, RobotModel) diff --git a/src/main/scala/li/cil/oc/client/renderer/block/NetSplitterModel.scala b/src/main/scala/li/cil/oc/client/renderer/block/NetSplitterModel.scala new file mode 100644 index 000000000..9a6d41ff9 --- /dev/null +++ b/src/main/scala/li/cil/oc/client/renderer/block/NetSplitterModel.scala @@ -0,0 +1,106 @@ +package li.cil.oc.client.renderer.block + +import li.cil.oc.client.Textures +import li.cil.oc.common.block +import li.cil.oc.common.item.data.PrintData +import li.cil.oc.common.tileentity +import net.minecraft.block.state.IBlockState +import net.minecraft.client.renderer.block.model.BakedQuad +import net.minecraft.item.ItemStack +import net.minecraft.util.EnumFacing +import net.minecraft.util.Vec3 +import net.minecraftforge.client.model.ISmartItemModel +import net.minecraftforge.common.property.IExtendedBlockState + +import scala.collection.convert.WrapAsJava.bufferAsJavaList +import scala.collection.mutable + +object NetSplitterModel extends SmartBlockModelBase with ISmartItemModel { + override def handleBlockState(state: IBlockState) = state match { + case extended: IExtendedBlockState => new BlockModel(extended) + case _ => missingModel + } + + override def handleItemState(stack: ItemStack) = new ItemModel(stack) + + protected def splitterTexture = Array( + Textures.getSprite(Textures.Block.NetSplitterTop), + Textures.getSprite(Textures.Block.NetSplitterTop), + Textures.getSprite(Textures.Block.NetSplitterSide), + Textures.getSprite(Textures.Block.NetSplitterSide), + Textures.getSprite(Textures.Block.NetSplitterSide), + Textures.getSprite(Textures.Block.NetSplitterSide) + ) + + protected final val BaseModel = { + val faces = mutable.ArrayBuffer.empty[BakedQuad] + + // Bottom. + faces ++= bakeQuads(makeBox(new Vec3(0 / 16f, 0 / 16f, 5 / 16f), new Vec3(5 / 16f, 5 / 16f, 11 / 16f)), splitterTexture, None) + faces ++= bakeQuads(makeBox(new Vec3(11 / 16f, 0 / 16f, 5 / 16f), new Vec3(16 / 16f, 5 / 16f, 11 / 16f)), splitterTexture, None) + faces ++= bakeQuads(makeBox(new Vec3(5 / 16f, 0 / 16f, 0 / 16f), new Vec3(11 / 16f, 5 / 16f, 5 / 16f)), splitterTexture, None) + faces ++= bakeQuads(makeBox(new Vec3(5 / 16f, 0 / 16f, 11 / 16f), new Vec3(11 / 16f, 5 / 16f, 16 / 16f)), splitterTexture, None) + // Corners. + faces ++= bakeQuads(makeBox(new Vec3(0 / 16f, 0 / 16f, 0 / 16f), new Vec3(5 / 16f, 16 / 16f, 5 / 16f)), splitterTexture, None) + faces ++= bakeQuads(makeBox(new Vec3(11 / 16f, 0 / 16f, 0 / 16f), new Vec3(16 / 16f, 16 / 16f, 5 / 16f)), splitterTexture, None) + faces ++= bakeQuads(makeBox(new Vec3(0 / 16f, 0 / 16f, 11 / 16f), new Vec3(5 / 16f, 16 / 16f, 16 / 16f)), splitterTexture, None) + faces ++= bakeQuads(makeBox(new Vec3(11 / 16f, 0 / 16f, 11 / 16f), new Vec3(16 / 16f, 16 / 16f, 16 / 16f)), splitterTexture, None) + // Top. + faces ++= bakeQuads(makeBox(new Vec3(0 / 16f, 11 / 16f, 5 / 16f), new Vec3(5 / 16f, 16 / 16f, 11 / 16f)), splitterTexture, None) + faces ++= bakeQuads(makeBox(new Vec3(11 / 16f, 11 / 16f, 5 / 16f), new Vec3(16 / 16f, 16 / 16f, 11 / 16f)), splitterTexture, None) + faces ++= bakeQuads(makeBox(new Vec3(5 / 16f, 11 / 16f, 0 / 16f), new Vec3(11 / 16f, 16 / 16f, 5 / 16f)), splitterTexture, None) + faces ++= bakeQuads(makeBox(new Vec3(5 / 16f, 11 / 16f, 11 / 16f), new Vec3(11 / 16f, 16 / 16f, 16 / 16f)), splitterTexture, None) + + faces.toArray + } + + protected def addSideQuads(faces: mutable.ArrayBuffer[BakedQuad], openSides: Array[Boolean]): Unit = { + val down = openSides(EnumFacing.DOWN.ordinal()) + faces ++= bakeQuads(makeBox(new Vec3(5 / 16f, if (down) 0 / 16f else 2 / 16f, 5 / 16f), new Vec3(11 / 16f, 5 / 16f, 11 / 16f)), splitterTexture, None) + + val up = openSides(EnumFacing.UP.ordinal()) + faces ++= bakeQuads(makeBox(new Vec3(5 / 16f, 11 / 16f, 5 / 16f), new Vec3(11 / 16f, if (up) 16 / 16f else 14f / 16f, 11 / 16f)), splitterTexture, None) + + val north = openSides(EnumFacing.NORTH.ordinal()) + faces ++= bakeQuads(makeBox(new Vec3(5 / 16f, 5 / 16f, if (north) 0 / 16f else 2 / 16f), new Vec3(11 / 16f, 11 / 16f, 5 / 16f)), splitterTexture, None) + + val south = openSides(EnumFacing.SOUTH.ordinal()) + faces ++= bakeQuads(makeBox(new Vec3(5 / 16f, 5 / 16f, 11 / 16f), new Vec3(11 / 16f, 11 / 16f, if (south) 16 / 16f else 14 / 16f)), splitterTexture, None) + + val west = openSides(EnumFacing.WEST.ordinal()) + faces ++= bakeQuads(makeBox(new Vec3(if (west) 0 / 16f else 2 / 16f, 5 / 16f, 5 / 16f), new Vec3(5 / 16f, 11 / 16f, 11 / 16f)), splitterTexture, None) + + val east = openSides(EnumFacing.EAST.ordinal()) + faces ++= bakeQuads(makeBox(new Vec3(11 / 16f, 5 / 16f, 5 / 16f), new Vec3(if (east) 16 / 16f else 14 / 16f, 11 / 16f, 11 / 16f)), splitterTexture, None) + } + + class BlockModel(val state: IExtendedBlockState) extends SmartBlockModelBase { + override def getGeneralQuads = + state.getValue(block.property.PropertyTile.Tile) match { + case t: tileentity.NetSplitter => + val faces = mutable.ArrayBuffer.empty[BakedQuad] + + faces ++= BaseModel + addSideQuads(faces, EnumFacing.values().map(t.isSideOpen)) + + bufferAsJavaList(faces) + case _ => super.getGeneralQuads + } + } + + class ItemModel(val stack: ItemStack) extends SmartBlockModelBase { + val data = new PrintData(stack) + + override def getGeneralQuads = { + val faces = mutable.ArrayBuffer.empty[BakedQuad] + + Textures.Block.bind() + + faces ++= BaseModel + addSideQuads(faces, EnumFacing.values().map(_ => false)) + + bufferAsJavaList(faces) + } + } + +} diff --git a/src/main/scala/li/cil/oc/client/renderer/block/PrintModel.scala b/src/main/scala/li/cil/oc/client/renderer/block/PrintModel.scala index c390050b2..897cc4da1 100644 --- a/src/main/scala/li/cil/oc/client/renderer/block/PrintModel.scala +++ b/src/main/scala/li/cil/oc/client/renderer/block/PrintModel.scala @@ -32,11 +32,11 @@ object PrintModel extends SmartBlockModelBase with ISmartItemModel { class BlockModel(val state: IExtendedBlockState) extends SmartBlockModelBase { override def getGeneralQuads = state.getValue(block.property.PropertyTile.Tile) match { - case print: tileentity.Print => + case t: tileentity.Print => val faces = mutable.ArrayBuffer.empty[BakedQuad] - for (shape <- if (print.state) print.data.stateOn else print.data.stateOff if !Strings.isNullOrEmpty(shape.texture)) { - val bounds = shape.bounds.rotateTowards(print.facing) + for (shape <- if (t.state) t.data.stateOn else t.data.stateOff if !Strings.isNullOrEmpty(shape.texture)) { + val bounds = shape.bounds.rotateTowards(t.facing) val texture = resolveTexture(shape.texture) faces ++= bakeQuads(makeBox(bounds.min, bounds.max), Array.fill(6)(texture), shape.tint.getOrElse(NoTint)) } diff --git a/src/main/scala/li/cil/oc/client/renderer/tileentity/NetSplitterRenderer.scala b/src/main/scala/li/cil/oc/client/renderer/tileentity/NetSplitterRenderer.scala new file mode 100644 index 000000000..c09061dbf --- /dev/null +++ b/src/main/scala/li/cil/oc/client/renderer/tileentity/NetSplitterRenderer.scala @@ -0,0 +1,91 @@ +package li.cil.oc.client.renderer.tileentity + +import li.cil.oc.client.Textures +import li.cil.oc.common.tileentity +import li.cil.oc.util.RenderState +import net.minecraft.client.renderer.Tessellator +import net.minecraft.client.renderer.texture.TextureMap +import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer +import net.minecraft.tileentity.TileEntity +import net.minecraft.util.EnumFacing +import org.lwjgl.opengl.GL11 + +object NetSplitterRenderer extends TileEntitySpecialRenderer { + override def renderTileEntityAt(tileEntity: TileEntity, x: Double, y: Double, z: Double, f: Float, damage: Int) { + RenderState.checkError(getClass.getName + ".renderTileEntityAt: entering (aka: wasntme)") + + val splitter = tileEntity.asInstanceOf[tileentity.NetSplitter] + if (splitter.openSides.contains(!splitter.isInverted)) { + RenderState.pushAttrib() + RenderState.disableEntityLighting() + RenderState.makeItBlend() + + RenderState.pushMatrix() + + GL11.glTranslated(x + 0.5, y + 0.5, z + 0.5) + GL11.glScaled(1.0025, -1.0025, 1.0025) + GL11.glTranslatef(-0.5f, -0.5f, -0.5f) + + bindTexture(TextureMap.locationBlocksTexture) + + val t = Tessellator.getInstance + val r = t.getWorldRenderer + + Textures.Block.bind() + r.startDrawingQuads() + + val sideActivity = Textures.getSprite(Textures.Block.NetSplitterOn) + + if (splitter.isSideOpen(EnumFacing.DOWN)) { + r.addVertexWithUV(0, 1, 0, sideActivity.getMaxU, sideActivity.getMinV) + r.addVertexWithUV(1, 1, 0, sideActivity.getMinU, sideActivity.getMinV) + r.addVertexWithUV(1, 1, 1, sideActivity.getMinU, sideActivity.getMaxV) + r.addVertexWithUV(0, 1, 1, sideActivity.getMaxU, sideActivity.getMaxV) + } + + if (splitter.isSideOpen(EnumFacing.UP)) { + r.addVertexWithUV(0, 0, 0, sideActivity.getMaxU, sideActivity.getMaxV) + r.addVertexWithUV(0, 0, 1, sideActivity.getMaxU, sideActivity.getMinV) + r.addVertexWithUV(1, 0, 1, sideActivity.getMinU, sideActivity.getMinV) + r.addVertexWithUV(1, 0, 0, sideActivity.getMinU, sideActivity.getMaxV) + } + + if (splitter.isSideOpen(EnumFacing.NORTH)) { + r.addVertexWithUV(1, 1, 0, sideActivity.getMinU, sideActivity.getMaxV) + r.addVertexWithUV(0, 1, 0, sideActivity.getMaxU, sideActivity.getMaxV) + r.addVertexWithUV(0, 0, 0, sideActivity.getMaxU, sideActivity.getMinV) + r.addVertexWithUV(1, 0, 0, sideActivity.getMinU, sideActivity.getMinV) + } + + if (splitter.isSideOpen(EnumFacing.SOUTH)) { + r.addVertexWithUV(0, 1, 1, sideActivity.getMinU, sideActivity.getMaxV) + r.addVertexWithUV(1, 1, 1, sideActivity.getMaxU, sideActivity.getMaxV) + r.addVertexWithUV(1, 0, 1, sideActivity.getMaxU, sideActivity.getMinV) + r.addVertexWithUV(0, 0, 1, sideActivity.getMinU, sideActivity.getMinV) + } + + if (splitter.isSideOpen(EnumFacing.WEST)) { + r.addVertexWithUV(0, 1, 0, sideActivity.getMinU, sideActivity.getMaxV) + r.addVertexWithUV(0, 1, 1, sideActivity.getMaxU, sideActivity.getMaxV) + r.addVertexWithUV(0, 0, 1, sideActivity.getMaxU, sideActivity.getMinV) + r.addVertexWithUV(0, 0, 0, sideActivity.getMinU, sideActivity.getMinV) + } + + if (splitter.isSideOpen(EnumFacing.EAST)) { + r.addVertexWithUV(1, 1, 1, sideActivity.getMinU, sideActivity.getMaxV) + r.addVertexWithUV(1, 1, 0, sideActivity.getMaxU, sideActivity.getMaxV) + r.addVertexWithUV(1, 0, 0, sideActivity.getMaxU, sideActivity.getMinV) + r.addVertexWithUV(1, 0, 1, sideActivity.getMinU, sideActivity.getMinV) + } + + t.draw() + + RenderState.enableEntityLighting() + + RenderState.popMatrix() + RenderState.popAttrib() + } + + RenderState.checkError(getClass.getName + ".renderTileEntityAt: leaving") + } +} diff --git a/src/main/scala/li/cil/oc/common/Loot.scala b/src/main/scala/li/cil/oc/common/Loot.scala index 331adb785..0c45fa1d7 100644 --- a/src/main/scala/li/cil/oc/common/Loot.scala +++ b/src/main/scala/li/cil/oc/common/Loot.scala @@ -135,7 +135,7 @@ object Loot extends WeightedRandomChestContent(new ItemStack(null: Item), 1, 1, def createLootDisk(name: String, path: String, external: Boolean, color: Option[EnumDyeColor] = None) = { val callable = if (external) new Callable[FileSystem] { - override def call(): FileSystem = api.FileSystem.fromSaveDirectory("loot/" + path, 0, false) + override def call(): FileSystem = api.FileSystem.asReadOnly(api.FileSystem.fromSaveDirectory("loot/" + path, 0, false)) } else new Callable[FileSystem] { override def call(): FileSystem = api.FileSystem.fromClass(OpenComputers.getClass, Settings.resourceDomain, "loot/" + path) } diff --git a/src/main/scala/li/cil/oc/common/PacketType.scala b/src/main/scala/li/cil/oc/common/PacketType.scala index 94c6a744f..15254ad56 100644 --- a/src/main/scala/li/cil/oc/common/PacketType.scala +++ b/src/main/scala/li/cil/oc/common/PacketType.scala @@ -49,6 +49,7 @@ object PacketType extends Enumeration { TextBufferMultiRawSetBackground, TextBufferMultiRawSetForeground, TextBufferPowerChange, + NetSplitterState, ScreenTouchMode, ServerPresence, Sound, diff --git a/src/main/scala/li/cil/oc/common/block/Assembler.scala b/src/main/scala/li/cil/oc/common/block/Assembler.scala index 49a1d3dc9..b1f070e51 100644 --- a/src/main/scala/li/cil/oc/common/block/Assembler.scala +++ b/src/main/scala/li/cil/oc/common/block/Assembler.scala @@ -3,6 +3,7 @@ package li.cil.oc.common.block import li.cil.oc.Settings import li.cil.oc.common.GuiType import li.cil.oc.common.tileentity +import li.cil.oc.integration.coloredlights.ModColoredLights import net.minecraft.block.state.IBlockState import net.minecraft.util.BlockPos import net.minecraft.util.EnumFacing @@ -10,7 +11,7 @@ import net.minecraft.world.IBlockAccess import net.minecraft.world.World class Assembler extends SimpleBlock with traits.PowerAcceptor with traits.StateAware with traits.GUI { - setLightLevel(0.34f) + ModColoredLights.setLightLevel(this, 0, 3, 5) override def isOpaqueCube = false diff --git a/src/main/scala/li/cil/oc/common/block/Capacitor.scala b/src/main/scala/li/cil/oc/common/block/Capacitor.scala index a2a701035..91b1dfe7a 100644 --- a/src/main/scala/li/cil/oc/common/block/Capacitor.scala +++ b/src/main/scala/li/cil/oc/common/block/Capacitor.scala @@ -3,13 +3,15 @@ package li.cil.oc.common.block import java.util.Random import li.cil.oc.common.tileentity +import li.cil.oc.integration.coloredlights.ModColoredLights import net.minecraft.block.Block import net.minecraft.block.state.IBlockState import net.minecraft.util.BlockPos import net.minecraft.world.World class Capacitor extends SimpleBlock { - setLightLevel(0.34f) + ModColoredLights.setLightLevel(this, 5, 5, 5) + setTickRandomly(true) // ----------------------------------------------------------------------- // diff --git a/src/main/scala/li/cil/oc/common/block/Geolyzer.scala b/src/main/scala/li/cil/oc/common/block/Geolyzer.scala index 0960df828..f2e3e4588 100644 --- a/src/main/scala/li/cil/oc/common/block/Geolyzer.scala +++ b/src/main/scala/li/cil/oc/common/block/Geolyzer.scala @@ -1,11 +1,12 @@ package li.cil.oc.common.block import li.cil.oc.common.tileentity +import li.cil.oc.integration.coloredlights.ModColoredLights import net.minecraft.block.state.IBlockState import net.minecraft.world.World class Geolyzer extends SimpleBlock { - setLightLevel(0.14f) + ModColoredLights.setLightLevel(this, 3, 1, 1) // ----------------------------------------------------------------------- // 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 c7f10fa4b..d3cee1f58 100644 --- a/src/main/scala/li/cil/oc/common/block/Hologram.scala +++ b/src/main/scala/li/cil/oc/common/block/Hologram.scala @@ -3,6 +3,7 @@ package li.cil.oc.common.block import java.util import li.cil.oc.common.tileentity +import li.cil.oc.integration.coloredlights.ModColoredLights import li.cil.oc.util.Rarity import li.cil.oc.util.Tooltip import net.minecraft.block.state.IBlockState @@ -16,7 +17,7 @@ import net.minecraftforge.fml.relauncher.Side import net.minecraftforge.fml.relauncher.SideOnly class Hologram(val tier: Int) extends SimpleBlock { - setLightLevel(1) + ModColoredLights.setLightLevel(this, 15, 15, 15) setBlockBounds(0, 0, 0, 1, 0.5f, 1) // ----------------------------------------------------------------------- // diff --git a/src/main/scala/li/cil/oc/common/block/NetSplitter.scala b/src/main/scala/li/cil/oc/common/block/NetSplitter.scala new file mode 100644 index 000000000..afb0c9310 --- /dev/null +++ b/src/main/scala/li/cil/oc/common/block/NetSplitter.scala @@ -0,0 +1,58 @@ +package li.cil.oc.common.block + +import li.cil.oc.common.tileentity +import li.cil.oc.integration.util.Wrench +import net.minecraft.block.properties.IProperty +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 +import net.minecraftforge.common.property.IExtendedBlockState +import net.minecraftforge.common.property.IUnlistedProperty + +import scala.collection.mutable.ArrayBuffer + +class NetSplitter extends RedstoneAware with traits.Extended { + override protected def setDefaultExtendedState(state: IBlockState) = setDefaultState(state) + + override protected def addExtendedState(state: IBlockState, world: IBlockAccess, pos: BlockPos) = + (state, world.getTileEntity(pos)) match { + case (extendedState: IExtendedBlockState, t: tileentity.NetSplitter) => + super.addExtendedState(extendedState.withProperty(property.PropertyTile.Tile, t), world, pos) + case _ => None + } + + override protected def createProperties(listed: ArrayBuffer[IProperty], unlisted: ArrayBuffer[IUnlistedProperty[_]]) { + super.createProperties(listed, unlisted) + unlisted += property.PropertyTile.Tile + } + + // ----------------------------------------------------------------------- // + + override def isSideSolid(world: IBlockAccess, pos: BlockPos, side: EnumFacing): Boolean = false + + // ----------------------------------------------------------------------- // + + override def createNewTileEntity(world: World, meta: Int) = new tileentity.NetSplitter() + + // ----------------------------------------------------------------------- // + + // NOTE: must not be final for immibis microblocks to work. + override def onBlockActivated(world: World, pos: BlockPos, state: IBlockState, player: EntityPlayer, side: EnumFacing, hitX: Float, hitY: Float, hitZ: Float): Boolean = { + if (Wrench.holdsApplicableWrench(player, pos)) { + val sideToToggle = if (player.isSneaking) side.getOpposite else side + world.getTileEntity(pos) match { + case splitter: tileentity.NetSplitter => + if (!world.isRemote) { + val oldValue = splitter.openSides(sideToToggle.ordinal()) + splitter.setSideOpen(sideToToggle, !oldValue) + } + true + case _ => false + } + } + else super.onBlockActivated(world, pos, state, player, side, hitX, hitY, hitZ) + } +} diff --git a/src/main/scala/li/cil/oc/common/block/PowerDistributor.scala b/src/main/scala/li/cil/oc/common/block/PowerDistributor.scala index 6c6aaaf0d..0a04cc05c 100644 --- a/src/main/scala/li/cil/oc/common/block/PowerDistributor.scala +++ b/src/main/scala/li/cil/oc/common/block/PowerDistributor.scala @@ -1,11 +1,12 @@ package li.cil.oc.common.block import li.cil.oc.common.tileentity +import li.cil.oc.integration.coloredlights.ModColoredLights import net.minecraft.block.state.IBlockState import net.minecraft.world.World class PowerDistributor extends SimpleBlock { - setLightLevel(0.34f) + ModColoredLights.setLightLevel(this, 5, 5, 3) // ----------------------------------------------------------------------- // diff --git a/src/main/scala/li/cil/oc/common/block/Print.scala b/src/main/scala/li/cil/oc/common/block/Print.scala index 810aadde5..034f4e99b 100644 --- a/src/main/scala/li/cil/oc/common/block/Print.scala +++ b/src/main/scala/li/cil/oc/common/block/Print.scala @@ -48,8 +48,8 @@ class Print(protected implicit val tileTag: ClassTag[tileentity.Print]) extends override protected def addExtendedState(state: IBlockState, world: IBlockAccess, pos: BlockPos) = (state, world.getTileEntity(pos)) match { - case (extendedState: IExtendedBlockState, print: tileentity.Print) => - super.addExtendedState(extendedState.withProperty(property.PropertyTile.Tile, print), world, pos) + case (extendedState: IExtendedBlockState, t: tileentity.Print) => + super.addExtendedState(extendedState.withProperty(property.PropertyTile.Tile, t), world, pos) case _ => None } diff --git a/src/main/scala/li/cil/oc/common/block/Screen.scala b/src/main/scala/li/cil/oc/common/block/Screen.scala index c17c755f3..73e688304 100644 --- a/src/main/scala/li/cil/oc/common/block/Screen.scala +++ b/src/main/scala/li/cil/oc/common/block/Screen.scala @@ -8,6 +8,7 @@ import li.cil.oc.Settings import li.cil.oc.api import li.cil.oc.common.GuiType import li.cil.oc.common.tileentity +import li.cil.oc.integration.coloredlights.ModColoredLights import li.cil.oc.integration.util.Wrench import li.cil.oc.util.Color import li.cil.oc.util.PackedColor @@ -33,7 +34,7 @@ import net.minecraftforge.fml.relauncher.SideOnly import scala.collection.mutable.ArrayBuffer class Screen(val tier: Int) extends RedstoneAware with traits.OmniRotatable { - setLightLevel(0.34f) + ModColoredLights.setLightLevel(this, 5, 5, 5) override def isSideSolid(world: IBlockAccess, pos: BlockPos, side: EnumFacing) = toLocal(world, pos, side) != EnumFacing.SOUTH @@ -89,7 +90,7 @@ class Screen(val tier: Int) extends RedstoneAware with traits.OmniRotatable { if (Wrench.holdsApplicableWrench(player, pos) && getValidRotations(world, pos).contains(side) && !force) false else if (api.Items.get(player.getHeldItem) == api.Items.get(Constants.ItemName.Analyzer)) false else world.getTileEntity(pos) match { - case screen: tileentity.Screen if screen.hasKeyboard && (force || player.isSneaking == screen.invertTouchMode) => + case screen: tileentity.Screen if screen.hasKeyboard && (force || player.isSneaking == screen.origin.invertTouchMode) => // Yep, this GUI is actually purely client side. We could skip this // if, but it is clearer this way (to trigger it from the server we // would have to give screens a "container", which we do not want). diff --git a/src/main/scala/li/cil/oc/common/block/SimpleBlock.scala b/src/main/scala/li/cil/oc/common/block/SimpleBlock.scala index 1ddd8db22..f03624d52 100644 --- a/src/main/scala/li/cil/oc/common/block/SimpleBlock.scala +++ b/src/main/scala/li/cil/oc/common/block/SimpleBlock.scala @@ -190,10 +190,10 @@ abstract class SimpleBlock(material: Material = Material.iron) extends BlockCont override def recolorBlock(world: World, pos: BlockPos, side: EnumFacing, color: EnumDyeColor) = world.getTileEntity(pos) match { - case colored: Colored if colored.color != color => - colored.color = color + case colored: Colored if colored.color != Color.byMeta(color) => + colored.color = Color.byMeta(color) world.markBlockForUpdate(pos) - false // Don't consume items. + true // Blame Vexatos. case _ => super.recolorBlock(world, pos, side, color) } diff --git a/src/main/scala/li/cil/oc/common/command/SimpleCommand.scala b/src/main/scala/li/cil/oc/common/command/SimpleCommand.scala new file mode 100644 index 000000000..b9fb94f11 --- /dev/null +++ b/src/main/scala/li/cil/oc/common/command/SimpleCommand.scala @@ -0,0 +1,22 @@ +package li.cil.oc.common.command + +import net.minecraft.command.CommandBase +import net.minecraft.command.ICommandSender +import net.minecraft.util.BlockPos + +import scala.collection.convert.WrapAsJava._ +import scala.collection.mutable + +abstract class SimpleCommand(val name: String) extends CommandBase { + protected var aliases = mutable.ListBuffer.empty[String] + + override def getName = name + + override def getAliases = aliases + + override def canCommandSenderUse(source: ICommandSender) = true + + override def isUsernameIndex(command: Array[String], i: Int) = false + + override def addTabCompletionOptions(source: ICommandSender, command: Array[String], pos: BlockPos) = List.empty[AnyRef] +} diff --git a/src/main/scala/li/cil/oc/common/component/TextBuffer.scala b/src/main/scala/li/cil/oc/common/component/TextBuffer.scala index 7debe237f..67b29919d 100644 --- a/src/main/scala/li/cil/oc/common/component/TextBuffer.scala +++ b/src/main/scala/li/cil/oc/common/component/TextBuffer.scala @@ -63,6 +63,10 @@ class TextBuffer(val host: EnvironmentHost) extends prefab.ManagedEnvironment wi private var _pendingCommands: Option[PacketBuilder] = None + private val syncInterval = 100 + + private var syncCooldown = syncInterval + private def pendingCommands = _pendingCommands.getOrElse { val pb = new CompressedPacketBuilder(PacketType.TextBufferMulti) pb.writeUTF(node.address) @@ -89,6 +93,8 @@ class TextBuffer(val host: EnvironmentHost) extends prefab.ManagedEnvironment wi val data = new util.TextBuffer(maxResolution, PackedColor.Depth.format(maxDepth)) + def markInitialized(): Unit = syncCooldown = -1 // Stop polling for init state. + // ----------------------------------------------------------------------- // override val canUpdate = true @@ -128,6 +134,14 @@ class TextBuffer(val host: EnvironmentHost) extends prefab.ManagedEnvironment wi _pendingCommands.foreach(_.sendToPlayersNearHost(host, Option(Settings.get.maxWirelessRange * Settings.get.maxWirelessRange))) _pendingCommands = None } + + if (SideTracker.isClient && syncCooldown > 0) { + syncCooldown -= 1 + if (syncCooldown == 0) { + syncCooldown = syncInterval + ClientPacketSender.sendTextBufferInit(proxy.nodeAddress) + } + } } // ----------------------------------------------------------------------- // diff --git a/src/main/scala/li/cil/oc/common/init/Blocks.scala b/src/main/scala/li/cil/oc/common/init/Blocks.scala index c59427f83..1d3a6b21d 100644 --- a/src/main/scala/li/cil/oc/common/init/Blocks.scala +++ b/src/main/scala/li/cil/oc/common/init/Blocks.scala @@ -34,6 +34,7 @@ object Blocks { GameRegistry.registerTileEntity(classOf[tileentity.Switch], Settings.namespace + "switch") GameRegistry.registerTileEntity(classOf[tileentity.Screen], Settings.namespace + "screen") GameRegistry.registerTileEntity(classOf[tileentity.ServerRack], Settings.namespace + "serverRack") + GameRegistry.registerTileEntity(classOf[tileentity.NetSplitter], Settings.namespace + "netSplitter") GameRegistry.registerTileEntity(classOf[tileentity.Waypoint], Settings.namespace + "waypoint") Recipes.addBlock(new AccessPoint(), Constants.BlockName.AccessPoint, "oc:accessPoint") @@ -73,5 +74,8 @@ object Blocks { // v1.5.10 Recipes.addBlock(new FakeEndstone(), Constants.BlockName.Endstone, "oc:stoneEndstone") + + // v1.5.14 + Recipes.addBlock(new NetSplitter(), Constants.BlockName.NetSplitter, "oc:netSplitter") } } diff --git a/src/main/scala/li/cil/oc/common/template/AssemblerTemplates.scala b/src/main/scala/li/cil/oc/common/template/AssemblerTemplates.scala index 336b3b4dc..974296bee 100644 --- a/src/main/scala/li/cil/oc/common/template/AssemblerTemplates.scala +++ b/src/main/scala/li/cil/oc/common/template/AssemblerTemplates.scala @@ -3,6 +3,7 @@ package li.cil.oc.common.template import java.lang.reflect.Method import com.google.common.base.Strings +import li.cil.oc.OpenComputers import li.cil.oc.api import li.cil.oc.api.driver.EnvironmentHost import li.cil.oc.common.IMC @@ -74,7 +75,11 @@ object AssemblerTemplates { def validate(inventory: IInventory, slot: Int, stack: ItemStack) = validator match { case Some(method) => IMC.tryInvokeStatic(method, inventory, slot.underlying(), tier.underlying(), stack)(false) case _ => Option(hostClass.fold(api.Driver.driverFor(stack))(api.Driver.driverFor(stack, _))) match { - case Some(driver) => driver.slot(stack) == kind && driver.tier(stack) <= tier + case Some(driver) => try driver.slot(stack) == kind && driver.tier(stack) <= tier catch { + case t: AbstractMethodError => + OpenComputers.log.warn(s"Error trying to query driver '${driver.getClass.getName}' for slot and/or tier information. Probably their fault. Yell at them before coming to OpenComputers for support. :P") + false + } case _ => false } } diff --git a/src/main/scala/li/cil/oc/common/tileentity/AccessPoint.scala b/src/main/scala/li/cil/oc/common/tileentity/AccessPoint.scala index 170217b63..35b2746bc 100644 --- a/src/main/scala/li/cil/oc/common/tileentity/AccessPoint.scala +++ b/src/main/scala/li/cil/oc/common/tileentity/AccessPoint.scala @@ -34,7 +34,7 @@ class AccessPoint extends Switch with WirelessEndpoint with traits.PowerAcceptor case _ => None } - override protected def energyThroughput = Settings.get.accessPointRate + override def energyThroughput = Settings.get.accessPointRate // ----------------------------------------------------------------------- // diff --git a/src/main/scala/li/cil/oc/common/tileentity/Assembler.scala b/src/main/scala/li/cil/oc/common/tileentity/Assembler.scala index f28c3acb0..f067d6c7d 100644 --- a/src/main/scala/li/cil/oc/common/tileentity/Assembler.scala +++ b/src/main/scala/li/cil/oc/common/tileentity/Assembler.scala @@ -41,7 +41,7 @@ class Assembler extends traits.Environment with traits.PowerAcceptor with traits override protected def connector(side: EnumFacing) = Option(if (side != EnumFacing.UP) node else null) - override protected def energyThroughput = Settings.get.assemblerRate + override def energyThroughput = Settings.get.assemblerRate override def currentState = { if (isAssembling) util.EnumSet.of(traits.State.IsWorking) diff --git a/src/main/scala/li/cil/oc/common/tileentity/Case.scala b/src/main/scala/li/cil/oc/common/tileentity/Case.scala index 722e822ec..2904a4870 100644 --- a/src/main/scala/li/cil/oc/common/tileentity/Case.scala +++ b/src/main/scala/li/cil/oc/common/tileentity/Case.scala @@ -29,7 +29,7 @@ class Case(var tier: Int) extends traits.PowerAcceptor with traits.Computer with override protected def connector(side: EnumFacing) = Option(if (side != facing && machine != null) machine.node.asInstanceOf[Connector] else null) - override protected def energyThroughput = Settings.get.caseRate(tier) + override def energyThroughput = Settings.get.caseRate(tier) def isCreative = tier == Tier.Four diff --git a/src/main/scala/li/cil/oc/common/tileentity/Charger.scala b/src/main/scala/li/cil/oc/common/tileentity/Charger.scala index c94aadc58..294602978 100644 --- a/src/main/scala/li/cil/oc/common/tileentity/Charger.scala +++ b/src/main/scala/li/cil/oc/common/tileentity/Charger.scala @@ -45,7 +45,7 @@ class Charger extends traits.Environment with traits.PowerAcceptor with traits.R override protected def connector(side: EnumFacing) = Option(if (side != facing) node else null) - override protected def energyThroughput = Settings.get.chargerRate + override def energyThroughput = Settings.get.chargerRate override def currentState = { // TODO Refine to only report working if present robots/drones actually *need* power. diff --git a/src/main/scala/li/cil/oc/common/tileentity/Disassembler.scala b/src/main/scala/li/cil/oc/common/tileentity/Disassembler.scala index 12835a3a5..151354086 100644 --- a/src/main/scala/li/cil/oc/common/tileentity/Disassembler.scala +++ b/src/main/scala/li/cil/oc/common/tileentity/Disassembler.scala @@ -36,7 +36,7 @@ class Disassembler extends traits.Environment with traits.PowerAcceptor with tra var disassembleNextInstantly = false - def progress = if (queue.isEmpty) 0 else (1 - (queue.size * Settings.get.disassemblerItemCost - buffer) / totalRequiredEnergy) * 100 + def progress = if (queue.isEmpty) 0.0 else (1 - (queue.size * Settings.get.disassemblerItemCost - buffer) / totalRequiredEnergy) * 100 private def setActive(value: Boolean) = if (value != isActive) { isActive = value @@ -51,7 +51,7 @@ class Disassembler extends traits.Environment with traits.PowerAcceptor with tra override protected def connector(side: EnumFacing) = Option(if (side != EnumFacing.UP) node else null) - override protected def energyThroughput = Settings.get.disassemblerRate + override def energyThroughput = Settings.get.disassemblerRate override def currentState = { if (isActive) util.EnumSet.of(traits.State.IsWorking) @@ -113,7 +113,7 @@ class Disassembler extends traits.Environment with traits.PowerAcceptor with tra private def drop(stack: ItemStack) { if (stack != null) { for (side <- EnumFacing.values if stack.stackSize > 0) { - InventoryUtils.insertIntoInventoryAt(stack, BlockPosition(this).offset(side), side.getOpposite) + InventoryUtils.insertIntoInventoryAt(stack, BlockPosition(this).offset(side), Some(side.getOpposite)) } if (stack.stackSize > 0) { spawnStackInWorld(stack, Option(EnumFacing.UP)) @@ -160,7 +160,7 @@ class Disassembler extends traits.Environment with traits.PowerAcceptor with tra override def isItemValidForSlot(i: Int, stack: ItemStack) = allowDisassembling(stack) && (((Settings.get.disassembleAllTheThings || api.Items.get(stack) != null) && ItemUtils.getIngredients(stack).nonEmpty) || - DisassemblerTemplates.select(stack) != None) + DisassemblerTemplates.select(stack).isDefined) private def allowDisassembling(stack: ItemStack) = stack != null && (!stack.hasTagCompound || !stack.getTagCompound.getBoolean(Settings.namespace + "undisassemblable")) diff --git a/src/main/scala/li/cil/oc/common/tileentity/Microcontroller.scala b/src/main/scala/li/cil/oc/common/tileentity/Microcontroller.scala index 45a489c00..32398b457 100644 --- a/src/main/scala/li/cil/oc/common/tileentity/Microcontroller.scala +++ b/src/main/scala/li/cil/oc/common/tileentity/Microcontroller.scala @@ -57,7 +57,7 @@ class Microcontroller extends traits.PowerAcceptor with traits.Hub with traits.C override protected def connector(side: EnumFacing) = Option(if (side != facing) snooperNode else null) - override protected def energyThroughput = Settings.get.caseRate(Tier.One) + override def energyThroughput = Settings.get.caseRate(Tier.One) // ----------------------------------------------------------------------- // diff --git a/src/main/scala/li/cil/oc/common/tileentity/NetSplitter.scala b/src/main/scala/li/cil/oc/common/tileentity/NetSplitter.scala new file mode 100644 index 000000000..30b107ba6 --- /dev/null +++ b/src/main/scala/li/cil/oc/common/tileentity/NetSplitter.scala @@ -0,0 +1,106 @@ +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.EventHandler +import li.cil.oc.server.{PacketSender => ServerPacketSender} +import net.minecraft.nbt.NBTTagCompound +import net.minecraft.util.EnumFacing +import net.minecraftforge.fml.relauncher.Side +import net.minecraftforge.fml.relauncher.SideOnly + +class NetSplitter extends traits.Environment with traits.RedstoneAware with api.network.SidedEnvironment { + private final val SideCount = EnumFacing.values().length + + _isOutputEnabled = true + + val node = api.Network.newNode(this, Visibility.None). + create() + + var isInverted = false + + var openSides = Array.fill(SideCount)(false) + + def compressSides = (EnumFacing.values(), openSides).zipped.foldLeft(0)((acc, entry) => acc | (if (entry._2) 1 << entry._1.ordinal() else 0)).toByte + + def uncompressSides(byte: Byte) = EnumFacing.values().map(d => ((1 << d.ordinal()) & byte) != 0) + + def isSideOpen(side: EnumFacing) = side != null && { + val isOpen = openSides(side.ordinal()) + if (isInverted) !isOpen else isOpen + } + + def setSideOpen(side: EnumFacing, value: Boolean): Unit = if (side != null && openSides(side.ordinal()) != value) { + openSides(side.ordinal()) = value + if (isServer) { + node.remove() + api.Network.joinOrCreateNetwork(this) + ServerPacketSender.sendNetSplitterState(this) + world.playSoundEffect(x + 0.5, y + 0.5, z + 0.5, "tile.piston.out", 0.5f, world.rand.nextFloat() * 0.25f + 0.7f) + } + else { + world.markBlockForUpdate(getPos) + } + } + + // ----------------------------------------------------------------------- // + + override def sidedNode(side: EnumFacing) = if (isSideOpen(side)) node else null + + @SideOnly(Side.CLIENT) + override def canConnect(side: EnumFacing) = isSideOpen(side) + + // ----------------------------------------------------------------------- // + + override def canUpdate = false + + override protected def initialize(): Unit = { + super.initialize() + EventHandler.schedule(this) + } + + // ----------------------------------------------------------------------- // + + override protected def onRedstoneInputChanged(side: EnumFacing, oldMaxValue: Int, newMaxValue: Int): Unit = { + super.onRedstoneInputChanged(side, oldMaxValue, newMaxValue) + val oldIsInverted = isInverted + isInverted = newMaxValue > 0 + if (isInverted != oldIsInverted) { + if (isServer) { + node.remove() + api.Network.joinOrCreateNetwork(this) + ServerPacketSender.sendNetSplitterState(this) + world.playSoundEffect(x + 0.5, y + 0.5, z + 0.5, "tile.piston.in", 0.5f, world.rand.nextFloat() * 0.25f + 0.7f) + } + else { + world.markBlockForUpdate(getPos) + } + } + } + + override def readFromNBTForServer(nbt: NBTTagCompound): Unit = { + super.readFromNBTForServer(nbt) + isInverted = nbt.getBoolean(Settings.namespace + "isInverted") + openSides = uncompressSides(nbt.getByte(Settings.namespace + "openSides")) + } + + override def writeToNBTForServer(nbt: NBTTagCompound): Unit = { + super.writeToNBTForServer(nbt) + nbt.setBoolean(Settings.namespace + "isInverted", isInverted) + nbt.setByte(Settings.namespace + "openSides", compressSides) + } + + @SideOnly(Side.CLIENT) override + def readFromNBTForClient(nbt: NBTTagCompound): Unit = { + super.readFromNBTForClient(nbt) + isInverted = nbt.getBoolean(Settings.namespace + "isInverted") + openSides = uncompressSides(nbt.getByte(Settings.namespace + "openSides")) + } + + override def writeToNBTForClient(nbt: NBTTagCompound): Unit = { + super.writeToNBTForClient(nbt) + nbt.setBoolean(Settings.namespace + "isInverted", isInverted) + nbt.setByte(Settings.namespace + "openSides", compressSides) + } +} diff --git a/src/main/scala/li/cil/oc/common/tileentity/PowerConverter.scala b/src/main/scala/li/cil/oc/common/tileentity/PowerConverter.scala index 24abb5474..ecb375fe6 100644 --- a/src/main/scala/li/cil/oc/common/tileentity/PowerConverter.scala +++ b/src/main/scala/li/cil/oc/common/tileentity/PowerConverter.scala @@ -17,7 +17,7 @@ class PowerConverter extends traits.PowerAcceptor with traits.Environment with t override protected def connector(side: EnumFacing) = Option(node) - override protected def energyThroughput = Settings.get.powerConverterRate + override def energyThroughput = Settings.get.powerConverterRate override def canUpdate = isServer } diff --git a/src/main/scala/li/cil/oc/common/tileentity/Screen.scala b/src/main/scala/li/cil/oc/common/tileentity/Screen.scala index 631f7caa0..f581f50fa 100644 --- a/src/main/scala/li/cil/oc/common/tileentity/Screen.scala +++ b/src/main/scala/li/cil/oc/common/tileentity/Screen.scala @@ -244,7 +244,7 @@ class Screen(var tier: Int) extends traits.TextBuffer with SidedEnvironment with } }) } - if (arrows.size > 0) { + if (arrows.nonEmpty) { for (arrow <- arrows) { val hitX = arrow.posX - x val hitY = arrow.posY - y diff --git a/src/main/scala/li/cil/oc/common/tileentity/ServerRack.scala b/src/main/scala/li/cil/oc/common/tileentity/ServerRack.scala index 8e60e1184..96de9d7f9 100644 --- a/src/main/scala/li/cil/oc/common/tileentity/ServerRack.scala +++ b/src/main/scala/li/cil/oc/common/tileentity/ServerRack.scala @@ -58,7 +58,7 @@ class ServerRack extends traits.PowerAcceptor with traits.Hub with traits.PowerB override protected def connector(side: EnumFacing) = Option(if (side != facing) sidedNode(side).asInstanceOf[Connector] else null) - override protected def energyThroughput = Settings.get.serverRackRate + override def energyThroughput = Settings.get.serverRackRate // ----------------------------------------------------------------------- // diff --git a/src/main/scala/li/cil/oc/common/tileentity/traits/RedstoneAware.scala b/src/main/scala/li/cil/oc/common/tileentity/traits/RedstoneAware.scala index 4c40e6740..657d07fcf 100644 --- a/src/main/scala/li/cil/oc/common/tileentity/traits/RedstoneAware.scala +++ b/src/main/scala/li/cil/oc/common/tileentity/traits/RedstoneAware.scala @@ -1,6 +1,7 @@ package li.cil.oc.common.tileentity.traits import li.cil.oc.Settings +import li.cil.oc.common.EventHandler import li.cil.oc.integration.Mods import li.cil.oc.integration.util.BundledRedstone import li.cil.oc.server.{PacketSender => ServerPacketSender} @@ -78,13 +79,18 @@ trait RedstoneAware extends RotationAware /* with IConnectable with IRedstoneEmi if (isServer) { if (shouldUpdateInput) { shouldUpdateInput = false - for (side <- EnumFacing.values) { - updateRedstoneInput(side) - } + EnumFacing.values().foreach(updateRedstoneInput) } } } + override def validate(): Unit = { + super.validate() + if (!canUpdate) { + EventHandler.schedule(() => EnumFacing.values().foreach(updateRedstoneInput)) + } + } + def updateRedstoneInput(side: EnumFacing) { input(side, BundledRedstone.computeInput(position, side)) } diff --git a/src/main/scala/li/cil/oc/common/tileentity/traits/power/Common.scala b/src/main/scala/li/cil/oc/common/tileentity/traits/power/Common.scala index e90394201..f60fddb01 100644 --- a/src/main/scala/li/cil/oc/common/tileentity/traits/power/Common.scala +++ b/src/main/scala/li/cil/oc/common/tileentity/traits/power/Common.scala @@ -1,11 +1,11 @@ package li.cil.oc.common.tileentity.traits.power -import net.minecraftforge.fml.relauncher.Side -import net.minecraftforge.fml.relauncher.SideOnly import li.cil.oc.Settings import li.cil.oc.api.network.Connector import li.cil.oc.common.tileentity.traits.TileEntity import net.minecraft.util.EnumFacing +import net.minecraftforge.fml.relauncher.Side +import net.minecraftforge.fml.relauncher.SideOnly trait Common extends TileEntity { @SideOnly(Side.CLIENT) @@ -15,7 +15,7 @@ trait Common extends TileEntity { // ----------------------------------------------------------------------- // - protected def energyThroughput: Double + def energyThroughput: Double protected def tryAllSides(provider: (Double, EnumFacing) => Double, ratio: Double) { // We make sure to only call this every `Settings.get.tickFrequency` ticks, @@ -37,7 +37,15 @@ trait Common extends TileEntity { def canConnectPower(side: EnumFacing) = !Settings.get.ignorePower && (if (isClient) hasConnector(side) else connector(side).isDefined) - def tryChangeBuffer(side: EnumFacing, amount: Double, doReceive: Boolean = true) = + /** + * Tries to inject the specified amount of energy into the buffer via the specified side. + * + * @param side the side to change the buffer through. + * @param amount the amount to change the buffer by. + * @param doReceive whether to actually inject energy or only simulate it. + * @return the amount of energy that was actually injected. + */ + def tryChangeBuffer(side: EnumFacing, amount: Double, doReceive: Boolean = true): Double = if (isClient || Settings.get.ignorePower) 0 else connector(side) match { case Some(node) => @@ -47,14 +55,14 @@ trait Common extends TileEntity { case _ => 0 } - def globalBuffer(side: EnumFacing) = + def globalBuffer(side: EnumFacing): Double = if (isClient) 0 else connector(side) match { case Some(node) => node.globalBuffer case _ => 0 } - def globalBufferSize(side: EnumFacing) = + def globalBufferSize(side: EnumFacing): Double = if (isClient) 0 else connector(side) match { case Some(node) => node.globalBufferSize diff --git a/src/main/scala/li/cil/oc/integration/Mods.scala b/src/main/scala/li/cil/oc/integration/Mods.scala index 0f30f2094..b401e5492 100644 --- a/src/main/scala/li/cil/oc/integration/Mods.scala +++ b/src/main/scala/li/cil/oc/integration/Mods.scala @@ -32,6 +32,7 @@ object Mods { val CoFHItem = new SimpleMod(IDs.CoFHItem) val CoFHTileEntity = new SimpleMod(IDs.CoFHTileEntity) val CoFHTransport = new SimpleMod(IDs.CoFHTransport) + val ColoredLights = new SimpleMod(IDs.ColoredLights) val ComputerCraft = new SimpleMod(IDs.ComputerCraft, version = "@[1.73,)") val CraftingCosts = new SimpleMod(IDs.CraftingCosts) val DeepStorageUnit = new ClassBasedMod(IDs.DeepStorageUnit, "powercrystals.minefactoryreloaded.api.IDeepStorageUnit")() @@ -56,6 +57,7 @@ object Mods { val NotEnoughKeys = new SimpleMod(IDs.NotEnoughKeys) val OpenComputers = new SimpleMod(IDs.OpenComputers) val PortalGun = new SimpleMod(IDs.PortalGun) + val PowerAdvantage = new SimpleMod(IDs.PowerAdvantage, version = "@[1.2.0,)", providesPower = true) val ProjectRedCore = new SimpleMod(IDs.ProjectRedCore) val ProjectRedTransmission = new SimpleMod(IDs.ProjectRedTransmission) val Railcraft = new SimpleMod(IDs.Railcraft) @@ -105,6 +107,7 @@ object Mods { // integration.mystcraft.ModMystcraft, // integration.nek.ModNotEnoughKeys, // integration.projectred.ModProjectRed, + integration.poweradvantage.ModPowerAdvantage, // integration.railcraft.ModRailcraft, // integration.redlogic.ModRedLogic, // integration.stargatetech2.ModStargateTech2, @@ -165,6 +168,7 @@ object Mods { final val CoFHItem = "CoFHAPI|item" final val CoFHTileEntity = "CoFHAPI|tileentity" final val CoFHTransport = "CoFHAPI|transport" + final val ColoredLights = "easycoloredlights" final val ComputerCraft = "ComputerCraft" final val CraftingCosts = "CraftingCosts" final val ElectricalAge = "Eln" @@ -174,8 +178,7 @@ object Mods { final val Factorization = "factorization" final val Forestry = "Forestry" final val ForgeMultipart = "ForgeMultipart" - final val DeepStorageUnit = "MineFactoryReloaded|DeepStorageUnit" - // Doesn't really exist. + final val DeepStorageUnit = "MineFactoryReloaded|DeepStorageUnit" // Doesn't really exist. final val Galacticraft = "Galacticraft API" final val GregTech = "gregtech" final val IndustrialCraft2 = "IC2" @@ -190,6 +193,7 @@ object Mods { final val NotEnoughKeys = "notenoughkeys" final val OpenComputers = "OpenComputers" final val PortalGun = "PortalGun" + final val PowerAdvantage = "poweradvantage" final val ProjectRedCore = "ProjRed|Core" final val ProjectRedTransmission = "ProjRed|Transmission" final val Railcraft = "Railcraft" diff --git a/src/main/scala/li/cil/oc/integration/coloredlights/ModColoredLights.scala b/src/main/scala/li/cil/oc/integration/coloredlights/ModColoredLights.scala new file mode 100644 index 000000000..ce8076b6b --- /dev/null +++ b/src/main/scala/li/cil/oc/integration/coloredlights/ModColoredLights.scala @@ -0,0 +1,29 @@ +package li.cil.oc.integration.coloredlights + +/* TODO Colored Lights +import coloredlightscore.src.api.CLApi +*/ +import li.cil.oc.integration.Mods +import net.minecraft.block.Block + +// Doesn't need initialization, just a thin wrapper for block light value initialization. +object ModColoredLights { + def setLightLevel(block: Block, r: Int, g: Int, b: Int): Unit = { + // Extra layer of indirection because I've learned to be paranoid when it comes to class loading... + if (Mods.ColoredLights.isAvailable) + setColoredLightLevel(block, r, g, b) + else + setPlainLightLevel(block, r, g, b) + } + + private def setColoredLightLevel(block: Block, r: Int, g: Int, b: Int): Unit = { +/* TODO Colored Lights + CLApi.setBlockColorRGB(block, r, g, b) +*/ + } + + private def setPlainLightLevel(block: Block, r: Int, g: Int, b: Int): Unit = { + val brightness = Array(r, g, b).max + block.setLightLevel((brightness + 0.1f) / 15f) + } +} diff --git a/src/main/scala/li/cil/oc/integration/computercraft/SwitchPeripheral.scala b/src/main/scala/li/cil/oc/integration/computercraft/SwitchPeripheral.scala index a00364eeb..804b6bb47 100644 --- a/src/main/scala/li/cil/oc/integration/computercraft/SwitchPeripheral.scala +++ b/src/main/scala/li/cil/oc/integration/computercraft/SwitchPeripheral.scala @@ -121,7 +121,7 @@ class SwitchPeripheral(val switch: Switch) extends IPeripheral { } private def checkPort(args: Array[AnyRef], index: Int) = { - if (args.length < index - 1 || !args(index).isInstanceOf[Double]) + if (args.length < index - 1 || !args(index).isInstanceOf[Number]) throw new IllegalArgumentException(s"bad argument #${index + 1} (number expected)") val port = args(index).asInstanceOf[Double].toInt if (port < 0 || port > 0xFFFF) diff --git a/src/main/scala/li/cil/oc/integration/fmp/CablePart.scala b/src/main/scala/li/cil/oc/integration/fmp/CablePart.scala index 81343cf4e..da2c66455 100644 --- a/src/main/scala/li/cil/oc/integration/fmp/CablePart.scala +++ b/src/main/scala/li/cil/oc/integration/fmp/CablePart.scala @@ -4,6 +4,10 @@ import codechicken.lib.data.MCDataInput import codechicken.lib.data.MCDataOutput import codechicken.lib.vec.Cuboid6 import codechicken.lib.vec.Vector3 +import codechicken.microblock.ISidedHollowConnect +import codechicken.multipart._ +import cpw.mods.fml.relauncher.Side +import cpw.mods.fml.relauncher.SideOnly import li.cil.oc.Constants import li.cil.oc.Settings import li.cil.oc.api @@ -27,7 +31,7 @@ import net.minecraft.util.MovingObjectPosition import scala.collection.convert.WrapAsJava import scala.collection.convert.WrapAsScala._ -class CablePart(val original: Option[tileentity.Cable] = None) extends SimpleBlockPart with TCuboidPart with TNormalOcclusion with network.Environment { +class CablePart(val original: Option[tileentity.Cable] = None) extends SimpleBlockPart with TCuboidPart with TSlottedPart with ISidedHollowConnect with TNormalOcclusion with network.Environment { val node = api.Network.newNode(this, Visibility.None).create() private var _color = Color.LightGray @@ -64,6 +68,11 @@ class CablePart(val original: Option[tileentity.Cable] = None) extends SimpleBlo override def getRenderBounds = new Cuboid6(Cable.bounds(world, x, y, z).offset(x, y, z)) + override def getHollowSize(side: Int) = 4 // 4 pixels as this is width of cable. + + override def getSlotMask = 1 << 6 // 6 is center part. + + // ----------------------------------------------------------------------- // override def activate(player: EntityPlayer, hit: MovingObjectPosition, item: ItemStack) = { diff --git a/src/main/scala/li/cil/oc/integration/forestry/ConverterIIndividual.java b/src/main/scala/li/cil/oc/integration/forestry/ConverterIIndividual.java index 0280904d9..8635de86e 100644 --- a/src/main/scala/li/cil/oc/integration/forestry/ConverterIIndividual.java +++ b/src/main/scala/li/cil/oc/integration/forestry/ConverterIIndividual.java @@ -245,7 +245,6 @@ public class ConverterIIndividual implements Converter { output.put("generation", bee.getGeneration()); output.put("hasEffect", bee.hasEffect()); output.put("isAlive", bee.isAlive()); - output.put("isIrregularMating", bee.isIrregularMating()); output.put("isNatural", bee.isNatural()); if (isAnalyzed) genomeReader = new BeeGenomeReader(bee.getGenome()); diff --git a/src/main/scala/li/cil/oc/integration/opencomputers/DriverAPU.scala b/src/main/scala/li/cil/oc/integration/opencomputers/DriverAPU.scala index a41112f13..17493abaa 100644 --- a/src/main/scala/li/cil/oc/integration/opencomputers/DriverAPU.scala +++ b/src/main/scala/li/cil/oc/integration/opencomputers/DriverAPU.scala @@ -27,7 +27,7 @@ object DriverAPU extends DriverCPU with HostAware with EnvironmentAware { override def cpuTier(stack: ItemStack) = Delegator.subItem(stack) match { - case Some(apu: common.item.APU) => apu.tier + case Some(apu: common.item.APU) => apu.cpuTier case _ => Tier.One } diff --git a/src/main/scala/li/cil/oc/integration/opencomputers/DriverCPU.scala b/src/main/scala/li/cil/oc/integration/opencomputers/DriverCPU.scala index df3cdd997..14db12664 100644 --- a/src/main/scala/li/cil/oc/integration/opencomputers/DriverCPU.scala +++ b/src/main/scala/li/cil/oc/integration/opencomputers/DriverCPU.scala @@ -33,7 +33,7 @@ abstract class DriverCPU extends Item with Processor { def cpuTier(stack: ItemStack): Int = Delegator.subItem(stack) match { - case Some(cpu: item.CPU) => cpu.tier + case Some(cpu: item.CPU) => cpu.cpuTier case _ => Tier.One } diff --git a/src/main/scala/li/cil/oc/integration/opencomputers/DriverGraphicsCard.scala b/src/main/scala/li/cil/oc/integration/opencomputers/DriverGraphicsCard.scala index 31b594c1d..b39c4f4d8 100644 --- a/src/main/scala/li/cil/oc/integration/opencomputers/DriverGraphicsCard.scala +++ b/src/main/scala/li/cil/oc/integration/opencomputers/DriverGraphicsCard.scala @@ -30,7 +30,7 @@ object DriverGraphicsCard extends Item with HostAware with EnvironmentAware { override def tier(stack: ItemStack) = Delegator.subItem(stack) match { - case Some(gpu: common.item.GraphicsCard) => gpu.tier + case Some(gpu: common.item.GraphicsCard) => gpu.gpuTier case _ => Tier.One } diff --git a/src/main/scala/li/cil/oc/integration/poweradvantage/LightWeightPowerAcceptor.scala b/src/main/scala/li/cil/oc/integration/poweradvantage/LightWeightPowerAcceptor.scala new file mode 100644 index 000000000..9f540b9e7 --- /dev/null +++ b/src/main/scala/li/cil/oc/integration/poweradvantage/LightWeightPowerAcceptor.scala @@ -0,0 +1,46 @@ +package li.cil.oc.integration.poweradvantage + +import cyano.poweradvantage.api.ConduitType +import cyano.poweradvantage.api.modsupport.ILightWeightPowerAcceptor +import cyano.poweradvantage.api.modsupport.LightWeightPowerRegistry +import li.cil.oc.Settings +import li.cil.oc.common.block +import li.cil.oc.common.tileentity.traits.PowerAcceptor +import net.minecraft.block.Block +import net.minecraft.tileentity.TileEntity +import net.minecraft.util.EnumFacing + +import scala.collection.convert.WrapAsScala._ + +object LightWeightPowerAcceptor extends ILightWeightPowerAcceptor { + def init(): Unit = { + Block.blockRegistry.collect { + case b: Block with block.traits.PowerAcceptor => + LightWeightPowerRegistry.registerLightWeightPowerAcceptor(b, this) + } + } + + def canAcceptEnergyType(powerType: ConduitType) = ConduitType.areSameType(powerType, "electricity") + + def getEnergyDemand(tileEntity: TileEntity, powerType: ConduitType) = tileEntity match { + case acceptor: PowerAcceptor if canAcceptEnergyType(powerType) => + (EnumFacing.values().map(side => { + val capacity = acceptor.globalBufferSize(side) + val stored = acceptor.globalBuffer(side) + capacity - stored + }).max / Settings.get.ratioPowerAdvantage).toInt + case _ => 0 + } + + def addEnergy(tileEntity: TileEntity, amountAdded: Float, powerType: ConduitType) = tileEntity match { + case acceptor: PowerAcceptor if canAcceptEnergyType(powerType) => + var remainingEnergy = math.min(amountAdded, acceptor.energyThroughput) * Settings.get.ratioPowerAdvantage + // .exists() for early exit. + EnumFacing.values().exists(side => { + remainingEnergy -= acceptor.tryChangeBuffer(side, remainingEnergy) + remainingEnergy <= 0 + }) + amountAdded - (remainingEnergy / Settings.get.ratioPowerAdvantage).toFloat + case _ => 0 + } +} diff --git a/src/main/scala/li/cil/oc/integration/poweradvantage/ModPowerAdvantage.scala b/src/main/scala/li/cil/oc/integration/poweradvantage/ModPowerAdvantage.scala new file mode 100644 index 000000000..c512283d8 --- /dev/null +++ b/src/main/scala/li/cil/oc/integration/poweradvantage/ModPowerAdvantage.scala @@ -0,0 +1,12 @@ +package li.cil.oc.integration.poweradvantage + +import li.cil.oc.integration.ModProxy +import li.cil.oc.integration.Mods + +object ModPowerAdvantage extends ModProxy { + override def getMod = Mods.PowerAdvantage + + override def initialize(): Unit = { + LightWeightPowerAcceptor.init() + } +} diff --git a/src/main/scala/li/cil/oc/server/CommandHandler.scala b/src/main/scala/li/cil/oc/server/CommandHandler.scala deleted file mode 100644 index 9213b5100..000000000 --- a/src/main/scala/li/cil/oc/server/CommandHandler.scala +++ /dev/null @@ -1,90 +0,0 @@ -package li.cil.oc.server - -import li.cil.oc.Settings -import net.minecraft.command.CommandBase -import net.minecraft.command.ICommandSender -import net.minecraft.command.WrongUsageException -import net.minecraft.entity.player.EntityPlayer -import net.minecraft.nbt.NBTTagCompound -import net.minecraft.util.BlockPos -import net.minecraftforge.fml.common.event.FMLServerStartingEvent - -import scala.collection.convert.wrapAsJava._ -import scala.collection.mutable - -object CommandHandler { - def register(e: FMLServerStartingEvent) { - e.registerServerCommand(WirelessRenderingCommand) - e.registerServerCommand(NonDisassemblyAgreementCommand) - } - - // OP levels for reference: - // 1 - Ops can bypass spawn protection. - // 2 - Ops can use /clear, /difficulty, /effect, /gamemode, /gamerule, /give, /summon, /setblock and /tp, and can edit command blocks. - // 3 - Ops can use /ban, /deop, /kick, and /op. - // 4 - Ops can use /stop. - - object WirelessRenderingCommand extends SimpleCommand("oc_renderWirelessNetwork") { - aliases += "oc_wlan" - - override def getCommandUsage(source: ICommandSender) = name + " " - - override def execute(sender: ICommandSender, command: Array[String]) { - Settings.rTreeDebugRenderer = - if (command != null && command.length > 0) - CommandBase.parseBoolean(command(0)) - else - !Settings.rTreeDebugRenderer - } - - override def getRequiredPermissionLevel = 2 - } - - object NonDisassemblyAgreementCommand extends SimpleCommand("oc_preventDisassembling") { - aliases += "oc_nodis" - aliases += "oc_prevdis" - - override def getCommandUsage(source: ICommandSender) = name + " " - - override def execute(sender: ICommandSender, command: Array[String]) { - sender match { - case player: EntityPlayer => - val stack = player.getHeldItem - if (stack != null) { - if (!stack.hasTagCompound) { - stack.setTagCompound(new NBTTagCompound()) - } - val nbt = stack.getTagCompound - val preventDisassembly = - if (command != null && command.length > 0) - CommandBase.parseBoolean(command(0)) - else - !nbt.getBoolean(Settings.namespace + "undisassemblable") - if (preventDisassembly) - nbt.setBoolean(Settings.namespace + "undisassemblable", true) - else - nbt.removeTag(Settings.namespace + "undisassemblable") - if (nbt.hasNoTags) stack.setTagCompound(null) - } - case _ => throw new WrongUsageException("Can only be used by players.") - } - } - - override def getRequiredPermissionLevel = 2 - } - - abstract class SimpleCommand(val name: String) extends CommandBase { - protected var aliases = mutable.ListBuffer.empty[String] - - override def getName = name - - override def getAliases = aliases - - override def canCommandSenderUse(sender: ICommandSender) = true - - override def addTabCompletionOptions(sender: ICommandSender, args: Array[String], pos: BlockPos) = List.empty[AnyRef] - - override def isUsernameIndex(command: Array[String], i: Int) = false - } - -} diff --git a/src/main/scala/li/cil/oc/server/PacketSender.scala b/src/main/scala/li/cil/oc/server/PacketSender.scala index e01552273..d710bcd5f 100644 --- a/src/main/scala/li/cil/oc/server/PacketSender.scala +++ b/src/main/scala/li/cil/oc/server/PacketSender.scala @@ -522,6 +522,16 @@ object PacketSender { pb.sendToPlayersNearHost(host) } + def sendNetSplitterState(t: tileentity.NetSplitter): Unit = { + val pb = new SimplePacketBuilder(PacketType.NetSplitterState) + + pb.writeTileEntity(t) + pb.writeBoolean(t.isInverted) + pb.writeByte(t.compressSides) + + pb.sendToPlayersNearTileEntity(t) + } + def sendScreenTouchMode(t: tileentity.Screen, value: Boolean) { val pb = new SimplePacketBuilder(PacketType.ScreenTouchMode) diff --git a/src/main/scala/li/cil/oc/server/command/CommandHandler.scala b/src/main/scala/li/cil/oc/server/command/CommandHandler.scala new file mode 100644 index 000000000..ea9a21b77 --- /dev/null +++ b/src/main/scala/li/cil/oc/server/command/CommandHandler.scala @@ -0,0 +1,11 @@ +package li.cil.oc.server.command + +import net.minecraftforge.fml.common.event.FMLServerStartingEvent + +object CommandHandler { + def register(e: FMLServerStartingEvent) { + e.registerServerCommand(NonDisassemblyAgreementCommand) + e.registerServerCommand(WirelessRenderingCommand) + e.registerServerCommand(SpawnComputerCommand) + } +} diff --git a/src/main/scala/li/cil/oc/server/command/NonDisassemblyAgreementCommand.scala b/src/main/scala/li/cil/oc/server/command/NonDisassemblyAgreementCommand.scala new file mode 100644 index 000000000..09a758fff --- /dev/null +++ b/src/main/scala/li/cil/oc/server/command/NonDisassemblyAgreementCommand.scala @@ -0,0 +1,48 @@ +package li.cil.oc.server.command + +import li.cil.oc.Settings +import li.cil.oc.common.command.SimpleCommand +import net.minecraft.command.CommandBase +import net.minecraft.command.ICommandSender +import net.minecraft.command.WrongUsageException +import net.minecraft.entity.player.EntityPlayer +import net.minecraft.nbt.NBTTagCompound + +object NonDisassemblyAgreementCommand extends SimpleCommand("oc_preventDisassembling") { + aliases += "oc_nodis" + aliases += "oc_prevdis" + + override def getCommandUsage(source: ICommandSender) = name + " " + + override def execute(source: ICommandSender, command: Array[String]) { + source match { + case player: EntityPlayer => + val stack = player.getHeldItem + if (stack != null) { + if (!stack.hasTagCompound) { + stack.setTagCompound(new NBTTagCompound()) + } + val nbt = stack.getTagCompound + val preventDisassembly = + if (command != null && command.length > 0) + CommandBase.parseBoolean(command(0)) + else + !nbt.getBoolean(Settings.namespace + "undisassemblable") + if (preventDisassembly) + nbt.setBoolean(Settings.namespace + "undisassemblable", true) + else + nbt.removeTag(Settings.namespace + "undisassemblable") + if (nbt.hasNoTags) stack.setTagCompound(null) + } + case _ => throw new WrongUsageException("Can only be used by players.") + } + } + + // OP levels for reference: + // 1 - Ops can bypass spawn protection. + // 2 - Ops can use /clear, /difficulty, /effect, /gamemode, /gamerule, /give, /summon, /setblock and /tp, and can edit command blocks. + // 3 - Ops can use /ban, /deop, /kick, and /op. + // 4 - Ops can use /stop. + + override def getRequiredPermissionLevel = 2 +} diff --git a/src/main/scala/li/cil/oc/server/command/SpawnComputerCommand.scala b/src/main/scala/li/cil/oc/server/command/SpawnComputerCommand.scala new file mode 100644 index 000000000..f3d240ac6 --- /dev/null +++ b/src/main/scala/li/cil/oc/server/command/SpawnComputerCommand.scala @@ -0,0 +1,76 @@ +package li.cil.oc.server.command + +import li.cil.oc.Constants +import li.cil.oc.api +import li.cil.oc.common.command.SimpleCommand +import li.cil.oc.common.tileentity +import li.cil.oc.util.BlockPosition +import li.cil.oc.util.ExtendedWorld._ +import li.cil.oc.util.InventoryUtils +import net.minecraft.command.ICommandSender +import net.minecraft.command.WrongUsageException +import net.minecraft.entity.player.EntityPlayer +import net.minecraft.util.ChatComponentText +import net.minecraft.util.EnumFacing +import net.minecraft.util.MovingObjectPosition +import net.minecraft.util.Vec3 + +object SpawnComputerCommand extends SimpleCommand("oc_spawnComputer") { + aliases += "oc_sc" + + final val MaxDistance = 16 + + override def getCommandUsage(source: ICommandSender): String = name + + override def execute(source: ICommandSender, command: Array[String]) { + source match { + case player: EntityPlayer => + val world = player.getEntityWorld + val origin = new Vec3(player.posX, player.posY + player.getEyeHeight, player.posZ) + val direction = player.getLookVec + val lookAt = origin.addVector(direction.xCoord * MaxDistance, direction.yCoord * MaxDistance, direction.zCoord * MaxDistance) + world.rayTraceBlocks(origin, lookAt) match { + case hit: MovingObjectPosition if hit.typeOfHit == MovingObjectPosition.MovingObjectType.BLOCK => + val hitPos = BlockPosition(hit.getBlockPos, world) + val casePos = hitPos.offset(hit.sideHit) + val screenPos = casePos.offset(EnumFacing.UP) + val keyboardPos = screenPos.offset(EnumFacing.UP) + + if (!world.isAirBlock(casePos) || !world.isAirBlock(screenPos) || !world.isAirBlock(keyboardPos)) { + player.addChatMessage(new ChatComponentText("Target position obstructed.")) + return + } + + world.setBlock(casePos, api.Items.get(Constants.BlockName.CaseCreative).block()) + world.setBlock(screenPos, api.Items.get(Constants.BlockName.ScreenTier2).block()) + world.setBlock(keyboardPos, api.Items.get(Constants.BlockName.Keyboard).block()) + world.getTileEntity(keyboardPos) match { + case t: tileentity.traits.Rotatable => t.setFromFacing(EnumFacing.UP) + case _ => // ??? + } + world.getTileEntity(screenPos) match { + case t: tileentity.traits.Rotatable => t.setFromFacing(EnumFacing.NORTH) + case _ => // ??? + } + + api.Network.joinOrCreateNetwork(world.getTileEntity(casePos)) + + InventoryUtils.insertIntoInventoryAt(api.Items.get(Constants.ItemName.APUCreative).createItemStack(1), casePos) + InventoryUtils.insertIntoInventoryAt(api.Items.get(Constants.ItemName.RAMTier6).createItemStack(2), casePos) + InventoryUtils.insertIntoInventoryAt(api.Items.get(Constants.ItemName.HDDTier3).createItemStack(1), casePos) + InventoryUtils.insertIntoInventoryAt(api.Items.get(Constants.ItemName.LuaBios).createItemStack(1), casePos) + InventoryUtils.insertIntoInventoryAt(api.Items.get(Constants.ItemName.OpenOS).createItemStack(1), casePos) + case _ => player.addChatMessage(new ChatComponentText("You need to be looking at a nearby block.")) + } + case _ => throw new WrongUsageException("Can only be used by players.") + } + } + + // OP levels for reference: + // 1 - Ops can bypass spawn protection. + // 2 - Ops can use /clear, /difficulty, /effect, /gamemode, /gamerule, /give, /summon, /setblock and /tp, and can edit command blocks. + // 3 - Ops can use /ban, /deop, /kick, and /op. + // 4 - Ops can use /stop. + + override def getRequiredPermissionLevel = 2 +} diff --git a/src/main/scala/li/cil/oc/server/command/WirelessRenderingCommand.scala b/src/main/scala/li/cil/oc/server/command/WirelessRenderingCommand.scala new file mode 100644 index 000000000..52b07eeab --- /dev/null +++ b/src/main/scala/li/cil/oc/server/command/WirelessRenderingCommand.scala @@ -0,0 +1,28 @@ +package li.cil.oc.server.command + +import li.cil.oc.Settings +import li.cil.oc.common.command.SimpleCommand +import net.minecraft.command.CommandBase +import net.minecraft.command.ICommandSender + +object WirelessRenderingCommand extends SimpleCommand("oc_renderWirelessNetwork") { + aliases += "oc_wlan" + + override def getCommandUsage(source: ICommandSender) = name + " " + + override def execute(source: ICommandSender, command: Array[String]) { + Settings.rTreeDebugRenderer = + if (command != null && command.length > 0) + CommandBase.parseBoolean(command(0)) + else + !Settings.rTreeDebugRenderer + } + + // OP levels for reference: + // 1 - Ops can bypass spawn protection. + // 2 - Ops can use /clear, /difficulty, /effect, /gamemode, /gamerule, /give, /summon, /setblock and /tp, and can edit command blocks. + // 3 - Ops can use /ban, /deop, /kick, and /op. + // 4 - Ops can use /stop. + + override def getRequiredPermissionLevel = 2 +} 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 63b465451..7f79483f3 100755 --- a/src/main/scala/li/cil/oc/server/fs/FileSystem.scala +++ b/src/main/scala/li/cil/oc/server/fs/FileSystem.scala @@ -99,6 +99,10 @@ object FileSystem extends api.detail.FileSystemAPI { def fromMemory(capacity: Long): api.fs.FileSystem = new RamFileSystem(capacity) + override def asReadOnly(fileSystem: api.fs.FileSystem) = + if (fileSystem.isReadOnly) fileSystem + else new ReadOnlyWrapper(fileSystem) + def asManagedEnvironment(fileSystem: api.fs.FileSystem, label: Label, host: EnvironmentHost, accessSound: String, speed: Int) = Option(fileSystem).flatMap(fs => Some(component.FileSystem(fs, label, Option(host), Option(accessSound), speed))).orNull diff --git a/src/main/scala/li/cil/oc/server/fs/ReadOnlyWrapper.scala b/src/main/scala/li/cil/oc/server/fs/ReadOnlyWrapper.scala new file mode 100644 index 000000000..8b8be08c5 --- /dev/null +++ b/src/main/scala/li/cil/oc/server/fs/ReadOnlyWrapper.scala @@ -0,0 +1,47 @@ +package li.cil.oc.server.fs + +import java.io.FileNotFoundException + +import li.cil.oc.api +import li.cil.oc.api.fs.Mode +import net.minecraft.nbt.NBTTagCompound + +private class ReadOnlyWrapper(val fileSystem: api.fs.FileSystem) extends api.fs.FileSystem { + override def isReadOnly = true + + override def spaceTotal = fileSystem.spaceUsed() + + override def spaceUsed = fileSystem.spaceUsed() + + override def exists(path: String) = fileSystem.exists(path) + + override def size(path: String) = fileSystem.size(path) + + override def isDirectory(path: String) = fileSystem.isDirectory(path) + + override def lastModified(path: String) = fileSystem.lastModified(path) + + override def list(path: String) = fileSystem.list(path) + + override def delete(path: String) = false + + override def makeDirectory(path: String) = false + + override def rename(from: String, to: String) = false + + override def setLastModified(path: String, time: Long) = false + + override def open(path: String, mode: Mode) = mode match { + case Mode.Read => fileSystem.open(path, mode) + case Mode.Write => throw new FileNotFoundException() + case Mode.Append => throw new FileNotFoundException() + } + + override def getHandle(handle: Int) = fileSystem.getHandle(handle) + + override def close() = fileSystem.close() + + override def load(nbt: NBTTagCompound) = fileSystem.load(nbt) + + override def save(nbt: NBTTagCompound) = fileSystem.save(nbt) +} diff --git a/src/main/scala/li/cil/oc/server/machine/luac/OSAPI.scala b/src/main/scala/li/cil/oc/server/machine/luac/OSAPI.scala index 94047e9ee..6ae6d04bf 100644 --- a/src/main/scala/li/cil/oc/server/machine/luac/OSAPI.scala +++ b/src/main/scala/li/cil/oc/server/machine/luac/OSAPI.scala @@ -25,7 +25,7 @@ class OSAPI(owner: NativeLuaArchitecture) extends NativeLuaAPI(owner) { else "%d/%m/%y %H:%M:%S" val time = if (lua.getTop > 1 && lua.isNumber(2)) lua.toNumber(2) * 1000 / 60 / 60 - else machine.worldTime + 5000 + else machine.worldTime + 6000 val dt = GameTimeFormatter.parse(time) def fmt(format: String) { diff --git a/src/main/scala/li/cil/oc/server/machine/luaj/OSAPI.scala b/src/main/scala/li/cil/oc/server/machine/luaj/OSAPI.scala index 439e74057..b0050abc7 100644 --- a/src/main/scala/li/cil/oc/server/machine/luaj/OSAPI.scala +++ b/src/main/scala/li/cil/oc/server/machine/luaj/OSAPI.scala @@ -18,7 +18,7 @@ class OSAPI(owner: LuaJLuaArchitecture) extends LuaJAPI(owner) { else "%d/%m/%y %H:%M:%S" val time = if (args.narg > 1 && args.isnumber(2)) args.todouble(2) * 1000 / 60 / 60 - else machine.worldTime + 5000 + else machine.worldTime + 6000 val dt = GameTimeFormatter.parse(time) def fmt(format: String) = { diff --git a/src/main/scala/li/cil/oc/util/Color.scala b/src/main/scala/li/cil/oc/util/Color.scala index 3d20a9b67..8d319ccb0 100644 --- a/src/main/scala/li/cil/oc/util/Color.scala +++ b/src/main/scala/li/cil/oc/util/Color.scala @@ -64,6 +64,8 @@ object Color { val byTier = Array(EnumDyeColor.SILVER, EnumDyeColor.YELLOW, EnumDyeColor.CYAN, EnumDyeColor.MAGENTA) + def byMeta(meta: EnumDyeColor) = byOreName(dyes(meta.getDyeDamage)) + def findDye(stack: ItemStack) = byOreName.keys.find(OreDictionary.getOres(_).exists(oreStack => OreDictionary.itemMatches(stack, oreStack, false))) def isDye(stack: ItemStack) = findDye(stack).isDefined diff --git a/src/main/scala/li/cil/oc/util/GameTimeFormatter.scala b/src/main/scala/li/cil/oc/util/GameTimeFormatter.scala index c72e37b85..fe57294e3 100644 --- a/src/main/scala/li/cil/oc/util/GameTimeFormatter.scala +++ b/src/main/scala/li/cil/oc/util/GameTimeFormatter.scala @@ -67,8 +67,8 @@ object GameTimeFormatter { def parse(time: Double) = { var day = (time / 24000).toLong val weekDay = ((4 + day) % 7).toInt - val year = 1970 + (day / 365.2425).toInt - val yearDay = (day % 365.2425).toInt + val year = 1970 + (day / 364.2425).toInt + val yearDay = (day % 364.2425).toInt day = yearDay val monthLengths = monthLengthsForYear(year) var month = 0 @@ -80,7 +80,7 @@ object GameTimeFormatter { var seconds = ((time % 24000) * 60 * 60 / 1000).toInt var minutes = seconds / 60 seconds = seconds % 60 - val hours = (1 + minutes / 60) % 24 + val hours = (minutes / 60) % 24 minutes = minutes % 60 new DateTime(year, month + 1, day.toInt + 1, weekDay + 1, yearDay + 1, hours, minutes, seconds) @@ -107,7 +107,6 @@ object GameTimeFormatter { val monthLengths = monthLengthsForYear(year) val days = ((year - 1970) * 365.2425).ceil.toInt + (0 until mon - 1).foldLeft(0)((d, m) => d + monthLengths(m)) + mday - 1 val secs = sec + (min + (hour - 1 + days * 24) * 60) * 60 - if (secs < 0) None - else Option(secs) + Option(secs) } } diff --git a/src/main/scala/li/cil/oc/util/InventoryUtils.scala b/src/main/scala/li/cil/oc/util/InventoryUtils.scala index 0b031c7d8..b27e2154e 100644 --- a/src/main/scala/li/cil/oc/util/InventoryUtils.scala +++ b/src/main/scala/li/cil/oc/util/InventoryUtils.scala @@ -211,8 +211,8 @@ object InventoryUtils { * Utility method for calling insertIntoInventory on an inventory * in the world. */ - def insertIntoInventoryAt(stack: ItemStack, position: BlockPosition, side: EnumFacing, limit: Int = 64, simulate: Boolean = false): Boolean = - inventoryAt(position).exists(insertIntoInventory(stack, _, Option(side), limit, simulate)) + def insertIntoInventoryAt(stack: ItemStack, position: BlockPosition, side: Option[EnumFacing] = None, limit: Int = 64, simulate: Boolean = false): Boolean = + inventoryAt(position).exists(insertIntoInventory(stack, _, side, limit, simulate)) /** * Utility method for calling extractFromInventory on an inventory diff --git a/src/main/scala/li/cil/oc/util/RTree.scala b/src/main/scala/li/cil/oc/util/RTree.scala index 08355d98e..dc20b9424 100644 --- a/src/main/scala/li/cil/oc/util/RTree.scala +++ b/src/main/scala/li/cil/oc/util/RTree.scala @@ -12,13 +12,14 @@ class RTree[Data](private val M: Int)(implicit val coordinate: Data => (Double, private var root = new NonLeaf() - def apply(value: Data): Option[(Double, Double, Double)] = + def apply(value: Data): Option[(Double, Double, Double)] = this.synchronized { entries.get(value).fold(None: Option[(Double, Double, Double)])(position => Some(position.bounds.min.asTuple)) + } // Allows debug rendering of the tree. - def allBounds = root.allBounds(0) + def allBounds = this.synchronized(root.allBounds(0)) - def add(value: Data): Boolean = { + def add(value: Data): Boolean = this.synchronized { val replaced = remove(value) val entry = new Leaf(value, new Point(value)) entries += value -> entry @@ -29,7 +30,7 @@ class RTree[Data](private val M: Int)(implicit val coordinate: Data => (Double, !replaced } - def remove(value: Data): Boolean = + def remove(value: Data): Boolean = this.synchronized { entries.remove(value) match { case Some(node) => val change = root.remove(node) @@ -43,9 +44,11 @@ class RTree[Data](private val M: Int)(implicit val coordinate: Data => (Double, true case _ => false } + } - def query(from: (Double, Double, Double), to: (Double, Double, Double)) = + def query(from: (Double, Double, Double), to: (Double, Double, Double)) = this.synchronized { root.query(new Rectangle(new Point(from), new Point(to))) + } private abstract class Node { def bounds: Rectangle