Documented new API some more.

Fixed values returned from gpu.get.
Added parameter for vertical gpu.set.
This commit is contained in:
Florian Nücke 2014-05-06 11:32:43 +02:00
parent e7c7ad31e6
commit 9264d3c3d0
16 changed files with 632 additions and 244 deletions

View File

@ -1,173 +0,0 @@
package li.cil.oc.api.component;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import li.cil.oc.api.Persistable;
import li.cil.oc.api.network.ManagedEnvironment;
import net.minecraft.entity.player.EntityPlayer;
/**
* This interface is implemented by screens' environments.
* <p/>
* This allows re-using the built-in screens in third-party code without
* access to the internals of OC.
* <p/>
* To get an instance of the screen component, use its item driver, e.g.:
* <pre>
* final ItemStack stack = li.cil.oc.api.Items.get("screen1").createItemStack(1);
* final Screen screen = (Screen) li.cil.oc.api.Driver.driverFor(stack).createEnvironment(stack, this);
* </pre>
*/
public interface Screen extends ManagedEnvironment, Persistable {
void setEnergyCostPerTick(double value);
double getEnergyCostPerTick();
void setPowerState(boolean value);
boolean getPowerState();
/**
* Sets the maximum resolution supported by this screen.
*
* @param width the maximum horizontal resolution, in characters.
* @param height the maximum vertical resolution, in characters.
*/
void setMaximumResolution(int width, int height);
int getMaximumWidth();
int getMaximumHeight();
void setAspectRatio(double width, double height);
double getAspectRatio();
boolean setResolution(int width, int height);
int getWidth();
int getHeight();
/**
* Sets the maximum color depth supported by this screen.
* <p/>
* Note that this is the <em>maximum</em> supported depth, lower depths
* will be supported, too. So when setting this to four bit, one bit will
* be supported, too. When setting this to eight bit, four and one bit
* will be supported, also.
*
* @param depth the maximum color depth of the screen.
*/
void setMaximumColorDepth(ColorDepth depth);
ColorDepth getMaximumColorDepth();
boolean setColorDepth(ColorDepth depth);
ColorDepth getColorDepth();
void setPaletteColor(int index, int color);
int getPaletteColor(int index);
void setForegroundColor(int color);
void setForegroundColor(int color, boolean isFromPalette);
int getForegroundColor();
boolean isForegroundFromPalette();
void setBackgroundColor(int color);
void setBackgroundColor(int color, boolean isFromPalette);
int getBackgroundColor();
boolean isBackgroundFromPalette();
void copy(int column, int row, int width, int height, int horizontalTranslation, int verticalTranslation);
void fill(int column, int row, int width, int height, char value);
void set(int column, int row, String value);
char get(int column, int row);
/**
* Renders the <em>text</em> displayed on the screen.
* <p/>
* You are responsible for setting up the actual context and applying any
* transformations necessary to properly position and scale the text before
* calling this. The text should be rendered on a black background.
* <p/>
* You can use this to either render the text in a GUI or in the world.
*/
@SideOnly(Side.CLIENT)
void renderText();
/**
* The natural width of the rendered text.
* <p/>
* This is the width of the complete text buffer, in pixels. In other
* words, this is the width of the buffer in chars times the actual width
* of a single char in pixels.
*
* @return the total width of the rendered buffer, in pixels.
*/
@SideOnly(Side.CLIENT)
int renderWidth();
/**
* The natural height of the rendered text.
* <p/>
* This is the height of the complete text buffer, in pixels. In other
* words, this is the height of the buffer in chars times the actual height
* of a single char in pixels.
*
* @return the total height of the rendered buffer, in pixels.
*/
@SideOnly(Side.CLIENT)
int renderHeight();
@SideOnly(Side.CLIENT)
void setRenderingEnabled(boolean enabled);
@SideOnly(Side.CLIENT)
boolean isRenderingEnabled();
void keyDown(char character, int code, EntityPlayer player);
void keyUp(char character, int code, EntityPlayer player);
void clipboard(String value, EntityPlayer player);
void mouseDown(int x, int y, int button, EntityPlayer player);
void mouseDrag(int x, int y, int button, EntityPlayer player);
void mouseUp(int x, int y, int button, EntityPlayer player);
void mouseScroll(int x, int y, int delta, EntityPlayer player);
/**
* Used when setting a screens maximum color depth.
*/
public static enum ColorDepth {
/**
* Monochrome color, black and white.
*/
OneBit,
/**
* 16 color palette, defaults to Minecraft colors.
*/
FourBit,
/**
* 240 colors, 16 color palette, defaults to grayscale.
*/
EightBit
}
}

View File

