mirror of
https://github.com/MightyPirates/OpenComputers.git
synced 2025-09-25 22:14:09 -04:00
Merge branch 'master' of https://github.com/MightyPirates/OpenComputers into MC1.7
Conflicts: src/main/scala/li/cil/oc/Blocks.scala src/main/scala/li/cil/oc/Items.scala src/main/scala/li/cil/oc/client/Proxy.scala src/main/scala/li/cil/oc/client/renderer/tileentity/ScreenRenderer.scala src/main/scala/li/cil/oc/common/PacketBuilder.scala src/main/scala/li/cil/oc/common/PacketHandler.scala
This commit is contained in:
commit
44798834c1
@ -1155,7 +1155,7 @@ public class StringLib extends TwoArgFunction {
|
||||
if ( poff == plen || poff + 1 == plen ) {
|
||||
error( "unbalanced pattern" );
|
||||
}
|
||||
if ( s.luaByte( soff ) != p.luaByte( poff ) )
|
||||
if ( soff >= s.length() || s.luaByte( soff ) != p.luaByte( poff ) )
|
||||
return -1;
|
||||
else {
|
||||
int b = p.luaByte( poff );
|
||||
|
@ -12,6 +12,7 @@ oc:tile.Case2.name=Computergehäuse (Stufe 3)
|
||||
oc:tile.Charger.name=Ladestation
|
||||
oc:tile.DiskDrive.name=Diskettenlaufwerk
|
||||
oc:tile.Keyboard.name=Tastatur
|
||||
oc:tile.Hologram.name=Hologrammprojektor
|
||||
oc:tile.PowerConverter.name=Leistungswandler
|
||||
oc:tile.PowerDistributor.name=Stromverteiler
|
||||
oc:tile.Redstone.name=Redstone-I/O
|
||||
@ -136,6 +137,7 @@ oc:tooltip.GraphicsCard=Erlaubt es, den angezeigten Inhalt von Bildschirmen zu
|
||||
oc:tooltip.InternetCard=Diese Karte erlaubt es, HTTP-Anfragen zu senden und echte TCP Sockets zu verwenden.
|
||||
oc:tooltip.IronNugget=Ein Nugget, das aus Eisen besteht, darum wird es ja auch Eisennugget genannt, duh...
|
||||
oc:tooltip.Keyboard=Kann an Bildschirmen befestigt werden, um auf ihnen zu tippen.
|
||||
oc:tooltip.Hologram=Ein Volumendisplay das beliebige, von Computern festgelegte Voxelstrukturen anzeigt.[nl] Auflösung: §f48x32x48§7. [nl] Farbtiefe: §fMonochrom§7.
|
||||
oc:tooltip.Memory=Braucht ein jeder Computer, um zu starten. Je mehr vorhanden, desto komplexere Programme können ausgeführt werden.
|
||||
oc:tooltip.Microchip=Tritt auch unter dem Alias Integrierter Schaltkreis auf. Keine Ahnung, warum das auch mit Redstone klappt, aber es funktioniert.
|
||||
oc:tooltip.NetworkCard=Erlaubt es Computern, die über mehrere Blöcke miteinander verbunden sind (z.B. Kabel), mittels Netzwerknachrichten zu kommunizieren.
|
||||
|
@ -12,6 +12,7 @@ oc:tile.Case2.name=Computer Case (Tier 3)
|
||||
oc:tile.Charger.name=Charger
|
||||
oc:tile.DiskDrive.name=Disk Drive
|
||||
oc:tile.Keyboard.name=Keyboard
|
||||
oc:tile.Hologram.name=Hologram Projector
|
||||
oc:tile.PowerConverter.name=Power Converter
|
||||
oc:tile.PowerDistributor.name=Power Distributor
|
||||
oc:tile.Redstone.name=Redstone I/O
|
||||
@ -136,6 +137,7 @@ oc:tooltip.GraphicsCard=Used to change what's displayed on screens.[nl] Maximum
|
||||
oc:tooltip.InternetCard=This card allows making HTTP requests and using real TCP sockets.
|
||||
oc:tooltip.IronNugget=A nugget made of iron, that's why it's called an Iron Nugget, duh...
|
||||
oc:tooltip.Keyboard=Can be attached to screens to allow typing on them.
|
||||
oc:tooltip.Hologram=A volumetric display that can be controlled by computers to display arbitrary voxel structures.[nl] Resolution: §f48x32x48§7. [nl] Color depth: §fMonochrome§7.
|
||||
oc:tooltip.Memory=Required to get computers to run. The more you have, the more complex the programs you can run.
|
||||
oc:tooltip.Microchip=The chip formerly known as Integrated Circuit. I have no idea why this works with redstone, but it does.
|
||||
oc:tooltip.NetworkCard=Allows distant computers connected by other blocks (such as cable) to communicate by sending messages to each other.
|
||||
|
@ -41,12 +41,8 @@ end
|
||||
|
||||
-- utility method for reply tracking tables.
|
||||
function autocreate(table, key)
|
||||
local value = rawget(table, key)
|
||||
if not value then
|
||||
value = {}
|
||||
rawset(table, key, value)
|
||||
end
|
||||
return value
|
||||
table[key] = {}
|
||||
return table[key]
|
||||
end
|
||||
|
||||
-- extract nickname from identity.
|
||||
@ -172,36 +168,36 @@ local function handleCommand(prefix, command, args, message)
|
||||
print(message)
|
||||
elseif command == commands.RPL_WHOISUSER then
|
||||
local nick = args[2]:lower()
|
||||
whois[nick].nick = nick
|
||||
whois[nick].nick = args[2]
|
||||
whois[nick].user = args[3]
|
||||
whois[nick].host = args[4]
|
||||
whois[nick].realName = message
|
||||
elseif command == commands.RPL_WHOISSERVER then
|
||||
local nick = args[2]
|
||||
local nick = args[2]:lower()
|
||||
whois[nick].server = args[3]
|
||||
whois[nick].serverInfo = message
|
||||
elseif command == commands.RPL_WHOISOPERATOR then
|
||||
local nick = args[2]
|
||||
local nick = args[2]:lower()
|
||||
whois[nick].isOperator = true
|
||||
elseif command == commands.RPL_WHOISIDLE then
|
||||
local nick = args[2]
|
||||
local nick = args[2]:lower()
|
||||
whois[nick].idle = tonumber(args[3])
|
||||
elseif command == commands.RPL_ENDOFWHOIS then
|
||||
local nick = args[2]
|
||||
local nick = args[2]:lower()
|
||||
local info = whois[nick]
|
||||
print("Nick: " .. info.nick)
|
||||
print("User name: " .. info.user)
|
||||
print("Real name: " .. info.realName)
|
||||
print("Host: " .. info.host)
|
||||
print("Server: " .. info.server .. "(" .. info.serverInfo .. ")")
|
||||
print("Channels: " .. info.channels)
|
||||
print("Idle for: " .. info.idle)
|
||||
if info.nick then print("Nick: " .. info.nick) end
|
||||
if info.user then print("User name: " .. info.user) end
|
||||
if info.realName then print("Real name: " .. info.realName) end
|
||||
if info.host then print("Host: " .. info.host) end
|
||||
if info.server then print("Server: " .. info.server .. (info.serverInfo and (" (" .. info.serverInfo .. ")") or "")) end
|
||||
if info.channels then print("Channels: " .. info.channels) end
|
||||
if info.idle then print("Idle for: " .. info.idle) end
|
||||
whois[nick] = nil
|
||||
elseif command == commands.RPL_WHOISCHANNELS then
|
||||
local nick = args[1]
|
||||
local nick = args[2]:lower()
|
||||
whois[nick].channels = message
|
||||
elseif command == commands.RPL_CHANNELMODEIS then
|
||||
print("Channel mode for " .. args[1] .. ": " .. args[2] .. "(" .. args[3] .. ")")
|
||||
print("Channel mode for " .. args[1] .. ": " .. args[2] .. " (" .. args[3] .. ")")
|
||||
elseif command == commands.RPL_NOTOPIC then
|
||||
print("No topic is set for " .. args[1] .. ".")
|
||||
elseif command == commands.RPL_TOPIC then
|
||||
@ -310,7 +306,9 @@ local result, reason = pcall(function()
|
||||
print("[" .. (target or "?") .. "] me: " .. line, true)
|
||||
if line:lower():sub(1, 5) == "/msg " then
|
||||
local user, message = line:sub(6):match("^(%S+) (.+)$")
|
||||
message = text.trim(message)
|
||||
if message then
|
||||
message = text.trim(message)
|
||||
end
|
||||
if not user or not message or message == "" then
|
||||
print("Invalid use of /msg. Usage: /msg nick|channel message.")
|
||||
line = ""
|
||||
@ -342,7 +340,7 @@ local result, reason = pcall(function()
|
||||
print("Error: " .. tostring(reason))
|
||||
elseif type(reason) == "function" then
|
||||
callback = reason
|
||||
else
|
||||
elseif reason then
|
||||
line = tostring(reason)
|
||||
end
|
||||
end
|
||||
@ -368,7 +366,9 @@ if sock then
|
||||
sock:write("QUIT\r\n")
|
||||
sock:close()
|
||||
end
|
||||
event.cancel(timer)
|
||||
if timer then
|
||||
event.cancel(timer)
|
||||
end
|
||||
|
||||
if not result then
|
||||
error(reason, 0)
|
||||
|
@ -1,5 +1,5 @@
|
||||
local hookInterval = 100
|
||||
local deadline = 0
|
||||
local deadline = math.huge
|
||||
local function checkDeadline()
|
||||
if computer.realTime() > deadline then
|
||||
debug.sethook(coroutine.running(), checkDeadline, "", 1)
|
||||
@ -91,7 +91,11 @@ sandbox = {
|
||||
loadfile = nil, -- in boot/*_base.lua
|
||||
next = next,
|
||||
pairs = pairs,
|
||||
pcall = pcall,
|
||||
pcall = function(...)
|
||||
local result = table.pack(pcall(...))
|
||||
checkDeadline()
|
||||
return table.unpack(result, 1, result.n)
|
||||
end,
|
||||
print = nil, -- in boot/*_base.lua
|
||||
rawequal = rawequal,
|
||||
rawget = rawget,
|
||||
@ -103,7 +107,11 @@ sandbox = {
|
||||
tostring = tostring,
|
||||
type = type,
|
||||
_VERSION = "Lua 5.2",
|
||||
xpcall = xpcall,
|
||||
xpcall = function(...)
|
||||
local result = table.pack(xpcall(...))
|
||||
checkDeadline()
|
||||
return table.unpack(result, 1, result.n)
|
||||
end,
|
||||
|
||||
coroutine = {
|
||||
create = function(f)
|
||||
|
@ -121,7 +121,7 @@ if #args == 0 and (io.input() == io.stdin or options.i) and not options.c then
|
||||
elseif command ~= "" then
|
||||
local result, reason = execute(command)
|
||||
if not result then
|
||||
io.stderr:write(reason .. "\n")
|
||||
io.stderr:write((tostring(reason) or "unknown error").. "\n")
|
||||
elseif term.getCursor() > 1 then
|
||||
term.write("\n")
|
||||
end
|
||||
|
@ -13,8 +13,9 @@ while true do
|
||||
io.write(_OSVERSION .. " (" .. math.floor(computer.totalMemory() / 1024) .. "k RAM)\n")
|
||||
local result, reason = os.execute(os.getenv("SHELL") .. " -")
|
||||
if not result then
|
||||
io.stderr:write((reason or "unknown error") .. "\n")
|
||||
io.stderr:write((tostring(reason) or "unknown error") .. "\n")
|
||||
print("Press any key to continue.")
|
||||
os.sleep(0.5)
|
||||
event.pull("key")
|
||||
end
|
||||
end
|
@ -338,7 +338,7 @@ function term.write(value, wrap)
|
||||
end
|
||||
local blink = term.getCursorBlink()
|
||||
term.setCursorBlink(false)
|
||||
local line, nl = value
|
||||
local line, nl
|
||||
repeat
|
||||
local wrapAfter, margin = math.huge, math.huge
|
||||
if wrap then
|
||||
@ -356,7 +356,7 @@ function term.write(value, wrap)
|
||||
component.gpu.fill(1, h, w, 1, " ")
|
||||
cursorY = h
|
||||
end
|
||||
until not wrap or not value
|
||||
until not value
|
||||
term.setCursorBlink(blink)
|
||||
end
|
||||
|
||||
|
@ -271,7 +271,7 @@ powerDistributor {
|
||||
rack {
|
||||
input: [["oc:circuitTier2", "oc:componentCardWLan", "oc:circuitTier2"]
|
||||
[fenceIron, chest, fenceIron]
|
||||
["oc:craftingRouter", "oc:craftingCircuitBoardPrinted","oc:craftingPowerDistributor"]]
|
||||
["oc:craftingRouter", "oc:craftingCircuitBoardPrinted", "oc:craftingPowerDistributor"]]
|
||||
}
|
||||
redstone {
|
||||
input: [[ingotIron, blockRedstone, ingotIron]
|
||||
@ -302,4 +302,9 @@ screen3 {
|
||||
input: [[obsidian, yellowDust, obsidian]
|
||||
[yellowDust, "oc:circuitTier3", glass]
|
||||
[obsidian, yellowDust, obsidian]]
|
||||
}
|
||||
hologram {
|
||||
input: [[obsidian, glass, obsidian]
|
||||
["oc:craftingCircuitBoardPrinted", diamond, "oc:craftingCircuitBoardPrinted"]
|
||||
["oc:circuitTier3", blazeRod, "oc:circuitTier3"]]
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 157 B |
Binary file not shown.
After Width: | Height: | Size: 185 B |
Binary file not shown.
After Width: | Height: | Size: 421 B |
@ -456,6 +456,11 @@ opencomputers {
|
||||
# tick.
|
||||
screen: 0.05
|
||||
|
||||
# The amount of energy a hologram projetor consumes per tick. This
|
||||
# is the cost if every column is lit. If not a single voxel is
|
||||
# displayed the hologram projector will not drain energy.
|
||||
hologram: 0.2
|
||||
|
||||
# Energy it takes read one kilobyte from a file system. Note that non
|
||||
# I/O operations on file systems such as `list` or `getFreeSpace` do
|
||||
# *not* consume power. Note that this very much determines how much
|
||||
|
@ -21,6 +21,7 @@ object Blocks {
|
||||
var diskDrive: DiskDrive = _
|
||||
var keyboard: Keyboard = _
|
||||
var keyboardDeprecated: KeyboardDeprecated = _
|
||||
var hologram: Hologram = _
|
||||
var powerConverter: PowerConverter = _
|
||||
var powerDistributor: PowerDistributor = _
|
||||
var redstone: Redstone = _
|
||||
@ -92,6 +93,7 @@ object Blocks {
|
||||
GameRegistry.registerTileEntity(classOf[tileentity.Charger], Settings.namespace + "charger")
|
||||
GameRegistry.registerTileEntity(classOf[tileentity.DiskDrive], Settings.namespace + "disk_drive")
|
||||
GameRegistry.registerTileEntity(classOf[tileentity.Keyboard], Settings.namespace + "keyboard")
|
||||
GameRegistry.registerTileEntity(classOf[tileentity.Hologram], Settings.namespace + "hologram")
|
||||
GameRegistry.registerTileEntity(classOf[tileentity.PowerConverter], Settings.namespace + "power_converter")
|
||||
GameRegistry.registerTileEntity(classOf[tileentity.PowerDistributor], Settings.namespace + "power_distributor")
|
||||
GameRegistry.registerTileEntity(classOf[tileentity.Redstone], Settings.namespace + "redstone")
|
||||
@ -100,6 +102,9 @@ object Blocks {
|
||||
GameRegistry.registerTileEntity(classOf[tileentity.Screen], Settings.namespace + "screen")
|
||||
GameRegistry.registerTileEntity(classOf[tileentity.Rack], Settings.namespace + "serverRack")
|
||||
|
||||
// v1.2.2
|
||||
hologram = Recipes.addBlockDelegate(new Hologram(blockSpecial), "hologram")
|
||||
|
||||
register("oc:craftingCable", cable.createItemStack())
|
||||
register("oc:craftingCapacitor", capacitor.createItemStack())
|
||||
register("oc:craftingCaseTier1", case1.createItemStack())
|
||||
|
@ -94,9 +94,6 @@ object Items {
|
||||
upgradeGenerator = Recipes.addItemDelegate(new item.UpgradeGenerator(multi), "generatorUpgrade")
|
||||
|
||||
ironNugget = new item.IronNugget(multi)
|
||||
if (OreDictionary.getOres("nuggetIron").exists(ironNugget.createItemStack().isItemEqual)) {
|
||||
Recipes.addItemDelegate(ironNugget, "nuggetIron")
|
||||
}
|
||||
|
||||
cuttingWire = Recipes.addItemDelegate(new item.CuttingWire(multi), "cuttingWire")
|
||||
acid = Recipes.addItemDelegate(new item.Acid(multi), "acid")
|
||||
@ -181,6 +178,10 @@ object Items {
|
||||
register("oc:craftingAcid", acid.createItemStack())
|
||||
register("oc:craftingGenerator", upgradeGenerator.createItemStack())
|
||||
register("oc:craftingSolarGenerator", upgradeSolarGenerator.createItemStack())
|
||||
|
||||
if (OreDictionary.getOres("nuggetIron").exists(ironNugget.createItemStack().isItemEqual)) {
|
||||
Recipes.addItemDelegate(ironNugget, "nuggetIron")
|
||||
}
|
||||
}
|
||||
|
||||
def register(name: String, item: ItemStack) {
|
||||
|
@ -111,6 +111,7 @@ class Settings(config: Config) {
|
||||
val robotCost = config.getDouble("power.cost.robot") max 0
|
||||
val sleepCostFactor = config.getDouble("power.cost.sleepFactor") max 0
|
||||
val screenCost = config.getDouble("power.cost.screen") max 0
|
||||
val hologramCost = config.getDouble("power.cost.hologram") max 0
|
||||
val hddReadCost = (config.getDouble("power.cost.hddRead") max 0) / 1024
|
||||
val hddWriteCost = (config.getDouble("power.cost.hddWrite") max 0) / 1024
|
||||
val gpuSetCost = (config.getDouble("power.cost.gpuSet") max 0) / Settings.basicScreenPixels
|
||||
|
@ -15,21 +15,26 @@ import net.minecraftforge.common.util.ForgeDirection
|
||||
import org.lwjgl.input.Keyboard
|
||||
|
||||
object PacketHandler extends CommonPacketHandler {
|
||||
@SubscribeEvent
|
||||
def onPacket(e: ClientCustomPacketEvent) =
|
||||
onPacketData(e.packet.payload, Minecraft.getMinecraft.thePlayer)
|
||||
|
||||
protected override def world(player: EntityPlayer, dimension: Int) = {
|
||||
val world = player.worldObj
|
||||
if (world.provider.dimensionId == dimension) Some(world)
|
||||
else None
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
def onPacket(e: ClientCustomPacketEvent) {
|
||||
val p = new PacketParser(e.packet.payload, Minecraft.getMinecraft.thePlayer)
|
||||
override def dispatch(p: PacketParser) {
|
||||
p.packetType match {
|
||||
case PacketType.AbstractBusState => onAbstractBusState(p)
|
||||
case PacketType.Analyze => onAnalyze(p)
|
||||
case PacketType.ChargerState => onChargerState(p)
|
||||
case PacketType.ComputerState => onComputerState(p)
|
||||
case PacketType.ComputerUserList => onComputerUserList(p)
|
||||
case PacketType.HologramClear => onHologramClear(p)
|
||||
case PacketType.HologramScale => onHologramScale(p)
|
||||
case PacketType.HologramSet => onHologramSet(p)
|
||||
case PacketType.PowerState => onPowerState(p)
|
||||
case PacketType.RedstoneState => onRedstoneState(p)
|
||||
case PacketType.RobotAnimateSwing => onRobotAnimateSwing(p)
|
||||
@ -104,6 +109,38 @@ object PacketHandler extends CommonPacketHandler {
|
||||
case _ => // Invalid packet.
|
||||
}
|
||||
|
||||
def onHologramClear(p: PacketParser) =
|
||||
p.readTileEntity[Hologram]() match {
|
||||
case Some(t) =>
|
||||
for (i <- 0 until t.volume.length) t.volume(i) = 0
|
||||
t.dirty = true
|
||||
case _ => // Invalid packet.
|
||||
}
|
||||
|
||||
def onHologramScale(p: PacketParser) =
|
||||
p.readTileEntity[Hologram]() match {
|
||||
case Some(t) =>
|
||||
t.scale = p.readDouble()
|
||||
t.dirty = true
|
||||
case _ => // Invalid packet.
|
||||
}
|
||||
|
||||
def onHologramSet(p: PacketParser) =
|
||||
p.readTileEntity[Hologram]() match {
|
||||
case Some(t) =>
|
||||
val fromX = p.readByte(): Int
|
||||
val untilX = p.readByte(): Int
|
||||
val fromZ = p.readByte(): Int
|
||||
val untilZ = p.readByte(): Int
|
||||
for (x <- fromX until untilX) {
|
||||
for (z <- fromZ until untilZ) {
|
||||
t.volume(x + z * t.width) = p.readInt()
|
||||
}
|
||||
}
|
||||
t.dirty = true
|
||||
case _ => // Invalid packet.
|
||||
}
|
||||
|
||||
def onPowerState(p: PacketParser) =
|
||||
p.readTileEntity[PowerInformation]() match {
|
||||
case Some(t) =>
|
||||
|
@ -32,6 +32,7 @@ private[oc] class Proxy extends CommonProxy {
|
||||
|
||||
ClientRegistry.bindTileEntitySpecialRenderer(classOf[tileentity.Cable], CableRenderer)
|
||||
ClientRegistry.bindTileEntitySpecialRenderer(classOf[tileentity.Case], CaseRenderer)
|
||||
ClientRegistry.bindTileEntitySpecialRenderer(classOf[tileentity.Hologram], HologramRenderer)
|
||||
ClientRegistry.bindTileEntitySpecialRenderer(classOf[tileentity.PowerDistributor], PowerDistributorRenderer)
|
||||
ClientRegistry.bindTileEntitySpecialRenderer(classOf[tileentity.Rack], RackRenderer)
|
||||
ClientRegistry.bindTileEntitySpecialRenderer(classOf[tileentity.RobotProxy], RobotRenderer)
|
||||
@ -45,6 +46,7 @@ private[oc] class Proxy extends CommonProxy {
|
||||
override def postInit(e: FMLPostInitializationEvent) {
|
||||
super.postInit(e)
|
||||
|
||||
FMLCommonHandler.instance().bus().register(HologramRenderer)
|
||||
FMLCommonHandler.instance().bus().register(ScreenRenderer)
|
||||
if (Settings.get.rTreeDebugRenderer) {
|
||||
MinecraftForge.EVENT_BUS.register(WirelessNetworkDebugRenderer)
|
||||
|
@ -21,6 +21,7 @@ object Textures {
|
||||
|
||||
val blockCable = new ResourceLocation(Settings.resourceDomain, "textures/blocks/cable.png")
|
||||
val blockCaseFrontOn = new ResourceLocation(Settings.resourceDomain, "textures/blocks/case_front_on.png")
|
||||
val blockHologram = new ResourceLocation(Settings.resourceDomain, "textures/blocks/hologram_effect.png")
|
||||
val blockPowerDistributorOn = new ResourceLocation(Settings.resourceDomain, "textures/blocks/power_distributor_on.png")
|
||||
val blockRackFrontOn = new ResourceLocation(Settings.resourceDomain, "textures/blocks/rack_front_on.png")
|
||||
val blockRobot = new ResourceLocation(Settings.resourceDomain, "textures/blocks/robot.png")
|
||||
|
@ -40,6 +40,7 @@ object CableRenderer extends TileEntitySpecialRenderer {
|
||||
|
||||
for (mask <- 0 to 0xFF >> 2) {
|
||||
GL11.glNewList(displayLists + mask, GL11.GL_COMPILE)
|
||||
t.startDrawingQuads()
|
||||
for (side <- ForgeDirection.VALID_DIRECTIONS) {
|
||||
val connects = (side.flag & mask) != 0
|
||||
val z = if (connects) 0 else lb
|
||||
@ -48,7 +49,6 @@ object CableRenderer extends TileEntitySpecialRenderer {
|
||||
exists(s => (s.flag & mask) != 0)) uo
|
||||
else 0
|
||||
|
||||
t.startDrawingQuads()
|
||||
t.setNormal(side.offsetX, side.offsetY, -side.offsetZ)
|
||||
val (tx, ty, tz, u, v) = side match {
|
||||
case ForgeDirection.WEST => (Array.fill(4)(z), t2, t1, uv1.reverse, uv2)
|
||||
@ -63,7 +63,6 @@ object CableRenderer extends TileEntitySpecialRenderer {
|
||||
t.addVertexWithUV(tx(1), ty(1), tz(1), u(1) + uc, v(1))
|
||||
t.addVertexWithUV(tx(2), ty(2), tz(2), u(2) + uc, v(2))
|
||||
t.addVertexWithUV(tx(3), ty(3), tz(3), u(3) + uc, v(3))
|
||||
t.draw()
|
||||
|
||||
if (connects) {
|
||||
val (axis, sign, uv1, uv2, uv3, uv4) = side match {
|
||||
@ -79,39 +78,32 @@ object CableRenderer extends TileEntitySpecialRenderer {
|
||||
val o1 = offsets((axis + sign + 3) % 3)
|
||||
val o2 = offsets((axis - sign + 3) % 3)
|
||||
|
||||
t.startDrawingQuads()
|
||||
normal(side, 0)
|
||||
t.addVertexWithUV(tx(0) - sign * tl(0), ty(0) - sign * tl(1), tz(0) - sign * tl(2), u(uv(0 + uv1)) + uo, v(uv(0 + uv1)) * vs)
|
||||
t.addVertexWithUV(tx(1) - sign * tl(0), ty(1) - sign * tl(1), tz(1) - sign * tl(2), u(uv(1 + uv1)) + uo, v(uv(1 + uv1)) * vs)
|
||||
t.addVertexWithUV(tx(2) + o1(0), ty(2) + o1(1), tz(2) + o1(2), u(uv(2 + uv1)) + uo, v(uv(2 + uv1)) * vs)
|
||||
t.addVertexWithUV(tx(3) + o1(0), ty(3) + o1(1), tz(3) + o1(2), u(uv(3 + uv1)) + uo, v(uv(3 + uv1)) * vs)
|
||||
t.draw()
|
||||
|
||||
t.startDrawingQuads()
|
||||
normal(side, 1)
|
||||
t.addVertexWithUV(tx(0) - o1(0), ty(0) - o1(1), tz(0) - o1(2), u(uv(0 + uv2)) + uo, v(uv(0 + uv2)) * vs)
|
||||
t.addVertexWithUV(tx(1) - o1(0), ty(1) - o1(1), tz(1) - o1(2), u(uv(1 + uv2)) + uo, v(uv(1 + uv2)) * vs)
|
||||
t.addVertexWithUV(tx(2) - sign * tl(0), ty(2) - sign * tl(1), tz(2) - sign * tl(2), u(uv(2 + uv2)) + uo, v(uv(2 + uv2)) * vs)
|
||||
t.addVertexWithUV(tx(3) - sign * tl(0), ty(3) - sign * tl(1), tz(3) - sign * tl(2), u(uv(3 + uv2)) + uo, v(uv(3 + uv2)) * vs)
|
||||
t.draw()
|
||||
|
||||
t.startDrawingQuads()
|
||||
normal(side, 2)
|
||||
t.addVertexWithUV(tx(0) - sign * tl(0), ty(0) - sign * tl(1), tz(0) - sign * tl(2), u(uv(0 + uv3)) + uo, v(uv(0 + uv3)) * vs)
|
||||
t.addVertexWithUV(tx(1) - o2(0), ty(1) - o2(1), tz(1) - o2(2), u(uv(1 + uv3)) + uo, v(uv(1 + uv3)) * vs)
|
||||
t.addVertexWithUV(tx(2) - o2(0), ty(2) - o2(1), tz(2) - o2(2), u(uv(2 + uv3)) + uo, v(uv(2 + uv3)) * vs)
|
||||
t.addVertexWithUV(tx(3) - sign * tl(0), ty(3) - sign * tl(1), tz(3) - sign * tl(2), u(uv(3 + uv3)) + uo, v(uv(3 + uv3)) * vs)
|
||||
t.draw()
|
||||
|
||||
t.startDrawingQuads()
|
||||
normal(side, 3)
|
||||
t.addVertexWithUV(tx(0) + o2(0), ty(0) + o2(1), tz(0) + o2(2), u(uv(0 + uv4)) + uo, v(uv(0 + uv4)) * vs)
|
||||
t.addVertexWithUV(tx(1) - sign * tl(0), ty(1) - sign * tl(1), tz(1) - sign * tl(2), u(uv(1 + uv4)) + uo, v(uv(1 + uv4)) * vs)
|
||||
t.addVertexWithUV(tx(2) - sign * tl(0), ty(2) - sign * tl(1), tz(2) - sign * tl(2), u(uv(2 + uv4)) + uo, v(uv(2 + uv4)) * vs)
|
||||
t.addVertexWithUV(tx(3) + o2(0), ty(3) + o2(1), tz(3) + o2(2), u(uv(3 + uv4)) + uo, v(uv(3 + uv4)) * vs)
|
||||
t.draw()
|
||||
}
|
||||
}
|
||||
t.draw()
|
||||
|
||||
GL11.glEndList()
|
||||
}
|
||||
|
@ -0,0 +1,178 @@
|
||||
package li.cil.oc.client.renderer.tileentity
|
||||
|
||||
import com.google.common.cache.{RemovalNotification, RemovalListener, CacheBuilder}
|
||||
import cpw.mods.fml.common.eventhandler.SubscribeEvent
|
||||
import cpw.mods.fml.common.gameevent.TickEvent.ClientTickEvent
|
||||
import java.util.concurrent.{Callable, TimeUnit}
|
||||
import li.cil.oc.common.tileentity.Hologram
|
||||
import li.cil.oc.util.RenderState
|
||||
import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer
|
||||
import net.minecraft.client.renderer.{GLAllocation, Tessellator}
|
||||
import net.minecraft.tileentity.TileEntity
|
||||
import org.lwjgl.opengl.GL11
|
||||
import scala.util.Random
|
||||
import li.cil.oc.client.Textures
|
||||
|
||||
object HologramRenderer extends TileEntitySpecialRenderer with Callable[Int] with RemovalListener[TileEntity, Int] {
|
||||
val random = new Random()
|
||||
|
||||
/** We cache the display lists for the projectors we render for performance. */
|
||||
val cache = com.google.common.cache.CacheBuilder.newBuilder().
|
||||
expireAfterAccess(2, TimeUnit.SECONDS).
|
||||
removalListener(this).
|
||||
asInstanceOf[CacheBuilder[Hologram, Int]].
|
||||
build[Hologram, Int]()
|
||||
|
||||
/** Used to pass the current screen along to call(). */
|
||||
private var hologram: Hologram = null
|
||||
|
||||
override def renderTileEntityAt(te: TileEntity, x: Double, y: Double, z: Double, f: Float) {
|
||||
hologram = te.asInstanceOf[Hologram]
|
||||
if (!hologram.hasPower) return
|
||||
|
||||
GL11.glPushAttrib(0xFFFFFFFF)
|
||||
|
||||
GL11.glPushMatrix()
|
||||
GL11.glTranslated(x + 0.5, y + 0.5, z + 0.5)
|
||||
GL11.glScaled(1.001, 1.001, 1.001) // Avoid z-fighting with other blocks.
|
||||
GL11.glTranslated(-1.5 * hologram.scale, 0, -1.5 * hologram.scale)
|
||||
|
||||
// Do a bit of flickering, because that's what holograms do!
|
||||
if (random.nextDouble() < 0.025) {
|
||||
GL11.glScaled(1 + random.nextGaussian() * 0.01, 1 + random.nextGaussian() * 0.001, 1 + random.nextGaussian() * 0.01)
|
||||
GL11.glTranslated(random.nextGaussian() * 0.01, random.nextGaussian() * 0.01, random.nextGaussian() * 0.01)
|
||||
}
|
||||
|
||||
// We do two passes here to avoid weird transparency effects: in the first
|
||||
// pass we find the front-most fragment, in the second we actually draw it.
|
||||
// TODO proper transparency shader? depth peeling e.g.
|
||||
GL11.glColorMask(false, false, false, false)
|
||||
val list = cache.get(hologram, this)
|
||||
compileOrDraw(list)
|
||||
GL11.glColorMask(true, true, true, true)
|
||||
GL11.glDepthFunc(GL11.GL_EQUAL)
|
||||
compileOrDraw(list)
|
||||
|
||||
GL11.glPopMatrix()
|
||||
GL11.glPopAttrib()
|
||||
}
|
||||
|
||||
def compileOrDraw(list: Int) = if (hologram.dirty) {
|
||||
val doCompile = !RenderState.compilingDisplayList
|
||||
if (doCompile) {
|
||||
hologram.dirty = false
|
||||
GL11.glNewList(list, GL11.GL_COMPILE_AND_EXECUTE)
|
||||
}
|
||||
|
||||
def isSolid(hx: Int, hy: Int, hz: Int) = {
|
||||
hx >= 0 && hy >= 0 && hz >= 0 && hx < hologram.width && hy < hologram.height && hz < hologram.width &&
|
||||
(hologram.volume(hx + hz * hologram.width) & (1 << hy)) != 0
|
||||
}
|
||||
|
||||
bindTexture(Textures.blockHologram)
|
||||
val t = Tessellator.instance
|
||||
t.startDrawingQuads()
|
||||
t.setColorRGBA_F(1, 1, 1, 0.5f)
|
||||
|
||||
// TODO merge quads for better rendering performance
|
||||
val s = 1f / 16f * hologram.scale
|
||||
for (hx <- 0 until hologram.width) {
|
||||
val wx = hx * s
|
||||
for (hz <- 0 until hologram.width) {
|
||||
val wz = hz * s
|
||||
for (hy <- 0 until hologram.height) {
|
||||
val wy = hy * s
|
||||
|
||||
if (isSolid(hx, hy, hz)) {
|
||||
/*
|
||||
0---1
|
||||
| N |
|
||||
0---3---2---1---0
|
||||
| W | U | E | D |
|
||||
5---6---7---4---5
|
||||
| S |
|
||||
5---4
|
||||
*/
|
||||
|
||||
// South
|
||||
if (!isSolid(hx, hy, hz + 1)) {
|
||||
t.setNormal(0, 0, 1)
|
||||
t.addVertexWithUV(wx + s, wy + s, wz + s, 0, 0) // 5
|
||||
t.addVertexWithUV(wx + 0, wy + s, wz + s, 1, 0) // 4
|
||||
t.addVertexWithUV(wx + 0, wy + 0, wz + s, 1, 1) // 7
|
||||
t.addVertexWithUV(wx + s, wy + 0, wz + s, 0, 1) // 6
|
||||
}
|
||||
// North
|
||||
if (!isSolid(hx, hy, hz - 1)) {
|
||||
t.setNormal(0, 0, -1)
|
||||
t.addVertexWithUV(wx + s, wy + 0, wz + 0, 0, 0) // 3
|
||||
t.addVertexWithUV(wx + 0, wy + 0, wz + 0, 1, 0) // 2
|
||||
t.addVertexWithUV(wx + 0, wy + s, wz + 0, 1, 1) // 1
|
||||
t.addVertexWithUV(wx + s, wy + s, wz + 0, 0, 1) // 0
|
||||
}
|
||||
|
||||
// East
|
||||
if (!isSolid(hx + 1, hy, hz)) {
|
||||
t.setNormal(1, 0, 0)
|
||||
t.addVertexWithUV(wx + s, wy + s, wz + s, 1, 0) // 5
|
||||
t.addVertexWithUV(wx + s, wy + 0, wz + s, 1, 1) // 6
|
||||
t.addVertexWithUV(wx + s, wy + 0, wz + 0, 0, 1) // 3
|
||||
t.addVertexWithUV(wx + s, wy + s, wz + 0, 0, 0) // 0
|
||||
}
|
||||
// West
|
||||
if (!isSolid(hx - 1, hy, hz)) {
|
||||
t.setNormal(-1, 0, 0)
|
||||
t.addVertexWithUV(wx + 0, wy + 0, wz + s, 1, 0) // 7
|
||||
t.addVertexWithUV(wx + 0, wy + s, wz + s, 1, 1) // 4
|
||||
t.addVertexWithUV(wx + 0, wy + s, wz + 0, 0, 1) // 1
|
||||
t.addVertexWithUV(wx + 0, wy + 0, wz + 0, 0, 0) // 2
|
||||
}
|
||||
|
||||
// Up
|
||||
if (!isSolid(hx, hy + 1, hz)) {
|
||||
t.setNormal(0, 1, 0)
|
||||
t.addVertexWithUV(wx + s, wy + s, wz + 0, 0, 0) // 0
|
||||
t.addVertexWithUV(wx + 0, wy + s, wz + 0, 1, 0) // 1
|
||||
t.addVertexWithUV(wx + 0, wy + s, wz + s, 1, 1) // 4
|
||||
t.addVertexWithUV(wx + s, wy + s, wz + s, 0, 1) // 5
|
||||
}
|
||||
// Down
|
||||
if (!isSolid(hx, hy - 1, hz)) {
|
||||
t.setNormal(0, -1, 0)
|
||||
t.addVertexWithUV(wx + s, wy + 0, wz + s, 0, 0) // 6
|
||||
t.addVertexWithUV(wx + 0, wy + 0, wz + s, 1, 0) // 7
|
||||
t.addVertexWithUV(wx + 0, wy + 0, wz + 0, 1, 1) // 2
|
||||
t.addVertexWithUV(wx + s, wy + 0, wz + 0, 0, 1) // 3
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
t.draw()
|
||||
|
||||
if (doCompile) {
|
||||
GL11.glEndList()
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
else GL11.glCallList(list)
|
||||
|
||||
// ----------------------------------------------------------------------- //
|
||||
// Cache
|
||||
// ----------------------------------------------------------------------- //
|
||||
|
||||
def call = {
|
||||
val list = GLAllocation.generateDisplayLists(1)
|
||||
hologram.dirty = true // Force compilation.
|
||||
list
|
||||
}
|
||||
|
||||
def onRemoval(e: RemovalNotification[TileEntity, Int]) {
|
||||
GLAllocation.deleteDisplayLists(e.getValue)
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
def onTick(e: ClientTickEvent) = cache.cleanUp()
|
||||
}
|
@ -74,8 +74,7 @@ object ScreenRenderer extends TileEntitySpecialRenderer with Callable[Int] with
|
||||
|
||||
if (screen.hasPower) {
|
||||
MonospaceFontRenderer.init(this.field_147501_a.field_147553_e)
|
||||
val list = cache.get(screen, this)
|
||||
compileOrDraw(list)
|
||||
compileOrDraw(cache.get(screen, this))
|
||||
}
|
||||
|
||||
GL11.glPopMatrix()
|
||||
|
@ -3,8 +3,8 @@ package li.cil.oc.common
|
||||
import cpw.mods.fml.common.FMLCommonHandler
|
||||
import cpw.mods.fml.common.network.internal.FMLProxyPacket
|
||||
import io.netty.buffer.Unpooled
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.io.DataOutputStream
|
||||
import java.io.{OutputStream, ByteArrayOutputStream, DataOutputStream}
|
||||
import java.util.zip.GZIPOutputStream
|
||||
import li.cil.oc.common.tileentity.TileEntity
|
||||
import li.cil.oc.OpenComputers
|
||||
import net.minecraft.entity.player.EntityPlayerMP
|
||||
@ -14,9 +14,8 @@ import net.minecraft.world.World
|
||||
import net.minecraftforge.common.util.ForgeDirection
|
||||
import scala.collection.convert.WrapAsScala._
|
||||
|
||||
class PacketBuilder(packetType: PacketType.Value, private val stream: ByteArrayOutputStream = new ByteArrayOutputStream) extends DataOutputStream(stream) {
|
||||
writeByte(packetType.id)
|
||||
|
||||
// Necessary to keep track of the GZIP stream.
|
||||
abstract class PacketBuilderBase[T <: OutputStream](protected val stream: T) extends DataOutputStream(stream) {
|
||||
def writeTileEntity(t: TileEntity) = {
|
||||
writeInt(t.world.provider.dimensionId)
|
||||
writeInt(t.x)
|
||||
@ -57,5 +56,30 @@ class PacketBuilder(packetType: PacketType.Value, private val stream: ByteArrayO
|
||||
|
||||
def sendToServer() = OpenComputers.channel.sendToServer(packet)
|
||||
|
||||
private def packet = new FMLProxyPacket(Unpooled.wrappedBuffer(stream.toByteArray), "OpenComputers")
|
||||
protected def packet: FMLProxyPacket
|
||||
}
|
||||
|
||||
class PacketBuilder(packetType: PacketType.Value) extends PacketBuilderBase(PacketBuilder.newData(compressed = false)) {
|
||||
writeByte(packetType.id)
|
||||
|
||||
override protected def packet = {
|
||||
new FMLProxyPacket(Unpooled.wrappedBuffer(stream.toByteArray), "OpenComputers")
|
||||
}
|
||||
}
|
||||
|
||||
class CompressedPacketBuilder(packetType: PacketType.Value, private val data: ByteArrayOutputStream = PacketBuilder.newData(compressed = true)) extends PacketBuilderBase(new GZIPOutputStream(data)) {
|
||||
writeByte(packetType.id)
|
||||
|
||||
override protected def packet = {
|
||||
stream.finish()
|
||||
new FMLProxyPacket(Unpooled.wrappedBuffer(data.toByteArray), "OpenComputers")
|
||||
}
|
||||
}
|
||||
|
||||
object PacketBuilder {
|
||||
def newData(compressed: Boolean) = {
|
||||
val data = new ByteArrayOutputStream
|
||||
data.write(if (compressed) 1 else 0)
|
||||
data
|
||||
}
|
||||
}
|
@ -1,8 +1,10 @@
|
||||
package li.cil.oc.common
|
||||
|
||||
import io.netty.buffer.{ByteBufInputStream, ByteBuf}
|
||||
import java.io.DataInputStream
|
||||
import li.cil.oc.Blocks
|
||||
import java.io.{InputStream, DataInputStream}
|
||||
import java.util.logging.Level
|
||||
import java.util.zip.GZIPInputStream
|
||||
import li.cil.oc.{Blocks, OpenComputers}
|
||||
import net.minecraft.entity.player.EntityPlayer
|
||||
import net.minecraft.item.ItemStack
|
||||
import net.minecraft.nbt.CompressedStreamTools
|
||||
@ -12,6 +14,21 @@ import scala.reflect.ClassTag
|
||||
import scala.reflect.classTag
|
||||
|
||||
abstract class PacketHandler {
|
||||
/** Top level dispatcher based on packet type. */
|
||||
protected def onPacketData(data: ByteBuf, player: EntityPlayer) {
|
||||
// Don't crash on badly formatted packets (may have been altered by a
|
||||
// malicious client, in which case we don't want to allow it to kill the
|
||||
// server like this). Just spam the log a bit... ;)
|
||||
try {
|
||||
val stream = new ByteBufInputStream(data)
|
||||
if (stream.read() == 0) dispatch(new PacketParser(stream, player))
|
||||
else dispatch(new PacketParser(new GZIPInputStream(stream), player))
|
||||
} catch {
|
||||
case e: Throwable =>
|
||||
OpenComputers.log.log(Level.WARNING, "Received a badly formatted packet.", e)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the world for the specified dimension.
|
||||
*
|
||||
@ -21,7 +38,9 @@ abstract class PacketHandler {
|
||||
*/
|
||||
protected def world(player: EntityPlayer, dimension: Int): Option[World]
|
||||
|
||||
protected class PacketParser(data: ByteBuf, val player: EntityPlayer) extends DataInputStream(new ByteBufInputStream(data)) {
|
||||
protected def dispatch(p: PacketParser)
|
||||
|
||||
protected class PacketParser(stream: InputStream, val player: EntityPlayer) extends DataInputStream(stream) {
|
||||
val packetType = PacketType(readByte())
|
||||
|
||||
def getTileEntity[T: ClassTag](dimension: Int, x: Int, y: Int, z: Int): Option[T] = {
|
||||
|
@ -8,6 +8,9 @@ object PacketType extends Enumeration {
|
||||
ChargerState,
|
||||
ComputerState,
|
||||
ComputerUserList,
|
||||
HologramClear,
|
||||
HologramScale,
|
||||
HologramSet,
|
||||
PowerState,
|
||||
RedstoneState,
|
||||
RobotAnimateSwing,
|
||||
|
@ -44,11 +44,11 @@ trait Delegate {
|
||||
// items in 1.7 when needed since IDs are no problem anymore.
|
||||
// def canPlaceBlockOnSide(world: World, x: Int, y: Int, z: Int, side: ForgeDirection) = true
|
||||
|
||||
def bounds(world: World, x: Int, y: Int, z: Int) =
|
||||
def bounds(world: IBlockAccess, x: Int, y: Int, z: Int) =
|
||||
AxisAlignedBB.getAABBPool.getAABB(0, 0, 0, 1, 1, 1)
|
||||
|
||||
def updateBounds(world: IBlockAccess, x: Int, y: Int, z: Int) =
|
||||
parent.setBlockBounds(0, 0, 0, 1, 1, 1)
|
||||
parent.setBlockBounds(bounds(world, x, y, z))
|
||||
|
||||
def intersect(world: World, x: Int, y: Int, z: Int, origin: Vec3, direction: Vec3) =
|
||||
parent.superCollisionRayTrace(world, x, y, z, origin, direction)
|
||||
|
53
src/main/scala/li/cil/oc/common/block/Hologram.scala
Normal file
53
src/main/scala/li/cil/oc/common/block/Hologram.scala
Normal file
@ -0,0 +1,53 @@
|
||||
package li.cil.oc.common.block
|
||||
|
||||
import java.util
|
||||
import li.cil.oc.Settings
|
||||
import li.cil.oc.common.tileentity
|
||||
import li.cil.oc.util.Tooltip
|
||||
import net.minecraft.client.renderer.texture.IIconRegister
|
||||
import net.minecraft.entity.player.EntityPlayer
|
||||
import net.minecraft.item.{ItemStack, EnumRarity}
|
||||
import net.minecraft.world.{World, IBlockAccess}
|
||||
import net.minecraft.util.{IIcon, AxisAlignedBB}
|
||||
import net.minecraftforge.common.util.ForgeDirection
|
||||
|
||||
class Hologram(val parent: SpecialDelegator) extends SpecialDelegate {
|
||||
val unlocalizedName = "Hologram"
|
||||
|
||||
private val icons = Array.fill[IIcon](6)(null)
|
||||
|
||||
override def rarity = EnumRarity.rare
|
||||
|
||||
override def tooltipLines(stack: ItemStack, player: EntityPlayer, tooltip: util.List[String], advanced: Boolean) {
|
||||
tooltip.addAll(Tooltip.get(unlocalizedName))
|
||||
}
|
||||
|
||||
override def icon(side: ForgeDirection) = Some(icons(side.ordinal()))
|
||||
|
||||
override def luminance(world: IBlockAccess, x: Int, y: Int, z: Int) = 15
|
||||
|
||||
override def isSolid(world: IBlockAccess, x: Int, y: Int, z: Int, side: ForgeDirection) = side == ForgeDirection.DOWN
|
||||
|
||||
override def bounds(world: IBlockAccess, x: Int, y: Int, z: Int) =
|
||||
AxisAlignedBB.getAABBPool.getAABB(0, 0, 0, 1, 3 / 16f, 1)
|
||||
|
||||
override def itemBounds() {
|
||||
parent.setBlockBounds(AxisAlignedBB.getAABBPool.getAABB(0, 0, 0, 1, 3 / 16f, 1))
|
||||
}
|
||||
|
||||
override def registerIcons(iconRegister: IIconRegister) = {
|
||||
icons(ForgeDirection.DOWN.ordinal) = iconRegister.registerIcon(Settings.resourceDomain + ":generic_top")
|
||||
icons(ForgeDirection.UP.ordinal) = iconRegister.registerIcon(Settings.resourceDomain + ":hologram_top")
|
||||
|
||||
icons(ForgeDirection.NORTH.ordinal) = iconRegister.registerIcon(Settings.resourceDomain + ":hologram_side")
|
||||
icons(ForgeDirection.SOUTH.ordinal) = icons(ForgeDirection.NORTH.ordinal)
|
||||
icons(ForgeDirection.WEST.ordinal) = icons(ForgeDirection.NORTH.ordinal)
|
||||
icons(ForgeDirection.EAST.ordinal) = icons(ForgeDirection.NORTH.ordinal)
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------- //
|
||||
|
||||
override def hasTileEntity = true
|
||||
|
||||
override def createTileEntity(world: World) = Some(new tileentity.Hologram())
|
||||
}
|
176
src/main/scala/li/cil/oc/common/tileentity/Hologram.scala
Normal file
176
src/main/scala/li/cil/oc/common/tileentity/Hologram.scala
Normal file
@ -0,0 +1,176 @@
|
||||
package li.cil.oc.common.tileentity
|
||||
|
||||
import cpw.mods.fml.relauncher.{Side, SideOnly}
|
||||
import li.cil.oc.api.network._
|
||||
import li.cil.oc.server.{PacketSender => ServerPacketSender}
|
||||
import li.cil.oc.{Settings, api}
|
||||
import net.minecraft.nbt.NBTTagCompound
|
||||
import net.minecraft.util.AxisAlignedBB
|
||||
import net.minecraftforge.common.util.ForgeDirection
|
||||
|
||||
class Hologram extends Environment with SidedEnvironment {
|
||||
val node = api.Network.newNode(this, Visibility.Network).
|
||||
withComponent("hologram").
|
||||
withConnector().
|
||||
create()
|
||||
|
||||
val width = 3 * 16
|
||||
|
||||
val height = 2 * 16 // 32 bit in an int
|
||||
|
||||
val volume = new Array[Int](width * width)
|
||||
|
||||
// Render scale.
|
||||
var scale = 1.0
|
||||
|
||||
// Relative number of lit columns (for energy cost).
|
||||
var litRatio = -1.0
|
||||
|
||||
// Whether we need to send an update packet/recompile our display list.
|
||||
var dirty = false
|
||||
|
||||
// Interval of dirty columns.
|
||||
var dirtyFromX = Int.MaxValue
|
||||
var dirtyUntilX = -1
|
||||
var dirtyFromZ = Int.MaxValue
|
||||
var dirtyUntilZ = -1
|
||||
|
||||
// Time to wait before sending another update packet.
|
||||
var cooldown = 5
|
||||
|
||||
var hasPower = true
|
||||
|
||||
def setDirty(x: Int, z: Int) {
|
||||
dirty = true
|
||||
dirtyFromX = math.min(dirtyFromX, x)
|
||||
dirtyUntilX = math.max(dirtyUntilX, x + 1)
|
||||
dirtyFromZ = math.min(dirtyFromZ, z)
|
||||
dirtyUntilZ = math.max(dirtyUntilZ, z + 1)
|
||||
litRatio = -1
|
||||
}
|
||||
|
||||
def resetDirtyFlag() {
|
||||
dirty = false
|
||||
dirtyFromX = Int.MaxValue
|
||||
dirtyUntilX = -1
|
||||
dirtyFromZ = Int.MaxValue
|
||||
dirtyUntilZ = -1
|
||||
cooldown = 5
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------- //
|
||||
|
||||
override def canConnect(side: ForgeDirection) = side != ForgeDirection.UP
|
||||
|
||||
override def sidedNode(side: ForgeDirection) = node
|
||||
|
||||
// ----------------------------------------------------------------------- //
|
||||
|
||||
@Callback(doc = """function() -- Clears the hologram.""")
|
||||
def clear(computer: Context, args: Arguments): Array[AnyRef] = this.synchronized {
|
||||
for (i <- 0 until volume.length) volume(i) = 0
|
||||
ServerPacketSender.sendHologramClear(this)
|
||||
resetDirtyFlag()
|
||||
litRatio = 0
|
||||
null
|
||||
}
|
||||
|
||||
@Callback(direct = true, doc = """function(x:number, z:number):number -- Returns the bit mask representing the specified column.""")
|
||||
def get(computer: Context, args: Arguments): Array[AnyRef] = this.synchronized {
|
||||
val x = args.checkInteger(0) - 1
|
||||
val z = args.checkInteger(1) - 1
|
||||
result(volume(x + z * width))
|
||||
}
|
||||
|
||||
@Callback(direct = true, limit = 256, doc = """function(x:number, z:number, value:number) -- Set the bit mask for the specified column.""")
|
||||
def set(computer: Context, args: Arguments): Array[AnyRef] = this.synchronized {
|
||||
val x = args.checkInteger(0) - 1
|
||||
val z = args.checkInteger(1) - 1
|
||||
val value = args.checkInteger(2)
|
||||
volume(x + z * width) = value
|
||||
setDirty(x, z)
|
||||
null
|
||||
}
|
||||
|
||||
@Callback(direct = true, limit = 128, doc = """function(x:number, z:number, height:number) -- Fills a column to the specified height.""")
|
||||
def fill(computer: Context, args: Arguments): Array[AnyRef] = this.synchronized {
|
||||
val x = args.checkInteger(0) - 1
|
||||
val z = args.checkInteger(1) - 1
|
||||
val height = math.min(32, math.max(0, args.checkInteger(2)))
|
||||
// Bit shifts in the JVM only use the lowest five bits... so we have to
|
||||
// manually check the height, to avoid the shift being a no-op.
|
||||
volume(x + z * width) = if (height > 0) 0xFFFFFFFF >>> (32 - height) else 0
|
||||
setDirty(x, z)
|
||||
null
|
||||
}
|
||||
|
||||
@Callback(doc = """function():number -- Returns the render scale of the hologram.""")
|
||||
def getScale(computer: Context, args: Arguments): Array[AnyRef] = {
|
||||
result(scale)
|
||||
}
|
||||
|
||||
@Callback(doc = """function(value:number) -- Set the render scale. A larger scale consumes more energy.""")
|
||||
def setScale(computer: Context, args: Arguments): Array[AnyRef] = {
|
||||
scale = math.max(0.333333, math.min(3, args.checkDouble(0)))
|
||||
ServerPacketSender.sendHologramScale(this)
|
||||
null
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------- //
|
||||
|
||||
override def updateEntity() {
|
||||
super.updateEntity()
|
||||
if (isServer) {
|
||||
if (dirty) {
|
||||
cooldown -= 1
|
||||
if (cooldown <= 0) {
|
||||
ServerPacketSender.sendHologramSet(this)
|
||||
resetDirtyFlag()
|
||||
}
|
||||
}
|
||||
if (litRatio < 0) {
|
||||
litRatio = 0
|
||||
for (i <- 0 until volume.length) {
|
||||
if (volume(i) != 0) litRatio += 1
|
||||
}
|
||||
litRatio /= volume.length
|
||||
}
|
||||
|
||||
hasPower = node.changeBuffer(-Settings.get.hologramCost * litRatio * scale) == 0
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------- //
|
||||
|
||||
override def shouldRenderInPass(pass: Int) = pass == 1
|
||||
|
||||
override def getRenderBoundingBox = AxisAlignedBB.getAABBPool.getAABB(xCoord + 0.5 - 1.5 * scale, yCoord, zCoord - scale, xCoord + 0.5 + 1.5 * scale, yCoord + 0.25 + 2 * scale, zCoord + 0.5 + 1.5 * scale)
|
||||
|
||||
// ----------------------------------------------------------------------- //
|
||||
|
||||
override def readFromNBT(nbt: NBTTagCompound) {
|
||||
super.readFromNBT(nbt)
|
||||
nbt.getIntArray(Settings.namespace + "volume").copyToArray(volume)
|
||||
scale = nbt.getDouble(Settings.namespace + "scale")
|
||||
}
|
||||
|
||||
override def writeToNBT(nbt: NBTTagCompound) = this.synchronized {
|
||||
super.writeToNBT(nbt)
|
||||
nbt.setIntArray(Settings.namespace + "volume", volume)
|
||||
nbt.setDouble(Settings.namespace + "scale", scale)
|
||||
}
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
override def readFromNBTForClient(nbt: NBTTagCompound) {
|
||||
super.readFromNBTForClient(nbt)
|
||||
nbt.getIntArray("volume").copyToArray(volume)
|
||||
scale = nbt.getDouble("scale")
|
||||
dirty = true
|
||||
}
|
||||
|
||||
override def writeToNBTForClient(nbt: NBTTagCompound) {
|
||||
super.writeToNBTForClient(nbt)
|
||||
nbt.setIntArray("volume", volume)
|
||||
nbt.setDouble("scale", scale)
|
||||
}
|
||||
}
|
@ -14,12 +14,14 @@ import net.minecraftforge.common.DimensionManager
|
||||
import net.minecraftforge.common.util.ForgeDirection
|
||||
|
||||
object PacketHandler extends CommonPacketHandler {
|
||||
@SubscribeEvent
|
||||
def onPacket(e: ServerCustomPacketEvent) =
|
||||
onPacketData(e.packet.payload, e.handler.asInstanceOf[NetHandlerPlayServer].playerEntity)
|
||||
|
||||
override protected def world(player: EntityPlayer, dimension: Int) =
|
||||
Option(DimensionManager.getWorld(dimension))
|
||||
|
||||
@SubscribeEvent
|
||||
def onPacket(e: ServerCustomPacketEvent) {
|
||||
val p = new PacketParser(e.packet.payload, e.handler.asInstanceOf[NetHandlerPlayServer].playerEntity)
|
||||
override def dispatch(p: PacketParser) {
|
||||
p.packetType match {
|
||||
case PacketType.ComputerPower => onComputerPower(p)
|
||||
case PacketType.KeyDown => onKeyDown(p)
|
||||
|
@ -1,9 +1,8 @@
|
||||
package li.cil.oc.server
|
||||
|
||||
import li.cil.oc.common
|
||||
import li.cil.oc.common.PacketBuilder
|
||||
import li.cil.oc.common.PacketType
|
||||
import li.cil.oc.common.tileentity._
|
||||
import li.cil.oc.common.{CompressedPacketBuilder, PacketBuilder, PacketType}
|
||||
import li.cil.oc.util.PackedColor
|
||||
import net.minecraft.entity.player.EntityPlayerMP
|
||||
import net.minecraft.item.ItemStack
|
||||
@ -55,6 +54,40 @@ object PacketSender {
|
||||
pb.sendToNearbyPlayers(t)
|
||||
}
|
||||
|
||||
def sendHologramClear(t: Hologram) {
|
||||
val pb = new PacketBuilder(PacketType.HologramClear)
|
||||
|
||||
pb.writeTileEntity(t)
|
||||
|
||||
pb.sendToNearbyPlayers(t)
|
||||
}
|
||||
|
||||
def sendHologramScale(t: Hologram) {
|
||||
val pb = new PacketBuilder(PacketType.HologramScale)
|
||||
|
||||
pb.writeTileEntity(t)
|
||||
pb.writeDouble(t.scale)
|
||||
|
||||
pb.sendToNearbyPlayers(t)
|
||||
}
|
||||
|
||||
def sendHologramSet(t: Hologram) {
|
||||
val pb = new CompressedPacketBuilder(PacketType.HologramSet)
|
||||
|
||||
pb.writeTileEntity(t)
|
||||
pb.writeByte(t.dirtyFromX)
|
||||
pb.writeByte(t.dirtyUntilX)
|
||||
pb.writeByte(t.dirtyFromZ)
|
||||
pb.writeByte(t.dirtyUntilZ)
|
||||
for (x <- t.dirtyFromX until t.dirtyUntilX) {
|
||||
for (z <- t.dirtyFromZ until t.dirtyUntilZ) {
|
||||
pb.writeInt(t.volume(x + z * t.width))
|
||||
}
|
||||
}
|
||||
|
||||
pb.sendToNearbyPlayers(t)
|
||||
}
|
||||
|
||||
def sendPowerState(t: PowerInformation) {
|
||||
val pb = new PacketBuilder(PacketType.PowerState)
|
||||
|
||||
|
@ -217,12 +217,12 @@ object LuaStateFactory {
|
||||
lua.getTop match {
|
||||
case 0 => lua.pushNumber(random.nextDouble())
|
||||
case 1 =>
|
||||
val u = lua.checkInteger(1)
|
||||
val u = lua.checkNumber(1).toInt
|
||||
lua.checkArg(1, 1 < u, "interval is empty")
|
||||
lua.pushInteger(1 + random.nextInt(u))
|
||||
case 2 =>
|
||||
val l = lua.checkInteger(1)
|
||||
val u = lua.checkInteger(2)
|
||||
val l = lua.checkNumber(1).toInt
|
||||
val u = lua.checkNumber(2).toInt
|
||||
lua.checkArg(1, l < u, "interval is empty")
|
||||
lua.pushInteger(l + random.nextInt(u - (l - 1)))
|
||||
case _ => throw new IllegalArgumentException("wrong number of arguments")
|
||||
|
Loading…
x
Reference in New Issue
Block a user