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

Conflicts:
	build.gradle
	src/main/scala/li/cil/oc/client/renderer/tileentity/HologramRenderer.scala
	src/main/scala/li/cil/oc/common/Loot.scala
	src/main/scala/li/cil/oc/common/tileentity/traits/BundledRedstoneAware.scala
	src/main/scala/li/cil/oc/common/tileentity/traits/RedstoneAware.scala
	src/main/scala/li/cil/oc/common/tileentity/traits/TileEntity.scala
	src/main/scala/li/cil/oc/integration/Mods.scala
	src/main/scala/li/cil/oc/util/Audio.scala
This commit is contained in:
Florian Nücke 2015-04-30 12:47:33 +02:00
commit 852c5b18db
46 changed files with 770 additions and 209 deletions

View File

@ -83,10 +83,26 @@ repositories {
name = "bc" name = "bc"
url = "http://mod-buildcraft.com/" url = "http://mod-buildcraft.com/"
} }
maven {
name = "BluePower"
url = "http://maven.bluepowermod.com/"
}
maven {
name = "chickenbones"
url = "http://chickenbones.net/maven/"
}
maven { maven {
name = "ic2, forestry" name = "ic2, forestry"
url = "http://maven.ic2.player.to/" url = "http://maven.ic2.player.to/"
} }
maven {
name = "IGW"
url = "http://maven.k-4u.nl/"
}
maven {
name = "mobius"
url = "http://mobiusstrip.eu/maven"
}
maven { maven {
name = "ue" name = "ue"
url = "http://calclavia.com/maven/" url = "http://calclavia.com/maven/"
@ -161,11 +177,15 @@ dependencies {
provided "codechicken:EnderStorage:${config.minecraft.version}-${config.es.version}:dev" provided "codechicken:EnderStorage:${config.minecraft.version}-${config.es.version}:dev"
provided "codechicken:ForgeMultipart:${config.minecraft.version}-${config.fmp.version}:dev" provided "codechicken:ForgeMultipart:${config.minecraft.version}-${config.fmp.version}:dev"
provided "codechicken:WR-CBE:${config.minecraft.version}-${config.wrcbe.version}:dev" provided "codechicken:WR-CBE:${config.minecraft.version}-${config.wrcbe.version}:dev"
provided "com.bluepowermod:BluePower:${config.bluepower.version}:deobf"
provided "com.gregoriust.gregtech:gregtech_${config.minecraft.version}:${config.gt.version}:dev" provided "com.gregoriust.gregtech:gregtech_${config.minecraft.version}:${config.gt.version}:dev"
provided "com.mod-buildcraft:buildcraft:${config.bc.version}:dev" provided "com.mod-buildcraft:buildcraft:${config.bc.version}:dev"
provided "dev.calclavia.resonantengine:resonant-engine:${config.re.version}:dev" provided "dev.calclavia.resonantengine:resonant-engine:${config.re.version}:dev"
provided "igwmod:IGW-Mod-1.7.10:${config.igwmod.version}:userdev"
provided "mcp.mobius.waila:Waila:${config.waila.version}_${config.minecraft.version}:dev"
provided "net.industrial-craft:industrialcraft-2:${config.ic2.version}:dev" provided "net.industrial-craft:industrialcraft-2:${config.ic2.version}:dev"
provided "net.sengir.forestry:forestry_${config.minecraft.version}:${config.forestry.version}:dev" provided "net.sengir.forestry:forestry_${config.minecraft.version}:${config.forestry.version}:dev"
provided "qmunity:QmunityLib:${config.qmunitylib.version}:deobf"
provided "tmech:TMechworks:${config.minecraft.version}-${config.tmech.version}:deobf" provided "tmech:TMechworks:${config.minecraft.version}-${config.tmech.version}:deobf"
provided name: 'GalacticraftCoreAll', version: config.gc.version, ext: 'jar' provided name: 'GalacticraftCoreAll', version: config.gc.version, ext: 'jar'
@ -226,7 +246,6 @@ minecraft {
// stable_# stables are built at the discretion of the MCP team. // stable_# stables are built at the discretion of the MCP team.
mappings = "snapshot_20141130" mappings = "snapshot_20141130"
replaceIn "li/cil/oc/OpenComputers.scala"
replace "@VERSION@", project.simpleVersion replace "@VERSION@", project.simpleVersion
} }

View File

@ -8,6 +8,7 @@ ae2.version=rv2-beta-26
bc.version=6.4.9 bc.version=6.4.9
bloodmagic.cf=2223/203 bloodmagic.cf=2223/203
bloodmagic.version=1.3.0a-1 bloodmagic.version=1.3.0a-1
bluepower.version=0.2.928
cc.cf=2216/236 cc.cf=2216/236
cc.version=1.65 cc.version=1.65
ccc.version=1.0.5.34 ccc.version=1.0.5.34
@ -23,12 +24,14 @@ gc.build=3
gc.version=3.0.7 gc.version=3.0.7
gt.version=5.04.06 gt.version=5.04.06
ic2.version=2.2.654-experimental ic2.version=2.2.654-experimental
igwmod.version=1.1.3-18
mekanism.build=5 mekanism.build=5
mekanism.version=7.1.2 mekanism.version=7.1.2
mfr.cf=2229/626 mfr.cf=2229/626
mfr.version=[1.7.10]2.8.0RC8-86 mfr.version=[1.7.10]2.8.0RC8-86
nei.version=1.0.5.82 nei.version=1.0.5.82
projred.version=4.5.8.59 projred.version=4.5.8.59
qmunitylib.version=0.1.105
rc.cf=2219/321 rc.cf=2219/321
rc.version=1.7.10-9.4.0.0 rc.version=1.7.10-9.4.0.0
redlogic.version=59.0.3 redlogic.version=59.0.3

View File

@ -1,11 +1,6 @@
package li.cil.oc.api; package li.cil.oc.api;
import li.cil.oc.api.detail.DriverAPI; import li.cil.oc.api.detail.*;
import li.cil.oc.api.detail.FileSystemAPI;
import li.cil.oc.api.detail.ItemAPI;
import li.cil.oc.api.detail.MachineAPI;
import li.cil.oc.api.detail.ManualAPI;
import li.cil.oc.api.detail.NetworkAPI;
/** /**
* Central reference for the API. * Central reference for the API.
@ -16,7 +11,7 @@ import li.cil.oc.api.detail.NetworkAPI;
*/ */
public class API { public class API {
public static final String ID_OWNER = "OpenComputers|Core"; public static final String ID_OWNER = "OpenComputers|Core";
public static final String VERSION = "5.2.2"; public static final String VERSION = "5.2.3";
public static DriverAPI driver = null; public static DriverAPI driver = null;
public static FileSystemAPI fileSystem = null; public static FileSystemAPI fileSystem = null;

View File

@ -141,6 +141,51 @@ public interface Machine extends ManagedEnvironment, Context {
*/ */
double cpuTime(); double cpuTime();
// ----------------------------------------------------------------------- //
/**
* Play a sound using the machine's built-in speaker.
* <p/>
* This is what's used to emit beep codes when an error occurs while trying
* to start the computer, for example, and what's used for playing sounds
* when <tt>computer.beep</tt> is called.
* <p/>
* Be responsible in how you limit calls to this, as each call will cause
* a packet to be sent to all nearby clients, and will cause the receiving
* clients to generate the required sound sample on-the-fly. It is
* therefore recommended to not call this too frequently, and to limit the
* length of the sound to something relatively short (not longer than a few
* seconds at most).
* <p/>
* The audio will be played at the machine's host's location.
*
* @param frequency the frequency of the tone to generate.
* @param duration the duration of the tone to generate, in milliseconds.
*/
void beep(short frequency, short duration);
/**
* Utility method for playing beep codes.
* <p/>
* The underlying functionality is similar to that of {@link #beep(short, short)},
* except that this will play tones at a fixed frequency, and two different
* durations - in a pattern as defined in the passed string.
* <p/>
* This is useful for generating beep codes, such as for boot errors. It
* has the advantage of only generating a single network packet, and
* generating a single, longer sound sample for the full pattern. As such
* the same considerations should be made as for {@link #beep(short, short)},
* i.e. prefer not to use overly long patterns.
* <p/>
* The passed pattern must consist of dots (<tt>.</tt>) and dashes (<tt>-</tt>),
* where a dot is short tone, and a dash is a long tone.
* <p/>
* The audio will be played at the machine's host's location.
*
* @param pattern the beep pattern to play.
*/
void beep(String pattern);
/** /**
* Crashes the computer. * Crashes the computer.
* <p/> * <p/>
@ -221,6 +266,8 @@ public interface Machine extends ManagedEnvironment, Context {
*/ */
Object[] invoke(Value value, String method, Object[] args) throws Exception; Object[] invoke(Value value, String method, Object[] args) throws Exception;
// ----------------------------------------------------------------------- //
/** /**
* The list of users registered on this machine. * The list of users registered on this machine.
* <p/> * <p/>

View File

@ -6,6 +6,6 @@
3D prints can be recycled by putting them as input into a [3D printer](printer.md). This will re-use some of the [chamelium](../item/chamelium.md) that was used to print them. Color that was used to print the model will not be recycled. 3D prints can be recycled by putting them as input into a [3D printer](printer.md). This will re-use some of the [chamelium](../item/chamelium.md) that was used to print them. Color that was used to print the model will not be recycled.
Holding the key for OpenComputers' extended tooltips (default is [Shift]), a print's active state will be shown, if any. Holding the key for OpenComputers' extended tooltips (default is `Shift`), a print's active state will be shown, if any.
Printed blocks are also Forge MultiPart compatible. If present, multiple prints can be placed into a single block-space, unless they do not collide, and the total number of shapes in the block-space does not exceed the limit for a single model. Due to the nature of Forge MultiPart, prints can therefore also be placed into the same block-space as any other Forge MultiPart compatible block, such as torches, levers, cables or red alloy wires from Project Red, for example. Printed blocks are also Forge MultiPart compatible. If present, multiple prints can be placed into a single block-space, unless they do not collide, and the total number of shapes in the block-space does not exceed the limit for a single model. Due to the nature of Forge MultiPart, prints can therefore also be placed into the same block-space as any other Forge MultiPart compatible block, such as torches, levers, cables or red alloy wires from Project Red, for example.

View File

@ -6,6 +6,6 @@
В дополнение к этому, точки доступа могут использоваться как повторители: они могут перенаправлять сообщения из проводной линии другим устройствам; или беспроводные сообщения как проводные, так и беспроводные. В дополнение к этому, точки доступа могут использоваться как повторители: они могут перенаправлять сообщения из проводной линии другим устройствам; или беспроводные сообщения как проводные, так и беспроводные.
Коммутаторы и [коммутаторы](switch.md) *не* отслеживают, какие пакеты и куда они передали, поэтому в сети могут образовываться петли или вы можете получать одно сообщение несколько раз. Из-за ограниченного буфера сообщений коммутатора, частое отправление сообщений приводит к их потере. Вы можете улучшить [коммутатор](switch.md) или точку доступа для увеличения скорости обработки сообщений, а также увеличения размера сообщений. Точки доступа и [коммутаторы](switch.md) *не* отслеживают, какие пакеты и куда они передали, поэтому в сети могут образовываться петли или вы можете получать одно сообщение несколько раз. Из-за ограниченного буфера сообщений коммутатора, частое отправление сообщений приводит к их потере. Вы можете улучшить [коммутатор](switch.md) или точку доступа для увеличения скорости обработки сообщений, а также увеличения размера сообщений.
Сообщения, могут перенаправлены всего несколько раз, поэтому цепочки с произвольным количеством коммутаторов или точек доступа невозможны. По умолчанию, сообщение может быть перенаправлено пять раз. Сообщения, могут перенаправлены всего несколько раз, поэтому цепочки с произвольным количеством коммутаторов или точек доступа невозможны. По умолчанию, сообщение может быть перенаправлено пять раз.

View File

@ -0,0 +1,9 @@
# Путевая точка
!["В этом направлении!" - "Нет, в этом!"](oredict:oc:waypoint)
Главное не что это такое, а как это использовать. [Навигационное улучшение](../item/navigationUpgrade.md) может обнаруживать путевые точки, что позволяет устройствам с этим улучшением ориентироваться в игровом мире. Это можно использовать для написания программ для [роботов](robot.md) и [дронов](../item/drone.md).
Обратите внимание, что актуальным местоположением считается *блок перед путевой точкой* (выделен с помощью частиц), именно это местоположение будет передано, при запросе его навигационным улучшением. Это позволяет поместить путевую точку рядом или над сундуком и позволит обратиться к путевой точке "над сундуком", без необходимости вращения самой точки.
Путевая точка имеет два параметра, которые могут быть использованы при ее опросе навигационным улучшением: уровень редстоун сигнала, который получает точка и изменяемое имя. Имя это строка, состоящая из 32 символов, оно может быть изменено через интерфейс или через API. Эти два параметра могут быть использованы устройством, для определения, что можно сделать с путевой точкой. Например, сортировочная программа может использовать блоки с высоким уровнем редстоун сигнала как входные, а с низким как выходные.

View File

@ -4,4 +4,6 @@
Данное улучшение добавляет навигацию и ориентацию для устройств. Получаемые координаты начинаются от центра карты, где было собрано улучшение, радиус функционирования зависит от размера карты. Данное улучшение добавляет навигацию и ориентацию для устройств. Получаемые координаты начинаются от центра карты, где было собрано улучшение, радиус функционирования зависит от размера карты.
Карта внутри улучшения может быть обновлена, повторным крафтом улучшения с новой картой. Старая карта при этом будет возвращена игроку. Карта внутри улучшения может быть обновлена, повторным крафтом улучшения с новой картой. Старая карта при этом будет возвращена игроку.
Наиболее эффективно это улучшение работает в паре с одной или несколькими [точками доступа](../block/waypoint.md).

View File

@ -35,6 +35,7 @@ tile.oc.screen2.name=Монитор (2-ой уровень)
tile.oc.screen3.name=Монитор (3-ий уровень) tile.oc.screen3.name=Монитор (3-ий уровень)
tile.oc.serverRack.name=Серверная стойка tile.oc.serverRack.name=Серверная стойка
tile.oc.switch.name=Коммутатор tile.oc.switch.name=Коммутатор
tile.oc.waypoint.name=Путевая точка
# Items # Items
item.oc.AbstractBusCard.name=Карта абстрактной шины item.oc.AbstractBusCard.name=Карта абстрактной шины
@ -133,6 +134,7 @@ item.oc.UpgradeSolarGenerator.name=Улучшение "Солнечный ген
item.oc.UpgradeTank.name=Улучшение "Бак для жидкостей" item.oc.UpgradeTank.name=Улучшение "Бак для жидкостей"
item.oc.UpgradeTankController.name=Улучшение "Контроллер бака" item.oc.UpgradeTankController.name=Улучшение "Контроллер бака"
item.oc.UpgradeTractorBeam.name=Улучшение "Притягивающий луч" item.oc.UpgradeTractorBeam.name=Улучшение "Притягивающий луч"
oc:tooltip.Waypoint=Добавляет путевую точку для устройств с навигационным улучшением.
item.oc.WirelessNetworkCard.name=Плата беспроводной сети item.oc.WirelessNetworkCard.name=Плата беспроводной сети
item.oc.WorldSensorCard.name=Карта-мировой сенсор item.oc.WorldSensorCard.name=Карта-мировой сенсор
item.oc.wrench.name=Ключ item.oc.wrench.name=Ключ

View File

@ -2,15 +2,21 @@ local event = require "event"
local component = require "component" local component = require "component"
local keyboard = require "keyboard" local keyboard = require "keyboard"
local args = {...}
local interactive = io.output() == io.stdout local interactive = io.output() == io.stdout
local color, isPal, evt local color, isPal, evt
if interactive then if interactive then
color, isPal = component.gpu.getForeground() color, isPal = component.gpu.getForeground()
end end
io.write("Press 'q' to exit\n") io.write("Press 'Ctrl-C' to exit\n")
pcall(function() pcall(function()
repeat repeat
evt = table.pack(event.pull()) if #args > 0 then
evt = table.pack(event.pullMultiple("interrupted", table.unpack(args)))
else
evt = table.pack(event.pull())
end
if interactive then component.gpu.setForeground(0xCC2200) end if interactive then component.gpu.setForeground(0xCC2200) end
io.write("[" .. os.date("%T") .. "] ") io.write("[" .. os.date("%T") .. "] ")
if interactive then component.gpu.setForeground(0x44CC00) end if interactive then component.gpu.setForeground(0x44CC00) end
@ -25,7 +31,7 @@ pcall(function()
end end
io.write("\n") io.write("\n")
until evt[1] == "key_down" and evt[4] == keyboard.keys.q until evt[1] == "interrupted"
end) end)
if interactive then if interactive then
component.gpu.setForeground(color, isPal) component.gpu.setForeground(color, isPal)

View File

@ -4,19 +4,6 @@ local keyboard = require("keyboard")
local event, listeners, timers = {}, {}, {} local event, listeners, timers = {}, {}, {}
local lastInterrupt = -math.huge local lastInterrupt = -math.huge
local function matches(signal, name, filter)
if name and not (type(signal[1]) == "string" and signal[1]:match(name))
then
return false
end
for i = 1, filter.n do
if filter[i] ~= nil and filter[i] ~= signal[i + 1] then
return false
end
end
return true
end
local function call(callback, ...) local function call(callback, ...)
local result, message = pcall(callback, ...) local result, message = pcall(callback, ...)
if not result and type(event.onError) == "function" then if not result and type(event.onError) == "function" then
@ -64,6 +51,45 @@ local function tick()
end end
end end
local function createPlainFilter(name, ...)
local filter = table.pack(...)
if name == nil and filter.n == 0 then
return nil
end
return function(...)
local signal = table.pack(...)
if name and not (type(signal[1]) == "string" and signal[1]:match(name)) then
return false
end
for i = 1, filter.n do
if filter[i] ~= nil and filter[i] ~= signal[i + 1] then
return false
end
end
return true
end
end
local function createMultipleFilter(...)
local filter = table.pack(...)
if filter.n == 0 then
return nil
end
return function(...)
local signal = table.pack(...)
if type(signal[1]) ~= "string" then
return false
end
for i = 1, filter.n do
if filter[i] ~= nil and signal[1]:match(filter[i]) then
return true
end
end
return false
end
end
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
function event.cancel(timerId) function event.cancel(timerId)
@ -118,28 +144,50 @@ end
function event.pull(...) function event.pull(...)
local args = table.pack(...) local args = table.pack(...)
local seconds, name, filter
if type(args[1]) == "string" then if type(args[1]) == "string" then
name = args[1] return event.pullFiltered(createPlainFilter(...))
filter = table.pack(table.unpack(args, 2, args.n))
else else
checkArg(1, args[1], "number", "nil") checkArg(1, args[1], "number", "nil")
checkArg(2, args[2], "string", "nil") checkArg(2, args[2], "string", "nil")
seconds = args[1] return event.pullFiltered(args[1], createPlainFilter(select(2, ...)))
name = args[2]
filter = table.pack(table.unpack(args, 3, args.n))
end end
end
local hasFilter = name ~= nil function event.pullMultiple(...)
if not hasFilter then local seconds
for i = 1, filter.n do local args
hasFilter = hasFilter or filter[i] ~= nil if type(...) == "number" then
seconds = ...
args = table.pack(select(2,...))
for i=1,args.n do
checkArg(i+1, args[i], "string", "nil")
end end
else
args = table.pack(...)
for i=1,args.n do
checkArg(i, args[i], "string", "nil")
end
end
return event.pullFiltered(seconds, createMultipleFilter(table.unpack(args, 1, args.n)))
end
function event.pullFiltered(...)
local args = table.pack(...)
local seconds, filter
if type(args[1]) == "function" then
filter = args[1]
else
checkArg(1, args[1], "number", "nil")
checkArg(2, args[2], "function", "nil")
seconds = args[1]
filter = args[2]
end end
local deadline = seconds and local deadline = seconds and
(computer.uptime() + seconds) or (computer.uptime() + seconds) or
(hasFilter and math.huge or 0) (filter and math.huge or 0)
repeat repeat
local closest = seconds and deadline or math.huge local closest = seconds and deadline or math.huge
for _, timer in pairs(timers) do for _, timer in pairs(timers) do
@ -154,9 +202,15 @@ function event.pull(...)
lastInterrupt = computer.uptime() lastInterrupt = computer.uptime()
error("interrupted", 0) error("interrupted", 0)
end end
if not (seconds or hasFilter) or matches(signal, name, filter) then if event.shouldSoftInterrupt() and (filter == nil or filter("interrupted", computer.uptime() - lastInterrupt)) then
local awaited = computer.uptime() - lastInterrupt
lastInterrupt = computer.uptime()
return "interrupted", awaited
end
if not (seconds or filter) or filter == nil or filter(table.unpack(signal, 1, signal.n)) then
return table.unpack(signal, 1, signal.n) return table.unpack(signal, 1, signal.n)
end end
until computer.uptime() >= deadline until computer.uptime() >= deadline
end end
@ -167,6 +221,12 @@ function event.shouldInterrupt()
keyboard.isKeyDown(keyboard.keys.c) keyboard.isKeyDown(keyboard.keys.c)
end end
function event.shouldSoftInterrupt()
return computer.uptime() - lastInterrupt > 1 and
keyboard.isControlDown() and
keyboard.isKeyDown(keyboard.keys.c)
end
function event.timer(interval, callback, times) function event.timer(interval, callback, times)
checkArg(1, interval, "number") checkArg(1, interval, "number")
checkArg(2, callback, "function") checkArg(2, callback, "function")

View File

@ -2,5 +2,12 @@ NAME
dmesg - display messages(events) dmesg - display messages(events)
SYNOPIS SYNOPIS
dmesg dmesg [EVENT]...
EXAMPLES
dmesg
Shows all events.
dmesg touch
Shows only "touch" events.

View File

@ -888,6 +888,26 @@ sandbox = {
}, },
debug = { debug = {
getinfo = function(...)
local result = debug.getinfo(...)
if result then
-- Only make primitive information available in the sandbox.
return {
source = result.source,
short_src = result.short_src,
linedefined = result.linedefined,
lastlinedefined = result.lastlinedefined,
what = result.what,
currentline = result.currentline,
nups = result.nups,
nparams = result.nparams,
isvararg = result.isvararg,
name = result.name,
namewhat = result.namewhat,
istailcall = result.istailcall
}
end
end,
traceback = debug.traceback traceback = debug.traceback
}, },

View File

@ -0,0 +1,5 @@
package li.cil.oc.client.renderer.markdown
object MarkupFormat extends Enumeration {
val Markdown, IGWMod = Value
}

View File

@ -1,6 +1,7 @@
package li.cil.oc.client.renderer.markdown.segment package li.cil.oc.client.renderer.markdown.segment
import li.cil.oc.client.renderer.markdown.Document import li.cil.oc.client.renderer.markdown.Document
import li.cil.oc.client.renderer.markdown.MarkupFormat
import net.minecraft.client.gui.FontRenderer import net.minecraft.client.gui.FontRenderer
trait BasicTextSegment extends Segment { trait BasicTextSegment extends Segment {
@ -38,6 +39,8 @@ trait BasicTextSegment extends Segment {
lines * lineHeight(renderer) lines * lineHeight(renderer)
} }
override def toString(format: MarkupFormat.Value): String = text
// ----------------------------------------------------------------------- // // ----------------------------------------------------------------------- //
protected def text: String protected def text: String

View File

@ -1,9 +1,13 @@
package li.cil.oc.client.renderer.markdown.segment package li.cil.oc.client.renderer.markdown.segment
import li.cil.oc.client.renderer.markdown.MarkupFormat
import net.minecraft.util.EnumChatFormatting import net.minecraft.util.EnumChatFormatting
private[markdown] class BoldSegment(parent: Segment, text: String) extends TextSegment(parent, text) { private[markdown] class BoldSegment(parent: Segment, text: String) extends TextSegment(parent, text) {
override protected def format = EnumChatFormatting.BOLD.toString override protected def format = EnumChatFormatting.BOLD.toString
override def toString: String = s"{BoldSegment: text = $text}" override def toString(format: MarkupFormat.Value): String = format match {
case MarkupFormat.Markdown => s"**$text**"
case MarkupFormat.IGWMod => s"[prefix{l}]$text [prefix{}]"
}
} }

View File

@ -1,6 +1,7 @@
package li.cil.oc.client.renderer.markdown.segment package li.cil.oc.client.renderer.markdown.segment
import li.cil.oc.client.renderer.TextBufferRenderCache import li.cil.oc.client.renderer.TextBufferRenderCache
import li.cil.oc.client.renderer.markdown.MarkupFormat
import net.minecraft.client.gui.FontRenderer import net.minecraft.client.gui.FontRenderer
import org.lwjgl.opengl.GL11 import org.lwjgl.opengl.GL11
@ -30,5 +31,8 @@ private[markdown] class CodeSegment(val parent: Segment, val text: String) exten
override protected def stringWidth(s: String, renderer: FontRenderer): Int = s.length * TextBufferRenderCache.renderer.charRenderWidth override protected def stringWidth(s: String, renderer: FontRenderer): Int = s.length * TextBufferRenderCache.renderer.charRenderWidth
override def toString: String = s"{CodeSegment: text = $text}" override def toString(format: MarkupFormat.Value): String = format match {
case MarkupFormat.Markdown => s"`$text`"
case MarkupFormat.IGWMod => s"[prefix{1}]$text [prefix{}]"
}
} }

View File

@ -1,5 +1,6 @@
package li.cil.oc.client.renderer.markdown.segment package li.cil.oc.client.renderer.markdown.segment
import li.cil.oc.client.renderer.markdown.MarkupFormat
import net.minecraft.util.EnumChatFormatting import net.minecraft.util.EnumChatFormatting
private[markdown] class HeaderSegment(parent: Segment, text: String, val level: Int) extends TextSegment(parent, text) { private[markdown] class HeaderSegment(parent: Segment, text: String, val level: Int) extends TextSegment(parent, text) {
@ -9,5 +10,8 @@ private[markdown] class HeaderSegment(parent: Segment, text: String, val level:
override protected def format = EnumChatFormatting.UNDERLINE.toString override protected def format = EnumChatFormatting.UNDERLINE.toString
override def toString: String = s"{HeaderSegment: text = $text, level = $level}" override def toString(format: MarkupFormat.Value): String = format match {
case MarkupFormat.Markdown => s"${"#" * level} $text"
case MarkupFormat.IGWMod => s"[prefix{l}]$text [prefix{}]"
}
} }

View File

@ -1,9 +1,13 @@
package li.cil.oc.client.renderer.markdown.segment package li.cil.oc.client.renderer.markdown.segment
import li.cil.oc.client.renderer.markdown.MarkupFormat
import net.minecraft.util.EnumChatFormatting import net.minecraft.util.EnumChatFormatting
private[markdown] class ItalicSegment(parent: Segment, text: String) extends TextSegment(parent, text) { private[markdown] class ItalicSegment(parent: Segment, text: String) extends TextSegment(parent, text) {
override protected def format = EnumChatFormatting.ITALIC.toString override protected def format = EnumChatFormatting.ITALIC.toString
override def toString: String = s"{ItalicSegment: text = $text}" override def toString(format: MarkupFormat.Value): String = format match {
case MarkupFormat.Markdown => s"*$text*"
case MarkupFormat.IGWMod => s"[prefix{o}]$text [prefix{}]"
}
} }

View File

@ -3,8 +3,10 @@ package li.cil.oc.client.renderer.markdown.segment
import java.net.URI import java.net.URI
import li.cil.oc.Localization import li.cil.oc.Localization
import li.cil.oc.OpenComputers
import li.cil.oc.api import li.cil.oc.api
import li.cil.oc.client.Manual import li.cil.oc.client.Manual
import li.cil.oc.client.renderer.markdown.MarkupFormat
import net.minecraft.client.Minecraft import net.minecraft.client.Minecraft
private[markdown] class LinkSegment(parent: Segment, text: String, val url: String) extends TextSegment(parent, text) with InteractiveSegment { private[markdown] class LinkSegment(parent: Segment, text: String, val url: String) extends TextSegment(parent, text) with InteractiveSegment {
@ -54,5 +56,10 @@ private[markdown] class LinkSegment(parent: Segment, text: String, val url: Stri
} }
} }
override def toString: String = s"{LinkSegment: text = $text, url = $url}" override def toString(format: MarkupFormat.Value): String = format match {
case MarkupFormat.Markdown => s"[$text]($url)"
case MarkupFormat.IGWMod =>
if (url.startsWith("http://") || url.startsWith("https://")) text
else s"[link{${OpenComputers.ID}:$url}]$text [link{}]"
}
} }

View File

@ -3,6 +3,7 @@ package li.cil.oc.client.renderer.markdown.segment
import li.cil.oc.api.manual.ImageRenderer import li.cil.oc.api.manual.ImageRenderer
import li.cil.oc.api.manual.InteractiveImageRenderer import li.cil.oc.api.manual.InteractiveImageRenderer
import li.cil.oc.client.renderer.markdown.Document import li.cil.oc.client.renderer.markdown.Document
import li.cil.oc.client.renderer.markdown.MarkupFormat
import net.minecraft.client.gui.FontRenderer import net.minecraft.client.gui.FontRenderer
import org.lwjgl.opengl.GL11 import org.lwjgl.opengl.GL11
@ -74,5 +75,8 @@ private[markdown] class RenderSegment(val parent: Segment, val title: String, va
hovered hovered
} }
override def toString: String = s"{RendererSegment: title = $title, imageRenderer = $imageRenderer}" override def toString(format: MarkupFormat.Value): String = format match {
case MarkupFormat.Markdown => s"![$title]($imageRenderer)"
case MarkupFormat.IGWMod => "(Sorry, images only work in the OpenComputers manual for now.)" // TODO
}
} }

View File

@ -1,8 +1,10 @@
package li.cil.oc.client.renderer.markdown.segment package li.cil.oc.client.renderer.markdown.segment
import li.cil.oc.client.renderer.markdown.MarkupFormat
import net.minecraft.client.gui.FontRenderer import net.minecraft.client.gui.FontRenderer
import scala.annotation.tailrec import scala.annotation.tailrec
import scala.collection.mutable
import scala.util.matching.Regex import scala.util.matching.Regex
trait Segment { trait Segment {
@ -46,6 +48,25 @@ trait Segment {
*/ */
def render(x: Int, y: Int, indent: Int, maxWidth: Int, renderer: FontRenderer, mouseX: Int, mouseY: Int): Option[InteractiveSegment] = None def render(x: Int, y: Int, indent: Int, maxWidth: Int, renderer: FontRenderer, mouseX: Int, mouseY: Int): Option[InteractiveSegment] = None
def renderAsText(format: MarkupFormat.Value): Iterable[String] = {
var segment = this
val result = mutable.Buffer.empty[String]
val builder = mutable.StringBuilder.newBuilder
while (segment != null) {
builder.append(segment.toString(format))
if (segment.isLast) {
result += builder.toString()
builder.clear()
}
segment = segment.next
}
result.toIterable
}
def toString(format: MarkupFormat.Value): String
override def toString: String = toString(MarkupFormat.Markdown)
// ----------------------------------------------------------------------- // // ----------------------------------------------------------------------- //
// Used during construction, checks a segment for inner segments. // Used during construction, checks a segment for inner segments.

View File

@ -1,9 +1,13 @@
package li.cil.oc.client.renderer.markdown.segment package li.cil.oc.client.renderer.markdown.segment
import li.cil.oc.client.renderer.markdown.MarkupFormat
import net.minecraft.util.EnumChatFormatting import net.minecraft.util.EnumChatFormatting
private[markdown] class StrikethroughSegment(parent: Segment, text: String) extends TextSegment(parent, text) { private[markdown] class StrikethroughSegment(parent: Segment, text: String) extends TextSegment(parent, text) {
override protected def format = EnumChatFormatting.STRIKETHROUGH.toString override protected def format = EnumChatFormatting.STRIKETHROUGH.toString
override def toString: String = s"{StrikethroughSegment: text = $text}" override def toString(format: MarkupFormat.Value): String = format match {
case MarkupFormat.Markdown => s"~~$text~~"
case MarkupFormat.IGWMod => s"[prefix{m}]$text [prefix{}]"
}
} }

View File

@ -96,6 +96,4 @@ private[markdown] class TextSegment(val parent: Segment, val text: String) exten
case _ => None case _ => None
} }
} }
override def toString: String = s"{TextSegment: text = $text}"
} }

