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"
url = "http://mod-buildcraft.com/"
}
maven {
name = "BluePower"
url = "http://maven.bluepowermod.com/"
}
maven {
name = "chickenbones"
url = "http://chickenbones.net/maven/"
}
maven {
name = "ic2, forestry"
url = "http://maven.ic2.player.to/"
}
maven {
name = "IGW"
url = "http://maven.k-4u.nl/"
}
maven {
name = "mobius"
url = "http://mobiusstrip.eu/maven"
}
maven {
name = "ue"
url = "http://calclavia.com/maven/"
@ -161,11 +177,15 @@ dependencies {
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"
provided "com.bluepowermod:BluePower:${config.bluepower.version}:deobf"
provided "com.gregoriust.gregtech:gregtech_${config.minecraft.version}:${config.gt.version}:dev"
provided "com.mod-buildcraft:buildcraft:${config.bc.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.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 name: 'GalacticraftCoreAll', version: config.gc.version, ext: 'jar'
@ -226,7 +246,6 @@ minecraft {
// stable_# stables are built at the discretion of the MCP team.
mappings = "snapshot_20141130"
replaceIn "li/cil/oc/OpenComputers.scala"
replace "@VERSION@", project.simpleVersion
}

View File

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

View File

@ -1,11 +1,6 @@
package li.cil.oc.api;
import li.cil.oc.api.detail.DriverAPI;
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;
import li.cil.oc.api.detail.*;
/**
* Central reference for the API.
@ -16,7 +11,7 @@ import li.cil.oc.api.detail.NetworkAPI;
*/
public class API {
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 FileSystemAPI fileSystem = null;

View File

@ -141,6 +141,51 @@ public interface Machine extends ManagedEnvironment, Context {
*/
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.
* <p/>
@ -221,6 +266,8 @@ public interface Machine extends ManagedEnvironment, Context {
*/
Object[] invoke(Value value, String method, Object[] args) throws Exception;
// ----------------------------------------------------------------------- //
/**
* The list of users registered on this machine.
* <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.
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.

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

View File

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

View File

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

View File

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

View File

@ -888,6 +888,26 @@ sandbox = {
},
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
},

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

View File

@ -1,9 +1,13 @@
package li.cil.oc.client.renderer.markdown.segment
import li.cil.oc.client.renderer.markdown.MarkupFormat
import net.minecraft.util.EnumChatFormatting
private[markdown] class BoldSegment(parent: Segment, text: String) extends TextSegment(parent, text) {
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
import li.cil.oc.client.renderer.TextBufferRenderCache
import li.cil.oc.client.renderer.markdown.MarkupFormat
import net.minecraft.client.gui.FontRenderer
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 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
import li.cil.oc.client.renderer.markdown.MarkupFormat
import net.minecraft.util.EnumChatFormatting
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 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
import li.cil.oc.client.renderer.markdown.MarkupFormat
import net.minecraft.util.EnumChatFormatting
private[markdown] class ItalicSegment(parent: Segment, text: String) extends TextSegment(parent, text) {
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 li.cil.oc.Localization
import li.cil.oc.OpenComputers
import li.cil.oc.api
import li.cil.oc.client.Manual
import li.cil.oc.client.renderer.markdown.MarkupFormat
import net.minecraft.client.Minecraft
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.InteractiveImageRenderer
import li.cil.oc.client.renderer.markdown.Document
import li.cil.oc.client.renderer.markdown.MarkupFormat
import net.minecraft.client.gui.FontRenderer
import org.lwjgl.opengl.GL11
@ -74,5 +75,8 @@ private[markdown] class RenderSegment(val parent: Segment, val title: String, va
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
import li.cil.oc.client.renderer.markdown.MarkupFormat
import net.minecraft.client.gui.FontRenderer
import scala.annotation.tailrec
import scala.collection.mutable
import scala.util.matching.Regex
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 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.

View File

@ -1,9 +1,13 @@
package li.cil.oc.client.renderer.markdown.segment
import li.cil.oc.client.renderer.markdown.MarkupFormat
import net.minecraft.util.EnumChatFormatting
private[markdown] class StrikethroughSegment(parent: Segment, text: String) extends TextSegment(parent, text) {
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
}
}
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(). */
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) {
if (failed) {
HologramRendererFallback.renderTileEntityAt(tileEntity, x, y, z, f, damage)
return
}
RenderState.checkError(getClass.getName + ".renderTileEntityAt: entering (aka: wasntme)")
hologram = tileEntity.asInstanceOf[Hologram]
@ -143,12 +154,13 @@ object HologramRenderer extends TileEntitySpecialRenderer with Callable[Int] wit
}
def draw(glBuffer: Int) {
initialize()
validate(glBuffer)
publish(glBuffer)
if (initialize()) {
validate(glBuffer)
publish(glBuffer)
}
}
private def initialize() {
private def initialize(): Boolean = !failed && (try {
// First run only, create structure information.
if (commonBuffer == 0) {
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.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) {
// Refresh indexes when the hologram's data changed.

View File

@ -7,7 +7,7 @@ import net.minecraft.tileentity.TileEntity
import org.lwjgl.opengl.GL11
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) {
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) =>
ChestGenHooks.generateStacks(random, disk,
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
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

View File

@ -16,6 +16,7 @@ import net.minecraft.world.World
@Injectable.InterfaceList(Array(
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 = "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 = "crazypants.enderio.tool.ITool", modid = Mods.IDs.EnderIO),
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
// BluePower
def damage(stack: ItemStack, damage: Int, player: EntityPlayer, simulated: Boolean): Boolean = damage == 0
// BuildCraft
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.integration.Mods
import li.cil.oc.integration.util.BundledRedstone
import li.cil.oc.util.ExtendedNBT._
import net.minecraftforge.fml.common.Optional
/* TODO RedLogic
import mods.immibis.redlogic.api.wiring.IBundledEmitter
import mods.immibis.redlogic.api.wiring.IBundledUpdatable
import mods.immibis.redlogic.api.wiring.IInsulatedRedstoneWire
*/
/* TODO Project Red
import mrtjp.projectred.api.IBundledTile
import mrtjp.projectred.api.ProjectRedAPI
*/
import net.minecraft.nbt.NBTTagCompound
@ -55,6 +54,23 @@ trait BundledRedstoneAware extends RedstoneAware /* with IBundledEmitter with IB
def bundledInput(side: EnumFacing) =
(_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) =
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) {
super.updateRedstoneInput(side)
val ownBundledInput = _bundledInput(side.ordinal())
val newBundledInput = computeBundledInput(side)
val oldMaxValue = ownBundledInput.max
var changed = false
if (newBundledInput != null) for (color <- 0 until 16) {
changed = changed || (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)
}
bundledInput(side, BundledRedstone.computeBundledInput(position, side))
}
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() {
/* TODO MFR
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.integration.Mods
import li.cil.oc.integration.util.BundledRedstone
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.relauncher.Side
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 net.minecraft.init.Blocks
import net.minecraft.nbt.NBTTagCompound
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, 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 output(side: EnumFacing) = _output(toLocal(side).ordinal())
@ -81,12 +86,7 @@ trait RedstoneAware extends RotationAware /* with IConnectable with IRedstoneEmi
}
def updateRedstoneInput(side: EnumFacing) {
val oldInput = _input(side.ordinal())
val newInput = computeInput(side)
_input(side.ordinal()) = newInput
if (oldInput >= 0 && newInput != oldInput) {
onRedstoneInputChanged(side, oldInput, newInput)
}
input(side, BundledRedstone.computeInput(position, side))
}
// ----------------------------------------------------------------------- //
@ -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 onRedstoneOutputEnabledChanged() {

View File

@ -22,6 +22,7 @@ object Mods {
val AppliedEnergistics2 = new SimpleMod(IDs.AppliedEnergistics2, version = "@[rv1,)", providesPower = true)
val BattleGear2 = new SimpleMod(IDs.BattleGear2)
val BloodMagic = new SimpleMod(IDs.BloodMagic)
val BluePower = new SimpleMod(IDs.BluePower)
val BuildCraft = new SimpleMod(IDs.BuildCraft)
val BuildCraftTiles = new SimpleMod(IDs.BuildCraftTiles)
val BuildCraftTools = new SimpleMod(IDs.BuildCraftTools)
@ -43,6 +44,7 @@ object Mods {
val GregTech = new ClassBasedMod(IDs.GregTech, "gregtech.api.GregTech_API")()
val IndustrialCraft2 = new SimpleMod(IDs.IndustrialCraft2, 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 Minecraft = new SimpleMod(IDs.Minecraft)
val MineFactoryReloaded = new SimpleMod(IDs.MineFactoryReloaded)
@ -76,43 +78,50 @@ object Mods {
// ----------------------------------------------------------------------- //
val Proxies = Array(
// integration.appeng.ModAppEng,
// integration.bloodmagic.ModBloodMagic,
// integration.buildcraft.tools.ModBuildCraftAPITools,
// integration.buildcraft.tiles.ModBuildCraftAPITiles,
// integration.buildcraft.transport.ModBuildCraftAPITransport,
// integration.cofh.energy.ModCoFHEnergy,
// integration.cofh.item.ModCoFHItem,
// integration.cofh.tileentity.ModCoFHTileEntity,
// integration.cofh.transport.ModCoFHTransport,
// integration.enderstorage.ModEnderStorage,
// integration.dsu.ModDeepStorageUnit,
// integration.forestry.ModForestry,
// integration.fmp.ModForgeMultipart,
// integration.gc.ModGalacticraft,
// integration.gregtech.ModGregtech,
// integration.ic2.ModIndustrialCraft2,
// integration.mfr.ModMineFactoryReloaded,
// integration.mystcraft.ModMystcraft,
// integration.railcraft.ModRailcraft,
// integration.stargatetech2.ModStargateTech2,
// integration.thaumcraft.ModThaumcraft,
// integration.thermalexpansion.ModThermalExpansion,
// integration.tcon.ModTinkersConstruct,
// integration.tmechworks.ModTMechworks,
// integration.appeng.ModAppEng,
// integration.bloodmagic.ModBloodMagic,
// integration.bluepower.ModBluePower,
// integration.buildcraft.tools.ModBuildCraftAPITools,
// integration.buildcraft.tiles.ModBuildCraftAPITiles,
// integration.buildcraft.transport.ModBuildCraftAPITransport,
// integration.cofh.energy.ModCoFHEnergy,
// integration.cofh.item.ModCoFHItem,
// integration.cofh.tileentity.ModCoFHTileEntity,
// integration.cofh.transport.ModCoFHTransport,
// integration.enderstorage.ModEnderStorage,
// integration.dsu.ModDeepStorageUnit,
// integration.forestry.ModForestry,
// integration.fmp.ModForgeMultipart,
// integration.gc.ModGalacticraft,
// integration.gregtech.ModGregtech,
// integration.ic2.ModIndustrialCraft2,
// integration.mfr.ModMineFactoryReloaded,
// integration.mystcraft.ModMystcraft,
// integration.projectred.ModProjectRed,
// integration.railcraft.ModRailcraft,
// integration.redlogic.ModRedLogic,
// integration.stargatetech2.ModStargateTech2,
// integration.thaumcraft.ModThaumcraft,
// integration.thermalexpansion.ModThermalExpansion,
// integration.tcon.ModTinkersConstruct,
// integration.tmechworks.ModTMechworks,
integration.vanilla.ModVanilla,
// integration.versionchecker.ModVersionChecker,
// integration.waila.ModWaila,
// integration.wrcbe.ModWRCBE,
// integration.wrsve.ModWRSVE,
integration.versionchecker.ModVersionChecker,
integration.waila.ModWaila,
// integration.wrcbe.ModWRCBE,
// integration.wrsve.ModWRSVE,
// // Register the general IPeripheral driver last, if at all, to avoid it
// // being used rather than other more concrete implementations.
// integration.computercraft.ModComputerCraft,
// // Register the general IPeripheral driver last, if at all, to avoid it
// // being used rather than other more concrete implementations.
// integration.computercraft.ModComputerCraft,
// We go last to ensure all other mod integration is done, e.g. to
// We go late to ensure all other mod integration is done, e.g. to
// allow properly checking if wireless redstone is present.
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 = {
@ -139,6 +148,7 @@ object Mods {
final val AppliedEnergistics2 = "appliedenergistics2"
final val BattleGear2 = "battlegear2"
final val BloodMagic = "AWWayofTime"
final val BluePower = "bluepowerAPI"
final val BuildCraft = "BuildCraft|Core"
final val BuildCraftPower = "BuildCraftAPI|power"
final val BuildCraftTiles = "BuildCraftAPI|tiles"
@ -161,6 +171,7 @@ object Mods {
final val GregTech = "gregtech"
final val IndustrialCraft2 = "IC2"
final val IndustrialCraft2Classic = "IC2-Classic"
final val IngameWiki = "IGWMod"
final val Mekanism = "Mekanism"
final val Minecraft = "Minecraft"
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
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 {
def isAvailable = Mods.RedLogic.isAvailable ||
Mods.MineFactoryReloaded.isAvailable ||
Mods.ProjectRedTransmission.isAvailable
val providers = mutable.Buffer.empty[RedstoneProvider]
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.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 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 initialize() {
@ -36,5 +43,16 @@ object ModVanilla extends ModProxy {
Driver.add(ConverterWorldProvider)
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)) {
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")
codeData = newData
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)) {
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")
volatileData = newData
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
})
private def beep(pattern: String) {
PacketSender.sendSound(host.world, host.xPosition, host.yPosition, host.zPosition, pattern)
}
override def pause(seconds: Double): Boolean = {
val ticksToPause = math.max((seconds * 20).toInt, 0)
def shouldPause(state: Machine.State.Value) = state match {
@ -270,6 +266,14 @@ class Machine(val host: MachineHost) extends prefab.ManagedEnvironment with mach
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) = {
this.message = Option(message)
state.synchronized {

View File

@ -5,7 +5,9 @@ import java.nio.ByteBuffer
import li.cil.oc.OpenComputers
import li.cil.oc.Settings
import net.minecraft.client.Minecraft
import net.minecraft.client.audio.PositionedSoundRecord
import net.minecraft.client.audio.SoundCategory
import net.minecraft.util.ResourceLocation
import net.minecraftforge.fml.common.FMLCommonHandler
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
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 = {
if (!disableAudio) {
val distanceBasedGain = math.max(0, 1 - Minecraft.getMinecraft.thePlayer.getDistance(x, y, z) / 12).toFloat
val gain = distanceBasedGain * volume
if (gain > 0 && amplitude > 0 && AL.isCreated) {
val mc = Minecraft.getMinecraft
val distanceBasedGain = math.max(0, 1 - mc.thePlayer.getDistance(x, y, z) / 12).toFloat
val gain = distanceBasedGain * volume
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.
map(ch => if (ch == '.') durationInMilliseconds else 2 * durationInMilliseconds).
map(_ * sampleRate / 1000)

View File

@ -73,13 +73,13 @@ object ItemUtils {
def getIngredients(stack: ItemStack): Array[ItemStack] = try {
def getFilteredInputs(inputs: Iterable[ItemStack], outputSize: Double) = inputs.filter(input =>
input != null &&
input.getItem != null &&
math.floor(input.stackSize / outputSize) > 0 &&
// 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
// to make it output fluids into fluiducts or such, sorry).
!input.getItem.isInstanceOf[ItemBucket]).toArray
def getOutputSize(recipe: IRecipe) =
input.getItem != null &&
math.floor(input.stackSize / outputSize) > 0 &&
// 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
// to make it output fluids into fluiducts or such, sorry).
!input.getItem.isInstanceOf[ItemBucket]).toArray
def getOutputSize(recipe: IRecipe): Double =
if (recipe != null && recipe.getRecipeOutput != null)
recipe.getRecipeOutput.stackSize
else
@ -93,11 +93,11 @@ object ItemUtils {
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: ShapelessOreRecipe) => getFilteredInputs(resolveOreDictEntries(recipe.getInput), getOutputSize(recipe))
case _ => Array.empty
case _ => Array.empty[ItemStack]
}
// Avoid positive feedback loops.
if (ingredients.exists(ingredient => ingredient.isItemEqual(stack))) {
return Array.empty
return Array.empty[ItemStack]
}
// Merge equal items for size division by output size.
val merged = mutable.ArrayBuffer.empty[ItemStack]
@ -122,7 +122,7 @@ object ItemUtils {
catch {
case t: Throwable =>
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()