@ -0,0 +1,510 @@
package li.cil.oc.api.component;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import li.cil.oc.api.Persistable;
import li.cil.oc.api.network.ManagedEnvironment;
import net.minecraft.entity.player.EntityPlayer;
/**
* This interface implements functionality for displaying and manipulating
* text, like screens and robots. An implementation can be obtained via the
* screens' item driver.
* <p/>
* This allows re-using the built-in screen logic in third-party code without
* access to the internals of OC.
* <p/>
* To get an instance of the buffer component, use its item driver, e.g.:
* <pre>
* final ItemStack stack = li.cil.oc.api.Items.get("screen1").createItemStack(1);
* final TextBuffer buffer = (TextBuffer) li.cil.oc.api.Driver.driverFor(stack).createEnvironment(stack, this);
* </pre>
*/
public interface TextBuffer extends ManagedEnvironment, Persistable {
/**
* Controls how much energy the buffer will consume per tick.
* <p/>
* This is <em>not</em> necessarily the actual amount consumed per tick,
* instead it is a base value that cost is based on, incorporating a few
* other factors. This is the cost a tier one screen will consume if every
* character is lit (non-black). Larger buffers (i.e. buffers with a higher
* maximum resolution) cost proportionally more.
* <p/>
* Note that this amount of energy is not necessarily subtracted each tick,
* instead every n ticks, n times the amount of energy it costs to run the
* buffer will be consumed, where n is configurable in the OC config.
* <p/>
* This defaults to OC's built-in default value.
*
* @param value the base energy cost per tick.
* @see #getEnergyCostPerTick()
*/
void setEnergyCostPerTick(double value);
/**
* Get the energy cost per tick.
*
* @return the base energy cost per tick.
* @see #setEnergyCostPerTick(double)
*/
double getEnergyCostPerTick();
/**
* Set whether the buffer is powered on.
* <p/>
* For example, screens can be powered on and off by sending a redstone
* pulse into them, in addition to their component API.
*
* @param value whether the buffer should be on or not.
* @see #getPowerState()
*/
void setPowerState(boolean value);
/**
* Get the current power state.
*
* @return whether the buffer is powered on.
* @see #setPowerState(boolean)
*/
boolean getPowerState();
/**
* Sets the maximum resolution supported by this buffer.
*
* @param width the maximum horizontal resolution, in characters.
* @param height the maximum vertical resolution, in characters.
*/
void setMaximumResolution(int width, int height);
/**
* Get the maximum horizontal size of the buffer.
*/
int getMaximumWidth();
/**
* Get the maximum vertical size of the buffer.
*/
int getMaximumHeight();
/**
* Set the 'aspect ratio' of the buffer.
* <p/>
* Not to be confused with the maximum resolution of the buffer, this
* refers to the 'physical' size of the buffer's container. For multi-
* block screens, for example, this is the number of horizontal and
* vertical blocks.
*
* @param width the horizontal size of the physical representation.
* @param height the vertical size of the physical representation.
*/
void setAspectRatio(double width, double height);
/**
* Get the aspect ratio of the buffer.
* <p/>
* Note that this is in fact <tt>width / height</tt>.
*
* @see #setAspectRatio(double, double)
*/
double getAspectRatio();
/**
* Set the buffer's active resolution.
*
* @param width the horizontal resolution.
* @param height the vertical resolution.
* @return <tt>true</tt> if the resolution changed.
*/
boolean setResolution(int width, int height);
/**
* Get the current horizontal resolution.
*
* @see #setResolution(int, int)
*/
int getWidth();
/**
* Get the current vertical resolution.
*
* @see #setResolution(int, int)
*/
int getHeight();
/**
* Sets the maximum color depth supported by this buffer.
* <p/>
* Note that this is the <em>maximum</em> supported depth, lower depths
* will be supported, too. So when setting this to four bit, one bit will
* be supported, too. When setting this to eight bit, four and one bit
* will be supported, also.
*
* @param depth the maximum color depth of the buffer.
*/
void setMaximumColorDepth(ColorDepth depth);
/**
* Get the maximum color depth supported.
*/
ColorDepth getMaximumColorDepth();
/**
* Set the active color depth for this buffer.
*
* @param depth the new color depth.
* @return <tt>true</tt> if the color depth changed.
*/
boolean setColorDepth(ColorDepth depth);
/**
* Get the active color depth of this buffer.
*/
ColorDepth getColorDepth();
/**
* Set the color of the active color palette at the specified index.
* <p/>
* This will error if the current depth does not have a palette (one bit).
*
* @param index the index at which to set the color.
* @param color the color to set for the specified index.
*/
void setPaletteColor(int index, int color);
/**
* Get the color in the active color palette at the specified index.
* <p/>
* This will error if the current depth does not have a palette (one bit).
*
* @param index the index at which to get the color.
* @return the color in the active palette at the specified index.
*/
int getPaletteColor(int index);
/**
* Set the active foreground color, not using a palette.
*
* @param color the new foreground color.
* @see #setForegroundColor(int, boolean)
*/
void setForegroundColor(int color);
/**
* Set the active foreground color.
* <p/>
* If the value is not from the palette, the actually stored value may
* differ from the specified one, as it is converted to the buffer's
* current color depth.
* <p/>
* For palette-only color formats (four bit) the best fit from the palette
* is chosen, if the value is not from the palette.
*
* @param color the color or palette index.
* @param isFromPalette <tt>true</tt>if <tt>color</tt> specifies a palette index.
*/
void setForegroundColor(int color, boolean isFromPalette);
/**
* The active foreground color.
*/
int getForegroundColor();
/**
* <tt>true</tt> if the foreground color is from the color palette, meaning
* the value returned from {@link #getForegroundColor()} is the color
* palette index.
*/
boolean isForegroundFromPalette();
/**
* Set the active background color, not using a palette.
*
* @param color the new background color.
* @see #setBackgroundColor(int, boolean)
*/
void setBackgroundColor(int color);
/**
* Set the active background color.
* <p/>
* If the value is not from the palette, the actually stored value may
* differ from the specified one, as it is converted to the buffer's
* current color depth.
* <p/>
* For palette-only color formats (four bit) the best fit from the palette
* is chosen, if the value is not from the palette.
*
* @param color the color or palette index.
* @param isFromPalette <tt>true</tt>if <tt>color</tt> specifies a palette index.
*/
void setBackgroundColor(int color, boolean isFromPalette);
/**
* The active background color.
*/
int getBackgroundColor();
/**
* <tt>true</tt> if the background color is from the color palette, meaning
* the value returned from {@link #getBackgroundColor()} is the color
* palette index.
*/
boolean isBackgroundFromPalette();
/**
* Copy a portion of the text buffer.
* <p/>
* This will copy the area's text and colors.
*
* @param column the starting horizontal index of the area to copy.
* @param row the starting vertical index of the area to copy.
* @param width the width of the area to copy.
* @param height the height of the area to copy.
* @param horizontalTranslation the horizontal offset, relative to the starting column to copy the are to.
* @param verticalTranslation the vertical offset, relative to the starting row to copy the are to.
*/
void copy(int column, int row, int width, int height, int horizontalTranslation, int verticalTranslation);
/**
* Fill a portion of the text buffer.
* <p/>
* This will set the area's colors to the currently active ones.
*
* @param column the starting horizontal index of the area to fill.
* @param row the starting vertical index of the area to fill.
* @param width the width of the area to fill.
* @param height the height of the area to fill.
* @param value the character to fill the area with.
*/
void fill(int column, int row, int width, int height, char value);
/**
* Write a string into the text buffer.
* <p/>
* This will apply the currently active colors to the changed area.
*
* @param column the starting horizontal index to write at.
* @param row the starting vertical index to write at.
* @param value the string to write.
* @param vertical <tt>true</tt> if the string should be written vertically instead of horizontally.
*/
void set(int column, int row, String value, boolean vertical);
/**
* Get the character in the text buffer at the specified location.
*
* @param column the horizontal index.
* @param row the vertical index.
* @return the character at that index.
*/
char get(int column, int row);
/**
* Get the character in the text buffer at the specified location.
*
* @param column the horizontal index.
* @param row the vertical index.
* @return the foregound color at that index.
*/
int getForegroundColor(int column, int row);
/**
* Whether the foreground color of the text buffer at the specified
* location if from the color palette.
*
* @param column the horizontal index.
* @param row the vertical index.
* @return whether the foreground at that index is from the palette.
*/
boolean isForegroundFromPalette(int column, int row);
/**
* Get the background color of the text buffer at the specified location.
*
* @param column the horizontal index.
* @param row the vertical index.
* @return the background color at that index.
*/
int getBackgroundColor(int column, int row);
/**
* Whether the background color of the text buffer at the specified
* location if from the color palette.
*
* @param column the horizontal index.
* @param row the vertical index.
* @return whether the background at that index is from the palette.
*/
boolean isBackgroundFromPalette(int column, int row);
// ----------------------------------------------------------------------- //
/**
* Renders the <em>text</em> displayed on the buffer.
* <p/>
* You are responsible for setting up the actual context and applying any
* transformations necessary to properly position and scale the text before
* calling this. The text should be rendered on a black background.
* <p/>
* You can use this to either render the text in a GUI or in the world.
*/
@SideOnly(Side.CLIENT)
void renderText();
/**
* The natural width of the rendered text.
* <p/>
* This is the width of the complete text buffer, in pixels. In other
* words, this is the width of the buffer in chars times the actual width
* of a single char in pixels.
*
* @return the total width of the rendered buffer, in pixels.
*/
@SideOnly(Side.CLIENT)
int renderWidth();
/**
* The natural height of the rendered text.
* <p/>
* This is the height of the complete text buffer, in pixels. In other
* words, this is the height of the buffer in chars times the actual height
* of a single char in pixels.
*
* @return the total height of the rendered buffer, in pixels.
*/
@SideOnly(Side.CLIENT)
int renderHeight();
/**
* Set whether the contents of the buffer should currently be rendered.
* <p/>
* Note that this is automatically overwritten when the buffer's power
* state changes, i.e. when it runs out of power or gets back power.
*
* @param enabled whether the text buffer should be rendered.
*/
@SideOnly(Side.CLIENT)
void setRenderingEnabled(boolean enabled);
/**
* Gets whether the contents of the buffer should currently be rendered.
*
* @see #setRenderingEnabled(boolean)
*/
@SideOnly(Side.CLIENT)
boolean isRenderingEnabled();
// ----------------------------------------------------------------------- //
/**
* Signals a key down event for the buffer.
* <p/>
* On the client side this causes a packet to be sent to the server. On the
* server side this will trigger a message that will be picked up by
* keyboards, which will then cause a signal in attached machines.
*
* @param character the character of the pressed key.
* @param code the key code of the pressed key.
* @param player the player that pressed the key. Pass <tt>null</tt> on the client side.
*/
void keyDown(char character, int code, EntityPlayer player);
/**
* Signals a key up event for the buffer.
* <p/>
* On the client side this causes a packet to be sent to the server. On the
* server side this will trigger a message that will be picked up by
* keyboards, which will then cause a signal in attached machines.
*
* @param character the character of the released key.
* @param code the key code of the released key.
* @param player the player that released the key. Pass <tt>null</tt> on the client side.
*/
void keyUp(char character, int code, EntityPlayer player);
/**
* Signals a clipboard paste event for the buffer.
* <p/>
* On the client side this causes a packet to be sent to the server. On the
* server side this will trigger a message that will be picked up by
* keyboards, which will then cause a signal in attached machines.
*
* @param value the text that was pasted.
* @param player the player that pasted the text. Pass <tt>null</tt> on the client side.
*/
void clipboard(String value, EntityPlayer player);
/**
* Signals a mouse button down event for the buffer.
* <p/>
* On the client side this causes a packet to be sent to the server. On the
* server side this will cause a signal in attached machines.
*
* @param x the horizontal coordinate of the mouse, in characters.
* @param y the vertical coordinate of the mouse, in characters.
* @param button the button of the mouse that was pressed.
* @param player the player that pressed the mouse button. Pass <tt>null</tt> on the client side.
*/
void mouseDown(int x, int y, int button, EntityPlayer player);
/**
* Signals a mouse drag event for the buffer.
* <p/>
* On the client side this causes a packet to be sent to the server. On the
* server side this will cause a signal in attached machines.
*
* @param x the horizontal coordinate of the mouse, in characters.
* @param y the vertical coordinate of the mouse, in characters.
* @param button the button of the mouse that is pressed.
* @param player the player that moved the mouse. Pass <tt>null</tt> on the client side.
*/
void mouseDrag(int x, int y, int button, EntityPlayer player);
/**
* Signals a mouse button release event for the buffer.
* <p/>
* On the client side this causes a packet to be sent to the server. On the
* server side this will cause a signal in attached machines.
*
* @param x the horizontal coordinate of the mouse, in characters.
* @param y the vertical coordinate of the mouse, in characters.
* @param button the button of the mouse that was released.
* @param player the player that released the mouse button. Pass <tt>null</tt> on the client side.
*/
void mouseUp(int x, int y, int button, EntityPlayer player);
/**
* Signals a mouse wheel scroll event for the buffer.
* <p/>
* On the client side this causes a packet to be sent to the server. On the
* server side this will cause a signal in attached machines.
*
* @param x the horizontal coordinate of the mouse, in characters.
* @param y the vertical coordinate of the mouse, in characters.
* @param delta indicates the direction of the mouse scroll.
* @param player the player that scrolled the mouse wheel. Pass <tt>null</tt> on the client side.
*/
void mouseScroll(int x, int y, int delta, EntityPlayer player);
// ----------------------------------------------------------------------- //
/**
* Used when setting a buffer's maximum color depth.
*/
public static enum ColorDepth {
/**
* Monochrome color, black and white.
*/
OneBit,
/**
* 16 color palette, defaults to Minecraft colors.
*/
FourBit,
/**
* 240 colors, 16 color palette, defaults to grayscale.
*/
EightBit
}
}