View File

@ -57,7 +57,18 @@ object HologramRenderer extends TileEntitySpecialRenderer with Callable[Int] wit
/** Used to pass the current screen along to call(). */ /** Used to pass the current screen along to call(). */
private var hologram: Hologram = null private var hologram: Hologram = null
/**
* Whether initialization failed (e.g. due to an out of memory error) and we
* should render using the fallback renderer instead.
*/
private var failed = false
override def renderTileEntityAt(tileEntity: TileEntity, x: Double, y: Double, z: Double, f: Float, damage: Int) { override def renderTileEntityAt(tileEntity: TileEntity, x: Double, y: Double, z: Double, f: Float, damage: Int) {
if (failed) {
HologramRendererFallback.renderTileEntityAt(tileEntity, x, y, z, f, damage)
return
}
RenderState.checkError(getClass.getName + ".renderTileEntityAt: entering (aka: wasntme)") RenderState.checkError(getClass.getName + ".renderTileEntityAt: entering (aka: wasntme)")
hologram = tileEntity.asInstanceOf[Hologram] hologram = tileEntity.asInstanceOf[Hologram]
@ -143,12 +154,13 @@ object HologramRenderer extends TileEntitySpecialRenderer with Callable[Int] wit
} }
def draw(glBuffer: Int) { def draw(glBuffer: Int) {
initialize() if (initialize()) {
validate(glBuffer) validate(glBuffer)
publish(glBuffer) publish(glBuffer)
}
} }
private def initialize() { private def initialize(): Boolean = !failed && (try {
// First run only, create structure information. // First run only, create structure information.
if (commonBuffer == 0) { if (commonBuffer == 0) {
dataBuffer = BufferUtils.createIntBuffer(hologram.width * hologram.width * hologram.height * 6 * 4 * 2) dataBuffer = BufferUtils.createIntBuffer(hologram.width * hologram.width * hologram.height * 6 * 4 * 2)
@ -223,7 +235,14 @@ object HologramRenderer extends TileEntitySpecialRenderer with Callable[Int] wit
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, commonBuffer) GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, commonBuffer)
GL15.glBufferData(GL15.GL_ARRAY_BUFFER, data, GL15.GL_STATIC_DRAW) GL15.glBufferData(GL15.GL_ARRAY_BUFFER, data, GL15.GL_STATIC_DRAW)
} }
true
} }
catch {
case oom: OutOfMemoryError =>
HologramRendererFallback.text = "Not enough memory"
failed = true
false
})
private def validate(glBuffer: Int) { private def validate(glBuffer: Int) {
// Refresh indexes when the hologram's data changed. // Refresh indexes when the hologram's data changed.

View File

@ -7,7 +7,7 @@ import net.minecraft.tileentity.TileEntity
import org.lwjgl.opengl.GL11 import org.lwjgl.opengl.GL11
object HologramRendererFallback extends TileEntitySpecialRenderer { object HologramRendererFallback extends TileEntitySpecialRenderer {
val text = "Requires OpenGL 1.5" var text = "Requires OpenGL 1.5"
override def renderTileEntityAt(tileEntity: TileEntity, x: Double, y: Double, z: Double, f: Float, damage: Int) { override def renderTileEntityAt(tileEntity: TileEntity, x: Double, y: Double, z: Double, f: Float, damage: Int) {
RenderState.checkError(getClass.getName + ".renderTileEntityAt: entering (aka: wasntme)") RenderState.checkError(getClass.getName + ".renderTileEntityAt: entering (aka: wasntme)")

View File

@ -124,6 +124,6 @@ object Loot extends WeightedRandomChestContent(new ItemStack(null: Item), 1, 1,
case Some(disk) => case Some(disk) =>
ChestGenHooks.generateStacks(random, disk, ChestGenHooks.generateStacks(random, disk,
theMinimumChanceToGenerateItem, theMaximumChanceToGenerateItem) theMinimumChanceToGenerateItem, theMaximumChanceToGenerateItem)
case _ => Array.empty case _ => Array.empty[ItemStack]
} }
} }

View File

@ -31,9 +31,9 @@ import net.minecraftforge.fml.common.registry.GameRegistry
import scala.collection.mutable import scala.collection.mutable
object Items extends ItemAPI { object Items extends ItemAPI {
private val descriptors = mutable.Map.empty[String, ItemInfo] val descriptors = mutable.Map.empty[String, ItemInfo]
private val names = mutable.Map.empty[Any, String] val names = mutable.Map.empty[Any, String]
override def get(name: String): ItemInfo = descriptors.get(name).orNull override def get(name: String): ItemInfo = descriptors.get(name).orNull

View File

@ -16,6 +16,7 @@ import net.minecraft.world.World
@Injectable.InterfaceList(Array( @Injectable.InterfaceList(Array(
new Injectable.Interface(value = "appeng.api.implementations.items.IAEWrench", modid = Mods.IDs.AppliedEnergistics2), new Injectable.Interface(value = "appeng.api.implementations.items.IAEWrench", modid = Mods.IDs.AppliedEnergistics2),
new Injectable.Interface(value = "buildcraft.api.tools.IToolWrench", modid = Mods.IDs.BuildCraftTools), new Injectable.Interface(value = "buildcraft.api.tools.IToolWrench", modid = Mods.IDs.BuildCraftTools),
new Injectable.Interface(value = "com.bluepowermod.api.misc.IScrewdriver", modid = Mods.IDs.BluePower),
new Injectable.Interface(value = "cofh.api.item.IToolHammer", modid = Mods.IDs.CoFHItem), new Injectable.Interface(value = "cofh.api.item.IToolHammer", modid = Mods.IDs.CoFHItem),
new Injectable.Interface(value = "crazypants.enderio.tool.ITool", modid = Mods.IDs.EnderIO), new Injectable.Interface(value = "crazypants.enderio.tool.ITool", modid = Mods.IDs.EnderIO),
new Injectable.Interface(value = "mekanism.api.IMekWrench", modid = Mods.IDs.Mekanism), new Injectable.Interface(value = "mekanism.api.IMekWrench", modid = Mods.IDs.Mekanism),
@ -49,6 +50,9 @@ class Wrench extends SimpleItem with api.internal.Wrench {
def canWrench(stack: ItemStack, player: EntityPlayer, pos: BlockPos): Boolean = true def canWrench(stack: ItemStack, player: EntityPlayer, pos: BlockPos): Boolean = true
// BluePower
def damage(stack: ItemStack, damage: Int, player: EntityPlayer, simulated: Boolean): Boolean = damage == 0
// BuildCraft // BuildCraft
def canWrench(player: EntityPlayer, pos: BlockPos): Boolean = true def canWrench(player: EntityPlayer, pos: BlockPos): Boolean = true

View File

@ -2,17 +2,16 @@ package li.cil.oc.common.tileentity.traits
import li.cil.oc.Settings import li.cil.oc.Settings
import li.cil.oc.integration.Mods import li.cil.oc.integration.Mods
import li.cil.oc.integration.util.BundledRedstone
import li.cil.oc.util.ExtendedNBT._ import li.cil.oc.util.ExtendedNBT._
import net.minecraftforge.fml.common.Optional import net.minecraftforge.fml.common.Optional
/* TODO RedLogic /* TODO RedLogic
import mods.immibis.redlogic.api.wiring.IBundledEmitter import mods.immibis.redlogic.api.wiring.IBundledEmitter
import mods.immibis.redlogic.api.wiring.IBundledUpdatable import mods.immibis.redlogic.api.wiring.IBundledUpdatable
import mods.immibis.redlogic.api.wiring.IInsulatedRedstoneWire
*/ */
/* TODO Project Red /* TODO Project Red
import mrtjp.projectred.api.IBundledTile import mrtjp.projectred.api.IBundledTile
import mrtjp.projectred.api.ProjectRedAPI
*/ */
import net.minecraft.nbt.NBTTagCompound import net.minecraft.nbt.NBTTagCompound
@ -55,6 +54,23 @@ trait BundledRedstoneAware extends RedstoneAware /* with IBundledEmitter with IB
def bundledInput(side: EnumFacing) = def bundledInput(side: EnumFacing) =
(_bundledInput(side.ordinal()), _rednetInput(side.ordinal())).zipped.map(math.max) (_bundledInput(side.ordinal()), _rednetInput(side.ordinal())).zipped.map(math.max)
def bundledInput(side: EnumFacing, newBundledInput: Array[Int]): Unit = {
val ownBundledInput = _bundledInput(side.ordinal())
val oldMaxValue = ownBundledInput.max
var changed = false
if (newBundledInput != null) for (color <- 0 until 16) {
changed = changed || (ownBundledInput(color) >= 0 && ownBundledInput(color) != newBundledInput(color))
ownBundledInput(color) = newBundledInput(color)
}
else for (color <- 0 until 16) {
changed = changed || ownBundledInput(color) > 0
ownBundledInput(color) = 0
}
if (changed) {
onRedstoneInputChanged(side, oldMaxValue, ownBundledInput.max)
}
}
def bundledInput(side: EnumFacing, color: Int) = def bundledInput(side: EnumFacing, color: Int) =
math.max(_bundledInput(side.ordinal())(color), _rednetInput(side.ordinal())(color)) math.max(_bundledInput(side.ordinal())(color), _rednetInput(side.ordinal())(color))
@ -92,21 +108,7 @@ trait BundledRedstoneAware extends RedstoneAware /* with IBundledEmitter with IB
override def updateRedstoneInput(side: EnumFacing) { override def updateRedstoneInput(side: EnumFacing) {
super.updateRedstoneInput(side) super.updateRedstoneInput(side)
val ownBundledInput = _bundledInput(side.ordinal()) bundledInput(side, BundledRedstone.computeBundledInput(position, side))
val newBundledInput = computeBundledInput(side)
val oldMaxValue = ownBundledInput.max
var changed = false
if (newBundledInput != null) for (color <- 0 until 16) {
changed = changed || (ownBundledInput(color) >= 0 && ownBundledInput(color) != newBundledInput(color))
ownBundledInput(color) = newBundledInput(color)
}
else for (color <- 0 until 16) {
changed = changed || ownBundledInput(color) > 0
ownBundledInput(color) = 0
}
if (changed) {
onRedstoneInputChanged(side, oldMaxValue, ownBundledInput.max)
}
} }
override def readFromNBTForServer(nbt: NBTTagCompound) { override def readFromNBTForServer(nbt: NBTTagCompound) {
@ -147,49 +149,6 @@ trait BundledRedstoneAware extends RedstoneAware /* with IBundledEmitter with IB
// ----------------------------------------------------------------------- // // ----------------------------------------------------------------------- //
protected def computeBundledInput(side: EnumFacing): Array[Int] = {
/* TODO RedLogic
val redLogic =
if (Mods.RedLogic.isAvailable) {
val (nx, ny, nz) = (x + side.offsetX, y + side.offsetY, z + side.offsetZ)
if (world.blockExists(nx, ny, nz)) world.getTileEntity(nx, ny, nz) match {
case wire: IInsulatedRedstoneWire =>
var strength: Array[Int] = null
for (face <- -1 to 5 if wire.wireConnectsInDirection(face, side.ordinal()) && strength == null) {
strength = Array.fill(16)(0)
strength(wire.getInsulatedWireColour) = wire.getEmittedSignalStrength(face, side.ordinal())
}
strength
case emitter: IBundledEmitter =>
var strength: Array[Int] = null
for (i <- -1 to 5 if strength == null) {
strength = Option(emitter.getBundledCableStrength(i, side.getOpposite.ordinal())).fold(null: Array[Int])(_.map(_ & 0xFF))
}
strength
case _ => null
}
else null
}
else null
*/
/* TODO Project Red
val projectRed =
if (Mods.ProjectRedTransmission.isAvailable) {
Option(ProjectRedAPI.transmissionAPI.getBundledInput(world, x, y, z, side.ordinal)).fold(null: Array[Int])(_.map(_ & 0xFF))
}
else null
*/
/* TODO RedLogic or Project Red
(redLogic, projectRed) match {
case (a: Array[Int], b: Array[Int]) => (a, b).zipped.map((r1, r2) => math.max(r1, r2))
case (a: Array[Int], _) => a
case (_, b: Array[Int]) => b
case _ => null
}
*/
null
}
override protected def onRedstoneOutputEnabledChanged() { override protected def onRedstoneOutputEnabledChanged() {
/* TODO MFR /* TODO MFR
if (Mods.MineFactoryReloaded.isAvailable) { if (Mods.MineFactoryReloaded.isAvailable) {

View File

@ -2,10 +2,8 @@ package li.cil.oc.common.tileentity.traits
import li.cil.oc.Settings import li.cil.oc.Settings
import li.cil.oc.integration.Mods import li.cil.oc.integration.Mods
import li.cil.oc.integration.util.BundledRedstone
import li.cil.oc.server.{PacketSender => ServerPacketSender} import li.cil.oc.server.{PacketSender => ServerPacketSender}
import li.cil.oc.util.BlockPosition
import li.cil.oc.util.ExtendedWorld._
import net.minecraft.block.BlockRedstoneWire
import net.minecraftforge.fml.common.Optional import net.minecraftforge.fml.common.Optional
import net.minecraftforge.fml.relauncher.Side import net.minecraftforge.fml.relauncher.Side
import net.minecraftforge.fml.relauncher.SideOnly import net.minecraftforge.fml.relauncher.SideOnly
@ -17,7 +15,6 @@ import mods.immibis.redlogic.api.wiring.IRedstoneUpdatable
import mods.immibis.redlogic.api.wiring.IWire import mods.immibis.redlogic.api.wiring.IWire
*/ */
import net.minecraft.init.Blocks
import net.minecraft.nbt.NBTTagCompound import net.minecraft.nbt.NBTTagCompound
import net.minecraft.util.EnumFacing import net.minecraft.util.EnumFacing
@ -52,6 +49,14 @@ trait RedstoneAware extends RotationAware /* with IConnectable with IRedstoneEmi
def input(side: EnumFacing) = _input(side.ordinal()) max 0 def input(side: EnumFacing) = _input(side.ordinal()) max 0
def input(side: EnumFacing, newInput: Int): Unit = {
val oldInput = _input(side.ordinal())
_input(side.ordinal()) = newInput
if (oldInput >= 0 && newInput != oldInput) {
onRedstoneInputChanged(side, oldInput, newInput)
}
}
def maxInput = EnumFacing.values.map(input).max def maxInput = EnumFacing.values.map(input).max
def output(side: EnumFacing) = _output(toLocal(side).ordinal()) def output(side: EnumFacing) = _output(toLocal(side).ordinal())
@ -81,12 +86,7 @@ trait RedstoneAware extends RotationAware /* with IConnectable with IRedstoneEmi
} }
def updateRedstoneInput(side: EnumFacing) { def updateRedstoneInput(side: EnumFacing) {
val oldInput = _input(side.ordinal()) input(side, BundledRedstone.computeInput(position, side))
val newInput = computeInput(side)
_input(side.ordinal()) = newInput
if (oldInput >= 0 && newInput != oldInput) {
onRedstoneInputChanged(side, oldInput, newInput)
}
} }
// ----------------------------------------------------------------------- // // ----------------------------------------------------------------------- //
@ -122,32 +122,6 @@ trait RedstoneAware extends RotationAware /* with IConnectable with IRedstoneEmi
// ----------------------------------------------------------------------- // // ----------------------------------------------------------------------- //
protected def computeInput(side: EnumFacing) = {
val blockPos = BlockPosition(x, y, z).offset(side)
if (!world.blockExists(blockPos)) 0
else {
// See BlockRedstoneLogic.getInputStrength() for reference.
val vanilla = math.max(world.getIndirectPowerLevelTo(blockPos, side),
if (world.getBlock(blockPos) == Blocks.redstone_wire) world.getBlockMetadata(blockPos).getValue(BlockRedstoneWire.POWER).asInstanceOf[Integer].intValue() else 0)
val redLogic = 0
/* TODO RedLogic
val redLogic = if (Mods.RedLogic.isAvailable) {
world.getTileEntity(blockPos) match {
case emitter: IRedstoneEmitter =>
var strength = 0
for (i <- -1 to 5) {
strength = math.max(strength, emitter.getEmittedSignalStrength(i, side.getOpposite.ordinal()))
}
strength
case _ => 0
}
}
else 0
*/
math.max(vanilla, redLogic)
}
}
protected def onRedstoneInputChanged(side: EnumFacing, oldMaxValue: Int, newMaxValue: Int) {} protected def onRedstoneInputChanged(side: EnumFacing, oldMaxValue: Int, newMaxValue: Int) {}
protected def onRedstoneOutputEnabledChanged() { protected def onRedstoneOutputEnabledChanged() {

View File

@ -22,6 +22,7 @@ object Mods {
val AppliedEnergistics2 = new SimpleMod(IDs.AppliedEnergistics2, version = "@[rv1,)", providesPower = true) val AppliedEnergistics2 = new SimpleMod(IDs.AppliedEnergistics2, version = "@[rv1,)", providesPower = true)
val BattleGear2 = new SimpleMod(IDs.BattleGear2) val BattleGear2 = new SimpleMod(IDs.BattleGear2)
val BloodMagic = new SimpleMod(IDs.BloodMagic) val BloodMagic = new SimpleMod(IDs.BloodMagic)
val BluePower = new SimpleMod(IDs.BluePower)
val BuildCraft = new SimpleMod(IDs.BuildCraft) val BuildCraft = new SimpleMod(IDs.BuildCraft)
val BuildCraftTiles = new SimpleMod(IDs.BuildCraftTiles) val BuildCraftTiles = new SimpleMod(IDs.BuildCraftTiles)
val BuildCraftTools = new SimpleMod(IDs.BuildCraftTools) val BuildCraftTools = new SimpleMod(IDs.BuildCraftTools)
@ -43,6 +44,7 @@ object Mods {
val GregTech = new ClassBasedMod(IDs.GregTech, "gregtech.api.GregTech_API")() val GregTech = new ClassBasedMod(IDs.GregTech, "gregtech.api.GregTech_API")()
val IndustrialCraft2 = new SimpleMod(IDs.IndustrialCraft2, providesPower = true) val IndustrialCraft2 = new SimpleMod(IDs.IndustrialCraft2, providesPower = true)
val IndustrialCraft2Classic = new SimpleMod(IDs.IndustrialCraft2Classic, providesPower = true) val IndustrialCraft2Classic = new SimpleMod(IDs.IndustrialCraft2Classic, providesPower = true)
val IngameWiki = new SimpleMod(IDs.IngameWiki, version = "@[1.1.3,)")
val Mekanism = new SimpleMod(IDs.Mekanism, providesPower = true) val Mekanism = new SimpleMod(IDs.Mekanism, providesPower = true)
val Minecraft = new SimpleMod(IDs.Minecraft) val Minecraft = new SimpleMod(IDs.Minecraft)
val MineFactoryReloaded = new SimpleMod(IDs.MineFactoryReloaded) val MineFactoryReloaded = new SimpleMod(IDs.MineFactoryReloaded)
@ -76,43 +78,50 @@ object Mods {
// ----------------------------------------------------------------------- // // ----------------------------------------------------------------------- //
val Proxies = Array( val Proxies = Array(
// integration.appeng.ModAppEng, // integration.appeng.ModAppEng,
// integration.bloodmagic.ModBloodMagic, // integration.bloodmagic.ModBloodMagic,
// integration.buildcraft.tools.ModBuildCraftAPITools, // integration.bluepower.ModBluePower,
// integration.buildcraft.tiles.ModBuildCraftAPITiles, // integration.buildcraft.tools.ModBuildCraftAPITools,
// integration.buildcraft.transport.ModBuildCraftAPITransport, // integration.buildcraft.tiles.ModBuildCraftAPITiles,
// integration.cofh.energy.ModCoFHEnergy, // integration.buildcraft.transport.ModBuildCraftAPITransport,
// integration.cofh.item.ModCoFHItem, // integration.cofh.energy.ModCoFHEnergy,
// integration.cofh.tileentity.ModCoFHTileEntity, // integration.cofh.item.ModCoFHItem,
// integration.cofh.transport.ModCoFHTransport, // integration.cofh.tileentity.ModCoFHTileEntity,
// integration.enderstorage.ModEnderStorage, // integration.cofh.transport.ModCoFHTransport,
// integration.dsu.ModDeepStorageUnit, // integration.enderstorage.ModEnderStorage,
// integration.forestry.ModForestry, // integration.dsu.ModDeepStorageUnit,
// integration.fmp.ModForgeMultipart, // integration.forestry.ModForestry,
// integration.gc.ModGalacticraft, // integration.fmp.ModForgeMultipart,
// integration.gregtech.ModGregtech, // integration.gc.ModGalacticraft,
// integration.ic2.ModIndustrialCraft2, // integration.gregtech.ModGregtech,
// integration.mfr.ModMineFactoryReloaded, // integration.ic2.ModIndustrialCraft2,
// integration.mystcraft.ModMystcraft, // integration.mfr.ModMineFactoryReloaded,
// integration.railcraft.ModRailcraft, // integration.mystcraft.ModMystcraft,
// integration.stargatetech2.ModStargateTech2, // integration.projectred.ModProjectRed,
// integration.thaumcraft.ModThaumcraft, // integration.railcraft.ModRailcraft,
// integration.thermalexpansion.ModThermalExpansion, // integration.redlogic.ModRedLogic,
// integration.tcon.ModTinkersConstruct, // integration.stargatetech2.ModStargateTech2,
// integration.tmechworks.ModTMechworks, // integration.thaumcraft.ModThaumcraft,
// integration.thermalexpansion.ModThermalExpansion,
// integration.tcon.ModTinkersConstruct,
// integration.tmechworks.ModTMechworks,
integration.vanilla.ModVanilla, integration.vanilla.ModVanilla,
// integration.versionchecker.ModVersionChecker, integration.versionchecker.ModVersionChecker,
// integration.waila.ModWaila, integration.waila.ModWaila,
// integration.wrcbe.ModWRCBE, // integration.wrcbe.ModWRCBE,
// integration.wrsve.ModWRSVE, // integration.wrsve.ModWRSVE,
// // Register the general IPeripheral driver last, if at all, to avoid it // // Register the general IPeripheral driver last, if at all, to avoid it
// // being used rather than other more concrete implementations. // // being used rather than other more concrete implementations.
// integration.computercraft.ModComputerCraft, // integration.computercraft.ModComputerCraft,
// We go last to ensure all other mod integration is done, e.g. to // We go late to ensure all other mod integration is done, e.g. to
// allow properly checking if wireless redstone is present. // allow properly checking if wireless redstone is present.
integration.opencomputers.ModOpenComputers integration.opencomputers.ModOpenComputers
// Run IGW registration after OC registration because we use the manual
// in there to know which pages to register.
// integration.igw.ModIngameWiki
) )
def init(): Unit = { def init(): Unit = {
@ -139,6 +148,7 @@ object Mods {
final val AppliedEnergistics2 = "appliedenergistics2" final val AppliedEnergistics2 = "appliedenergistics2"
final val BattleGear2 = "battlegear2" final val BattleGear2 = "battlegear2"
final val BloodMagic = "AWWayofTime" final val BloodMagic = "AWWayofTime"
final val BluePower = "bluepowerAPI"
final val BuildCraft = "BuildCraft|Core" final val BuildCraft = "BuildCraft|Core"
final val BuildCraftPower = "BuildCraftAPI|power" final val BuildCraftPower = "BuildCraftAPI|power"
final val BuildCraftTiles = "BuildCraftAPI|tiles" final val BuildCraftTiles = "BuildCraftAPI|tiles"
@ -161,6 +171,7 @@ object Mods {
final val GregTech = "gregtech" final val GregTech = "gregtech"
final val IndustrialCraft2 = "IC2" final val IndustrialCraft2 = "IC2"
final val IndustrialCraft2Classic = "IC2-Classic" final val IndustrialCraft2Classic = "IC2-Classic"
final val IngameWiki = "IGWMod"
final val Mekanism = "Mekanism" final val Mekanism = "Mekanism"
final val Minecraft = "Minecraft" final val Minecraft = "Minecraft"
final val MineFactoryReloaded = "MineFactoryReloaded" final val MineFactoryReloaded = "MineFactoryReloaded"

View File

@ -0,0 +1,38 @@
package li.cil.oc.integration.bluepower
import com.bluepowermod.api.BPApi
import com.bluepowermod.api.connect.ConnectionType
import com.bluepowermod.api.connect.IConnectionCache
import com.bluepowermod.api.misc.MinecraftColor
import com.bluepowermod.api.wire.redstone.IBundledDevice
import li.cil.oc.common.tileentity.traits.BundledRedstoneAware
import net.minecraft.world.World
import net.minecraftforge.common.util.ForgeDirection
class BundledRedstoneDevice(val tileEntity: BundledRedstoneAware) extends IBundledDevice {
lazy val cache = BPApi.getInstance.getRedstoneApi.createBundledConnectionCache(this)
override def getX: Int = tileEntity.x
override def getY: Int = tileEntity.y
override def getZ: Int = tileEntity.z
override def getWorld: World = tileEntity.world
override def canConnect(side: ForgeDirection, dev: IBundledDevice, connectionType: ConnectionType): Boolean = tileEntity.isOutputEnabled
override def isNormalFace(side: ForgeDirection): Boolean = true
override def getBundledConnectionCache: IConnectionCache[_ <: IBundledDevice] = cache
override def getBundledColor(side: ForgeDirection): MinecraftColor = MinecraftColor.ANY
override def getBundledOutput(side: ForgeDirection): Array[Byte] = tileEntity.bundledOutput(side).map(_.toByte)
override def getBundledPower(side: ForgeDirection): Array[Byte] = tileEntity.bundledInput(side).map(_.toByte)
override def setBundledPower(side: ForgeDirection, power: Array[Byte]): Unit = tileEntity.bundledInput(side, power.map(_ & 0xFF))
override def onBundledUpdate(): Unit = tileEntity.checkRedstoneInputChanged()
}

View File

@ -0,0 +1,39 @@
package li.cil.oc.integration.bluepower
import com.bluepowermod.api.BPApi
import com.bluepowermod.api.wire.redstone.IBundledDevice
import com.bluepowermod.api.wire.redstone.IRedstoneDevice
import li.cil.oc.integration.ModProxy
import li.cil.oc.integration.Mods
import li.cil.oc.integration.util.BundledRedstone
import li.cil.oc.integration.util.BundledRedstone.RedstoneProvider
import li.cil.oc.util.BlockPosition
import net.minecraftforge.common.util.ForgeDirection
object ModBluePower extends ModProxy with RedstoneProvider {
override def getMod = Mods.BluePower
override def initialize(): Unit = {
RedstoneProvider.init()
BundledRedstone.addProvider(this)
}
override def computeInput(pos: BlockPosition, side: ForgeDirection): Int = {
val world = pos.world.get
val (nx, ny, nz) = (pos.x + side.offsetX, pos.y + side.offsetY, pos.z + side.offsetZ)
ForgeDirection.values.map(BPApi.getInstance.getRedstoneApi.getRedstoneDevice(world, nx, ny, nz, _, ForgeDirection.UNKNOWN)).collect {
case device: IRedstoneDevice => device.getRedstonePower(side.getOpposite) & 0xFF
}.padTo(1, 0).max
}
def computeBundledInput(pos: BlockPosition, side: ForgeDirection): Array[Int] = {
val world = pos.world.get
val (nx, ny, nz) = (pos.x + side.offsetX, pos.y + side.offsetY, pos.z + side.offsetZ)
val inputs = ForgeDirection.values.map(BPApi.getInstance.getRedstoneApi.getBundledDevice(world, nx, ny, nz, _, ForgeDirection.UNKNOWN)).collect {
case device: IBundledDevice => Option(device.getBundledOutput(side.getOpposite)).fold(null: Array[Int])(_.map(_ & 0xFF))
}.filter(_ != null)
if (inputs.isEmpty) null
else inputs.reduce((a, b) => (a, b).zipped.map((l, r) => math.max(l, r)))
}
}

View File

@ -0,0 +1,33 @@
package li.cil.oc.integration.bluepower
import com.bluepowermod.api.BPApi
import com.bluepowermod.api.connect.ConnectionType
import com.bluepowermod.api.connect.IConnectionCache
import com.bluepowermod.api.wire.redstone.IRedstoneDevice
import li.cil.oc.common.tileentity.traits.RedstoneAware
import net.minecraft.world.World
import net.minecraftforge.common.util.ForgeDirection
class RedstoneDevice(val tileEntity: RedstoneAware) extends IRedstoneDevice {
lazy val cache = BPApi.getInstance.getRedstoneApi.createRedstoneConnectionCache(this)
override def getX: Int = tileEntity.x
override def getY: Int = tileEntity.y
override def getZ: Int = tileEntity.z
override def getWorld: World = tileEntity.world
override def canConnect(side: ForgeDirection, dev: IRedstoneDevice, connectionType: ConnectionType): Boolean = tileEntity.isOutputEnabled
override def isNormalFace(side: ForgeDirection): Boolean = true
override def getRedstoneConnectionCache: IConnectionCache[_ <: IRedstoneDevice] = cache
override def getRedstonePower(side: ForgeDirection): Byte = tileEntity.output(side).toByte
override def setRedstonePower(side: ForgeDirection, power: Byte): Unit = tileEntity.input(side, power & 0xFF)
override def onRedstoneUpdate(): Unit = tileEntity.checkRedstoneInputChanged()
}

View File

@ -0,0 +1,36 @@
package li.cil.oc.integration.bluepower
import com.bluepowermod.api.BPApi
import com.bluepowermod.api.wire.redstone.IBundledDevice
import com.bluepowermod.api.wire.redstone.IRedstoneDevice
import com.bluepowermod.api.wire.redstone.IRedstoneProvider
import li.cil.oc.common.tileentity.traits.BundledRedstoneAware
import li.cil.oc.common.tileentity.traits.RedstoneAware
import net.minecraft.world.World
import net.minecraftforge.common.util.ForgeDirection
import scala.collection.mutable
object RedstoneProvider extends IRedstoneProvider {
val redstoneDevices = mutable.WeakHashMap.empty[RedstoneAware, RedstoneDevice]
val bundledRedstoneDevices = mutable.WeakHashMap.empty[BundledRedstoneAware, BundledRedstoneDevice]
def init(): Unit = {
BPApi.getInstance.getRedstoneApi.registerRedstoneProvider(this)
}
override def getRedstoneDeviceAt(world: World, x: Int, y: Int, z: Int, side: ForgeDirection, face: ForgeDirection): IRedstoneDevice = {
world.getTileEntity(x, y, z) match {
case tileEntity: RedstoneAware => redstoneDevices.getOrElseUpdate(tileEntity, new RedstoneDevice(tileEntity))
case _ => null
}
}
override def getBundledDeviceAt(world: World, x: Int, y: Int, z: Int, side: ForgeDirection, face: ForgeDirection): IBundledDevice = {
world.getTileEntity(x, y, z) match {
case tileEntity: BundledRedstoneAware => bundledRedstoneDevices.getOrElseUpdate(tileEntity, new BundledRedstoneDevice(tileEntity))
case _ => null
}
}
}

View File

@ -0,0 +1,14 @@
package li.cil.oc.integration.igw
import li.cil.oc.api.Driver
import li.cil.oc.integration.ModProxy
import li.cil.oc.integration.Mods
import net.minecraftforge.common.MinecraftForge
object ModIngameWiki extends ModProxy {
override def getMod = Mods.IngameWiki
override def initialize(): Unit = {
WikiEventHandler.init()
}
}

View File

@ -0,0 +1,57 @@
package li.cil.oc.integration.igw
import java.util
import cpw.mods.fml.common.eventhandler.SubscribeEvent
import igwmod.api.PageChangeEvent
import igwmod.api.WikiRegistry
import li.cil.oc.OpenComputers
import li.cil.oc.api
import li.cil.oc.client.Manual
import li.cil.oc.client.renderer.markdown
import li.cil.oc.client.renderer.markdown.MarkupFormat
import li.cil.oc.common.init.Items
import net.minecraftforge.common.MinecraftForge
import scala.collection.convert.WrapAsJava._
import scala.collection.convert.WrapAsScala._
object WikiEventHandler {
var lastPath = ""
def init(): Unit = {
MinecraftForge.EVENT_BUS.register(this)
for ((name, info) <- Items.descriptors) {
val stack = info.createItemStack(1)
val path = api.Manual.pathFor(stack)
if (path != null && api.Manual.contentFor(path) != null) {
WikiRegistry.registerBlockAndItemPageEntry(stack)
}
}
}
@SubscribeEvent
def onPageChangeEvent(e: PageChangeEvent): Unit = {
val path =
if (e.associatedStack != null)
"/" + api.Manual.pathFor(e.associatedStack)
else if (e.currentFile.startsWith(OpenComputers.ID + ":"))
e.currentFile.stripPrefix(OpenComputers.ID + ":")
else null
val base = lastPath
lastPath = ""
if (path != null) {
val resolvedPath = Manual.makeRelative(path, base)
val content = api.Manual.contentFor(resolvedPath)
if (content != null) {
val document = markdown.Document.parse(content)
val processed = document.renderAsText(MarkupFormat.IGWMod)
e.pageText = new util.ArrayList[String](asJavaCollection(processed))
e.currentFile = resolvedPath
lastPath = resolvedPath
}
}
}
}

View File

@ -0,0 +1,24 @@
package li.cil.oc.integration.projectred
import li.cil.oc.integration.ModProxy
import li.cil.oc.integration.Mods
import li.cil.oc.integration.util.BundledRedstone
import li.cil.oc.integration.util.BundledRedstone.RedstoneProvider
import li.cil.oc.util.BlockPosition
import mrtjp.projectred.api.ProjectRedAPI
import net.minecraftforge.common.util.ForgeDirection
object ModProjectRed extends ModProxy with RedstoneProvider {
override def getMod = Mods.ProjectRedTransmission
override def initialize(): Unit = {
BundledRedstone.addProvider(this)
}
override def computeInput(pos: BlockPosition, side: ForgeDirection): Int = 0
def computeBundledInput(pos: BlockPosition, side: ForgeDirection): Array[Int] = {
Option(ProjectRedAPI.transmissionAPI.getBundledInput(pos.world.get, pos.x, pos.y, pos.z, side.ordinal)).
fold(null: Array[Int])(_.map(_ & 0xFF))
}
}

View File

@ -0,0 +1,53 @@
package li.cil.oc.integration.redlogic
import li.cil.oc.integration.ModProxy
import li.cil.oc.integration.Mods
import li.cil.oc.integration.util.BundledRedstone
import li.cil.oc.integration.util.BundledRedstone.RedstoneProvider
import li.cil.oc.util.BlockPosition
import li.cil.oc.util.ExtendedWorld._
import mods.immibis.redlogic.api.wiring.IBundledEmitter
import mods.immibis.redlogic.api.wiring.IInsulatedRedstoneWire
import mods.immibis.redlogic.api.wiring.IRedstoneEmitter
import net.minecraftforge.common.util.ForgeDirection
object ModRedLogic extends ModProxy with RedstoneProvider {
override def getMod = Mods.RedLogic
override def initialize(): Unit = {
BundledRedstone.addProvider(this)
}
override def computeInput(pos: BlockPosition, side: ForgeDirection): Int = {
pos.world.get.getTileEntity(pos) match {
case emitter: IRedstoneEmitter =>
var strength = 0
for (i <- -1 to 5) {
strength = math.max(strength, emitter.getEmittedSignalStrength(i, side.getOpposite.ordinal()))
}
strength
case _ => 0
}
}
def computeBundledInput(pos: BlockPosition, side: ForgeDirection): Array[Int] = {
val world = pos.world.get
val npos = pos.offset(side)
world.getTileEntity(npos) match {
case wire: IInsulatedRedstoneWire =>
var strength: Array[Int] = null
for (face <- -1 to 5 if wire.wireConnectsInDirection(face, side.ordinal())) {
if (strength == null) strength = Array.fill(16)(0)
strength(wire.getInsulatedWireColour) = math.max(strength(wire.getInsulatedWireColour), wire.getEmittedSignalStrength(face, side.ordinal()))
}
strength
case emitter: IBundledEmitter =>
var strength: Array[Int] = null
for (i <- -1 to 5 if strength == null) {
strength = Option(emitter.getBundledCableStrength(i, side.getOpposite.ordinal())).fold(null: Array[Int])(_.map(_ & 0xFF))
}
strength
case _ => null
}
}
}

View File

@ -1,9 +1,38 @@
package li.cil.oc.integration.util package li.cil.oc.integration.util
import li.cil.oc.integration.Mods import li.cil.oc.integration.Mods
import li.cil.oc.util.BlockPosition
import li.cil.oc.util.ExtendedWorld._
import net.minecraft.util.EnumFacing
import scala.collection.mutable
object BundledRedstone { object BundledRedstone {
def isAvailable = Mods.RedLogic.isAvailable || val providers = mutable.Buffer.empty[RedstoneProvider]
Mods.MineFactoryReloaded.isAvailable ||
Mods.ProjectRedTransmission.isAvailable def addProvider(provider: RedstoneProvider): Unit = providers += provider
def isAvailable = Mods.MineFactoryReloaded.isAvailable || providers.length > 0
def computeInput(pos: BlockPosition, side: EnumFacing): Int = {
if (pos.world.get.blockExists(pos.offset(side)))
providers.map(_.computeInput(pos, side)).padTo(1, 0).max
else 0
}
def computeBundledInput(pos: BlockPosition, side: EnumFacing): Array[Int] = {
if (pos.world.get.blockExists(pos.offset(side))) {
val inputs = providers.map(_.computeBundledInput(pos, side)).filter(_ != null)
if (inputs.isEmpty) null
else inputs.reduce((a, b) => (a, b).zipped.map((l, r) => math.max(l, r)))
}
else null
}
trait RedstoneProvider {
def computeInput(pos: BlockPosition, side: EnumFacing): Int
def computeBundledInput(pos: BlockPosition, side: EnumFacing): Array[Int]
}
} }

View File

@ -4,8 +4,15 @@ import li.cil.oc.Settings
import li.cil.oc.api.Driver import li.cil.oc.api.Driver
import li.cil.oc.integration.ModProxy import li.cil.oc.integration.ModProxy
import li.cil.oc.integration.Mods import li.cil.oc.integration.Mods
import li.cil.oc.integration.util.BundledRedstone
import li.cil.oc.integration.util.BundledRedstone.RedstoneProvider
import li.cil.oc.util.BlockPosition
import li.cil.oc.util.ExtendedWorld._
import net.minecraft.block.BlockRedstoneWire
import net.minecraft.init.Blocks
import net.minecraft.util.EnumFacing
object ModVanilla extends ModProxy { object ModVanilla extends ModProxy with RedstoneProvider {
def getMod = Mods.Minecraft def getMod = Mods.Minecraft
def initialize() { def initialize() {
@ -36,5 +43,16 @@ object ModVanilla extends ModProxy {
Driver.add(ConverterWorldProvider) Driver.add(ConverterWorldProvider)
RecipeHandler.init() RecipeHandler.init()
BundledRedstone.addProvider(this)
} }
override def computeInput(pos: BlockPosition, side: EnumFacing): Int = {
val world = pos.world.get
// See BlockRedstoneLogic.getInputStrength() for reference.
math.max(world.getIndirectPowerLevelTo(pos, side),
if (world.getBlock(pos) == Blocks.redstone_wire) world.getBlockMetadata(pos).getValue(BlockRedstoneWire.POWER).asInstanceOf[Integer].intValue() else 0)
}
override def computeBundledInput(pos: BlockPosition, side: EnumFacing): Array[Int] = null
} }

View File

@ -39,7 +39,7 @@ class EEPROM extends prefab.ManagedEnvironment {
if (!node.tryChangeBuffer(-Settings.get.eepromWriteCost)) { if (!node.tryChangeBuffer(-Settings.get.eepromWriteCost)) {
return result(Unit, "not enough energy") return result(Unit, "not enough energy")
} }
val newData = args.optByteArray(0, Array.empty) val newData = args.optByteArray(0, Array.empty[Byte])
if (newData.length > Settings.get.eepromSize) throw new IllegalArgumentException("not enough space") if (newData.length > Settings.get.eepromSize) throw new IllegalArgumentException("not enough space")
codeData = newData codeData = newData
context.pause(2) // deliberately slow to discourage use as normal storage medium context.pause(2) // deliberately slow to discourage use as normal storage medium
@ -85,7 +85,7 @@ class EEPROM extends prefab.ManagedEnvironment {
if (!node.tryChangeBuffer(-Settings.get.eepromWriteCost)) { if (!node.tryChangeBuffer(-Settings.get.eepromWriteCost)) {
return result(Unit, "not enough energy") return result(Unit, "not enough energy")
} }
val newData = args.optByteArray(0, Array.empty) val newData = args.optByteArray(0, Array.empty[Byte])
if (newData.length > Settings.get.eepromDataSize) throw new IllegalArgumentException("not enough space") if (newData.length > Settings.get.eepromDataSize) throw new IllegalArgumentException("not enough space")
volatileData = newData volatileData = newData
context.pause(1) // deliberately slow to discourage use as normal storage medium context.pause(1) // deliberately slow to discourage use as normal storage medium

View File

@ -235,10 +235,6 @@ class Machine(val host: MachineHost) extends prefab.ManagedEnvironment with mach
false false
}) })
private def beep(pattern: String) {
PacketSender.sendSound(host.world, host.xPosition, host.yPosition, host.zPosition, pattern)
}
override def pause(seconds: Double): Boolean = { override def pause(seconds: Double): Boolean = {
val ticksToPause = math.max((seconds * 20).toInt, 0) val ticksToPause = math.max((seconds * 20).toInt, 0)
def shouldPause(state: Machine.State.Value) = state match { def shouldPause(state: Machine.State.Value) = state match {
@ -270,6 +266,14 @@ class Machine(val host: MachineHost) extends prefab.ManagedEnvironment with mach
true true
}) })
override def beep(frequency: Short, duration: Short): Unit = {
PacketSender.sendSound(host.world, host.xPosition, host.yPosition, host.zPosition, frequency, duration)
}
override def beep(pattern: String) {
PacketSender.sendSound(host.world, host.xPosition, host.yPosition, host.zPosition, pattern)
}
override def crash(message: String) = { override def crash(message: String) = {
this.message = Option(message) this.message = Option(message)
state.synchronized { state.synchronized {

View File

@ -5,7 +5,9 @@ import java.nio.ByteBuffer
import li.cil.oc.OpenComputers import li.cil.oc.OpenComputers
import li.cil.oc.Settings import li.cil.oc.Settings
import net.minecraft.client.Minecraft import net.minecraft.client.Minecraft
import net.minecraft.client.audio.PositionedSoundRecord
import net.minecraft.client.audio.SoundCategory import net.minecraft.client.audio.SoundCategory
import net.minecraft.util.ResourceLocation
import net.minecraftforge.fml.common.FMLCommonHandler import net.minecraftforge.fml.common.FMLCommonHandler
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
import net.minecraftforge.fml.common.gameevent.TickEvent.ClientTickEvent import net.minecraftforge.fml.common.gameevent.TickEvent.ClientTickEvent
@ -39,10 +41,29 @@ object Audio {
} }
def play(x: Float, y: Float, z: Float, pattern: String, frequencyInHz: Int = 1000, durationInMilliseconds: Int = 200): Unit = { def play(x: Float, y: Float, z: Float, pattern: String, frequencyInHz: Int = 1000, durationInMilliseconds: Int = 200): Unit = {
if (!disableAudio) { val mc = Minecraft.getMinecraft
val distanceBasedGain = math.max(0, 1 - Minecraft.getMinecraft.thePlayer.getDistance(x, y, z) / 12).toFloat val distanceBasedGain = math.max(0, 1 - mc.thePlayer.getDistance(x, y, z) / 12).toFloat
val gain = distanceBasedGain * volume val gain = distanceBasedGain * volume
if (gain > 0 && amplitude > 0 && AL.isCreated) { if (gain <= 0 || amplitude <= 0) return
if (disableAudio) {
// Fallback audio generation, using built-in Minecraft sound. This can be
// necessary on certain systems with audio cards that do not have enough
// memory. May still fail, but at least we can say we tried!
// Valid range is 20-2000Hz, clamp it to that and get a relative value.
// MC's pitch system supports a minimum pitch of 0.5, however, so up it
// by that.
val clampedFrequency = ((frequencyInHz - 20) max 0 min 1980) / 1980f + 0.5f
var delay = 0
for (ch <- pattern) {
val record = new PositionedSoundRecord(new ResourceLocation("note.harp"), gain, clampedFrequency, x, y, z)
if (delay == 0) mc.getSoundHandler.playSound(record)
else mc.getSoundHandler.playDelayedSound(record, delay)
delay += ((if (ch == '.') durationInMilliseconds else 2 * durationInMilliseconds) * 20 / 1000) max 1
}
}
else {
if (AL.isCreated) {
val sampleCounts = pattern.toCharArray. val sampleCounts = pattern.toCharArray.
map(ch => if (ch == '.') durationInMilliseconds else 2 * durationInMilliseconds). map(ch => if (ch == '.') durationInMilliseconds else 2 * durationInMilliseconds).
map(_ * sampleRate / 1000) map(_ * sampleRate / 1000)

View File

@ -73,13 +73,13 @@ object ItemUtils {
def getIngredients(stack: ItemStack): Array[ItemStack] = try { def getIngredients(stack: ItemStack): Array[ItemStack] = try {
def getFilteredInputs(inputs: Iterable[ItemStack], outputSize: Double) = inputs.filter(input => def getFilteredInputs(inputs: Iterable[ItemStack], outputSize: Double) = inputs.filter(input =>
input != null && input != null &&
input.getItem != null && input.getItem != null &&
math.floor(input.stackSize / outputSize) > 0 && math.floor(input.stackSize / outputSize) > 0 &&
// Strip out buckets, because those are returned when crafting, and // Strip out buckets, because those are returned when crafting, and
// we have no way of returning the fluid only (and I can't be arsed // we have no way of returning the fluid only (and I can't be arsed
// to make it output fluids into fluiducts or such, sorry). // to make it output fluids into fluiducts or such, sorry).
!input.getItem.isInstanceOf[ItemBucket]).toArray !input.getItem.isInstanceOf[ItemBucket]).toArray
def getOutputSize(recipe: IRecipe) = def getOutputSize(recipe: IRecipe): Double =
if (recipe != null && recipe.getRecipeOutput != null) if (recipe != null && recipe.getRecipeOutput != null)
recipe.getRecipeOutput.stackSize recipe.getRecipeOutput.stackSize
else else
@ -93,11 +93,11 @@ object ItemUtils {
case Some(recipe: ShapelessRecipes) => getFilteredInputs(recipe.recipeItems.map(_.asInstanceOf[ItemStack]), getOutputSize(recipe)) case Some(recipe: ShapelessRecipes) => getFilteredInputs(recipe.recipeItems.map(_.asInstanceOf[ItemStack]), getOutputSize(recipe))
case Some(recipe: ShapedOreRecipe) => getFilteredInputs(resolveOreDictEntries(recipe.getInput), getOutputSize(recipe)) case Some(recipe: ShapedOreRecipe) => getFilteredInputs(resolveOreDictEntries(recipe.getInput), getOutputSize(recipe))
case Some(recipe: ShapelessOreRecipe) => getFilteredInputs(resolveOreDictEntries(recipe.getInput), getOutputSize(recipe)) case Some(recipe: ShapelessOreRecipe) => getFilteredInputs(resolveOreDictEntries(recipe.getInput), getOutputSize(recipe))
case _ => Array.empty case _ => Array.empty[ItemStack]
} }
// Avoid positive feedback loops. // Avoid positive feedback loops.
if (ingredients.exists(ingredient => ingredient.isItemEqual(stack))) { if (ingredients.exists(ingredient => ingredient.isItemEqual(stack))) {
return Array.empty return Array.empty[ItemStack]
} }
// Merge equal items for size division by output size. // Merge equal items for size division by output size.
val merged = mutable.ArrayBuffer.empty[ItemStack] val merged = mutable.ArrayBuffer.empty[ItemStack]
@ -122,7 +122,7 @@ object ItemUtils {
catch { catch {
case t: Throwable => case t: Throwable =>
OpenComputers.log.warn("Whoops, something went wrong when trying to figure out an item's parts.", t) OpenComputers.log.warn("Whoops, something went wrong when trying to figure out an item's parts.", t)
Array.empty Array.empty[ItemStack]
} }
private lazy val rng = new Random() private lazy val rng = new Random()