mirror of
https://github.com/MightyPirates/OpenComputers.git
synced 2025-09-18 11:48:02 -04:00
Cleaned up inventory util class some.
Added upgrade to allow choosing slot robot drops into / sucks from and change its equipped tool. Fixed formatting bug in tooltip code, realized most of the code was unneeded because the font renderer can do it -.-
This commit is contained in:
parent
c28cfa69fc
commit
d7143f5ff7
@ -30,4 +30,30 @@ public interface Rotatable {
|
||||
* @return the current facing.
|
||||
*/
|
||||
ForgeDirection facing();
|
||||
|
||||
/**
|
||||
* Converts a facing relative to the block's <em>local</em> coordinate
|
||||
* system to a <tt>global orientation</tt>, using south as the standard
|
||||
* orientation.
|
||||
* <p/>
|
||||
* For example, if the block is facing east, calling this with south will
|
||||
* return east, calling it with west will return south and so on.
|
||||
*
|
||||
* @param value the value to translate.
|
||||
* @return the translated orientation.
|
||||
*/
|
||||
ForgeDirection toGlobal(ForgeDirection value);
|
||||
|
||||
/**
|
||||
* Converts a <tt>global</tt> orientation to a facing relative to the
|
||||
* block's <em>local</em> coordinate system, using south as the standard
|
||||
* orientation.
|
||||
* <p/>
|
||||
* For example, if the block is facing east, calling this with south will
|
||||
* return east, calling it with west will return north and so on.
|
||||
*
|
||||
* @param value the value to translate.
|
||||
* @return the translated orientation.
|
||||
*/
|
||||
ForgeDirection toLocal(ForgeDirection value);
|
||||
}
|
||||
|
@ -89,6 +89,10 @@ public interface Robot extends ISidedInventory, Rotatable {
|
||||
|
||||
/**
|
||||
* Gets the index of the currently selected slot in the robot's inventory.
|
||||
* <p/>
|
||||
* This is the index in the underlying, <em>real</em> inventory. To get
|
||||
* the 'local' index, i.e. the way the robot itself addresses it, add
|
||||
* one for the tool and <tt>containerCount</tt> to this value.
|
||||
*
|
||||
* @return the index of the currently selected slot.
|
||||
*/
|
||||
|
@ -13,6 +13,7 @@ oc:tile.Case3.name=Computergehäuse (Kreativ)
|
||||
oc:tile.Charger.name=Ladestation
|
||||
oc:tile.Disassembler.name=Recycler
|
||||
oc:tile.DiskDrive.name=Diskettenlaufwerk
|
||||
oc:tile.Geolyzer.name=Geolyzer
|
||||
oc:tile.Keyboard.name=Tastatur
|
||||
oc:tile.Hologram0.name=Hologrammprojektor (Stufe 1)
|
||||
oc:tile.Hologram1.name=Hologrammprojektor (Stufe 2)
|
||||
@ -85,6 +86,7 @@ oc:item.UpgradeCrafting.name=Fertigungs-Upgrade
|
||||
oc:item.UpgradeExperience.name=Erfahrungs-Upgrade
|
||||
oc:item.UpgradeGenerator.name=Generator-Upgrade
|
||||
oc:item.UpgradeInventory.name=Inventar-Upgrade
|
||||
oc:item.UpgradeInventoryController.name=Inventarbedienungs-Upgrade
|
||||
oc:item.UpgradeNavigation.name=Navigationsupgrade
|
||||
oc:item.UpgradeSign.name=Schild-I/O-Upgrade
|
||||
oc:item.UpgradeSolarGenerator.name=Solargenerator-Upgrade
|
||||
@ -163,6 +165,7 @@ oc:tooltip.Disassembler=Zerlegt Gegenstände in ihre Einzelteile. §lWarnung§7:
|
||||
oc:tooltip.Disk=Sehr einfaches Speichermedium, das verwendet werden kann, um Disketten und Festplatten bauen.
|
||||
oc:tooltip.DiskDrive.CC=ComputerCraft-Disketten werden §aunterstützt§7.
|
||||
oc:tooltip.DiskDrive=Erlaubt es, Disketten zu lesen und zu beschreiben.
|
||||
oc:tooltip.Geolyzer=Erlaubt es die Härte der Blöcke in der Umgebung abzufragen. Hilfreich um Hologramme der Gegend zu erzeugen, oder um Erze zu entdecken.
|
||||
oc:tooltip.GraphicsCard=Erlaubt es, den angezeigten Inhalt von Bildschirmen zu ändern.[nl] Höchstauflösung: §f%sx%s§7.[nl] Maximale Farbtiefe: §f%s§7.[nl] Operationen/Tick: §f%s§7.
|
||||
oc:tooltip.InternetCard=Diese Karte erlaubt es, HTTP-Anfragen zu senden und echte TCP Sockets zu verwenden.
|
||||
oc:tooltip.Interweb=Kann in einer Internetkarte verwendet werden, um Computer mit dem rechtsfreien Raum kommunizieren zu lassen.
|
||||
@ -209,6 +212,7 @@ oc:tooltip.UpgradeCrafting=Ermöglicht Robotern, in dem oberen linken Bereich ih
|
||||
oc:tooltip.UpgradeExperience=Dieses Upgrade erlaubt es Robotern durch verschiedene Aktionen Erfahrung zu sammeln. Je mehr Erfahrung ein Roboter hat, desto mehr Energie kann er speichern, desto schneller kann er Blöcke abbauen und desto effizienter kann er mit Werkzeugen umgehen.
|
||||
oc:tooltip.UpgradeGenerator=Kann verwendet werden, um unterwegs Energie aus Brennstoffen zu erzeugen. Verbraucht Gegenstände über einen ihrem Brennwert gemäßen Zeitraum.[nl] §fEffizienz§7: §a%s%%§7
|
||||
oc:tooltip.UpgradeInventory=Dieses Upgrade gibt Robotern ein internes Inventar. Ohne ein solches Upgrade können Roboter keine Gegenstände verwahren.
|
||||
oc:tooltip.UpgradeInventoryController=Dieses Upgrade erlaubt es dem Roboter präziser mit externen Inventaren zu interagieren, und erlaubt es ihm das angelegte Werkzeug mit einem Gegenstand in seinem Inventar auszutauschen.
|
||||
oc:tooltip.UpgradeNavigation=Erlaubt es Robotern, ihre Position und Ausrichtung zu bestimmen. Die Position ist relativ zur Mitte der Karte, die in diesem Upgrade verbaut wurde.
|
||||
oc:tooltip.UpgradeSign=Erlaubt das Lesen und Schreiben von Text auf Schildern.
|
||||
oc:tooltip.UpgradeSolarGenerator=Kann verwendet werden, um unterwegs Energie aus Sonnenlicht zu generieren. Benötigt eine ungehinderte Sicht zum Himmel über dem Roboter. Generiert Energie mit %s%% der Geschwindigkeit eines Stirlingmotors.
|
||||
|
@ -13,6 +13,7 @@ oc:tile.Case3.name=Computer Case (Creative)
|
||||
oc:tile.Charger.name=Charger
|
||||
oc:tile.Disassembler.name=Disassembler
|
||||
oc:tile.DiskDrive.name=Disk Drive
|
||||
oc:tile.Geolyzer.name=Geolyzer
|
||||
oc:tile.Keyboard.name=Keyboard
|
||||
oc:tile.Hologram0.name=Hologram Projector (Tier 1)
|
||||
oc:tile.Hologram1.name=Hologram Projector (Tier 2)
|
||||
@ -85,6 +86,7 @@ oc:item.UpgradeCrafting.name=Crafting Upgrade
|
||||
oc:item.UpgradeExperience.name=Experience Upgrade
|
||||
oc:item.UpgradeGenerator.name=Generator Upgrade
|
||||
oc:item.UpgradeInventory.name=Inventory Upgrade
|
||||
oc:item.UpgradeInventoryController.name=Inventory Controller Upgrade
|
||||
oc:item.UpgradeNavigation.name=Navigation Upgrade
|
||||
oc:item.UpgradeSign.name=Sign I/O Upgrade
|
||||
oc:item.UpgradeSolarGenerator.name=Solar Generator Upgrade
|
||||
@ -163,6 +165,7 @@ oc:tooltip.Disassembler=Separates items into their original components. §lWarni
|
||||
oc:tooltip.Disk=Primitive medium that can be used to build persistent storage devices.
|
||||
oc:tooltip.DiskDrive.CC=ComputerCraft floppies are §asupported§7.
|
||||
oc:tooltip.DiskDrive=Allows reading and writing floppies.
|
||||
oc:tooltip.Geolyzer=Allows scanning the surrounding area's blocks' hardness. This information can be useful for generating holograms of the area or for detecting ores.
|
||||
oc:tooltip.GraphicsCard=Used to change what's displayed on screens.[nl] Maximum resolution: §f%sx%s§7.[nl] Maximum color depth: §f%s§7.[nl] Operations/tick: §f%s§7.
|
||||
oc:tooltip.InternetCard=This card allows making HTTP requests and using real TCP sockets.
|
||||
oc:tooltip.Interweb=Congratulations, you win one (1) interweb. You can connect to it using an Internet Card. Beware: don't feed the trolls.
|
||||
@ -209,6 +212,7 @@ oc:tooltip.UpgradeCrafting=Enables robots to use the top left area of their inve
|
||||
oc:tooltip.UpgradeExperience=This upgrade allows robots to accumulate experience by performing various operations. The more experience they have, the more energy they can store, the faster they can harvest blocks and the more efficiently they can use tools.
|
||||
oc:tooltip.UpgradeGenerator=Can be used to generate energy from fuel on the go. Burns items to generate energy over time, based on their fuel value.[nl] §fEfficiency§7: §a%s%%§7
|
||||
oc:tooltip.UpgradeInventory=This upgrade provides inventory space to the robot. Without one of these, robots will not be able to store items internally.
|
||||
oc:tooltip.UpgradeInventoryController=This upgrade allows the robot more control in how it interacts with external inventories, and allows it to swap its equipped tool with an item in its inventory.
|
||||
oc:tooltip.UpgradeNavigation=Can be used to determine the position and orientation of the robot. The position is relative to the center of the map that was used to craft this upgrade.
|
||||
oc:tooltip.UpgradeSign=Allows reading text on and writing text to signs.
|
||||
oc:tooltip.UpgradeSolarGenerator=Can be used to generate energy from sunlight on the go. Requires a clear line of sight to the sky above the robot. Generates energy at %s%% of the speed of a Stirling Engine.
|
||||
|
@ -142,6 +142,11 @@ inventoryUpgrade {
|
||||
[dispenser, chest, craftingPiston]
|
||||
[plankWood, "oc:circuitChip1", plankWood]]
|
||||
}
|
||||
inventoryControllerUpgrade {
|
||||
input: [[ingotGold, "oc:analyzer", ingotGold]
|
||||
[dispenser, "oc:circuitChip2", craftingPiston]
|
||||
[ingotGold, "oc:materialCircuitBoardPrinted", ingotGold]]
|
||||
}
|
||||
navigationUpgrade {
|
||||
input: [[ingotGold, compass, ingotGold]
|
||||
["oc:circuitChip3", {item=map, subID=any}, "oc:circuitChip3"]
|
||||
|
Binary file not shown.
After Width: | Height: | Size: 517 B |
@ -212,5 +212,7 @@ object Items extends ItemAPI {
|
||||
stack
|
||||
}
|
||||
}, "openOS")
|
||||
|
||||
Recipes.addItem(new item.UpgradeInventoryController(multi), "inventoryControllerUpgrade", "oc:inventoryControllerUpgrade")
|
||||
}
|
||||
}
|
@ -76,6 +76,7 @@ class Proxy {
|
||||
api.Driver.add(driver.item.UpgradeExperience)
|
||||
api.Driver.add(driver.item.UpgradeGenerator)
|
||||
api.Driver.add(driver.item.UpgradeInventory)
|
||||
api.Driver.add(driver.item.UpgradeInventoryController)
|
||||
api.Driver.add(driver.item.UpgradeNavigation)
|
||||
api.Driver.add(driver.item.UpgradeSign)
|
||||
api.Driver.add(driver.item.UpgradeSolarGenerator)
|
||||
|
@ -0,0 +1,25 @@
|
||||
package li.cil.oc.common.item
|
||||
|
||||
import java.util
|
||||
import li.cil.oc.{Settings, server}
|
||||
import li.cil.oc.util.{Tooltip, Rarity}
|
||||
import net.minecraft.entity.player.EntityPlayer
|
||||
import net.minecraft.item.ItemStack
|
||||
import net.minecraft.client.renderer.texture.IconRegister
|
||||
|
||||
class UpgradeInventoryController(val parent: Delegator) extends Delegate {
|
||||
val unlocalizedName = "UpgradeInventoryController"
|
||||
|
||||
override def rarity = Rarity.byTier(server.driver.item.UpgradeInventoryController.tier(createItemStack()))
|
||||
|
||||
override def tooltipLines(stack: ItemStack, player: EntityPlayer, tooltip: util.List[String], advanced: Boolean) {
|
||||
tooltip.addAll(Tooltip.get(unlocalizedName))
|
||||
super.tooltipLines(stack, player, tooltip, advanced)
|
||||
}
|
||||
|
||||
override def registerIcons(iconRegister: IconRegister) = {
|
||||
super.registerIcons(iconRegister)
|
||||
|
||||
icon = iconRegister.registerIcon(Settings.resourceDomain + ":upgrade_inventory_controller")
|
||||
}
|
||||
}
|
@ -162,7 +162,7 @@ class Disassembler extends traits.Environment with traits.Inventory {
|
||||
private def drop(stack: ItemStack) {
|
||||
if (stack != null) {
|
||||
for (side <- ForgeDirection.VALID_DIRECTIONS if stack.stackSize > 0) {
|
||||
InventoryUtils.tryDropIntoInventoryAt(stack, world, x + side.offsetX, y + side.offsetY, z + side.offsetZ, side.getOpposite)
|
||||
InventoryUtils.insertIntoInventoryAt(stack, world, x + side.offsetX, y + side.offsetY, z + side.offsetZ, side.getOpposite)
|
||||
}
|
||||
if (stack.stackSize > 0) {
|
||||
spawnStackInWorld(stack, ForgeDirection.UP)
|
||||
|
@ -0,0 +1,94 @@
|
||||
package li.cil.oc.server.component
|
||||
|
||||
import li.cil.oc.Settings
|
||||
import li.cil.oc.api.machine.Robot
|
||||
import li.cil.oc.api.Network
|
||||
import li.cil.oc.api.network._
|
||||
import li.cil.oc.common.component.ManagedComponent
|
||||
import li.cil.oc.util.InventoryUtils
|
||||
import li.cil.oc.util.ExtendedArguments._
|
||||
import net.minecraft.tileentity.TileEntity
|
||||
|
||||
class UpgradeInventoryController(val owner: TileEntity with Robot) extends ManagedComponent {
|
||||
val node = Network.newNode(this, Visibility.Network).
|
||||
withComponent("inventory_controller", Visibility.Neighbors).
|
||||
withConnector().
|
||||
create()
|
||||
|
||||
// ----------------------------------------------------------------------- //
|
||||
|
||||
@Callback(doc = """function():number -- Get the number of slots in the inventory on the specified side of the robot.""")
|
||||
def getInventorySize(context: Context, args: Arguments): Array[AnyRef] = {
|
||||
val facing = checkSideForAction(args, 0)
|
||||
InventoryUtils.inventoryAt(owner.getWorldObj, owner.xCoord + facing.offsetX, owner.yCoord + facing.offsetY, owner.zCoord + facing.offsetZ) match {
|
||||
case Some(inventory) => result(inventory.getSizeInventory)
|
||||
case _ => result(Unit, "no inventory")
|
||||
}
|
||||
}
|
||||
|
||||
@Callback(doc = """function(facing:number, slot:number[, count:number]):boolean -- Drops the selected item stack into the specified slot of an inventory.""")
|
||||
def dropIntoSlot(context: Context, args: Arguments): Array[AnyRef] = {
|
||||
val facing = checkSideForAction(args, 0)
|
||||
val count = args.optionalItemCount(2)
|
||||
val selectedSlot = owner.selectedSlot
|
||||
val stack = owner.getStackInSlot(selectedSlot)
|
||||
if (stack != null && stack.stackSize > 0) {
|
||||
InventoryUtils.inventoryAt(owner.getWorldObj, owner.xCoord + facing.offsetX, owner.yCoord + facing.offsetY, owner.zCoord + facing.offsetZ) match {
|
||||
case Some(inventory) =>
|
||||
val slot = args.checkSlot(inventory, 1)
|
||||
if (!InventoryUtils.insertIntoInventorySlot(stack, inventory, facing.getOpposite, slot, count)) {
|
||||
// Cannot drop into that inventory.
|
||||
return result(false, "inventory full")
|
||||
}
|
||||
else if (stack.stackSize == 0) {
|
||||
// Dropped whole stack.
|
||||
owner.setInventorySlotContents(selectedSlot, null)
|
||||
}
|
||||
else {
|
||||
// Dropped partial stack.
|
||||
owner.onInventoryChanged()
|
||||
}
|
||||
case _ => return result(false, "no inventory")
|
||||
}
|
||||
|
||||
context.pause(Settings.get.dropDelay)
|
||||
|
||||
result(true)
|
||||
}
|
||||
else result(false)
|
||||
}
|
||||
|
||||
@Callback(doc = """function(facing:number, slot:number[, count:number]):boolean -- Sucks items from the specified slot of an inventory.""")
|
||||
def suckFromSlot(context: Context, args: Arguments): Array[AnyRef] = {
|
||||
val facing = checkSideForAction(args, 0)
|
||||
val count = args.optionalItemCount(2)
|
||||
|
||||
InventoryUtils.inventoryAt(owner.getWorldObj, owner.xCoord + facing.offsetX, owner.yCoord + facing.offsetY, owner.zCoord + facing.offsetZ) match {
|
||||
case Some(inventory) =>
|
||||
val slot = args.checkSlot(inventory, 1)
|
||||
if (InventoryUtils.extractFromInventorySlot(owner.player.inventory.addItemStackToInventory, inventory, facing.getOpposite, slot, count)) {
|
||||
context.pause(Settings.get.suckDelay)
|
||||
result(true)
|
||||
}
|
||||
else result(false)
|
||||
case _ => result(false, "no inventory")
|
||||
}
|
||||
}
|
||||
|
||||
@Callback(doc = """function():boolean -- Swaps the equipped tool with the content of the currently selected inventory slot.""")
|
||||
def equip(context: Context, args: Arguments): Array[AnyRef] = {
|
||||
if (owner.inventorySize > 0) {
|
||||
val selectedSlot = owner.selectedSlot
|
||||
val equipped = owner.getStackInSlot(0)
|
||||
val selected = owner.getStackInSlot(selectedSlot)
|
||||
owner.setInventorySlotContents(0, selected)
|
||||
owner.setInventorySlotContents(selectedSlot, equipped)
|
||||
result(true)
|
||||
}
|
||||
else result(false)
|
||||
}
|
||||
|
||||
private def checkSlot(args: Arguments, n: Int) = args.checkSlot(owner, n)
|
||||
|
||||
private def checkSideForAction(args: Arguments, n: Int) = owner.toGlobal(args.checkSideForAction(n))
|
||||
}
|
@ -115,7 +115,7 @@ class Inventory(player: Player) extends InventoryPlayer(player) {
|
||||
|
||||
override def readFromNBT(nbt: NBTTagList) {}
|
||||
|
||||
override def getSizeInventory = robot.getSizeInventory
|
||||
override def getSizeInventory = 1 + robot.containerCount + robot.inventorySize
|
||||
|
||||
override def getStackInSlot(slot: Int) = robot.getStackInSlot(slot)
|
||||
|
||||
|
@ -6,12 +6,10 @@ import li.cil.oc.common.tileentity
|
||||
import li.cil.oc.server.{PacketSender => ServerPacketSender}
|
||||
import li.cil.oc.util.ExtendedNBT._
|
||||
import net.minecraft.block.{BlockFluid, Block}
|
||||
import net.minecraft.entity.item.{EntityMinecart, EntityMinecartContainer, EntityItem}
|
||||
import net.minecraft.entity.item.{EntityMinecart, EntityItem}
|
||||
import net.minecraft.entity.{EntityLivingBase, Entity}
|
||||
import net.minecraft.inventory.{IInventory, ISidedInventory}
|
||||
import net.minecraft.item.{ItemStack, ItemBlock}
|
||||
import net.minecraft.nbt.NBTTagCompound
|
||||
import net.minecraft.tileentity.TileEntityChest
|
||||
import net.minecraft.util.{MovingObjectPosition, EnumMovingObjectType}
|
||||
import net.minecraftforge.common.{MinecraftForge, ForgeDirection}
|
||||
import net.minecraftforge.event.world.BlockEvent
|
||||
@ -20,6 +18,7 @@ import scala.collection.convert.WrapAsScala._
|
||||
import li.cil.oc.common.component.ManagedComponent
|
||||
import li.cil.oc.api.event.RobotPlaceInAirEvent
|
||||
import li.cil.oc.util.InventoryUtils
|
||||
import li.cil.oc.util.ExtendedArguments._
|
||||
|
||||
class Robot(val robot: tileentity.Robot) extends ManagedComponent {
|
||||
val node = api.Network.newNode(this, Visibility.Neighbors).
|
||||
@ -57,6 +56,9 @@ class Robot(val robot: tileentity.Robot) extends ManagedComponent {
|
||||
|
||||
// ----------------------------------------------------------------------- //
|
||||
|
||||
@Callback
|
||||
def getInventorySize(context: Context, args: Arguments): Array[AnyRef] = result(robot.inventorySize)
|
||||
|
||||
@Callback
|
||||
def select(context: Context, args: Arguments): Array[AnyRef] = {
|
||||
if (args.count > 0 && args.checkAny(0) != null) {
|
||||
@ -104,7 +106,7 @@ class Robot(val robot: tileentity.Robot) extends ManagedComponent {
|
||||
@Callback
|
||||
def transferTo(context: Context, args: Arguments): Array[AnyRef] = {
|
||||
val slot = checkSlot(args, 0)
|
||||
val count = checkOptionalItemCount(args, 1)
|
||||
val count = args.optionalItemCount(1)
|
||||
if (slot == selectedSlot || count == 0) {
|
||||
result(true)
|
||||
}
|
||||
@ -158,16 +160,28 @@ class Robot(val robot: tileentity.Robot) extends ManagedComponent {
|
||||
@Callback
|
||||
def drop(context: Context, args: Arguments): Array[AnyRef] = {
|
||||
val facing = checkSideForAction(args, 0)
|
||||
val count = checkOptionalItemCount(args, 1)
|
||||
val stack = robot.decrStackSize(selectedSlot, count)
|
||||
val count = args.optionalItemCount(1)
|
||||
val stack = robot.getStackInSlot(selectedSlot)
|
||||
if (stack != null && stack.stackSize > 0) {
|
||||
val player = robot.player(facing)
|
||||
if (!InventoryUtils.tryDropIntoInventoryAt(stack, world, x + facing.offsetX, y + facing.offsetY, z + facing.offsetZ, facing.getOpposite)) {
|
||||
// No inventory to drop into, drop into the world.
|
||||
player.dropPlayerItemWithRandomChoice(stack, inPlace = false)
|
||||
InventoryUtils.inventoryAt(world, x + facing.offsetX, y + facing.offsetY, z + facing.offsetZ) match {
|
||||
case Some(inventory) =>
|
||||
if (!InventoryUtils.insertIntoInventory(stack, inventory, facing.getOpposite, count)) {
|
||||
// Cannot drop into that inventory.
|
||||
return result(false, "inventory full")
|
||||
}
|
||||
else if (stack.stackSize == 0) {
|
||||
// Dropped whole stack.
|
||||
robot.setInventorySlotContents(selectedSlot, null)
|
||||
}
|
||||
else {
|
||||
// Dropped partial stack.
|
||||
robot.onInventoryChanged()
|
||||
}
|
||||
case _ =>
|
||||
// No inventory to drop into, drop into the world.
|
||||
player.dropPlayerItemWithRandomChoice(robot.decrStackSize(selectedSlot, count), inPlace = false)
|
||||
}
|
||||
// Put back whatever remained of the stack.
|
||||
player.inventory.addItemStackToInventory(stack)
|
||||
|
||||
context.pause(Settings.get.dropDelay)
|
||||
|
||||
@ -219,55 +233,23 @@ class Robot(val robot: tileentity.Robot) extends ManagedComponent {
|
||||
@Callback
|
||||
def suck(context: Context, args: Arguments): Array[AnyRef] = {
|
||||
val facing = checkSideForAction(args, 0)
|
||||
val count = checkOptionalItemCount(args, 1)
|
||||
val count = args.optionalItemCount(1)
|
||||
|
||||
def trySuckFromInventory(inventory: IInventory, filter: (Int) => Boolean) = {
|
||||
var success = false
|
||||
for (slot <- 0 until inventory.getSizeInventory if !success && filter(slot)) {
|
||||
val stack = inventory.getStackInSlot(slot)
|
||||
if (stack != null) {
|
||||
val maxStackSize = math.min(robot.getInventoryStackLimit, stack.getMaxStackSize)
|
||||
val amount = math.min(maxStackSize, math.min(stack.stackSize, count))
|
||||
val sucked = stack.splitStack(amount)
|
||||
success = player.inventory.addItemStackToInventory(sucked)
|
||||
stack.stackSize += sucked.stackSize
|
||||
if (stack.stackSize == 0) {
|
||||
inventory.setInventorySlotContents(slot, null)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (success) {
|
||||
inventory.onInventoryChanged()
|
||||
}
|
||||
success
|
||||
if (InventoryUtils.extractFromInventoryAt(player.inventory.addItemStackToInventory, world, x + facing.offsetX, y + facing.offsetY, z + facing.offsetZ, facing.getOpposite, count)) {
|
||||
context.pause(Settings.get.suckDelay)
|
||||
result(true)
|
||||
}
|
||||
|
||||
world.getBlockTileEntity(x + facing.offsetX, y + facing.offsetY, z + facing.offsetZ) match {
|
||||
case chest: TileEntityChest if chest.isUseableByPlayer(player) =>
|
||||
val inventory = Block.chest.getInventory(world, chest.xCoord, chest.yCoord, chest.zCoord)
|
||||
result(trySuckFromInventory(inventory, slot => true))
|
||||
case inventory: ISidedInventory if inventory.isUseableByPlayer(player) =>
|
||||
result(trySuckFromInventory(inventory,
|
||||
slot => inventory.canExtractItem(slot, inventory.getStackInSlot(slot), facing.getOpposite.ordinal())))
|
||||
case inventory: IInventory if inventory.isUseableByPlayer(player) =>
|
||||
result(trySuckFromInventory(inventory, slot => true))
|
||||
case _ =>
|
||||
val player = robot.player(facing)
|
||||
for (entity <- player.entitiesOnSide[EntityMinecartContainer](facing) if entity.isUseableByPlayer(player)) {
|
||||
if (trySuckFromInventory(entity, slot => true)) {
|
||||
return result(true)
|
||||
}
|
||||
else {
|
||||
for (entity <- player.entitiesOnSide[EntityItem](facing) if !entity.isDead && entity.delayBeforeCanPickup <= 0) {
|
||||
val stack = entity.getEntityItem
|
||||
val size = stack.stackSize
|
||||
entity.onCollideWithPlayer(player)
|
||||
if (stack.stackSize < size || entity.isDead) {
|
||||
context.pause(Settings.get.suckDelay)
|
||||
return result(true)
|
||||
}
|
||||
for (entity <- player.entitiesOnSide[EntityItem](facing) if !entity.isDead && entity.delayBeforeCanPickup <= 0) {
|
||||
val stack = entity.getEntityItem
|
||||
val size = stack.stackSize
|
||||
entity.onCollideWithPlayer(player)
|
||||
if (stack.stackSize < size || entity.isDead) {
|
||||
context.pause(Settings.get.suckDelay)
|
||||
return result(true)
|
||||
}
|
||||
}
|
||||
result(false)
|
||||
}
|
||||
result(false)
|
||||
}
|
||||
}
|
||||
|
||||
@ -457,7 +439,7 @@ class Robot(val robot: tileentity.Robot) extends ManagedComponent {
|
||||
|
||||
@Callback
|
||||
def move(context: Context, args: Arguments): Array[AnyRef] = {
|
||||
val direction = checkSideForMovement(args, 0)
|
||||
val direction = robot.toGlobal(args.checkSideForMovement(0))
|
||||
if (robot.isAnimatingMove) {
|
||||
// This shouldn't really happen due to delays being enforced, but just to
|
||||
// be on the safe side...
|
||||
@ -624,33 +606,9 @@ class Robot(val robot: tileentity.Robot) extends ManagedComponent {
|
||||
|
||||
// ----------------------------------------------------------------------- //
|
||||
|
||||
private def checkOptionalItemCount(args: Arguments, n: Int) =
|
||||
if (args.count > n && args.checkAny(n) != null) {
|
||||
math.max(args.checkInteger(n), math.min(0, robot.getInventoryStackLimit))
|
||||
}
|
||||
else robot.getInventoryStackLimit
|
||||
private def checkSlot(args: Arguments, n: Int) = args.checkSlot(robot, n)
|
||||
|
||||
private def checkSlot(args: Arguments, n: Int) = {
|
||||
val slot = args.checkInteger(n) - 1
|
||||
if (slot < 0 || slot > 15) {
|
||||
throw new IllegalArgumentException("invalid slot")
|
||||
}
|
||||
actualSlot(slot)
|
||||
}
|
||||
private def checkSideForAction(args: Arguments, n: Int) = robot.toGlobal(args.checkSideForAction(n))
|
||||
|
||||
private def checkSideForAction(args: Arguments, n: Int) = checkSide(args, n, ForgeDirection.SOUTH, ForgeDirection.UP, ForgeDirection.DOWN)
|
||||
|
||||
private def checkSideForMovement(args: Arguments, n: Int) = checkSide(args, n, ForgeDirection.SOUTH, ForgeDirection.NORTH, ForgeDirection.UP, ForgeDirection.DOWN)
|
||||
|
||||
private def checkSideForFace(args: Arguments, n: Int, facing: ForgeDirection) = checkSide(args, n, ForgeDirection.VALID_DIRECTIONS.filter(_ != robot.toLocal(facing).getOpposite): _*)
|
||||
|
||||
private def checkSide(args: Arguments, n: Int, allowed: ForgeDirection*) = {
|
||||
val side = args.checkInteger(n)
|
||||
if (side < 0 || side > 5) {
|
||||
throw new IllegalArgumentException("invalid side")
|
||||
}
|
||||
val direction = ForgeDirection.getOrientation(side)
|
||||
if (allowed.isEmpty || (allowed contains direction)) robot.toGlobal(direction)
|
||||
else throw new IllegalArgumentException("unsupported side")
|
||||
}
|
||||
private def checkSideForFace(args: Arguments, n: Int, facing: ForgeDirection) = robot.toGlobal(args.checkSideForFace(n, robot.toLocal(facing)))
|
||||
}
|
||||
|
@ -0,0 +1,21 @@
|
||||
package li.cil.oc.server.driver.item
|
||||
|
||||
import li.cil.oc.api
|
||||
import li.cil.oc.api.driver.Slot
|
||||
import li.cil.oc.server.component
|
||||
import net.minecraft.item.ItemStack
|
||||
import net.minecraft.tileentity.TileEntity
|
||||
import li.cil.oc.api.machine.Robot
|
||||
|
||||
object UpgradeInventoryController extends Item {
|
||||
override def worksWith(stack: ItemStack) = isOneOf(stack, api.Items.get("inventoryControllerUpgrade"))
|
||||
|
||||
override def createEnvironment(stack: ItemStack, container: component.Container) = container.tileEntity match {
|
||||
case Some(robot: TileEntity with Robot) => new component.UpgradeInventoryController(robot)
|
||||
case _ => null
|
||||
}
|
||||
|
||||
override def slot(stack: ItemStack) = Slot.Upgrade
|
||||
|
||||
override def tier(stack: ItemStack) = 1
|
||||
}
|
52
src/main/scala/li/cil/oc/util/ExtendedArguments.scala
Normal file
52
src/main/scala/li/cil/oc/util/ExtendedArguments.scala
Normal file
@ -0,0 +1,52 @@
|
||||
package li.cil.oc.util
|
||||
|
||||
import li.cil.oc.api.machine.Robot
|
||||
import li.cil.oc.api.network.Arguments
|
||||
import net.minecraftforge.common.ForgeDirection
|
||||
import net.minecraft.inventory.IInventory
|
||||
|
||||
object ExtendedArguments {
|
||||
|
||||
implicit def extendedArguments(args: Arguments) = new ExtendedArguments(args)
|
||||
|
||||
class ExtendedArguments(val args: Arguments) {
|
||||
def optionalItemCount(n: Int) =
|
||||
if (args.count > n && args.checkAny(n) != null) {
|
||||
math.max(0, math.min(64, args.checkInteger(n)))
|
||||
}
|
||||
else 64
|
||||
|
||||
def checkSlot(inventory: IInventory, n: Int) = {
|
||||
val slot = args.checkInteger(n) - 1
|
||||
if (slot < 0 || slot >= inventory.getSizeInventory) {
|
||||
throw new IllegalArgumentException("invalid slot")
|
||||
}
|
||||
slot
|
||||
}
|
||||
|
||||
def checkSlot(robot: Robot, n: Int) = {
|
||||
val slot = args.checkInteger(n) - 1
|
||||
if (slot < 0 || slot >= robot.inventorySize) {
|
||||
throw new IllegalArgumentException("invalid slot")
|
||||
}
|
||||
slot + 1 + robot.containerCount
|
||||
}
|
||||
|
||||
def checkSideForAction(n: Int) = checkSide(n, ForgeDirection.SOUTH, ForgeDirection.UP, ForgeDirection.DOWN)
|
||||
|
||||
def checkSideForMovement(n: Int) = checkSide(n, ForgeDirection.SOUTH, ForgeDirection.NORTH, ForgeDirection.UP, ForgeDirection.DOWN)
|
||||
|
||||
def checkSideForFace(n: Int, facing: ForgeDirection) = checkSide(n, ForgeDirection.VALID_DIRECTIONS.filter(_ != facing.getOpposite): _*)
|
||||
|
||||
private def checkSide(n: Int, allowed: ForgeDirection*) = {
|
||||
val side = args.checkInteger(n)
|
||||
if (side < 0 || side > 5) {
|
||||
throw new IllegalArgumentException("invalid side")
|
||||
}
|
||||
val direction = ForgeDirection.getOrientation(side)
|
||||
if (allowed.isEmpty || (allowed contains direction)) direction
|
||||
else throw new IllegalArgumentException("unsupported side")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -11,60 +11,188 @@ import scala.collection.convert.WrapAsScala._
|
||||
import net.minecraftforge.common.ForgeDirection
|
||||
|
||||
object InventoryUtils {
|
||||
def tryDropIntoInventoryAt(stack: ItemStack, world: World, x: Int, y: Int, z: Int, side: ForgeDirection): Boolean = {
|
||||
/**
|
||||
* Retrieves an actual inventory implementation for a specified world coordinate.
|
||||
* <p/>
|
||||
* This performs special handling for (double-)chests and also checks for
|
||||
* mine carts with chests.
|
||||
*/
|
||||
def inventoryAt(world: World, x: Int, y: Int, z: Int) = {
|
||||
world.getBlockTileEntity(x, y, z) match {
|
||||
case chest: TileEntityChest =>
|
||||
val inventory = Block.chest.getInventory(world, chest.xCoord, chest.yCoord, chest.zCoord)
|
||||
tryDropIntoInventory(stack, inventory, side)
|
||||
case inventory: ISidedInventory =>
|
||||
tryDropIntoInventory(stack, inventory, side)
|
||||
case inventory: IInventory =>
|
||||
tryDropIntoInventory(stack, inventory, side)
|
||||
case _ =>
|
||||
val mineCarts = world.getEntitiesWithinAABB(classOf[EntityMinecartContainer],
|
||||
AxisAlignedBB.getBoundingBox(x, y, z, x + 1, y + 1, z + 1)).
|
||||
map(_.asInstanceOf[EntityMinecartContainer])
|
||||
for (inventory <- mineCarts if !inventory.isDead) {
|
||||
if (tryDropIntoInventory(stack, inventory, side)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
false
|
||||
case chest: TileEntityChest => Option(Block.chest.getInventory(world, chest.xCoord, chest.yCoord, chest.zCoord))
|
||||
case inventory: IInventory => Some(inventory)
|
||||
case _ => world.getEntitiesWithinAABB(classOf[EntityMinecartContainer],
|
||||
AxisAlignedBB.getBoundingBox(x, y, z, x + 1, y + 1, z + 1)).
|
||||
map(_.asInstanceOf[EntityMinecartContainer]).
|
||||
find(!_.isDead)
|
||||
}
|
||||
}
|
||||
|
||||
def tryDropIntoInventory(stack: ItemStack, inventory: IInventory, side: ForgeDirection) = {
|
||||
def isSideValidForSlot: (Int) => Boolean = inventory match {
|
||||
case inventory: ISidedInventory => (slot) => inventory.canInsertItem(slot, stack, side.ordinal)
|
||||
case _ => (slot) => true
|
||||
}
|
||||
var success = false
|
||||
val maxStackSize = math.min(inventory.getInventoryStackLimit, stack.getMaxStackSize)
|
||||
val shouldTryMerge = !stack.isItemStackDamageable && stack.getMaxStackSize > 1 && inventory.getInventoryStackLimit > 1
|
||||
if (shouldTryMerge) {
|
||||
for (slot <- 0 until inventory.getSizeInventory if stack.stackSize > 0 && inventory.isItemValidForSlot(slot, stack) && isSideValidForSlot(slot)) {
|
||||
/**
|
||||
* Inserts a stack into an inventory.
|
||||
* <p/>
|
||||
* Only tries to insert into the specified slot. This <em>cannot</em> be
|
||||
* used to empty a slot. It can only insert stacks into empty slots and
|
||||
* merge additional items into an existing stack in the slot.
|
||||
* <p/>
|
||||
* The passed stack's size will be adjusted to reflect the number of items
|
||||
* inserted into the inventory, i.e. if 10 more items could fit into the
|
||||
* slot, the stack's size will be 10 smaller than before the call.
|
||||
* <p/>
|
||||
* This will return <tt>true</tt> if <em>at least</em> one item could be
|
||||
* inserted into the slot. It will return <tt>false</tt> if the passed
|
||||
* stack did not change.
|
||||
* <p/>
|
||||
* This takes care of handling special cases such as sided inventories,
|
||||
* maximum inventory and item stack sizes.
|
||||
* <p/>
|
||||
* The number of items inserted can be limited, to avoid unnecessary
|
||||
* changes to the inventory the stack may come from, for example.
|
||||
*/
|
||||
def insertIntoInventorySlot(stack: ItemStack, inventory: IInventory, side: ForgeDirection, slot: Int, limit: Int = 64) =
|
||||
(stack != null && limit > 0) && {
|
||||
val isSideValidForSlot = inventory match {
|
||||
case inventory: ISidedInventory => inventory.canInsertItem(slot, stack, side.ordinal)
|
||||
case _ => true
|
||||
}
|
||||
(stack.stackSize > 0 && inventory.isItemValidForSlot(slot, stack) && isSideValidForSlot) && {
|
||||
val maxStackSize = math.min(inventory.getInventoryStackLimit, stack.getMaxStackSize)
|
||||
val existing = inventory.getStackInSlot(slot)
|
||||
val shouldMerge = existing != null && existing.stackSize < maxStackSize &&
|
||||
existing.isItemEqual(stack) && ItemStack.areItemStackTagsEqual(existing, stack)
|
||||
if (shouldMerge) {
|
||||
val space = maxStackSize - existing.stackSize
|
||||
val amount = math.min(space, stack.stackSize)
|
||||
assert(amount > 0)
|
||||
success = true
|
||||
val amount = math.min(space, math.min(stack.stackSize, limit))
|
||||
existing.stackSize += amount
|
||||
stack.stackSize -= amount
|
||||
inventory.onInventoryChanged()
|
||||
true
|
||||
}
|
||||
else (existing == null) && {
|
||||
val amount = math.min(maxStackSize, math.min(stack.stackSize, limit))
|
||||
inventory.setInventorySlotContents(slot, stack.splitStack(amount))
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (slot <- 0 until inventory.getSizeInventory if stack.stackSize > 0 && inventory.getStackInSlot(slot) == null && inventory.isItemValidForSlot(slot, stack) && isSideValidForSlot(slot)) {
|
||||
val amount = math.min(maxStackSize, stack.stackSize)
|
||||
inventory.setInventorySlotContents(slot, stack.splitStack(amount))
|
||||
success = true
|
||||
/**
|
||||
* Extracts a stack from an inventory.
|
||||
* <p/>
|
||||
* Only tries to extract from the specified slot. This <em>can</em> be used
|
||||
* to empty a slot. It will extract items using the specified consumer method
|
||||
* which is called with the extracted stack before the stack in the inventory
|
||||
* that we extract from is cleared from. This allows placing back excess
|
||||
* items with as few inventory updates as possible.
|
||||
* <p/>
|
||||
* The consumer is the only way to retrieve the actually extracted stack. It
|
||||
* is called with a separate stack instance, so it does not have to be copied
|
||||
* again.
|
||||
* <p/>
|
||||
* This will return <tt>true</tt> if <em>at least</em> one item could be
|
||||
* extracted from the slot. It will return <tt>false</tt> if the stack in
|
||||
* the slot did not change.
|
||||
* <p/>
|
||||
* This takes care of handling special cases such as sided inventories and
|
||||
* maximum stack sizes.
|
||||
* <p/>
|
||||
* The number of items extracted can be limited, to avoid unnecessary
|
||||
* changes to the inventory the stack is extracted from. Note that this could
|
||||
* also be achieved by a check in the consumer, but it saves some unnecessary
|
||||
* code repetition this way.
|
||||
*/
|
||||
def extractFromInventorySlot(consumer: (ItemStack) => Unit, inventory: IInventory, side: ForgeDirection, slot: Int, limit: Int = 64) = {
|
||||
val stack = inventory.getStackInSlot(slot)
|
||||
(stack != null && limit > 0) && {
|
||||
val isSideValidForSlot = inventory match {
|
||||
case inventory: ISidedInventory => inventory.canExtractItem(slot, stack, side.ordinal)
|
||||
case _ => true
|
||||
}
|
||||
(stack.stackSize > 0 && isSideValidForSlot) && {
|
||||
val maxStackSize = math.min(inventory.getInventoryStackLimit, stack.getMaxStackSize)
|
||||
val amount = math.min(maxStackSize, math.min(stack.stackSize, limit))
|
||||
val extracted = stack.splitStack(amount)
|
||||
consumer(extracted)
|
||||
val success = extracted.stackSize < amount
|
||||
stack.stackSize += extracted.stackSize
|
||||
if (stack.stackSize == 0) {
|
||||
inventory.setInventorySlotContents(slot, null)
|
||||
}
|
||||
else if (success) {
|
||||
inventory.onInventoryChanged()
|
||||
}
|
||||
success
|
||||
}
|
||||
}
|
||||
if (success) {
|
||||
inventory.onInventoryChanged()
|
||||
}
|
||||
success
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts a stack into an inventory.
|
||||
* <p/>
|
||||
* This will try to fit the stack in any and as many as necessary slots in
|
||||
* the inventory. It will first try to merge the stack in stacks already
|
||||
* present in the inventory. After that it will try to fit the stack into
|
||||
* empty slots in the inventory.
|
||||
* <p/>
|
||||
* This uses the <tt>insertIntoInventorySlot</tt> method, and therefore
|
||||
* handles special cases such as sided inventories and stack size limits.
|
||||
* <p/>
|
||||
* This returns <tt>true</tt> if at least one item was inserted. The passed
|
||||
* item stack will be adjusted to reflect the number items inserted, by
|
||||
* having its size decremented accordingly.
|
||||
*/
|
||||
def insertIntoInventory(stack: ItemStack, inventory: IInventory, side: ForgeDirection, limit: Int = 64) =
|
||||
(stack != null && limit > 0) && {
|
||||
var success = false
|
||||
var remaining = limit
|
||||
|
||||
val shouldTryMerge = !stack.isItemStackDamageable && stack.getMaxStackSize > 1 && inventory.getInventoryStackLimit > 1
|
||||
if (shouldTryMerge) {
|
||||
for (slot <- 0 until inventory.getSizeInventory) {
|
||||
val stackSize = stack.stackSize
|
||||
if ((inventory.getStackInSlot(slot) != null) && insertIntoInventorySlot(stack, inventory, side, slot, remaining)) {
|
||||
remaining -= stackSize - stack.stackSize
|
||||
success = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (slot <- 0 until inventory.getSizeInventory) {
|
||||
val stackSize = stack.stackSize
|
||||
if ((inventory.getStackInSlot(slot) == null) && insertIntoInventorySlot(stack, inventory, side, slot, remaining)) {
|
||||
remaining -= stackSize - stack.stackSize
|
||||
success = true
|
||||
}
|
||||
}
|
||||
|
||||
success
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts a slot from an inventory.
|
||||
* </p>
|
||||
* This will try to extract a stack from any inventory slot. It will iterate
|
||||
* all slots until an item can be extracted from a slot.
|
||||
* <p/>
|
||||
* This uses the <tt>extractFromInventorySlot</tt> method, and therefore
|
||||
* handles special cases such as sided inventories and stack size limits.
|
||||
* <p/>
|
||||
* This returns <tt>true</tt> if at least one item was extracted.
|
||||
*/
|
||||
def extractFromInventory(consumer: (ItemStack) => Unit, inventory: IInventory, side: ForgeDirection, limit: Int = 64) =
|
||||
(0 until inventory.getSizeInventory).exists(slot => extractFromInventorySlot(consumer, inventory, side, slot, limit))
|
||||
|
||||
/**
|
||||
* Utility method for calling <tt>insertIntoInventory</tt> on an inventory
|
||||
* in the world.
|
||||
*/
|
||||
def insertIntoInventoryAt(stack: ItemStack, world: World, x: Int, y: Int, z: Int, side: ForgeDirection, limit: Int = 64): Boolean =
|
||||
inventoryAt(world, x, y, z).exists(insertIntoInventory(stack, _, side, limit))
|
||||
|
||||
/**
|
||||
* Utility method for calling <tt>extractFromInventory</tt> on an inventory
|
||||
* in the world.
|
||||
*/
|
||||
def extractFromInventoryAt(consumer: (ItemStack) => Unit, world: World, x: Int, y: Int, z: Int, side: ForgeDirection, limit: Int = 64) =
|
||||
inventoryAt(world, x, y, z).exists(extractFromInventory(consumer, _, side, limit))
|
||||
}
|
||||
|
@ -5,11 +5,11 @@ import li.cil.oc.Settings
|
||||
import net.minecraft.client.Minecraft
|
||||
import net.minecraft.util.StatCollector
|
||||
import scala.collection.convert.WrapAsJava._
|
||||
import scala.collection.mutable
|
||||
import scala.collection.convert.WrapAsScala._
|
||||
import org.lwjgl.input.Keyboard
|
||||
|
||||
object Tooltip {
|
||||
val maxWidth = 200
|
||||
val maxWidth = 220
|
||||
|
||||
def get(name: String, args: Any*): java.util.List[String] = {
|
||||
val tooltip = StatCollector.translateToLocal(Settings.namespace + "tooltip." + name).format(args.map(_.toString): _*)
|
||||
@ -22,50 +22,11 @@ object Tooltip {
|
||||
}
|
||||
else {
|
||||
val nl = """\[nl\]"""
|
||||
val lines = mutable.ArrayBuffer.empty[String]
|
||||
tooltip.split(nl).foreach(line => {
|
||||
val formatted = line.trim.stripLineEnd
|
||||
var position = 0
|
||||
var start = 0
|
||||
var lineEnd = 0
|
||||
var width = 0
|
||||
var lineWidth = 0
|
||||
val iterator = formatted.iterator
|
||||
while (iterator.hasNext) {
|
||||
val c = iterator.next()
|
||||
if (c == '§') {
|
||||
iterator.next()
|
||||
position += 2
|
||||
}
|
||||
else {
|
||||
if (c == ' ') {
|
||||
lineEnd = position
|
||||
lineWidth = width
|
||||
}
|
||||
else {
|
||||
width += font.getCharWidth(c)
|
||||
}
|
||||
position += 1
|
||||
if (width > maxWidth) {
|
||||
if (lineEnd > start) {
|
||||
lines += formatted.substring(start, lineEnd)
|
||||
start = lineEnd + 1
|
||||
width -= lineWidth
|
||||
lineWidth = 0
|
||||
}
|
||||
else {
|
||||
lines += formatted.substring(start, position)
|
||||
start = position
|
||||
width = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (start < formatted.length) {
|
||||
lines += formatted.substring(start)
|
||||
}
|
||||
})
|
||||
lines
|
||||
tooltip.
|
||||
split(nl).
|
||||
map(font.listFormattedStringToWidth(_, maxWidth).map(_.asInstanceOf[String].trim() + " ")).
|
||||
flatten.
|
||||
toList
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user