Preparing for public release

This commit is contained in:
bdew committed 2013-11-28 23:03:28 +02:00
commit 9156249843
60 files changed
+2825

No files matched your search

+11
View File
@@ -0,0 +1,11 @@
package net.bdew.lib
import cpw.mods.fml.common.Mod
import cpw.mods.fml.common.event.FMLPreInitializationEvent
@Mod(modid = "bdlib", version = "@BdLibVer@", modLanguage = "scala")
object BdLib {
def preInit(ev: FMLPreInitializationEvent) {
ev.getModLog.info("bdlib @BdLibVer@ loaded")
}
}
+34
View File
@@ -0,0 +1,34 @@
/*
* Copyright (c) bdew, 2013
* https://github.com/bdew/bdlib
*
* This mod is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt
*/
package net.bdew.lib
class EventBase[T] extends {
var listeners = Seq.empty[T]
def listen(x: T) = listeners :+= x
def hasListeners = listeners.size > 0
}
class Event0 extends EventBase[() => Unit] {
def trigger() = for (x <- listeners) x()
}
class Event1[T] extends EventBase[(T) => Unit] {
def trigger(p1: T) = for (x <- listeners) x(p1)
}
class Event2[T, R] extends EventBase[(T, R) => Unit] {
def trigger(p1: T, p2: R) = for (x <- listeners) x(p1, p2)
}
object Event {
def apply(t: Unit) = new Event0
def apply[T] = new Event1[T]
def apply[T, R] = new Event2[T, R]
}
+66
View File
@@ -0,0 +1,66 @@
/*
* Copyright (c) bdew, 2013
* https://github.com/bdew/bdlib
*
* This mod is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt
*/
package net.bdew.lib
import cpw.mods.fml.common.registry.GameRegistry
import net.minecraft.nbt.{NBTTagCompound, NBTTagList}
import net.minecraft.util.StatCollector
import net.minecraft.item.ItemStack
import cpw.mods.fml.common.versioning.{ArtifactVersion, VersionParser}
import cpw.mods.fml.common.Loader
import net.minecraftforge.oredict.ShapedOreRecipe
object Misc {
def iterNbtList[X](list: NBTTagList) =
for (i <- 0 until list.tagCount()) yield list.tagAt(i).asInstanceOf[X]
def toLocal(s: String) = StatCollector.translateToLocal(s)
def toLocalF(s: String, params: Any*) = StatCollector.translateToLocal(s).format(params: _*)
def flattenRecipe(pattern: Seq[String], items: Map[Char, AnyRef]) =
pattern ++ items.map {
case (k, v) => Seq(new Character(k), v)
}.flatten
def wrapTag(n: String, f: (NBTTagCompound) => Any)(t: NBTTagCompound) {
val p = t.getCompoundTag(n)
f(p)
t.setCompoundTag(n, p)
}
def addRecipe(result: ItemStack, pattern: Seq[String], items: Map[Char, AnyRef]) =
GameRegistry.addRecipe(result, flattenRecipe(pattern, items): _*)
def addRecipeOD(result: ItemStack, pattern: Seq[String], items: Map[Char, AnyRef]) =
GameRegistry.addRecipe(new ShapedOreRecipe(result, flattenRecipe(pattern, items): _*))
def min[T](vals: T*)(implicit o: Ordering[T]): T = vals.min(o)
def max[T](vals: T*)(implicit o: Ordering[T]): T = vals.max(o)
def clamp[T](value: T, min: T, max: T)(implicit o: Ordering[T]): T = if (o.gt(value,max)) max else if (o.lt(value,min)) min else value
def iterSome[T](list: Seq[T], indexes: Iterable[Int]): Iterable[T] = for (i <- indexes) yield list(i)
def iterSomeEnum[T](list: Seq[T], indexes: Iterable[Int]): Iterable[(Int, T)] = for (i <- indexes) yield i -> list(i)
def filterType[T](from: Iterable[_], cls: Class[T]) = from.filter(cls.isInstance).asInstanceOf[Iterable[T]]
def haveModVersion(spec: String): Boolean = {
val req = VersionParser.parseVersionReference(spec)
val modid = req.getLabel
if (!Loader.instance.getIndexedModList.containsKey(modid)) return false
val found: ArtifactVersion = Loader.instance.getIndexedModList.get(modid).getProcessedVersion
if (found == null || !req.containsVersion(found)) return false
return true
}
}
+34
View File
@@ -0,0 +1,34 @@
/*
* Copyright (c) bdew, 2013
* https://github.com/bdew/bdlib
*
* This mod is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt
*/
package net.bdew.lib.block
import net.minecraft.block.{ITileEntityProvider, Block}
import net.minecraft.world.{IBlockAccess, World}
import net.minecraft.tileentity.TileEntity
import cpw.mods.fml.common.FMLCommonHandler
trait HasTE[T] extends Block with ITileEntityProvider {
val TEClass: Class[_ <: TileEntity]
def createNewTileEntity(world: World): TileEntity = TEClass.newInstance()
def getTE(w: IBlockAccess, x: Int, y: Int, z: Int): T = {
var t = w.getBlockTileEntity(x, y, z)
if ((t == null) || !TEClass.isInstance(t)) {
FMLCommonHandler.instance().getFMLLogger.severe("Tile entity for block %s at (%d,%d,%d) is corrupt or missing - recreating".format(this, x, y, z))
w match {
case ww: World =>
t = createNewTileEntity(ww)
ww.setBlockTileEntity(x, y, z, t)
case _ =>
sys.error("Unable to recreate TE")
}
}
return t.asInstanceOf[T]
}
}
@@ -0,0 +1,19 @@
/*
* Copyright (c) bdew, 2013
* https://github.com/bdew/bdlib
*
* This mod is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt
*/
package net.bdew.lib.data
import net.minecraft.nbt.NBTTagCompound
import net.bdew.lib.data.base.{UpdateKind, TileDataSlots, DataSlotVal}
case class DataSlotBoolean(name: String, parent: TileDataSlots, default: Boolean = false) extends DataSlotVal[Boolean] {
var cval = default
def save(t: NBTTagCompound, kind: UpdateKind.Value) = t.setBoolean(name, cval)
def load(t: NBTTagCompound, kind: UpdateKind.Value) = cval = t.getBoolean(name)
}
@@ -0,0 +1,20 @@
/*
* Copyright (c) bdew, 2013
* https://github.com/bdew/bdlib
*
* This mod is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt
*/
package net.bdew.lib.data
import net.bdew.lib.data.base.{TileDataSlots, UpdateKind, DataSlotVal}
import net.minecraftforge.common.ForgeDirection
import net.minecraft.nbt.NBTTagCompound
case class DataSlotDirection(name: String, parent: TileDataSlots) extends DataSlotVal[ForgeDirection] {
var cval = ForgeDirection.UP
def save(t: NBTTagCompound, kind: UpdateKind.Value) = t.setByte(name, cval.ordinal().toByte)
def load(t: NBTTagCompound, kind: UpdateKind.Value) = cval = ForgeDirection.getOrientation(t.getByte(name))
}
+18
View File
@@ -0,0 +1,18 @@
/*
* Copyright (c) bdew, 2013
* https://github.com/bdew/bdlib
*
* This mod is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt
*/
package net.bdew.lib.data
import net.minecraft.nbt.NBTTagCompound
import net.bdew.lib.data.base.{UpdateKind, TileDataSlots, DataSlotNumeric}
case class DataSlotFloat(name: String, parent: TileDataSlots, default: Float = 0) extends DataSlotNumeric[Float](default) {
def save(t: NBTTagCompound, kind: UpdateKind.Value) = t.setFloat(name, cval)
def load(t: NBTTagCompound, kind: UpdateKind.Value) = cval = t.getFloat(name)
}
+18
View File
@@ -0,0 +1,18 @@
/*
* Copyright (c) bdew, 2013
* https://github.com/bdew/bdlib
*
* This mod is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt
*/
package net.bdew.lib.data
import net.minecraft.nbt.NBTTagCompound
import net.bdew.lib.data.base.{UpdateKind, TileDataSlots, DataSlotNumeric}
case class DataSlotInt(name: String, parent: TileDataSlots, default: Int = 0) extends DataSlotNumeric[Int](default) {
def save(t: NBTTagCompound, kind: UpdateKind.Value) = t.setInteger(name, cval)
def load(t: NBTTagCompound, kind: UpdateKind.Value) = cval = t.getInteger(name)
}
@@ -0,0 +1,32 @@
/*
* Copyright (c) bdew, 2013
* https://github.com/bdew/bdlib
*
* This mod is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt
*/
package net.bdew.lib.data
import net.bdew.lib.data.base.{TileDataSlots, UpdateKind, DataSlotVal}
import net.minecraft.nbt.NBTTagCompound
import net.minecraft.item.ItemStack
case class DataSlotItemStack(name: String, parent: TileDataSlots) extends DataSlotVal[ItemStack] {
var cval: ItemStack = null
override def update(v: ItemStack) = {
if (!ItemStack.areItemStacksEqual(v, cval)) {
cval = if (v == null) null else v.copy()
parent.dataSlotChanged(this)
}
}
def save(t: NBTTagCompound, kind: UpdateKind.Value) = {
val tag = new NBTTagCompound()
if (cval != null) cval.writeToNBT(tag)
t.setCompoundTag(name, tag)
}
def load(t: NBTTagCompound, kind: UpdateKind.Value) = cval = ItemStack.loadItemStackFromNBT(t.getCompoundTag(name))
}
@@ -0,0 +1,19 @@
/*
* Copyright (c) bdew, 2013
* https://github.com/bdew/bdlib
*
* This mod is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt
*/
package net.bdew.lib.data
import net.minecraft.nbt.NBTTagCompound
import net.bdew.lib.data.base.{UpdateKind, TileDataSlots, DataSlotVal}
case class DataSlotString(name: String, parent: TileDataSlots, default: String = null) extends DataSlotVal[String] {
var cval: String = default
def save(t: NBTTagCompound, kind: UpdateKind.Value) = if (cval != null) t.setString(name, cval)
def load(t: NBTTagCompound, kind: UpdateKind.Value) = cval = if (t.hasKey(name)) t.getString(name) else null
}
+62
View File
@@ -0,0 +1,62 @@
/*
* Copyright (c) bdew, 2013
* https://github.com/bdew/bdlib
*
* This mod is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt
*/
package net.bdew.lib.data
import net.minecraftforge.fluids.{IFluidTank, FluidTank, FluidStack}
import net.minecraft.nbt.NBTTagCompound
import net.bdew.lib.data.base.{UpdateKind, TileDataSlots, DataSlot}
abstract class DataSlotTankBase(sz: Int) extends FluidTank(sz) with IFluidTank with DataSlot {
var oldStack: FluidStack = null
var size: Int
parent.serverTick.listen(checkUpdate)
updateKind = Set(UpdateKind.GUI, UpdateKind.SAVE)
def checkUpdate() {
if (!isSame(oldStack, fluid)) {
oldStack = if (fluid == null) null else fluid.copy()
parent.dataSlotChanged(this)
}
}
def isSame(v1: FluidStack, v2: FluidStack): Boolean = {
if (v1 == null && v2 == null) return true
if (v1 == null || v2 == null) return false
return v1.isFluidStackIdentical(v2)
}
def save(t: NBTTagCompound, k: UpdateKind.Value) {
val tag = new NBTTagCompound()
writeToNBT(tag)
if (k == UpdateKind.GUI)
tag.setInteger("size", size)
t.setCompoundTag(name, tag)
}
def load(t: NBTTagCompound, k: UpdateKind.Value) {
val tag = t.getCompoundTag(name)
readFromNBT(tag)
if (k == UpdateKind.GUI)
size = tag.getInteger("size")
}
}
case class DataSlotTank(name: String, parent: TileDataSlots, var size: Int) extends DataSlotTankBase(size)
case class DataSlotTankRestricted(name: String, parent: TileDataSlots, var size: Int, fluidID: Int) extends DataSlotTankBase(size) {
def fill(amount: Int, doFill: Boolean) = super.fill(new FluidStack(fluidID, amount), doFill)
override def fill(resource: FluidStack, doFill: Boolean): Int = {
if ((resource != null) && (resource.fluidID != fluidID)) return 0
return super.fill(resource, doFill)
}
}
@@ -0,0 +1,39 @@
/*
* Copyright (c) bdew, 2013
* https://github.com/bdew/bdlib
*
* This mod is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt
*/
package net.bdew.lib.data.base
import net.minecraft.entity.player.EntityPlayerMP
import net.bdew.lib.gui.BaseContainer
import net.minecraft.inventory.ICrafting
trait ContainerDataSlots extends BaseContainer {
val dataSource: TileDataSlots
var lastSentChange = dataSource.lastChange
override def addCraftingToCrafters(crafter: ICrafting) {
super.addCraftingToCrafters(crafter)
if (crafter.isInstanceOf[EntityPlayerMP]) {
val pkt = dataSource.getDataSlotPacket
crafter.asInstanceOf[EntityPlayerMP].playerNetServerHandler.sendPacketToPlayer(pkt)
}
}
override def detectAndSendChanges() {
super.detectAndSendChanges()
// only send updates every 10 ticks
if (dataSource.lastChange >= lastSentChange + 10 || (dataSource.lastChange > lastSentChange && lastSentChange + 10 < dataSource.worldObj.getTotalWorldTime)) {
lastSentChange = dataSource.lastChange
val pkt = dataSource.getDataSlotPacket
for (player <- players)
player.playerNetServerHandler.sendPacketToPlayer(pkt)
}
}
}
+42
View File
@@ -0,0 +1,42 @@
/*
* Copyright (c) bdew, 2013
* https://github.com/bdew/bdlib
*
* This mod is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt
*/
package net.bdew.lib.data.base
import net.minecraft.nbt.NBTTagCompound
/**
* Base trait for all data slots
*/
trait DataSlot {
/**
* Tile Entity that owns this slot
* Accessed in constructor, so should be in parameters or a lazy val, otherwise will crash
*/
val parent: TileDataSlots
/**
* Unique name
* Accessed in constructor, so should be in parameters or a lazy val, otherwise will crash
*/
val name: String
parent.dataSlots += (name -> this)
// Where should it sync
var updateKind = Set(UpdateKind.GUI)
def save(t: NBTTagCompound, kind: UpdateKind.Value)
def load(t: NBTTagCompound, kind: UpdateKind.Value)
def setUpdate(vals: UpdateKind.Value*): this.type = {
updateKind = vals.toSet
return this
}
}
@@ -0,0 +1,22 @@
/*
* Copyright (c) bdew, 2013
* https://github.com/bdew/bdlib
*
* This mod is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt
*/
package net.bdew.lib.data.base
/**
* Base class for data slots that hold numeric values
* adds convinience operators to modify the value
*/
abstract class DataSlotNumeric[T](default: T)(implicit n: Numeric[T]) extends DataSlotVal[T] {
var cval = default
def +=(that: T) = update(n.plus(cval, that))
def -=(that: T) = update(n.minus(cval, that))
def *=(that: T) = update(n.times(cval, that))
}
@@ -0,0 +1,21 @@
/*
* Copyright (c) bdew, 2013
* https://github.com/bdew/bdlib
*
* This mod is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt
*/
package net.bdew.lib.data.base
/**
* Base class for data slots that hold values with ordering operators, adds more convinience operators
* TODO: Do i need this? normal operators can be used with the implicit conversion
*/
abstract class DataSlotOrdered[T](implicit n: Ordering[T]) extends DataSlotVal[T] {
def :>(that: T) = n.compare(cval, that) > 0
def :<(that: T) = n.compare(cval, that) < 0
def :>=(that: T) = n.compare(cval, that) >= 0
def :<=(that: T) = n.compare(cval, that) <= 0
}
@@ -0,0 +1,39 @@
/*
* Copyright (c) bdew, 2013
* https://github.com/bdew/bdlib
*
* This mod is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt
*/
package net.bdew.lib.data.base
import language.implicitConversions
/**
* Base trait for data slots that hold primitive values
* Defines some convinience operators to access the value and an implicit conversion to the value
*/
trait DataSlotVal[T] extends DataSlot {
var cval: T
def isSame(v: T) = v == cval
def :=(that: T) = update(that)
def :!=(that: T) = cval != that
def :==(that: T) = cval == that
def update(v: T) {
if (!isSame(v)) {
cval = v
parent.dataSlotChanged(this)
}
}
}
object DataSlotVal {
implicit def slot2val[T](slot: DataSlotVal[T]): T = slot.cval
}
@@ -0,0 +1,64 @@
/*
* Copyright (c) bdew, 2013
* https://github.com/bdew/bdlib
*
* This mod is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt
*/
package net.bdew.lib.data.base
import net.minecraft.network.packet.Packet132TileEntityData
import scala.collection.mutable
import net.minecraft.nbt.NBTTagCompound
import net.bdew.lib.tile.TileExtended
trait TileDataSlots extends TileExtended {
val dataSlots = mutable.HashMap.empty[String, DataSlot]
var lastChange = 0L
final val TRACE = true
def doSave(kind: UpdateKind.Value, t: NBTTagCompound) {
for ((n, s) <- dataSlots if s.updateKind.contains(kind)) {
s.save(t, kind)
if (TRACE) printf("%s: %s S=> %s\n".format(kind, n, t.getTag(n)))
}
}
def doLoad(kind: UpdateKind.Value, t: NBTTagCompound) {
for ((n, s) <- dataSlots if s.updateKind.contains(kind)) {
if (TRACE) printf("%s: %s L<= %s\n".format(kind, n, t.getTag(n)))
s.load(t, kind)
}
}
persistSave.listen(doSave(UpdateKind.SAVE, _))
persistLoad.listen(doLoad(UpdateKind.SAVE, _))
sendClientUpdate.listen(doSave(UpdateKind.WORLD, _))
handleClientUpdate.listen(doLoad(UpdateKind.WORLD, _))
def dataSlotChanged(slot: DataSlot) {
if (worldObj != null) {
if (slot.updateKind.contains(UpdateKind.GUI))
lastChange = worldObj.getTotalWorldTime
if (slot.updateKind.contains(UpdateKind.WORLD))
worldObj.markBlockForUpdate(xCoord, yCoord, zCoord)
if (slot.updateKind.contains(UpdateKind.SAVE))
worldObj.markTileEntityChunkModified(xCoord, yCoord, zCoord, this)
}
}
def getDataSlotPacket: Packet132TileEntityData = {
val tag = new NBTTagCompound()
doSave(UpdateKind.GUI, tag)
return new Packet132TileEntityData(this.xCoord, this.yCoord, this.zCoord, ACT_GUI, tag)
}
override protected def extDataPacket(id: Int, data: NBTTagCompound) {
if (id == ACT_GUI)
doLoad(UpdateKind.GUI, data)
super.extDataPacket(id, data)
}
}
@@ -0,0 +1,16 @@
/*
* Copyright (c) bdew, 2013
* https://github.com/bdew/bdlib
*
* This mod is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt
*/
package net.bdew.lib.data.base
object UpdateKind extends Enumeration {
val WORLD = Value("WORLD")
val GUI = Value("GUI")
val SAVE = Value("SAVE")
}
+46
View File
@@ -0,0 +1,46 @@
/*
* Copyright (c) bdew, 2013
* https://github.com/bdew/bdlib
*
* This mod is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt
*/
package net.bdew.lib.gui
import net.minecraft.inventory.{IInventory, Slot, Container}
import net.minecraft.entity.player.{EntityPlayerMP, EntityPlayer, InventoryPlayer}
import net.minecraft.item.ItemStack
import net.bdew.lib.items.ItemUtils
import net.bdew.lib.Misc
abstract class BaseContainer(te: IInventory) extends Container {
import scala.collection.JavaConversions._
def players = Misc.filterType(crafters, classOf[EntityPlayerMP])
protected def bindPlayerInventory(inv: InventoryPlayer, xOffs: Int, yOffsInv: Int, yOffsHotbar: Int) {
for (i <- 0 until 3; j <- 0 until 9)
addSlotToContainer(new Slot(inv, j + i * 9 + 9, xOffs + j * 18, yOffsInv + i * 18))
for (i <- 0 until 9)
addSlotToContainer(new Slot(inv, i, xOffs + i * 18, yOffsHotbar))
}
override def transferStackInSlot(player: EntityPlayer, slot: Int): ItemStack = {
var stack = getSlot(slot).getStack
if (getSlot(slot).inventory == player.inventory) {
stack = ItemUtils.addStackToSlots(stack, te, 0 until te.getSizeInventory, true)
} else {
stack = ItemUtils.addStackToSlots(stack, player.inventory, 9 until player.inventory.mainInventory.length, true)
// Only put in hotbar if the rest is full
if (stack != null)
stack = ItemUtils.addStackToSlots(stack, player.inventory, 0 until 9, true)
}
getSlot(slot).putStack(stack)
return null
}
}
+89
View File
@@ -0,0 +1,89 @@
/*
* Copyright (c) bdew, 2013
* https://github.com/bdew/bdlib
*
* This mod is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt
*/
package net.bdew.lib.gui
import net.minecraft.client.gui.inventory.GuiContainer
import net.minecraft.inventory.Container
import scala.collection.mutable
import net.minecraft.client.gui.GuiButton
import net.bdew.lib.gui.widgets.Widget
import net.minecraft.util.ResourceLocation
import org.lwjgl.opengl.GL11
abstract class BaseScreen(cont: Container, xSz: Int, ySz: Int) extends GuiContainer(cont) {
xSize = xSz
ySize = ySz
val widgets = mutable.MutableList.empty[Widget]
val texture: ResourceLocation
def rect = new Rect(guiLeft, guiTop, xSize, ySize)
def getFontRenderer = fontRenderer
override def initGui() {
super.initGui()
widgets.clear()
buttonList.clear()
}
def addButton[T <: GuiButton](w: T): T = {
buttonList.asInstanceOf[java.util.ArrayList[GuiButton]].add(w)
return w
}
def addWidget[T <: Widget](w: T): T = {
widgets += w
w.parent = this
return w
}
protected override def keyTyped(c: Char, i: Int) {
for (w <- widgets)
if (w.keyTyped(c, i))
return
super.keyTyped(c, i)
}
protected override def mouseClicked(x: Int, y: Int, bt: Int) {
super.mouseClicked(x, y, bt)
val p = new Point(x, y) - rect.origin
for (w <- widgets if w.rect.contains(p))
w.mouseClicked(p - w.rect.origin, bt)
}
protected override def drawGuiContainerForegroundLayer(x: Int, y: Int) {
for (w <- widgets)
w.draw()
}
protected override def drawScreen(x: Int, y: Int, f: Float) {
super.drawScreen(x, y, f)
val tip = mutable.MutableList.empty[String]
val p = new Point(x, y) - rect.origin
for (w <- widgets if w.rect.contains(p))
w.handleTooltip(p - w.rect.origin, tip)
import collection.JavaConversions._
if (tip.size > 0)
drawHoveringText(tip, x, y, fontRenderer)
}
protected def drawGuiContainerBackgroundLayer(f: Float, i: Int, j: Int) {
GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F)
mc.renderEngine.bindTexture(texture)
val x = (width - xSize) / 2
val y = (height - ySize) / 2
this.drawTexturedModalRect(x, y, 0, 0, xSize, ySize)
}
}
+18
View File
@@ -0,0 +1,18 @@
/*
* Copyright (c) bdew, 2013
* https://github.com/bdew/bdlib
*
* This mod is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt
*/
package net.bdew.lib.gui
object Direction extends Enumeration {
type Direction = Value
val UP = Value("UP")
val DOWN = Value("UP")
val LEFT = Value("UP")
val RIGHT = Value("UP")
}
+16
View File
@@ -0,0 +1,16 @@
/*
* Copyright (c) bdew, 2013
* https://github.com/bdew/bdlib
*
* This mod is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt
*/
package net.bdew.lib.gui
class Point(val x: Int, val y: Int) {
def this(p: Point) = this(p.x, p.y)
def +(that: Point) = new Point(this.x + that.x, this.y + that.y)
def -(that: Point) = new Point(this.x - that.x, this.y - that.y)
}
+16
View File
@@ -0,0 +1,16 @@
/*
* Copyright (c) bdew, 2013
* https://github.com/bdew/bdlib
*
* This mod is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt
*/
package net.bdew.lib.gui
class Rect(val x: Int, val y: Int, val w: Int, val h: Int) {
def this(p: Point, w: Int, h: Int) = this(p.x, p.y, w, h)
def contains(p: Point) = p.x >= x && p.y >= y && p.x <= x + w && p.y <= y + h
def origin = new Point(x, y)
}
+18
View File
@@ -0,0 +1,18 @@
/*
* Copyright (c) bdew, 2013
* https://github.com/bdew/bdlib
*
* This mod is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt
*/
package net.bdew.lib.gui
import net.minecraft.inventory.IInventory
import net.minecraft.inventory.Slot
import net.minecraft.item.ItemStack
class SlotValidating(inv: IInventory, slot: Int, x: Int, y: Int) extends Slot(inv, slot, x, y) {
override def isItemValid(stack: ItemStack) = inventory.isItemValidForSlot(getSlotIndex, stack)
}
@@ -0,0 +1,16 @@
/*
* Copyright (c) bdew, 2013
* https://github.com/bdew/bdlib
*
* This mod is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt
*/
package net.bdew.lib.gui
import net.minecraft.util.ResourceLocation
class TextureLocation(val resource: ResourceLocation, val p: Point) extends Point(p.x, p.y) {
def this(resource: ResourceLocation, x: Int, y: Int) = this(resource, new Point(x, y))
}
+26
View File
@@ -0,0 +1,26 @@
/*
* Copyright (c) bdew, 2013
* https://github.com/bdew/bdlib
*
* This mod is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt
*/
package net.bdew.lib.gui.widgets
import scala.collection.mutable
import net.bdew.lib.gui.{Point, BaseScreen, Rect}
import net.minecraft.util.ResourceLocation
import net.minecraft.client.Minecraft
trait Widget {
val rect: Rect
var parent: BaseScreen = null
def handleTooltip(p: Point, tip: mutable.MutableList[String]) {}
def mouseClicked(p: Point, button: Int) {}
def keyTyped(c: Char, i: Int): Boolean = false
def draw() {}
def bindTexture(res: ResourceLocation) = Minecraft.getMinecraft.renderEngine.bindTexture(res)
}
@@ -0,0 +1,39 @@
/*
* Copyright (c) bdew, 2013
* https://github.com/bdew/bdlib
*
* This mod is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt
*/
package net.bdew.lib.gui.widgets
import net.bdew.lib.gui.{TextureLocation, Rect}
import net.bdew.lib.gui.Direction
import net.bdew.lib.data.base.DataSlotNumeric
class WidgetFillDataslot[T](val rect: Rect, val texture: TextureLocation, dir: Direction.Direction, dslot: DataSlotNumeric[T], maxval: T)(implicit num: Numeric[T]) extends Widget {
def getFillArea(max: Int): Int = (num.toFloat(dslot) / num.toFloat(maxval) * max).round
override def draw() {
bindTexture(texture.resource)
dir match {
case Direction.UP =>
val fill = getFillArea(rect.h)
parent.drawTexturedModalRect(rect.x, rect.y + rect.h - fill, texture.x, texture.y + rect.h - fill, rect.w, fill)
case Direction.DOWN =>
val fill = getFillArea(rect.h)
parent.drawTexturedModalRect(rect.x, rect.y, texture.x, texture.y, rect.w, fill)
case Direction.LEFT =>
val fill = getFillArea(rect.w)
parent.drawTexturedModalRect(rect.x + rect.w - fill, rect.y, texture.x + rect.w - fill, texture.y, fill, rect.h)
case Direction.RIGHT =>
val fill = getFillArea(rect.w)
parent.drawTexturedModalRect(rect.x, rect.y, texture.x, texture.y, fill, rect.h)
}
}
}
@@ -0,0 +1,60 @@
/*
* Copyright (c) bdew, 2013
* https://github.com/bdew/bdlib
*
* This mod is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt
*/
package net.bdew.lib.gui.widgets
import net.bdew.lib.gui.{Point, TextureLocation, Rect}
import net.bdew.lib.data.DataSlotTankBase
import scala.collection.mutable
import net.minecraft.client.renderer.texture.TextureMap
import java.text.DecimalFormat
import net.bdew.lib.Misc
import org.lwjgl.opengl.GL11
class WidgetFluidGauge(val rect: Rect, overlay: TextureLocation, dslot: DataSlotTankBase) extends Widget {
val formater = new DecimalFormat("#,###")
override def handleTooltip(p: Point, tip: mutable.MutableList[String]) {
if (dslot.getFluid != null) {
tip += dslot.getFluid.getFluid.getLocalizedName
tip += "%s/%s mB".format(formater.format(dslot.getFluidAmount), formater.format(dslot.getCapacity))
} else {
tip += Misc.toLocal("gendustry.label.empty")
}
}
override def draw() {
GL11.glEnable(GL11.GL_BLEND)
GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA)
val fstack = dslot.getFluid
if (fstack != null && fstack.getFluid.getStillIcon != null) {
val icon = fstack.getFluid.getStillIcon
bindTexture(TextureMap.locationBlocksTexture)
var fillHeight: Int = (rect.h * fstack.amount / dslot.getCapacity).round
var yStart: Int = 0
while (fillHeight > 0) {
if (fillHeight > 16) {
parent.drawTexturedModelRectFromIcon(rect.x, rect.y + rect.h - 16 - yStart, icon, 16, 16)
fillHeight -= 16
} else {
parent.drawTexturedModelRectFromIcon(rect.x, rect.y + rect.h - fillHeight - yStart, icon, 16, fillHeight)
fillHeight = 0
}
yStart = yStart + 16
}
}
GL11.glDisable(GL11.GL_BLEND)
bindTexture(overlay.resource)
parent.drawTexturedModalRect(rect.x, rect.y, overlay.x, overlay.y, rect.w, rect.h)
}
}
@@ -0,0 +1,19 @@
/*
* Copyright (c) bdew, 2013
* https://github.com/bdew/bdlib
*
* This mod is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt
*/
package net.bdew.lib.gui.widgets
import net.bdew.lib.gui.Rect
class WidgetLabel(text: String, x: Int, y: Int, color: Int) extends Widget {
val rect: Rect = new Rect(x, y, 0, 0)
override def draw() {
parent.getFontRenderer.drawString(text, x, y, color)
}
}
@@ -0,0 +1,18 @@
/*
* Copyright (c) bdew, 2013
* https://github.com/bdew/bdlib
*
* This mod is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt
*/
package net.bdew.lib.gui.widgets
import net.bdew.lib.gui.{Point, Direction, TextureLocation, Rect}
import net.bdew.lib.data.DataSlotFloat
import scala.collection.mutable
class WidgetProgressBar(rect: Rect, texture: TextureLocation, dslot: DataSlotFloat) extends WidgetFillDataslot[Float](rect, texture, Direction.RIGHT, dslot, 1) {
override def handleTooltip(p: Point, tip: mutable.MutableList[String]) = tip += "%.0f".format(dslot.cval * 100) + "%"
}
@@ -0,0 +1,19 @@
/*
* Copyright (c) bdew, 2013
* https://github.com/bdew/bdlib
*
* This mod is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt
*/
package net.bdew.lib.gui.widgets
import net.minecraft.client.gui.{FontRenderer, GuiTextField}
import net.bdew.lib.gui.{Point, Rect}
class WidgetTextEdit(val rect: Rect, fr: FontRenderer) extends GuiTextField(fr, rect.x, rect.y, rect.w, rect.h) with Widget {
override def mouseClicked(p: Point, button: Int) = super.mouseClicked(p.x + rect.x, p.y + rect.y, button)
override def keyTyped(c: Char, i: Int): Boolean = super.textboxKeyTyped(c, i)
override def draw() = super.drawTextBox()
}
+79
View File
@@ -0,0 +1,79 @@
/*
* Copyright (c) bdew, 2013
* https://github.com/bdew/bdlib
*
* This mod is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt
*/
package net.bdew.lib.items
import net.minecraft.entity.item.EntityItem
import net.minecraft.item.ItemStack
import net.minecraft.world.World
import net.minecraft.entity.player.EntityPlayer
import net.minecraft.inventory.IInventory
import net.bdew.lib.Misc
object ItemUtils {
def throwItemAt(world: World, x: Int, y: Int, z: Int, stack: ItemStack) {
if ((stack == null) || world.isRemote) return
val dx = world.rand.nextFloat * 0.8
val dy = world.rand.nextFloat * 0.8
val dz = world.rand.nextFloat * 0.8
val entityitem: EntityItem = new EntityItem(world, x + dx, y + dy, z + dz, stack)
entityitem.motionX = world.rand.nextGaussian * 0.05
entityitem.motionY = world.rand.nextGaussian * 0.05 + 0.2
entityitem.motionZ = world.rand.nextGaussian * 0.05
world.spawnEntityInWorld(entityitem)
}
def dropItemToPlayer(world: World, player: EntityPlayer, stack: ItemStack) {
if ((stack == null) || world.isRemote) return
world.spawnEntityInWorld(new EntityItem(world, player.posX, player.posY, player.posZ, stack))
}
def isSameItem(stack1: ItemStack, stack2: ItemStack): Boolean = {
if (stack1 == null || stack2 == null)
return stack1 == stack2
if (stack1.itemID != stack2.itemID)
return false
if (stack1.getHasSubtypes && stack2.getItemDamage != stack1.getItemDamage)
return false
return ItemStack.areItemStackTagsEqual(stack2, stack1)
}
def addStackToSlots(stack: ItemStack, inv: IInventory, slots: Iterable[Int], checkvalid: Boolean): ItemStack = {
if (stack == null) return null
// Try merging into existing slots
for (slot <- slots if (!checkvalid || inv.isItemValidForSlot(slot, stack)) && isSameItem(stack, inv.getStackInSlot(slot))) {
val target = inv.getStackInSlot(slot)
val toAdd = Misc.min(target.getMaxStackSize - target.stackSize, inv.getInventoryStackLimit - target.stackSize, stack.stackSize)
if (toAdd >= stack.stackSize) {
target.stackSize += stack.stackSize
stack.stackSize = 0
inv.onInventoryChanged()
return null
} else if (toAdd > 0) {
target.stackSize += toAdd
stack.stackSize -= toAdd
inv.onInventoryChanged()
}
}
// Now find empty slots and stick any leftovers there
for (slot <- slots if (!checkvalid || inv.isItemValidForSlot(slot, stack)) && inv.getStackInSlot(slot) == null) {
if (inv.getInventoryStackLimit < stack.stackSize) {
inv.setInventorySlotContents(slot, stack.splitStack(inv.getInventoryStackLimit))
} else {
inv.setInventorySlotContents(slot, stack.copy())
stack.stackSize = 0
return null
}
}
return stack
}
}
+181
View File
@@ -0,0 +1,181 @@
/*
* Copyright (c) bdew, 2013
* https://github.com/bdew/bdlib
*
* This mod is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt
*/
package net.bdew.lib.recipes
/**
* Base class for everything that can be resolved to ItemStack or recipe component
* Actual processing is in:
* * [[net.bdew.lib.recipes.RecipeLoader.getRecipeComponent]]
* * [[net.bdew.lib.recipes.RecipeLoader.getConcreteStack]]
* * [[net.bdew.lib.recipes.RecipeLoader.getAllConcreteStacks]]
*
*/
abstract class StackRef
/**
* Ore Dictionary reference
* Syntax: OD:{identifier}
* Parser: [[net.bdew.lib.recipes.RecipeParser.specOD]]
* @param id OD entry name
*/
case class StackOreDict(id: String) extends StackRef
/**
* Mod item reference [[cpw.mods.fml.common.registry.GameRegistry.findItemStack]]
* Syntax: {modID}:{name}
* Parser: [[net.bdew.lib.recipes.RecipeParser.specModStack]]
* @param mod modId of owner mod
* @param id name of the stack
*/
case class StackMod(mod: String, id: String) extends StackRef
/**
* Vanilla block reference
* Syntax: B:{name} [@ {meta}]
* Parser: [[net.bdew.lib.recipes.RecipeParser.specMcBlock]]
* @param name Unlocalized name (without "tile.")
* @param meta Metadata / Damage
*/
case class StackMCBlock(name: String, meta: Int) extends StackRef
/**
* Vanilla item reference
* Syntax: I:{name} [@ {meta}]
* Parser: [[net.bdew.lib.recipes.RecipeParser.specMcItem]]
* @param name Unlocalized name (without "item.")
* @param meta Metadata / Damage
*/
case class StackMCItem(name: String, meta: Int) extends StackRef
/**
* Reference to an Item/Block/ItemStack pulic static field
* Syntax: {path}.{to}.{class}[{field}] [@ {meta}]
* Parser: [[net.bdew.lib.recipes.RecipeParser.specReflect]]
* @param cls Class name
* @param field Field name
* @param meta Metadata / Damage (Ignored for ItemStacks)
*/
case class StackReflect(cls: String, field: String, meta: Int) extends StackRef
/**
* Reference to an Item/Block/ItemStack pulic static getter
* Syntax: {path}.{to}.{class}.{method}({string}) [@ {meta}]
* Parser: [[net.bdew.lib.recipes.RecipeParser.specGetter]]
* @param cls Class name
* @param method Method name
* @param name Parameter to getter
* @param meta Metadata / Damage (Ignored for ItemStacks)
*/
case class StackGetter(cls: String, method: String, name: String, meta: Int) extends StackRef
/**
* Macro reference to a previous definition
* Syntax: ${char}
* Parser: [[net.bdew.lib.recipes.RecipeParser.specMacro]]
* @param id The underlying character
*/
case class StackMacro(id: Char) extends StackRef
/**
* Base class for statements
* Actual processing is in [[net.bdew.lib.recipes.RecipeLoader.processStatement]]
*/
abstract class Statement
/**
* Character assignment
* Syntax: {char} = {ref}
* Parser: [[net.bdew.lib.recipes.RecipeParser.charSpec]]
* @param char Character to assign
* @param spec ItemStack Reference
*/
case class StCharAssign(char: Char, spec: StackRef) extends Statement
/**
* Define class macro
* Syntax: def {id} = {name}
* Parser: [[net.bdew.lib.recipes.RecipeParser.classMacro]]
* @param id Macro identifier
* @param cls Class name
*/
case class StClassMacro(id: String, cls: String) extends Statement
/**
* Conditional block - checks if mod is loaded
* Syntax: ifMod {string} { {statements} } [else { {statements} }]
* Parser: [[net.bdew.lib.recipes.RecipeParser.ifMod]]
* @param mod mod and version to check [[cpw.mods.fml.common.versioning.VersionParser]]
* @param thn Statements to run if present
* @param els Statements to run otherwise
*/
case class StIfHaveMod(mod: String, thn: List[Statement], els: List[Statement]) extends Statement
/**
* Conditional block - checks if mod is loaded
* Syntax: ifOreDict {string} { {statements} } [else { {statements} }]
* Parser: [[net.bdew.lib.recipes.RecipeParser.ifOreDict]]
* @param id Ore Dictionary Entry
* @param thn Statements to run if present
* @param els Statements to run otherwise
*/
case class StIfHaveOD(id: String, thn: List[Statement], els: List[Statement]) extends Statement
/**
* Shaped recipe definition
*
* Syntax:
* XXX
* XXX => {result} [* {count}]
* XXX
*
* Parser: [[net.bdew.lib.recipes.RecipeParser.recipeShaped3x3]]
*
* Syntax:
* XX
* XX => {result} [* {count}]
*
* Parser: [[net.bdew.lib.recipes.RecipeParser.recipeShaped2x2]]
*
* Syntax: XXX XXX XXX => {result} [* {count}]
* Parser: [[net.bdew.lib.recipes.RecipeParser.recipeShaped9]]
*
* @param rec Recipe pattern
* @param res Result reference
* @param cnt Number of output items
*/
case class StRecipeShaped(rec: Seq[String], res: StackRef, cnt: Int) extends Statement
/**
* Shapeless recipe definition
* Syntax: shapeless: {characters} => {result} [* {count}]
* Parser: [[net.bdew.lib.recipes.RecipeParser.recipeShapeless]]
*
* @param rec Recipe pattehrn
* @param res Result reference
* @param cnt Number of output items
*/
case class StRecipeShapeless(rec: String, res: StackRef, cnt: Int) extends Statement
/**
* Smelting recipe definition
* Syntax: smelt: {input} => {output}, {XP}
* Parser [[net.bdew.lib.recipes.RecipeParser.recipeSmelting]]
*
* @param in Input Stack
* @param out Output Stack
* @param cnt Output Count
* @param xp XP for smelting
*/
case class StSmeltRecipe(in: StackRef, out: StackRef, cnt: Int, xp: Float) extends Statement
/**
* Used in statement processing to abort the current statement and show an error without a stack trace
*/
class StatementError(msg: String) extends Exception(msg)
+319
View File
@@ -0,0 +1,319 @@
/*
* Copyright (c) bdew, 2013
* https://github.com/bdew/bdlib
*
* This mod is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt
*/
package net.bdew.lib.recipes
import java.io.Reader
import net.minecraft.item.{Item, ItemStack}
import net.bdew.lib.Misc
import net.minecraft.block.Block
import cpw.mods.fml.common.registry.GameRegistry
import net.minecraftforge.oredict.{ShapelessOreRecipe, OreDictionary}
import java.util.logging.Logger
import cpw.mods.fml.common.FMLLog
import net.minecraft.item.crafting.FurnaceRecipes
/**
* Main recipe loader class
* The input file is parsed by [[net.bdew.lib.recipes.RecipeParser]]
* Into a list of [[net.bdew.lib.recipes.Statement]] subclasses
* That are then executed here
*/
class RecipeLoader {
/**
* Create a new parser, override in subclasses to use an extended parser
* @return New ConfigParser (or subclass) instance
*/
def newParser() = new RecipeParser()
val log: Logger = Logger.getLogger("RecipeLoader")
log.setParent(FMLLog.getLogger)
/**
* Current map of recipe characters to parser item references
*/
val currCharMap = collection.mutable.Map.empty[Char, StackRef].withDefault(x => error("Undefined recipe character '%s'", x))
/**
* Current map of class macros
*/
val currClassMacros = collection.mutable.Map.empty[String, String].withDefault(x => error("Undefined class macro '%s'", x))
/**
* Triggers an error with formatted string
*/
def error(msg: String, params: Any*) = throw new StatementError(msg.format(params: _*))
/**
* Looks up a recipe component
* @param s Parser ItemStack reference
* @return ItemStack or String that can be used as recipe components in MC functions
*/
def getRecipeComponent(s: StackRef): AnyRef = s match {
case StackOreDict(id) => id
case StackMacro(ch) => getRecipeComponent(currCharMap(ch))
case _ => getConcreteStack(s)
}
/**
* Resolve class name if it's a macro
*/
def getRealClassName(s: String): String = {
if (s.startsWith("$")) {
return currClassMacros(s.stripPrefix("$"))
}
return s
}
/**
* Sanitize items from reflection
* @param x The item
* @param source Human readable source (used in errors and warnings)
* @param meta Metadata or damage
* @param cnt Stack size
* @return
*/
def sanitizeReflectedItem(x: AnyRef, source: String, meta: Int, cnt: Int): ItemStack = x match {
case x: ItemStack =>
val l = x.copy()
l.stackSize = cnt
if (meta != OreDictionary.WILDCARD_VALUE && meta != l.getItemDamage) {
log.warning("%s requested with meta %d but specifies %d".format(source, meta, l.getItemDamage))
l.setItemDamage(meta)
}
return l
case x: Item =>
return new ItemStack(x, cnt, meta)
case x: Block =>
return new ItemStack(x, cnt, meta)
case _ =>
error("%s is %s which cannot be translated to an ItemStack", source, x.getClass.getName)
}
/**
* Fetches an ItemStack using reflection from static fields
* Item and Block instaces are converted to ItemStacks
* @param clsName Name of class to fetch from (can be a class macro)
* @param fldName Field name
* @param meta Metadata or damage
* @param cnt Stack size
* @return Matching itemstack
*/
def reflectStack(clsName: String, fldName: String, meta: Int, cnt: Int): ItemStack = {
val realName = getRealClassName(clsName)
val cls = Class.forName(realName)
val fld = cls.getField(fldName).get(null)
return sanitizeReflectedItem(fld, "%s.%s".format(realName, fldName), meta, cnt)
}
/**
* Fetches an ItemStack using reflection from static getters
* Item and Block instaces are converted to ItemStacks
* @param clsName Name of class to fetch from (can be a class macro)
* @param method Method name
* @param param Parameter to method
* @param meta Metadata or damage
* @param cnt Stack size
* @return Matching itemstack
*/
def reflectStackGetter(clsName: String, method: String, param: String, meta: Int, cnt: Int): ItemStack = {
var realName: String = clsName
var realMethod: String = method
//Some acrobatics to allow use with macros, even bare ones like $foo(bar)
if ((realName.length == 0) && realMethod.startsWith("$")) {
val v = getRealClassName(realMethod).split('.').reverse
realName = v.tail.reverse.mkString(".")
realMethod = v.head
}
if (realName.startsWith("$")) {
realName = getRealClassName(clsName)
}
val cls = Class.forName(realName)
val meth = cls.getMethod(realMethod, classOf[String])
val res = meth.invoke(null, param)
return sanitizeReflectedItem(res, "%s.%s(%s)".format(realName, realMethod, param), meta, cnt)
}
/**
* Returns all possible ItemStacks that match a reference
* Currently everything except OreDictionary references just returns one item
* @param s Parser ItemStack reference
* @param cnt Stack size
* @return List of matching ItemStacks
*/
def getAllConcreteStacks(s: StackRef, cnt: Int = 1): Iterable[ItemStack] = s match {
case StackOreDict(id) =>
import scala.collection.JavaConversions._
val c = OreDictionary.getOres(id).map(_.copy())
c.foreach(_.stackSize = cnt)
return c
case _ => Seq(getConcreteStack(s))
}
/**
* Returns an ItemStack that match a reference
* This is the main StackRef resolution method
* @param s Parser ItemStack reference
* @param cnt Stack size
* @return A matching ItemStack
*/
def getConcreteStack(s: StackRef, cnt: Int = 1): ItemStack = s match {
case StackOreDict(id) =>
val l = OreDictionary.getOres(id)
if (l.size == 0) error("Concrete ItemStack requested for OD entry '%s' that is empty", id)
val s = l.get(0).copy()
s.stackSize = cnt
log.info("Concrete ItemStack for OD entry '%s' -> %s".format(id, s))
return s
case StackMacro(ch) => getConcreteStack(currCharMap(ch), cnt)
case StackMod(mod, id) =>
val i = GameRegistry.findItemStack(mod, id, cnt)
if (i == null) error("Item %s:%s not found", mod, id)
i
case StackMCBlock(id, meta) => new ItemStack(Vanilla.blocks(id), cnt, meta)
case StackMCItem(id, meta) => new ItemStack(Vanilla.items(id), cnt, meta)
case StackReflect(cls, field, meta) => reflectStack(cls, field, meta, cnt)
case StackGetter(cls, method, param, meta) => reflectStackGetter(cls, method, param, meta, cnt)
}
/**
* Looks up all characters used in the recipe
* @param s The pattern
* @return Map from character to recipe components and a boolean that means OD-aware methods should be used
*/
def resolveRecipeComponents(s: Iterable[Char]): (Map[Char, AnyRef], Boolean) = {
var comp = Map.empty[Char, AnyRef]
var needOd = false
for (x <- s if !comp.contains(x) && x != '_') {
if (!currCharMap.contains(x)) error("Character %s is undefined", x)
val r = getRecipeComponent(currCharMap(x))
if (r.isInstanceOf[String]) needOd = true
log.info("%s -> %s".format(x, r))
comp += (x -> r)
}
return (comp, needOd)
}
/**
* Process a single statement, override this to add more statements
* @param s The statement
*/
def processStatement(s: Statement): Unit = s match {
case StCharAssign(c, r) =>
currCharMap(c) = r
log.info("Added %s = %s".format(c, r))
case StClassMacro(id, cls) =>
currClassMacros(id) = cls
log.info("Added def %s = %s".format(id, cls))
case StIfHaveMod(mod, thn, els) =>
if (Misc.haveModVersion(mod)) {
log.info("ifMod: %s found".format(mod))
processStatementsSafe(thn)
} else {
log.info("ifMod: %s not found".format(mod))
processStatementsSafe(els)
}
case StIfHaveOD(od, thn, els) =>
if (OreDictionary.getOres(od).size() > 0) {
log.info("ifOreDict: %s found".format(od))
processStatementsSafe(thn)
} else {
log.info("ifOreDict: %s not found".format(od))
processStatementsSafe(els)
}
case StRecipeShaped(rec, res, cnt) =>
log.info("Adding shaped recipe %s => %s * %d".format(rec, res, cnt))
val (comp, needOd) = resolveRecipeComponents(rec.mkString(""))
val resStack = getConcreteStack(res, cnt)
if (resStack.getItemDamage == OreDictionary.WILDCARD_VALUE) {
log.info("Result meta is unset, defaulting to 0")
resStack.setItemDamage(0)
}
if (needOd)
Misc.addRecipeOD(resStack, rec, comp)
else
Misc.addRecipe(resStack, rec, comp)
log.info("Done... result=%s, od=%s".format(resStack, needOd))
case StRecipeShapeless(rec, res, cnt) =>
log.info("Adding shapeless recipe %s => %s * %d".format(rec, res, cnt))
val (comp, needOd) = resolveRecipeComponents(rec)
val resStack = getConcreteStack(res, cnt)
val recTrans = rec.toCharArray.map(comp(_))
if (resStack.getItemDamage == OreDictionary.WILDCARD_VALUE) {
log.info("Result meta is unset, defaulting to 0")
resStack.setItemDamage(0)
}
if (needOd)
GameRegistry.addRecipe(new ShapelessOreRecipe(resStack, recTrans: _*))
else
GameRegistry.addShapelessRecipe(resStack, recTrans: _*)
log.info("Done... result=%s, od=%s".format(resStack, needOd))
case StSmeltRecipe(in, out, cnt, xp) =>
log.info("Adding smelting recipe %s => %s * %d (%f xp)".format(in, out, cnt, xp))
val outStack = getConcreteStack(out, cnt)
if (outStack.getItemDamage == OreDictionary.WILDCARD_VALUE) {
log.info("Result meta is unset, defaulting to 0")
outStack.setItemDamage(0)
}
for (inStack <- getAllConcreteStacks(in, 1)) {
if (inStack.getItemDamage == OreDictionary.WILDCARD_VALUE) {
FurnaceRecipes.smelting.addSmelting(inStack.itemID, outStack, xp)
log.info("added %d -> %s".format(inStack.itemID, outStack))
} else {
FurnaceRecipes.smelting.addSmelting(inStack.itemID, inStack.getItemDamage, outStack, xp)
log.info("added %d@%d -> %s".format(inStack.itemID, inStack.getItemDamage, outStack))
}
}
case x =>
log.severe("Can't process %s - this is a programing bug!".format(x))
}
/**
* Process a list of statements and catch all exceptions
* @param r The list to process
*/
def processStatementsSafe(r: List[Statement]): Unit = {
for (s <- r) {
try {
processStatement(s)
} catch {
case e: StatementError =>
log.severe("Error while processing %s: %s".format(s, e.getMessage))
case e: Throwable =>
log.severe("Error while processing %s: %s".format(s, e))
e.printStackTrace()
}
}
}
def load(f: Reader) {
log.info("Starting parsing")
val r = newParser().doParse(f)
log.info("Processing %d statements".format(r.size))
processStatementsSafe(r)
log.info("Done")
}
}
+124
View File
@@ -0,0 +1,124 @@
/*
* Copyright (c) bdew, 2013
* https://github.com/bdew/bdlib
*
* This mod is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt
*/
package net.bdew.lib.recipes
import java.io.Reader
import scala.util.parsing.combinator._
import org.apache.commons.lang3.StringEscapeUtils
import net.minecraftforge.oredict.OreDictionary
class RecipeParser extends JavaTokenParsers {
// Allows C-style comments
protected override val whiteSpace = """(\s|//.*|(?m)/\*(\*(?!/)|[^*])*\*/)+""".r
// Simple integer without signs
def int = "\\d+".r ^^ (_.toInt)
// Possible metadata suffix (defaults to wildcard value)
def maybeMeta = ("@" ~> int).? ^^ (_.getOrElse(OreDictionary.WILDCARD_VALUE))
// Qualified class name
def clsPath = (ident <~ ".").* ~ ident
// Single character usable in recipes (this could be extended)
def recipeChar = "[a-zA-Z0-9]".r ^^ (_.charAt(0))
// Set of 3 characters for 3x3 recipes (underscore = empty)
def recipeTriplet = repN(3, recipeChar | "_") ^^ (_.mkString(""))
// Set of 2 characters for 2x2 recipes
def recipeDuplet = repN(2, recipeChar | "_") ^^ (_.mkString(""))
// Quoted string with escape characters
def unescapeStr = stringLiteral ^^ { case x => StringEscapeUtils.unescapeJava(x.substring(1, x.length - 1)) }
// Identifier or quoted string
def str = ident | unescapeStr
// === Item references ===
def specOD = "OD" ~> ":" ~> ident ^^ StackOreDict
def specMcBlock = "B" ~> ":" ~> ident ~ maybeMeta ^^ { case b ~ m => StackMCBlock(b, m) }
def specMcItem = "I" ~> ":" ~> ident ~ maybeMeta ^^ { case b ~ m => StackMCItem(b, m) }
def specModStack = str ~ ":" ~ str ^^ { case m ~ c ~ n => StackMod(m, n) }
def specMacro = "$" ~> recipeChar ^^ StackMacro
def specReflect = clsPath ~ ("[" ~> ident <~ "]") ~ maybeMeta ^^ {
case (p ~ cl) ~ id ~ m => StackReflect((p :+ cl).mkString("."), id, m)
}
def specGetter = clsPath ~ ("(" ~> str <~ ")") ~ maybeMeta ^^ {
case (p ~ cl) ~ n ~ m => StackGetter(p.mkString("."), cl, n, m)
}
def spec = specMcBlock | specMcItem | specOD | specModStack | specGetter | specReflect | specMacro
// Spec with possible number of items
def specWithCount = spec ~ ("*" ~> int).?
// === Statements ===
def charSpec = recipeChar ~ "=" ~ spec ^^ {
case ch ~ eq ~ spec => new StCharAssign(ch, spec)
}
def classMacro = ("def" ~> ident <~ "=") ~ clsPath ^^ {
case id ~ (p ~ cl) => StClassMacro(id, (p :+ cl).mkString("."))
}
def ifMod = ("ifMod" ~> str) ~ ("{" ~> statements <~ "}") ~ ("else" ~> "{" ~> statements <~ "}").? ^^ {
case mod ~ thn ~ els => new StIfHaveMod(mod, thn, els.getOrElse(List.empty[Statement]))
}
def ifOreDict = ("ifOreDict" ~> str) ~ ("{" ~> statements <~ "}") ~ ("else" ~> "{" ~> statements <~ "}").? ^^ {
case id ~ thn ~ els => new StIfHaveOD(id, thn, els.getOrElse(List.empty[Statement]))
}
def recipeShaped3x3 = recipeTriplet ~ recipeTriplet ~ ("=>" ~> specWithCount) ~ recipeTriplet ^^ {
case r1 ~ r2 ~ (res ~ n) ~ r3 => StRecipeShaped(Seq(r1, r2, r3), res, n.getOrElse(1))
}
def recipeShaped2x2 = recipeDuplet ~ recipeDuplet ~ ("=>" ~> specWithCount) ^^ {
case r1 ~ r2 ~ (res ~ n) => StRecipeShaped(Seq(r1, r2), res, n.getOrElse(1))
}
def recipeShaped9 = recipeTriplet ~ recipeTriplet ~ recipeTriplet ~ ("=>" ~> specWithCount) ^^ {
case r1 ~ r2 ~ r3 ~ (res ~ n) => StRecipeShaped(Seq(r1, r2, r3), res, n.getOrElse(1))
}
def recipeShapeless = "shapeless" ~> ":" ~> recipeChar.+ ~ ("=>" ~> specWithCount) ^^ {
case r ~ (res ~ n) => StRecipeShapeless(r.mkString(""), res, n.getOrElse(1))
}
def recipeSmelting = "smelt" ~> ":" ~> spec ~ ("=>" ~> specWithCount) ~ ("," ~> decimalNumber).? ^^ {
case in ~ (out ~ n) ~ xp => StSmeltRecipe(in, out, n.getOrElse(1), xp.getOrElse("0").toFloat)
}
def statement: Parser[Statement] = (
charSpec
| classMacro
| ifMod
| recipeShaped3x3
| recipeShaped2x2
| recipeShaped9
| recipeShapeless
| recipeSmelting
)
def statements = statement.*
def doParse(r: Reader): List[Statement] = {
parseAll(statements, r) match {
case Success(res, next) => return res
case NoSuccess(msg, next) => sys.error("Config parsing failed at %s: %s".format(next.pos, msg))
}
}
}
+42
View File
@@ -0,0 +1,42 @@
/*
* Copyright (c) bdew, 2013
* https://github.com/bdew/bdlib
*
* This mod is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt
*/
package net.bdew.lib.recipes
import net.minecraft.block.Block
import net.minecraft.item.Item
import scala.reflect.ClassTag
import java.lang.reflect.Modifier
object Vanilla {
// Maps of vanilla blocks and items (without tile. / item. prefixes)
lazy val blocks = mkMap[Block](_.getUnlocalizedName.stripPrefix("tile.")).withDefault(x => throw new StatementError("Block %s not found".format(x)))
lazy val items = mkMap[Item](_.getUnlocalizedName.stripPrefix("item.")).withDefault(x => throw new StatementError("Item %s not found".format(x)))
/**
* Generates the maps
* @tparam T The base class
* @param namer A function that converts objects to names
*/
private def mkMap[T](namer: T => String)(implicit t: ClassTag[T]) = {
val c = t.runtimeClass
// Grab all the fields
c.getFields.filter(x => {
// Keep only static fields that match the base Class
c.isAssignableFrom(x.getType) && Modifier.isStatic(x.getModifiers)
}).map(x => {
// Retrieve the static value
val f = x.get(null).asInstanceOf[T]
// Convert to name -> object tuples
namer(f) -> f
}).toMap // and finally to a map
}
}
@@ -0,0 +1,56 @@
/*
* Copyright (c) bdew, 2013
* https://github.com/bdew/bdlib
*
* This mod is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt
*/
package net.bdew.lib.recipes.gencfg
abstract class CfgEntry
case class EntryDouble(v: Double) extends CfgEntry
case class EntryStr(v: String) extends CfgEntry
case class ConfigSection(pfx: String = "") extends CfgEntry with Iterable[(String, CfgEntry)] {
var raw = Map.empty[String, CfgEntry].withDefault(x => sys.error("Config value '%s%s' is missing".format(pfx,x)))
def iterator: Iterator[(String, CfgEntry)] = raw.iterator
def filterType[T<:CfgEntry](cls: Class[T]): Iterable[(String,T)] = raw.filter(x=>cls.isInstance(x._2)).map(x=>x.asInstanceOf[(String,T)])
def rawget[T](id: String, t: Class[T]): T = {
val v = raw(id)
if (t.isInstance(v))
return v.asInstanceOf[T]
else
sys.error("Config value '%s%s' is of the wrong type, expected %s, got %s".format(pfx, id, t.getName, v.getClass.getName))
}
def set(id: String, v: CfgEntry) = raw += id -> v
def getDouble(id: String) = rawget(id, classOf[EntryDouble]).v
def getString(id: String) = rawget(id, classOf[EntryStr]).v
def getSection(id: String) = rawget(id, classOf[ConfigSection])
final val trueVals = Set("y", "true", "yes", "on")
def getBoolean(id: String) = trueVals.contains(getString(id).toLowerCase)
def getOrAddSection(id: String) = {
if (raw.isDefinedAt(id)) {
rawget(id, classOf[ConfigSection])
} else {
val newSection = new ConfigSection(pfx + id + ".")
set(id, newSection)
newSection
}
}
def getInt(id: String) = getDouble(id).round.toInt
def getFloat(id: String) = getDouble(id).toFloat
}
@@ -0,0 +1,24 @@
/*
* Copyright (c) bdew, 2013
* https://github.com/bdew/bdlib
*
* This mod is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt
*/
package net.bdew.lib.recipes.gencfg
import net.bdew.lib.recipes.Statement
abstract class CfgStatement
case class CfgVal(id: String, value: CfgEntry) extends CfgStatement
case class CfgSub(id: String, vals: List[CfgStatement]) extends CfgStatement
case class StCfg(id: String, vals: List[CfgStatement]) extends Statement
@@ -0,0 +1,33 @@
/*
* Copyright (c) bdew, 2013
* https://github.com/bdew/bdlib
*
* This mod is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt
*/
package net.bdew.lib.recipes.gencfg
import net.bdew.lib.recipes.{Statement, RecipeLoader}
trait GenericConfigLoader extends RecipeLoader {
val cfgStore: ConfigSection
def processConfigStatement(section: ConfigSection, s: CfgStatement): Unit = s match {
case CfgVal(id, v) =>
log.info("Config: %s%s = %s".format(section.pfx, id, v))
section.set(id, v)
case CfgSub(id, st) => processConfigBlock(section.getOrAddSection(id), st)
case x =>
log.severe("Can't process %s - this is a programing bug!".format(x))
}
def processConfigBlock(view: ConfigSection, block: List[CfgStatement]) = for (s <- block) processConfigStatement(view, s)
override def processStatement(s: Statement) = s match {
case StCfg(id, st) => processConfigBlock(cfgStore.getOrAddSection(id), st)
case _ => super.processStatement(s)
}
}
@@ -0,0 +1,26 @@
/*
* Copyright (c) bdew, 2013
* https://github.com/bdew/bdlib
*
* This mod is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt
*/
package net.bdew.lib.recipes.gencfg
import net.bdew.lib.recipes.RecipeParser
trait GenericConfigParser extends RecipeParser {
override def statement = statementCfg | super.statement
def cfgStatementNum = ident ~ "=" ~ decimalNumber ^^ { case id ~ eq ~ n => CfgVal(id, EntryDouble(n.toDouble)) }
def cfgStatementStr = ident ~ "=" ~ str ^^ { case id ~ eq ~ s => CfgVal(id, EntryStr(s)) }
def cfgStatementSub = cfgBlock ^^ { case (id, st) => CfgSub(id, st) }
def cfgStatement = cfgStatementNum | cfgStatementStr | cfgStatementSub
// A bit of type acrobatics because this is recursive (via cfgStatementSub), the tuple is translated into the proper class in either cfgStatementSub or cfg
def cfgBlock: Parser[(String, List[CfgStatement])] = "cfg" ~> ident ~ ("{" ~> cfgStatement.* <~ "}") ^^ { case id ~ st => (id, st) }
def statementCfg = cfgBlock ^^ { case (id, st) => StCfg(id, st) }
}
@@ -0,0 +1,92 @@
/*
* Copyright (c) bdew, 2013
* https://github.com/bdew/bdlib
*
* This mod is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt
*/
package net.bdew.lib.rotate
import cpw.mods.fml.relauncher.Side
import cpw.mods.fml.relauncher.SideOnly
import net.minecraft.block.Block
import net.minecraft.entity.EntityLivingBase
import net.minecraft.item.ItemStack
import net.minecraft.util.Icon
import net.minecraft.util.MathHelper
import net.minecraft.world.IBlockAccess
import net.minecraft.world.World
import net.minecraftforge.common.ForgeDirection
import java.util.EnumSet
/**
* Basic logic for block rotatation
*/
trait BaseRotateableBlock extends Block {
/**
* Override this method to provide your textures, also called when rendering as item
*/
def getIcon(meta: Int, kind: IconType.Value): Icon
/**
* Override this method to provide your textures, if you need to check other state
*/
def getIcon(world: IBlockAccess, x: Int, y: Int, z: Int, kind: IconType.Value): Icon = getIcon(world.getBlockMetadata(x, y, z), kind)
/**
* Set of valid rotations, default is all of them
*/
def getValidFacings: EnumSet[ForgeDirection] = {
return EnumSet.allOf(classOf[ForgeDirection])
}
/**
* Rotation to show when it's unavailable (like rendering item in inventory)
*/
def getDefaultFacing: ForgeDirection = ForgeDirection.UP
/**
* Those will be overrided to provide concrete storage
*/
def setFacing(world: World, x: Int, y: Int, z: Int, facing: ForgeDirection)
def getFacing(world: IBlockAccess, x: Int, y: Int, z: Int): ForgeDirection
override def rotateBlock(worldObj: World, x: Int, y: Int, z: Int, axis: ForgeDirection): Boolean = {
if (getValidFacings.contains(axis)) {
setFacing(worldObj, x, y, z, axis)
return true
}
return false
}
@SideOnly(Side.CLIENT)
override def getIcon(side: Int, meta: Int): Icon = getIcon(meta, IconType.fromSideAndDir(side, getDefaultFacing))
@SideOnly(Side.CLIENT)
override def getBlockTexture(world: IBlockAccess, x: Int, y: Int, z: Int, side: Int): Icon = getIcon(world, x, y, z, IconType.fromSideAndDir(side, getFacing(world, x, y, z)))
override def getValidRotations(worldObj: World, x: Int, y: Int, z: Int): Array[ForgeDirection] = getValidFacings.toArray(Array.empty[ForgeDirection])
override def onBlockPlacedBy(world: World, x: Int, y: Int, z: Int, ent: EntityLivingBase, stack: ItemStack) {
val validRotations = getValidFacings
var dir = getDefaultFacing
if (ent != null) {
val pitch: Int = Math.round(ent.rotationPitch)
val yaw: Int = MathHelper.floor_double(ent.rotationYaw * 4.0F / 360.0F + 0.5D) & 3
dir = yaw match {
case _ if pitch >= 50 && validRotations.contains(ForgeDirection.UP) => ForgeDirection.UP
case _ if pitch <= -50 && validRotations.contains(ForgeDirection.DOWN) => ForgeDirection.DOWN
case 0 if validRotations.contains(ForgeDirection.NORTH) => ForgeDirection.NORTH
case 1 if validRotations.contains(ForgeDirection.EAST) => ForgeDirection.EAST
case 2 if validRotations.contains(ForgeDirection.SOUTH) => ForgeDirection.SOUTH
case 3 if validRotations.contains(ForgeDirection.WEST) => ForgeDirection.WEST
case _ => dir
}
}
setFacing(world, x, y, z, dir)
super.onBlockPlacedBy(world, x, y, z, ent, stack)
}
}
+28
View File
@@ -0,0 +1,28 @@
/*
* Copyright (c) bdew, 2013
* https://github.com/bdew/bdlib
*
* This mod is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt
*/
package net.bdew.lib.rotate
import net.minecraftforge.common.ForgeDirection
object IconType extends Enumeration {
val BACK = Value(0, "BACK")
val FRONT = Value(1, "FRONT")
val SIDE = Value(2, "SIDE")
def fromSideAndDir(side: Int, facing: ForgeDirection) = this(metaSideMap(side)(facing.ordinal))
val metaSideMap = Array(
Array(1, 0, 2, 2, 2, 2),
Array(0, 1, 2, 2, 2, 2),
Array(2, 2, 1, 0, 2, 2),
Array(2, 2, 0, 1, 2, 2),
Array(2, 2, 2, 2, 1, 0),
Array(2, 2, 2, 2, 0, 1))
}
@@ -0,0 +1,17 @@
/*
* Copyright (c) bdew, 2013
* https://github.com/bdew/bdlib
*
* This mod is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt
*/
package net.bdew.lib.rotate
import net.bdew.lib.data.base.{UpdateKind, TileDataSlots}
import net.bdew.lib.data.DataSlotDirection
trait RotateableTile extends TileDataSlots {
var rotation = DataSlotDirection("rotation", this).setUpdate(UpdateKind.SAVE, UpdateKind.WORLD)
}
@@ -0,0 +1,34 @@
/*
* Copyright (c) bdew, 2013
* https://github.com/bdew/bdlib
*
* This mod is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt
*/
package net.bdew.lib.rotate
import net.minecraft.block.ITileEntityProvider
import net.minecraft.world.IBlockAccess
import net.minecraft.world.World
import net.minecraftforge.common.ForgeDirection
import cpw.mods.fml.common.FMLCommonHandler
/**
* Stores rotation data in tile entity. The TE should implement {@link RotateableTile}
*/
trait RotateableTileBlock extends BaseRotateableBlock with ITileEntityProvider {
def setFacing(world: World, x: Int, y: Int, z: Int, facing: ForgeDirection) {
world.getBlockTileEntity(x, y, z).asInstanceOf[RotateableTile].rotation := facing
}
def getFacing(world: IBlockAccess, x: Int, y: Int, z: Int): ForgeDirection = {
val te: RotateableTile = world.getBlockTileEntity(x, y, z).asInstanceOf[RotateableTile]
if (te == null || te.rotation == null) {
FMLCommonHandler.instance().getFMLLogger.warning("Failed gettig rocation for block at %d, %d, %d".format(x, y, z))
return getDefaultFacing
}
return te.rotation
}
}
+14
View File
@@ -0,0 +1,14 @@
/*
* Copyright (c) bdew, 2013
* https://github.com/bdew/bdlib
*
* This mod is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt
*/
package net.bdew.lib.tile
trait Component {
def added(p: TileExtended, name: String)
}
+46
View File
@@ -0,0 +1,46 @@
/*
* Copyright (c) bdew, 2013
* https://github.com/bdew/bdlib
*
* This mod is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt
*/
package net.bdew.lib.tile
import net.minecraft.tileentity.TileEntity
import net.minecraftforge.fluids._
import net.minecraftforge.common.ForgeDirection
trait ExposeTank extends TileEntity with IFluidHandler {
def getTankFromDirection(dir: ForgeDirection): IFluidTank
def fill(from: ForgeDirection, resource: FluidStack, doFill: Boolean): Int = {
val tank = getTankFromDirection(from)
if (tank == null) return 0
return tank.fill(resource, doFill)
}
def drain(from: ForgeDirection, resource: FluidStack, doDrain: Boolean): FluidStack = {
val tank = getTankFromDirection(from)
if (tank == null || resource == null || !resource.isFluidEqual(tank.getFluid)) return null
return tank.drain(resource.amount, doDrain)
}
def drain(from: ForgeDirection, maxDrain: Int, doDrain: Boolean): FluidStack = {
val tank = getTankFromDirection(from)
if (tank == null) return null
getTankFromDirection(from).drain(maxDrain, doDrain)
}
def canFill(from: ForgeDirection, fluid: Fluid): Boolean = getTankFromDirection(from) != null
def canDrain(from: ForgeDirection, fluid: Fluid): Boolean = getTankFromDirection(from) != null
def getTankInfo(from: ForgeDirection): Array[FluidTankInfo] = {
val tank = getTankFromDirection(from)
if (tank == null) return Array.empty[FluidTankInfo]
return Array(tank.getInfo)
}
}
+69
View File
@@ -0,0 +1,69 @@
/*
* Copyright (c) bdew, 2013
* https://github.com/bdew/bdlib
*
* This mod is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt
*/
package net.bdew.lib.tile
import net.minecraft.tileentity.TileEntity
import net.minecraft.nbt.NBTTagCompound
import net.minecraft.network.INetworkManager
import net.minecraft.network.packet.Packet132TileEntityData
import net.bdew.lib.Event
class TileExtended extends TileEntity {
final val ACT_CLIENT = 1
final val ACT_GUI = 2
var clientTick = Event()
var serverTick = Event()
var persistSave = Event[NBTTagCompound]
var persistLoad = Event[NBTTagCompound]
var sendClientUpdate = Event[NBTTagCompound]
var handleClientUpdate = Event[NBTTagCompound]
def tickClient() {}
def tickServer() {}
override final def writeToNBT(tag: NBTTagCompound) = {
super.writeToNBT(tag)
persistSave.trigger(tag)
}
override final def readFromNBT(tag: NBTTagCompound) = {
super.readFromNBT(tag)
persistLoad.trigger(tag)
}
override final def getDescriptionPacket: Packet132TileEntityData = {
if (!sendClientUpdate.hasListeners) return null
val tag = new NBTTagCompound
sendClientUpdate.trigger(tag)
return new Packet132TileEntityData(this.xCoord, this.yCoord, this.zCoord, ACT_CLIENT, tag)
}
override final def onDataPacket(net: INetworkManager, pkt: Packet132TileEntityData) {
if (pkt.actionType == ACT_CLIENT)
handleClientUpdate.trigger(pkt.data)
else
extDataPacket(pkt.actionType, pkt.data)
}
override final def updateEntity() {
if (worldObj != null) {
if (worldObj.isRemote) {
tickClient()
clientTick.trigger()
} else {
tickServer()
serverTick.trigger()
}
}
}
protected def extDataPacket(id: Int, data: NBTTagCompound) {}
}
@@ -0,0 +1,66 @@
/*
* Copyright (c) bdew, 2013
* https://github.com/bdew/bdlib
*
* This mod is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt
*/
package net.bdew.lib.tile.inventory
import net.minecraft.inventory.IInventory
import net.minecraft.item.ItemStack
import net.minecraft.entity.player.EntityPlayer
trait BaseInventory extends IInventory {
var inv: Array[ItemStack] = new Array(getSizeInventory)
def getStackInSlot(i: Int): ItemStack = inv(i)
def getInvName = ""
def isInvNameLocalized = false
def getInventoryStackLimit = 64
def isUseableByPlayer(player: EntityPlayer) = true
def openChest() = Unit
def closeChest() = Unit
def isItemValidForSlot(slot: Int, stack: ItemStack) = true
def decrStackSize(slot: Int, n: Int): ItemStack = {
var item = inv(slot)
if (item != null) {
if (item.stackSize <= n) {
inv(slot) = null
onInventoryChanged()
return item
} else {
var newstack = item.splitStack(n)
if (item.stackSize == 0) {
inv(slot) = null
}
onInventoryChanged()
return newstack
}
} else {
return null
}
}
def getStackInSlotOnClosing(slot: Int): ItemStack = {
var tmp = inv(slot)
inv(slot) = null
onInventoryChanged()
return tmp
}
def setInventorySlotContents(slot: Int, stack: ItemStack) = {
inv(slot) = stack
onInventoryChanged()
}
}
@@ -0,0 +1,25 @@
/*
* Copyright (c) bdew, 2013
* https://github.com/bdew/bdlib
*
* This mod is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt
*/
package net.bdew.lib.tile.inventory
import net.minecraft.block.Block
import net.minecraft.world.World
trait BreakableInventoryBlock extends Block {
override def breakBlock(world: World, x: Int, y: Int, z: Int, blockId: Int, meta: Int) {
if (!world.isRemote) {
val te = world.getBlockTileEntity(x, y, z).asInstanceOf[BreakableInventoryTile]
if (te != null) {
te.dropItems()
}
}
super.breakBlock(world, x, y, z, blockId, meta)
}
}
@@ -0,0 +1,25 @@
/*
* Copyright (c) bdew, 2013
* https://github.com/bdew/bdlib
*
* This mod is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt
*/
package net.bdew.lib.tile.inventory
import net.minecraft.tileentity.TileEntity
import net.minecraft.item.ItemStack
import net.bdew.lib.items.ItemUtils
trait BreakableInventoryTile extends TileEntity with BaseInventory {
def dropItems() {
if (worldObj != null && !worldObj.isRemote) {
for (stack <- inv if stack != null) {
ItemUtils.throwItemAt(worldObj, xCoord, yCoord, zCoord, stack)
}
inv = new Array[ItemStack](inv.size)
}
}
}
@@ -0,0 +1,38 @@
/*
* Copyright (c) bdew, 2013
* https://github.com/bdew/bdlib
*
* This mod is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt
*/
package net.bdew.lib.tile.inventory
import net.minecraft.item.ItemStack
import net.minecraft.nbt.{NBTTagList, NBTTagCompound}
import net.bdew.lib.Misc
import net.bdew.lib.tile.TileExtended
trait PersistentInventoryTile extends TileExtended with BaseInventory {
persistLoad.listen((tag: NBTTagCompound) => {
inv = new Array[ItemStack](getSizeInventory)
for (nbtItem <- Misc.iterNbtList[NBTTagCompound](tag.getTagList("Items"))) {
val slot = nbtItem.getByte("Slot")
if (slot >= 0 && slot < inv.size) {
inv(slot) = ItemStack.loadItemStackFromNBT(nbtItem)
}
}
})
persistSave.listen((tag: NBTTagCompound) => {
val itemList = new NBTTagList
for ((item, i) <- inv.view.zipWithIndex if item != null) {
val itemNbt: NBTTagCompound = new NBTTagCompound
itemNbt.setByte("Slot", i.asInstanceOf[Byte])
item.writeToNBT(itemNbt)
itemList.appendTag(itemNbt)
}
tag.setTag("Items", itemList)
})
}
@@ -0,0 +1,23 @@
/*
* Copyright (c) bdew, 2013
* https://github.com/bdew/bdlib
*
* This mod is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt
*/
package net.bdew.lib.tile.inventory
import net.minecraft.inventory.ISidedInventory
import net.minecraft.item.ItemStack
trait SidedInventory extends BaseInventory with ISidedInventory {
var allowSided = false
def getAccessibleSlotsFromSide(side: Int): Array[Int] = (0 until inv.size).toArray
def canInsertItem(slot: Int, stack: ItemStack, side: Int) = allowSided && isItemValidForSlot(slot, stack)
def canExtractItem(slot: Int, stack: ItemStack, side: Int) = allowSided
}