View File

@ -3,7 +3,7 @@ package li.cil.oc
import com.typesafe.config.{ConfigRenderOptions, Config, ConfigFactory}
import java.io._
import java.util.logging.Level
import li.cil.oc.api.component.Screen.ColorDepth
import li.cil.oc.api.component.TextBuffer.ColorDepth
import li.cil.oc.util.mods.Mods
import org.apache.commons.lang3.StringEscapeUtils
import scala.collection.convert.WrapAsScala._

View File

@ -254,7 +254,7 @@ class PacketHandler extends CommonPacketHandler {
def onTextBufferColorChange(p: PacketParser) {
ComponentTracker.get(p.readUTF()) match {
case Some(buffer: component.Screen) =>
case Some(buffer: component.TextBuffer) =>
val foreground = p.readInt()
val foregroundIsPalette = p.readBoolean()
buffer.setForegroundColor(foreground, foregroundIsPalette)
@ -267,7 +267,7 @@ class PacketHandler extends CommonPacketHandler {
def onTextBufferCopy(p: PacketParser) {
ComponentTracker.get(p.readUTF()) match {
case Some(buffer: component.Screen) =>
case Some(buffer: component.TextBuffer) =>
val col = p.readInt()
val row = p.readInt()
val w = p.readInt()
@ -281,15 +281,15 @@ class PacketHandler extends CommonPacketHandler {
def onTextBufferDepthChange(p: PacketParser) {
ComponentTracker.get(p.readUTF()) match {
case Some(buffer: component.Screen) =>
buffer.setColorDepth(component.Screen.ColorDepth.values.apply(p.readInt()))
case Some(buffer: component.TextBuffer) =>
buffer.setColorDepth(component.TextBuffer.ColorDepth.values.apply(p.readInt()))
case _ => // Invalid packet.
}
}
def onTextBufferFill(p: PacketParser) {
ComponentTracker.get(p.readUTF()) match {
case Some(buffer: component.Screen) =>
case Some(buffer: component.TextBuffer) =>
val col = p.readInt()
val row = p.readInt()
val w = p.readInt()
@ -302,7 +302,7 @@ class PacketHandler extends CommonPacketHandler {
def onTextBufferPaletteChange(p: PacketParser) {
ComponentTracker.get(p.readUTF()) match {
case Some(buffer: component.Screen) =>
case Some(buffer: component.TextBuffer) =>
val index = p.readInt()
val color = p.readInt()
buffer.setPaletteColor(index, color)
@ -312,14 +312,14 @@ class PacketHandler extends CommonPacketHandler {
def onTextBufferPowerChange(p: PacketParser) =
ComponentTracker.get(p.readUTF()) match {
case Some(buffer: component.Screen) =>
case Some(buffer: component.TextBuffer) =>
buffer.setRenderingEnabled(p.readBoolean())
case _ => // Invalid packet.
}
def onTextBufferResolutionChange(p: PacketParser) {
ComponentTracker.get(p.readUTF()) match {
case Some(buffer: component.Screen) =>
case Some(buffer: component.TextBuffer) =>
val w = p.readInt()
val h = p.readInt()
buffer.setResolution(w, h)
@ -329,11 +329,12 @@ class PacketHandler extends CommonPacketHandler {
def onTextBufferSet(p: PacketParser) {
ComponentTracker.get(p.readUTF()) match {
case Some(buffer: component.Screen) =>
case Some(buffer: component.TextBuffer) =>
val col = p.readInt()
val row = p.readInt()
val s = p.readUTF()
buffer.set(col, row, s)
val vertical = p.readBoolean()
buffer.set(col, row, s, vertical)
case _ => // Invalid packet.
}
}

View File

@ -20,7 +20,7 @@ import net.minecraft.util.StatCollector
import org.lwjgl.input.Keyboard
import org.lwjgl.opengl.GL11
class Robot(playerInventory: InventoryPlayer, val robot: tileentity.Robot) extends GuiContainer(new container.Robot(playerInventory, robot)) with Buffer {
class Robot(playerInventory: InventoryPlayer, val robot: tileentity.Robot) extends GuiContainer(new container.Robot(playerInventory, robot)) with TextBuffer {
xSize = 256
ySize = 242

View File

@ -7,7 +7,7 @@ import li.cil.oc.util.RenderState
import org.lwjgl.input.Mouse
import org.lwjgl.opengl.GL11
class Screen(val buffer: api.component.Screen, val hasMouse: Boolean, val hasPower: () => Boolean) extends Buffer {
class Screen(val buffer: api.component.TextBuffer, val hasMouse: Boolean, val hasPower: () => Boolean) extends TextBuffer {
private val bufferMargin = BufferRenderer.margin + BufferRenderer.innerMargin
private var didDrag = false

View File

@ -12,8 +12,8 @@ import org.lwjgl.opengl.GL11
import scala.collection.mutable
import li.cil.oc.api
trait Buffer extends GuiScreen {
protected def buffer: api.component.Screen
trait TextBuffer extends GuiScreen {
protected def buffer: api.component.TextBuffer
private val pressedKeys = mutable.Map.empty[Int, Char]

View File

@ -5,7 +5,7 @@ import li.cil.oc.util.RenderState
import net.minecraft.client.renderer.texture.TextureManager
import net.minecraft.client.renderer.{Tessellator, GLAllocation}
import org.lwjgl.opengl.GL11
import li.cil.oc.api.component.Screen
import li.cil.oc.api.component.TextBuffer
object BufferRenderer {
val margin = 7
@ -72,7 +72,7 @@ object BufferRenderer {
GL11.glCallList(displayLists)
}
def drawText(screen: Screen) =
def drawText(screen: TextBuffer) =
if (textureManager.isDefined) {
GL11.glPushAttrib(GL11.GL_DEPTH_BUFFER_BIT)
GL11.glDepthMask(false)

View File

@ -2,7 +2,6 @@ package li.cil.oc.common.component
import cpw.mods.fml.relauncher.{Side, SideOnly}
import li.cil.oc.api
import li.cil.oc.api.component.{Screen, Keyboard}
import li.cil.oc.api.component.Keyboard.UsabilityChecker
import li.cil.oc.api.network.{Component, Node, Visibility}
import li.cil.oc.common.item
@ -16,7 +15,7 @@ import scala.collection.mutable
class Terminal(val rack: tileentity.Rack, val number: Int) {
val buffer = {
val screenItem = api.Items.get("screen1").createItemStack(1)
val buffer = api.Driver.driverFor(screenItem).createEnvironment(screenItem, rack).asInstanceOf[Screen]
val buffer = api.Driver.driverFor(screenItem).createEnvironment(screenItem, rack).asInstanceOf[api.component.TextBuffer]
val (maxWidth, maxHeight) = Settings.screenResolutionsByTier(1)
buffer.setMaximumResolution(maxWidth, maxHeight)
buffer.setMaximumColorDepth(Settings.screenDepthsByTier(1))
@ -25,9 +24,9 @@ class Terminal(val rack: tileentity.Rack, val number: Int) {
val keyboard = {
val keyboardItem = api.Items.get("keyboard").createItemStack(1)
val keyboard = api.Driver.driverFor(keyboardItem).createEnvironment(keyboardItem, rack).asInstanceOf[Keyboard]
val keyboard = api.Driver.driverFor(keyboardItem).createEnvironment(keyboardItem, rack).asInstanceOf[api.component.Keyboard]
keyboard.setUsableOverride(new UsabilityChecker {
override def isUsableByPlayer(keyboard: Keyboard, player: EntityPlayer) = {
override def isUsableByPlayer(keyboard: api.component.Keyboard, player: EntityPlayer) = {
val stack = player.getCurrentEquippedItem
Items.multi.subItem(stack) match {
case Some(t: item.Terminal) if stack.hasTagCompound => keys.contains(stack.getTagCompound.getString(Settings.namespace + "key"))

View File

@ -3,7 +3,7 @@ package li.cil.oc.common.component
import cpw.mods.fml.common.FMLCommonHandler
import cpw.mods.fml.relauncher.{SideOnly, Side}
import li.cil.oc.{api, Settings}
import li.cil.oc.api.component.Screen.ColorDepth
import li.cil.oc.api.component.TextBuffer.ColorDepth
import li.cil.oc.api.network._
import li.cil.oc.client.{PacketSender => ClientPacketSender, ComponentTracker => ClientComponentTracker}
import li.cil.oc.client.renderer.{MonospaceFontRenderer, TextBufferRenderCache}
@ -16,7 +16,7 @@ import net.minecraft.entity.player.EntityPlayer
import net.minecraft.nbt.NBTTagCompound
import scala.collection.convert.WrapAsScala._
class TextBuffer(val owner: component.Container) extends ManagedComponent with api.component.Screen {
class TextBuffer(val owner: component.Container) extends ManagedComponent with api.component.TextBuffer {
val node = api.Network.newNode(this, Visibility.Network).
withComponent("screen").
withConnector().
@ -228,18 +228,40 @@ class TextBuffer(val owner: component.Container) extends ManagedComponent with a
if (data.fill(col, row, w, h, c))
proxy.onScreenFill(col, row, w, h, c)
def set(col: Int, row: Int, s: String) = if (col < data.width && (col >= 0 || -col < s.length)) {
def set(col: Int, row: Int, s: String, vertical: Boolean) = if (col < data.width && (col >= 0 || -col < s.length)) {
// Make sure the string isn't longer than it needs to be, in particular to
// avoid sending too much data to our clients.
val (x, truncated) =
if (col < 0) (0, s.substring(-col))
else (col, s.substring(0, math.min(s.length, data.width - col)))
if (data.set(x, row, truncated))
proxy.onScreenSet(x, row, truncated)
val (x, y, truncated) =
if (vertical) {
if (row < 0) (col, 0, s.substring(-row))
else (col, row, s.substring(0, math.min(s.length, data.height - row)))
}
else {
if (col < 0) (0, row, s.substring(-col))
else (col, row, s.substring(0, math.min(s.length, data.width - col)))
}
if (data.set(x, y, truncated, vertical))
proxy.onScreenSet(x, row, truncated, vertical)
}
def get(col: Int, row: Int) = data.get(col, row)
override def getForegroundColor(column: Int, row: Int) =
PackedColor.unpackForeground(data.color(row)(column), data.format)
override def isForegroundFromPalette(column: Int, row: Int) = data.format match {
case palette: PackedColor.PaletteFormat => palette.isFromPalette(PackedColor.extractForeground(data.color(row)(column)))
case _ => false
}
override def getBackgroundColor(column: Int, row: Int) =
PackedColor.unpackBackground(data.color(row)(column), data.format)
override def isBackgroundFromPalette(column: Int, row: Int) = data.format match {
case palette: PackedColor.PaletteFormat => palette.isFromPalette(PackedColor.extractBackground(data.color(row)(column)))
case _ => false
}
@SideOnly(Side.CLIENT)
override def renderText() = proxy.render()
@ -357,7 +379,7 @@ object TextBuffer {
def onScreenResolutionChange(w: Int, h: Int)
def onScreenSet(col: Int, row: Int, s: String)
def onScreenSet(col: Int, row: Int, s: String, vertical: Boolean)
def keyDown(character: Char, code: Int, player: EntityPlayer)
@ -389,7 +411,7 @@ object TextBuffer {
override def onScreenResolutionChange(w: Int, h: Int) = dirty = true
override def onScreenSet(col: Int, row: Int, s: String) = dirty = true
override def onScreenSet(col: Int, row: Int, s: String, vertical: Boolean) = dirty = true
override def keyDown(character: Char, code: Int, player: EntityPlayer) =
ClientPacketSender.sendKeyDown(nodeAddress, character, code)
@ -447,10 +469,10 @@ object TextBuffer {
ServerPacketSender.sendTextBufferResolutionChange(buffer.node.address, w, h, buffer.owner)
}
override def onScreenSet(col: Int, row: Int, s: String) {
override def onScreenSet(col: Int, row: Int, s: String, vertical: Boolean) {
buffer.relativeLitArea = -1
buffer.owner.markChanged()
ServerPacketSender.sendTextBufferSet(buffer.node.address, col, row, s, buffer.owner)
ServerPacketSender.sendTextBufferSet(buffer.node.address, col, row, s, vertical, buffer.owner)
}
override def keyDown(character: Char, code: Int, player: EntityPlayer) {

View File

@ -7,7 +7,7 @@ import net.minecraft.nbt.NBTTagCompound
trait TextBuffer extends Environment {
lazy val buffer = {
val screenItem = api.Items.get("screen1").createItemStack(1)
val buffer = api.Driver.driverFor(screenItem).createEnvironment(screenItem, this).asInstanceOf[api.component.Screen]
val buffer = api.Driver.driverFor(screenItem).createEnvironment(screenItem, this).asInstanceOf[api.component.TextBuffer]
val (maxWidth, maxHeight) = Settings.screenResolutionsByTier(tier)
buffer.setMaximumResolution(maxWidth, maxHeight)
buffer.setMaximumColorDepth(Settings.screenDepthsByTier(tier))

View File

@ -66,28 +66,28 @@ class PacketHandler extends CommonPacketHandler {
def onKeyDown(p: PacketParser) {
ComponentTracker.get(p.readUTF()) match {
case Some(buffer: api.component.Screen) => buffer.keyDown(p.readChar(), p.readInt(), p.player.asInstanceOf[EntityPlayer])
case Some(buffer: api.component.TextBuffer) => buffer.keyDown(p.readChar(), p.readInt(), p.player.asInstanceOf[EntityPlayer])
case _ => // Invalid Packet
}
}
def onKeyUp(p: PacketParser) {
ComponentTracker.get(p.readUTF()) match {
case Some(buffer: api.component.Screen) => buffer.keyUp(p.readChar(), p.readInt(), p.player.asInstanceOf[EntityPlayer])
case Some(buffer: api.component.TextBuffer) => buffer.keyUp(p.readChar(), p.readInt(), p.player.asInstanceOf[EntityPlayer])
case _ => // Invalid Packet
}
}
def onClipboard(p: PacketParser) {
ComponentTracker.get(p.readUTF()) match {
case Some(buffer: api.component.Screen) => buffer.clipboard(p.readUTF(), p.player.asInstanceOf[EntityPlayer])
case Some(buffer: api.component.TextBuffer) => buffer.clipboard(p.readUTF(), p.player.asInstanceOf[EntityPlayer])
case _ => // Invalid Packet
}
}
def onMouseClick(p: PacketParser) {
ComponentTracker.get(p.readUTF()) match {
case Some(buffer: api.component.Screen) =>
case Some(buffer: api.component.TextBuffer) =>
val x = p.readShort()
val y = p.readShort()
val dragging = p.readBoolean()
@ -100,14 +100,14 @@ class PacketHandler extends CommonPacketHandler {
def onMouseUp(p: PacketParser) {
ComponentTracker.get(p.readUTF()) match {
case Some(buffer: api.component.Screen) => buffer.mouseUp(p.readShort(), p.readShort(), p.readByte(), p.player.asInstanceOf[EntityPlayer])
case Some(buffer: api.component.TextBuffer) => buffer.mouseUp(p.readShort(), p.readShort(), p.readByte(), p.player.asInstanceOf[EntityPlayer])
case _ => // Invalid Packet
}
}
def onMouseScroll(p: PacketParser) {
ComponentTracker.get(p.readUTF()) match {
case Some(buffer: api.component.Screen) => buffer.mouseScroll(p.readShort(), p.readShort(), p.readByte(), p.player.asInstanceOf[EntityPlayer])
case Some(buffer: api.component.TextBuffer) => buffer.mouseScroll(p.readShort(), p.readShort(), p.readByte(), p.player.asInstanceOf[EntityPlayer])
case _ => // Invalid Packet
}
}

View File

@ -8,7 +8,7 @@ import net.minecraft.entity.player.EntityPlayerMP
import net.minecraft.item.ItemStack
import net.minecraftforge.common.ForgeDirection
import net.minecraft.world.World
import li.cil.oc.api.component.Screen.ColorDepth
import li.cil.oc.api.component.TextBuffer.ColorDepth
import li.cil.oc.server.component.Container
object PacketSender {
@ -305,13 +305,14 @@ object PacketSender {
pb.sendToNearbyPlayers(container)
}
def sendTextBufferSet(address: String, col: Int, row: Int, s: String, container: Container) {
def sendTextBufferSet(address: String, col: Int, row: Int, s: String, vertical: Boolean, container: Container) {
val pb = new PacketBuilder(PacketType.TextBufferSet)
pb.writeUTF(address)
pb.writeInt(col)
pb.writeInt(row)
pb.writeUTF(s)
pb.writeBoolean(vertical)
pb.sendToNearbyPlayers(container)
}

View File

@ -2,14 +2,14 @@ package li.cil.oc.server.component
import li.cil.oc.Settings
import li.cil.oc.api.Network
import li.cil.oc.api.component.Screen.ColorDepth
import li.cil.oc.api.component.TextBuffer.ColorDepth
import li.cil.oc.api.network._
import li.cil.oc.common.component.ManagedComponent
import li.cil.oc.common.tileentity
import li.cil.oc.util.PackedColor
import net.minecraft.nbt.NBTTagCompound
import net.minecraft.util.StatCollector
import li.cil.oc.api.component.Screen
import li.cil.oc.api.component.TextBuffer
abstract class GraphicsCard extends ManagedComponent {
val node = Network.newNode(this, Visibility.Neighbors).
@ -23,9 +23,9 @@ abstract class GraphicsCard extends ManagedComponent {
private var screenAddress: Option[String] = None
private var screenInstance: Option[Screen] = None
private var screenInstance: Option[TextBuffer] = None
private def screen(f: (Screen) => Array[AnyRef]) = screenInstance match {
private def screen(f: (TextBuffer) => Array[AnyRef]) = screenInstance match {
case Some(screen) => screen.synchronized(f(screen))
case _ => Array(Unit, "no screen")
}
@ -38,8 +38,8 @@ abstract class GraphicsCard extends ManagedComponent {
super.update()
if (node.network != null && screenInstance.isEmpty && screenAddress.isDefined) {
Option(node.network.node(screenAddress.get)) match {
case Some(node: Node) if node.host.isInstanceOf[Screen] =>
screenInstance = Some(node.host.asInstanceOf[Screen])
case Some(node: Node) if node.host.isInstanceOf[TextBuffer] =>
screenInstance = Some(node.host.asInstanceOf[TextBuffer])
case _ =>
// This could theoretically happen after loading an old address, but
// if the screen either disappeared between saving and now or changed
@ -56,9 +56,9 @@ abstract class GraphicsCard extends ManagedComponent {
val address = args.checkString(0)
node.network.node(address) match {
case null => result(Unit, "invalid address")
case node: Node if node.host.isInstanceOf[Screen] =>
case node: Node if node.host.isInstanceOf[TextBuffer] =>
screenAddress = Option(address)
screenInstance = Some(node.host.asInstanceOf[Screen])
screenInstance = Some(node.host.asInstanceOf[TextBuffer])
screen(s => {
val (gmw, gmh) = maxResolution
val smw = s.getMaximumWidth
@ -172,7 +172,7 @@ abstract class GraphicsCard extends ManagedComponent {
val x = args.checkInteger(0) - 1
val y = args.checkInteger(1) - 1
screen(s => {
result(s.get(x, y), s.getForegroundColor, s.getBackgroundColor, s.isForegroundFromPalette, s.isBackgroundFromPalette)
result(s.get(x, y), s.getForegroundColor(x, y), s.getBackgroundColor(x, y), s.isForegroundFromPalette(x, y), s.isBackgroundFromPalette(x, y))
})
}
@ -180,10 +180,11 @@ abstract class GraphicsCard extends ManagedComponent {
val x = args.checkInteger(0) - 1
val y = args.checkInteger(1) - 1
val value = args.checkString(2)
val vertical = args.count > 3 && args.checkBoolean(3)
screen(s => {
if (consumePower(value.length, Settings.get.gpuSetCost)) {
s.set(x, y, value)
s.set(x, y, value, vertical)
result(true)
}
else result(Unit, "not enough energy")
@ -250,7 +251,7 @@ abstract class GraphicsCard extends ManagedComponent {
for ((line, idx) <- lines.zipWithIndex) {
val col = (w - line.length) / 2
val row = (h - lines.length) / 2 + idx
buffer.set(col, row, line)
buffer.set(col, row, line, false)
}
}
catch {

View File

@ -2,7 +2,7 @@ package li.cil.oc.util
import li.cil.oc.api.Persistable
import net.minecraft.nbt.NBTTagCompound
import li.cil.oc.api.component.Screen.ColorDepth
import li.cil.oc.api.component.TextBuffer.ColorDepth
object PackedColor {
@ -58,6 +58,8 @@ object PackedColor {
if (value.isPalette) (math.max(0, value.value) % palette.length).toByte
else palette.map(delta(value.value, _)).zipWithIndex.minBy(_._1)._2.toByte
def isFromPalette(value: Int): Boolean
protected def palette: Array[Int]
protected def delta(colorA: Int, colorB: Int) = {
@ -77,6 +79,8 @@ object PackedColor {
def update(index: Int, value: Int) = palette(index) = value
override def isFromPalette(value: Int) = true
protected val palette = Array(
0xFFFFFF, 0xFFCC33, 0xCC66CC, 0x6699FF,
0xFFFF33, 0x33CC33, 0xFF6699, 0x333333,
@ -108,7 +112,7 @@ object PackedColor {
override def depth = ColorDepth.EightBit
override def inflate(value: Int) =
if (value < palette.length) super.inflate(value)
if (isFromPalette(value)) super.inflate(value)
else {
val index = value - palette.length
val idxB = index % blues
@ -129,6 +133,8 @@ object PackedColor {
val idxB = (b * (blues - 1.0) / 0xFF + 0.5).toInt
(palette.length + idxR * greens * blues + idxG * blues + idxB).toByte
}
override def isFromPalette(value: Int) = value < palette.length
}
case class Color(value: Int, isPalette: Boolean = false)
@ -141,9 +147,13 @@ object PackedColor {
((format.deflate(foreground) << fgShift) | format.deflate(background)).toShort
}
def extractForeground(color: Short) = (color & 0xFFFF) >>> fgShift
def extractBackground(color: Short) = color & bgMask
def unpackForeground(color: Short, format: ColorFormat) =
format.inflate((color & 0xFFFF) >>> fgShift)
format.inflate(extractForeground(color))
def unpackBackground(color: Short, format: ColorFormat) =
format.inflate(color & bgMask)
format.inflate(extractBackground(color))
}

View File

@ -1,7 +1,7 @@
package li.cil.oc.util
import li.cil.oc.Settings
import li.cil.oc.api.component.Screen.ColorDepth
import li.cil.oc.api.component.TextBuffer.ColorDepth
import net.minecraft.nbt._
/**
@ -94,19 +94,36 @@ class TextBuffer(var width: Int, var height: Int, initialFormat: PackedColor.Col
def get(col: Int, row: Int) = buffer(row)(col)
/** String based fill starting at a specified location. */
def set(col: Int, row: Int, s: String): Boolean =
if (row < 0 || row >= height) false
else {
var changed = false
val line = buffer(row)
val lineColor = color(row)
for (x <- col until math.min(col + s.length, width)) if (x >= 0) {
val c = s(x - col)
changed = changed || (line(x) != c) || (lineColor(x) != packed)
line(x) = c
lineColor(x) = packed
def set(col: Int, row: Int, s: String, vertical: Boolean): Boolean =
if (vertical) {
if (col < 0 || col >= width) false
else {
var changed = false
for (y <- row until math.min(row + s.length, height)) if (y >= 0) {
val line = buffer(y)
val lineColor = color(y)
val c = s(y - row)
changed = changed || (line(col) != c) || (lineColor(col) != packed)
line(col) = c
lineColor(col) = packed
}
changed
}
}
else {
if (row < 0 || row >= height) false
else {
var changed = false
val line = buffer(row)
val lineColor = color(row)
for (x <- col until math.min(col + s.length, width)) if (x >= 0) {
val c = s(x - col)
changed = changed || (line(x) != c) || (lineColor(x) != packed)
line(x) = c
lineColor(x) = packed
}
changed
}
changed
}
/** Fills an area of the buffer with the specified character. */
@ -174,7 +191,7 @@ class TextBuffer(var width: Int, var height: Int, initialFormat: PackedColor.Col
val b = nbt.getTagList("buffer")
for (i <- 0 until math.min(h, b.tagCount)) {
b.tagAt(i) match {
case tag: NBTTagString => set(0, i, tag.data)
case tag: NBTTagString => set(0, i, tag.data, vertical = false)
case _ =>
}
}