mirror of
https://github.com/GTNewHorizons/bdlib.git
synced 2026-10-27 14:53:44 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8bbab862ab | ||
|
|
9e83d04487 | ||
|
|
9202b27340 | ||
|
|
70ee9fabd6 | ||
|
|
78d9bed924 | ||
|
|
92517cdcec | ||
|
|
bcb8edc8a5 | ||
|
|
9a837361e7 | ||
|
|
5ae0461f10 | ||
|
|
b3f8fb3c56 | ||
|
|
023ae4d77f | ||
|
|
b1e0e70fc4 | ||
|
|
5f01716310 | ||
|
|
0976fb4acc | ||
|
|
4effeafbb7 |
No files matched your search
+2
-2
@@ -21,7 +21,7 @@ buildscript {
|
||||
apply plugin: 'scala'
|
||||
apply plugin: 'forge'
|
||||
|
||||
version = "1.4.4"
|
||||
version = "1.5.0"
|
||||
|
||||
if (project.hasProperty('buildnum')) {
|
||||
project.version = project.version + '.' + project.buildnum
|
||||
@@ -34,7 +34,7 @@ archivesBaseName = "bdlib"
|
||||
ext.versuffix = "mc1710"
|
||||
|
||||
minecraft {
|
||||
version = "1.7.10-10.13.0.1180"
|
||||
version = "1.7.10-10.13.2.1231"
|
||||
replace("BDLIB_VER", project.version)
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
bdlib.multiblock.face.north=Sever
|
||||
bdlib.multiblock.face.south=Jih
|
||||
bdlib.multiblock.face.east=Západ
|
||||
bdlib.multiblock.face.west=Východ
|
||||
bdlib.multiblock.face.up=Vršek
|
||||
bdlib.multiblock.face.down=Spodek
|
||||
|
||||
bdlib.multiblock.disabled=Zakázáno
|
||||
bdlib.multiblock.incomplete=Tento stroj není kompletní, ještě potřebuje alespoň:
|
||||
bdlib.multiblock.notconnected=Nepřipojeno ke správnému stroji
|
||||
bdlib.multiblock.toomanyoutputs=Připojeno příliš mnoho výstupů, nemohu získat nové připojení
|
||||
|
||||
bdlib.rsmode.always=Vždy ZAPNUTO
|
||||
bdlib.rsmode.never=Zakázáno
|
||||
bdlib.rsmode.rs_on=Povoleno při ruditovém signálu
|
||||
bdlib.rsmode.rs_off=Zakázáno při ruditovém signálu
|
||||
|
||||
bdlib.label.empty=Prázdný
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
bdlib.multiblock.face.north=北方
|
||||
bdlib.multiblock.face.south=南方
|
||||
bdlib.multiblock.face.east=东方
|
||||
bdlib.multiblock.face.west=西方
|
||||
bdlib.multiblock.face.up=顶部
|
||||
bdlib.multiblock.face.down=底部
|
||||
|
||||
bdlib.multiblock.disabled=停用
|
||||
bdlib.multiblock.incomplete=这台多方块结构机器未搭建完成, 它至少需要安装一个:
|
||||
bdlib.multiblock.notconnected=未连接有效机器
|
||||
bdlib.multiblock.toomanyoutputs=连接的输出接口过多, 无法连接新的接口
|
||||
|
||||
bdlib.rsmode.always=一直启用
|
||||
bdlib.rsmode.never=一直停用
|
||||
bdlib.rsmode.rs_on=接收到红石信号时启用
|
||||
bdlib.rsmode.rs_off=接收到红石信号时停用
|
||||
|
||||
bdlib.label.empty=空
|
||||
@@ -11,7 +11,7 @@ package net.bdew.lib
|
||||
|
||||
import cpw.mods.fml.common.Mod
|
||||
import cpw.mods.fml.common.Mod.EventHandler
|
||||
import cpw.mods.fml.common.event.{FMLPreInitializationEvent, FMLServerStartingEvent}
|
||||
import cpw.mods.fml.common.event.{FMLPreInitializationEvent, FMLServerStartingEvent, FMLServerStoppingEvent}
|
||||
import net.bdew.lib.multiblock.network.NetHandler
|
||||
import net.minecraft.command.CommandHandler
|
||||
import org.apache.logging.log4j.Logger
|
||||
@@ -26,6 +26,9 @@ object BdLib {
|
||||
def logWarnException(msg: String, t: Throwable, args: Any*) = log.warn(msg.format(args: _*), t)
|
||||
def logErrorException(msg: String, t: Throwable, args: Any*) = log.error(msg.format(args: _*), t)
|
||||
|
||||
val onServerStarting = Event[FMLServerStartingEvent]
|
||||
val onServerStopping = Event[FMLServerStoppingEvent]
|
||||
|
||||
@EventHandler
|
||||
def preInit(ev: FMLPreInitializationEvent) {
|
||||
log = ev.getModLog
|
||||
@@ -37,5 +40,11 @@ object BdLib {
|
||||
def serverStarting(event: FMLServerStartingEvent) {
|
||||
val commandHandler = event.getServer.getCommandManager.asInstanceOf[CommandHandler]
|
||||
commandHandler.registerCommand(new CommandDumpRegistry)
|
||||
onServerStarting.trigger(event)
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
def serverStopping(event: FMLServerStoppingEvent) {
|
||||
onServerStopping.trigger(event)
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,7 @@
|
||||
package net.bdew.lib
|
||||
|
||||
import net.minecraft.client.Minecraft
|
||||
import net.minecraft.client.renderer.texture.TextureMap
|
||||
import org.lwjgl.input.Keyboard
|
||||
|
||||
/**
|
||||
@@ -21,6 +22,10 @@ object Client {
|
||||
def renderEngine = Minecraft.getMinecraft.renderEngine
|
||||
def world = Minecraft.getMinecraft.theWorld
|
||||
def player = Minecraft.getMinecraft.thePlayer
|
||||
def textureManager = Minecraft.getMinecraft.getTextureManager
|
||||
|
||||
def blockMissingIcon = textureManager.getTexture(TextureMap.locationBlocksTexture).asInstanceOf[TextureMap].getAtlasSprite("missingno")
|
||||
def itemMissingIcon = textureManager.getTexture(TextureMap.locationItemsTexture).asInstanceOf[TextureMap].getAtlasSprite("missingno")
|
||||
|
||||
def shiftDown: Boolean = {
|
||||
return Keyboard.isKeyDown(42) || Keyboard.isKeyDown(54)
|
||||
|
||||
@@ -46,7 +46,12 @@ class CommandDumpRegistry extends CommandBase {
|
||||
dumpWriter.write("\n\n")
|
||||
|
||||
dumpWriter.write("==== ORE DICT ====\n")
|
||||
dumpWriter.write(OreDictionary.getOreNames.sorted.mkString("\n"))
|
||||
dumpWriter.write((OreDictionary.getOreNames.sorted flatMap { name =>
|
||||
List(name) ++
|
||||
(OreDictionary.getOres(name) map { ore =>
|
||||
" - " + ore.toString
|
||||
})
|
||||
}).mkString("\n"))
|
||||
dumpWriter.write("\n\n")
|
||||
|
||||
dumpWriter.write("==== FLUIDS ====\n")
|
||||
|
||||
@@ -15,9 +15,10 @@ import cpw.mods.fml.common.versioning.{ArtifactVersion, VersionParser}
|
||||
import net.minecraft.item.ItemStack
|
||||
import net.minecraft.nbt.NBTTagCompound
|
||||
import net.minecraft.tileentity.TileEntity
|
||||
import net.minecraft.util.StatCollector
|
||||
import net.minecraft.util.{IIcon, StatCollector}
|
||||
import net.minecraft.world.biome.BiomeGenBase
|
||||
import net.minecraftforge.common.util.ForgeDirection
|
||||
import net.minecraftforge.fluids.{Fluid, FluidStack}
|
||||
import net.minecraftforge.oredict.ShapedOreRecipe
|
||||
|
||||
object Misc {
|
||||
@@ -86,6 +87,10 @@ object Misc {
|
||||
def asInstanceOpt[T](v: Any, cls: Class[T]) =
|
||||
if (cls.isInstance(v)) Some(v.asInstanceOf[T]) else None
|
||||
|
||||
// Same thing but in a way that's easier to use with map, etc.
|
||||
def asInstanceOpt[T](cls: Class[T])(v: Any) =
|
||||
if (cls.isInstance(v)) Some(v.asInstanceOf[T]) else None
|
||||
|
||||
def getNeighbourTile[T](origin: TileEntity, dir: ForgeDirection, cls: Class[T]) =
|
||||
Option(origin.getWorldObj.getTileEntity(origin.xCoord + dir.offsetX,
|
||||
origin.yCoord + dir.offsetY, origin.zCoord + dir.offsetZ)) flatMap (asInstanceOpt(_, cls))
|
||||
@@ -94,5 +99,20 @@ object Misc {
|
||||
f(init)
|
||||
init
|
||||
}
|
||||
|
||||
def getFluidIcon(fs: FluidStack): IIcon =
|
||||
if (fs != null && fs.getFluid != null && fs.getFluid.getIcon != null)
|
||||
fs.getFluid.getIcon(fs)
|
||||
else
|
||||
Client.blockMissingIcon
|
||||
|
||||
def getFluidIcon(f: Fluid): IIcon =
|
||||
if (f != null) getFluidIcon(new FluidStack(f, 1)) else Client.blockMissingIcon
|
||||
|
||||
def getFluidColor(fs: FluidStack): Int =
|
||||
if (fs != null && fs.getFluid != null) fs.getFluid.getColor(fs) else 0xFFFFFF
|
||||
|
||||
def getFluidColor(f: Fluid): Int =
|
||||
if (f != null) getFluidColor(new FluidStack(f, 1)) else 0xFFFFFF
|
||||
}
|
||||
|
||||
@@ -9,14 +9,20 @@
|
||||
|
||||
package net.bdew.lib.covers
|
||||
|
||||
import cpw.mods.fml.relauncher.{Side, SideOnly}
|
||||
import net.bdew.lib.Misc
|
||||
import net.bdew.lib.block.HasTE
|
||||
import net.bdew.lib.items.ItemUtils
|
||||
import net.minecraft.block.Block
|
||||
import net.minecraft.entity.player.EntityPlayer
|
||||
import net.minecraft.util.IIcon
|
||||
import net.minecraft.world.{IBlockAccess, World}
|
||||
import net.minecraftforge.common.util.ForgeDirection
|
||||
|
||||
trait BlockCoverable[T <: TileCoverable] extends HasTE[T] {
|
||||
@SideOnly(Side.CLIENT)
|
||||
override def getRenderType = CoverRenderer.id
|
||||
|
||||
override def onBlockActivated(world: World, x: Int, y: Int, z: Int, player: EntityPlayer, face: Int, xoffs: Float, yoffs: Float, zoffs: Float): Boolean = {
|
||||
val te = getTE(world, x, y, z)
|
||||
val side = Misc.forgeDirection(face)
|
||||
@@ -53,12 +59,12 @@ trait BlockCoverable[T <: TileCoverable] extends HasTE[T] {
|
||||
super.onBlockActivated(world, x, y, z, player, face, xoffs, yoffs, zoffs)
|
||||
}
|
||||
|
||||
override def getIcon(w: IBlockAccess, x: Int, y: Int, z: Int, side: Int) =
|
||||
(for {
|
||||
coverStack <- Option(getTE(w, x, y, z).covers(Misc.forgeDirection(side)).cval)
|
||||
coverItem <- Option(coverStack.getItem) flatMap (Misc.asInstanceOpt(_, classOf[ItemCover]))
|
||||
def getCoverIcon(w: IBlockAccess, x: Int, y: Int, z: Int, side: ForgeDirection): Option[IIcon] =
|
||||
for {
|
||||
coverStack <- Option(getTE(w, x, y, z).covers(side).cval)
|
||||
coverItemMaybe <- Option(coverStack.getItem)
|
||||
coverItem <- Misc.asInstanceOpt(coverItemMaybe, classOf[ItemCover])
|
||||
} yield coverItem.getCoverIcon(coverStack)
|
||||
) getOrElse super.getIcon(w, x, y, z, side)
|
||||
|
||||
override def breakBlock(world: World, x: Int, y: Int, z: Int, block: Block, meta: Int) {
|
||||
if (!world.isRemote)
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (c) bdew, 2013 - 2014
|
||||
* 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
|
||||
* http://bdew.net/minecraft-mod-public-license/
|
||||
*/
|
||||
|
||||
package net.bdew.lib.covers
|
||||
|
||||
import net.bdew.lib.Misc
|
||||
import net.bdew.lib.render.connected.ConnectedHelper
|
||||
import net.bdew.lib.render.{BaseBlockRenderHandler, RenderUtils}
|
||||
import net.minecraft.block.Block
|
||||
import net.minecraft.client.renderer.RenderBlocks
|
||||
import net.minecraft.world.IBlockAccess
|
||||
import net.minecraftforge.common.util.ForgeDirection
|
||||
|
||||
object CoverRenderer extends BaseBlockRenderHandler {
|
||||
override def renderInventoryBlock(block: Block, metadata: Int, modelId: Int, renderer: RenderBlocks) =
|
||||
RenderUtils.renderSimpleBlockItem(block, metadata, renderer)
|
||||
|
||||
override def renderWorldBlock(world: IBlockAccess, x: Int, y: Int, z: Int, block: Block, modelId: Int, renderer: RenderBlocks) = {
|
||||
renderer.renderStandardBlock(block, x, y, z)
|
||||
for {
|
||||
blockCov <- Misc.asInstanceOpt(block, classOf[BlockCoverable[_]])
|
||||
face <- ForgeDirection.VALID_DIRECTIONS
|
||||
icon <- blockCov.getCoverIcon(world, x, y, z, face)
|
||||
if block.shouldSideBeRendered(world, x + face.offsetX, y + face.offsetY, z + face.offsetZ, face.ordinal())
|
||||
} ConnectedHelper.draw(face, 8).doDraw(ConnectedHelper.Vec3F(x, y, z), icon)
|
||||
true
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
package net.bdew.lib.gui
|
||||
|
||||
import net.bdew.lib.Client
|
||||
import net.minecraft.client.Minecraft
|
||||
import net.minecraft.client.renderer.texture.TextureMap
|
||||
import net.minecraft.util.{IIcon, ResourceLocation}
|
||||
@@ -29,7 +30,13 @@ class InterpolatedTexture(val texture: Texture, rect: Rect) extends Texture {
|
||||
def v2 = rect.y2 * (texture.v2 - texture.v1) + texture.v1
|
||||
}
|
||||
|
||||
class IconWrapper(val resource: ResourceLocation, val icon: IIcon) extends Texture {
|
||||
class IconWrapper(val resource: ResourceLocation, picon: IIcon) extends Texture {
|
||||
val icon = if (picon == null) {
|
||||
if (resource == Texture.ITEMS) Client.itemMissingIcon
|
||||
else if (resource == Texture.BLOCKS) Client.blockMissingIcon
|
||||
else sys.error("Attempt to create IconWrapper for null IIcon")
|
||||
} else picon
|
||||
|
||||
def u1 = icon.getMinU
|
||||
def u2 = icon.getMaxU
|
||||
def v1 = icon.getMinV
|
||||
|
||||
@@ -35,11 +35,11 @@ class WidgetFluidGauge(val rect: Rect, overlay: Texture, dslot: DataSlotTankBase
|
||||
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 = Texture(Texture.BLOCKS, fstack.getFluid.getStillIcon)
|
||||
if (fstack != null) {
|
||||
val color = Color.fromInt(Misc.getFluidColor(fstack))
|
||||
val icon = Texture(Texture.BLOCKS, Misc.getFluidIcon(fstack))
|
||||
var fillHeight = if (dslot.getCapacity > 0) rect.h * fstack.amount / dslot.getCapacity else 0
|
||||
var yStart: Int = 0
|
||||
val color = Color.fromInt(fstack.getFluid.getColor(fstack))
|
||||
|
||||
while (fillHeight > 0) {
|
||||
if (fillHeight > 16) {
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
* Copyright (c) bdew, 2013 - 2014
|
||||
* 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
|
||||
* http://bdew.net/minecraft-mod-public-license/
|
||||
*/
|
||||
|
||||
package net.bdew.lib.gui.widgets
|
||||
|
||||
import net.bdew.lib.gui._
|
||||
|
||||
case class WidgetSimpleIcon(rect: Rect, icon: Texture) extends Widget {
|
||||
override def draw(mouse: Point) = parent.drawTexture(rect, icon)
|
||||
}
|
||||
@@ -9,8 +9,8 @@
|
||||
|
||||
package net.bdew.lib.multiblock.network
|
||||
|
||||
import net.bdew.lib.network.Message
|
||||
import net.bdew.lib.network.BaseMessage
|
||||
|
||||
abstract class MsgOutputCfg extends Message {
|
||||
abstract class MsgOutputCfg extends BaseMessage[NetHandler.type] {
|
||||
val output: Int
|
||||
}
|
||||
@@ -9,4 +9,4 @@
|
||||
|
||||
package net.bdew.lib.network
|
||||
|
||||
abstract class Message extends Serializable
|
||||
abstract class BaseMessage[CH <: NetChannel] extends Serializable
|
||||
@@ -13,18 +13,49 @@ import java.util
|
||||
|
||||
import cpw.mods.fml.common.network.{FMLEmbeddedChannel, FMLOutboundHandler, NetworkRegistry}
|
||||
import cpw.mods.fml.relauncher.Side
|
||||
import io.netty.channel.{ChannelFutureListener, ChannelHandler}
|
||||
import io.netty.channel.{ChannelFutureListener, ChannelHandler, ChannelHandlerContext, SimpleChannelInboundHandler}
|
||||
import net.bdew.lib.{BdLib, Misc}
|
||||
import net.minecraft.entity.player.EntityPlayerMP
|
||||
import net.minecraft.network.NetHandlerPlayServer
|
||||
|
||||
class NetChannel(val name: String) {
|
||||
var channels: util.EnumMap[Side, FMLEmbeddedChannel] = null
|
||||
|
||||
type Message = BaseMessage[this.type]
|
||||
|
||||
object ServerHandler extends SimpleChannelInboundHandler[Message] {
|
||||
def channelRead0(ctx: ChannelHandlerContext, msg: Message) {
|
||||
try {
|
||||
val player = ctx.channel().attr(NetworkRegistry.NET_HANDLER).get.asInstanceOf[NetHandlerPlayServer].playerEntity
|
||||
if (serverChain.isDefinedAt(msg, player))
|
||||
serverChain(msg, player)
|
||||
else
|
||||
BdLib.logWarn("Unable to handle message from user %s: %s", player.getDisplayName, msg)
|
||||
} catch {
|
||||
case e: Throwable => BdLib.logErrorException("Error handling packet", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object ClientHandler extends SimpleChannelInboundHandler[Message] {
|
||||
def channelRead0(ctx: ChannelHandlerContext, msg: Message) {
|
||||
try {
|
||||
if (clientChain.isDefinedAt(msg))
|
||||
clientChain(msg)
|
||||
else
|
||||
BdLib.logWarn("Unable to handle message from server: %s", msg)
|
||||
} catch {
|
||||
case e: Throwable => BdLib.logErrorException("Error handling packet", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def init() {
|
||||
if (channels != null) sys.error("Attempted to initalize a channel twice (%s)".format(name))
|
||||
channels = NetworkRegistry.INSTANCE.newChannel(name, new SerializedMessageCodec)
|
||||
BdLib.logInfo("Initialized network channel '%s' for mod '%s'", name, Misc.getActiveModId)
|
||||
addHandler(Side.SERVER, new NetChannelServerHandler(this))
|
||||
addHandler(Side.CLIENT, new NetChannelClientHandler(this))
|
||||
addHandler(Side.SERVER, ServerHandler)
|
||||
addHandler(Side.CLIENT, ClientHandler)
|
||||
}
|
||||
|
||||
var clientChain = PartialFunction.empty[Message, Unit]
|
||||
@@ -38,7 +69,7 @@ class NetChannel(val name: String) {
|
||||
|
||||
private def addHandler(side: Side, handler: ChannelHandler) {
|
||||
val ch = channels.get(side)
|
||||
val name = ch.findChannelHandlerNameForType(classOf[SerializedMessageCodec])
|
||||
val name = ch.findChannelHandlerNameForType(classOf[SerializedMessageCodec[this.type]])
|
||||
ch.pipeline().addAfter(name, side + "Handler", handler)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) bdew, 2013 - 2014
|
||||
* 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.network
|
||||
|
||||
import io.netty.channel.{ChannelHandlerContext, SimpleChannelInboundHandler}
|
||||
import net.bdew.lib.BdLib
|
||||
|
||||
class NetChannelClientHandler(ch: NetChannel) extends SimpleChannelInboundHandler[Message] {
|
||||
def channelRead0(ctx: ChannelHandlerContext, msg: Message) {
|
||||
try {
|
||||
if (ch.clientChain.isDefinedAt(msg))
|
||||
ch.clientChain(msg)
|
||||
else
|
||||
BdLib.logWarn("Unable to handle message from server: %s", msg)
|
||||
} catch {
|
||||
case e: Throwable => BdLib.logErrorException("Error handling packet", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) bdew, 2013 - 2014
|
||||
* 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.network
|
||||
|
||||
import cpw.mods.fml.common.network.NetworkRegistry
|
||||
import io.netty.channel.{ChannelHandlerContext, SimpleChannelInboundHandler}
|
||||
import net.bdew.lib.BdLib
|
||||
import net.minecraft.network.NetHandlerPlayServer
|
||||
|
||||
class NetChannelServerHandler(ch: NetChannel) extends SimpleChannelInboundHandler[Message] {
|
||||
def channelRead0(ctx: ChannelHandlerContext, msg: Message) {
|
||||
try {
|
||||
val player = ctx.channel().attr(NetworkRegistry.NET_HANDLER).get.asInstanceOf[NetHandlerPlayServer].playerEntity
|
||||
if (ch.serverChain.isDefinedAt(msg, player))
|
||||
ch.serverChain(msg, player)
|
||||
else
|
||||
BdLib.logWarn("Unable to handle message from user %s: %s", player.getDisplayName, msg)
|
||||
} catch {
|
||||
case e: Throwable => BdLib.logErrorException("Error handling packet", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -21,8 +21,8 @@ import io.netty.handler.codec.MessageToMessageCodec
|
||||
import net.bdew.lib.BdLib
|
||||
|
||||
@Sharable
|
||||
class SerializedMessageCodec extends MessageToMessageCodec[FMLProxyPacket, Message] {
|
||||
def encode(ctx: ChannelHandlerContext, msg: Message, out: util.List[AnyRef]) {
|
||||
class SerializedMessageCodec[T <: NetChannel] extends MessageToMessageCodec[FMLProxyPacket, BaseMessage[T]] {
|
||||
def encode(ctx: ChannelHandlerContext, msg: BaseMessage[T], out: util.List[AnyRef]) {
|
||||
val buff = Unpooled.buffer()
|
||||
val writer = new ObjectOutputStream(new ByteBufOutputStream(buff))
|
||||
writer.writeObject(msg)
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (c) bdew, 2013 - 2014
|
||||
* 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
|
||||
* http://bdew.net/minecraft-mod-public-license/
|
||||
*/
|
||||
|
||||
package net.bdew.lib.player
|
||||
|
||||
import cpw.mods.fml.common.FMLCommonHandler
|
||||
import cpw.mods.fml.common.eventhandler.SubscribeEvent
|
||||
import cpw.mods.fml.common.gameevent.PlayerEvent._
|
||||
import net.bdew.lib.BdLib
|
||||
import net.minecraft.entity.player.EntityPlayer
|
||||
|
||||
import scala.collection.mutable
|
||||
|
||||
class PlayerCache[T] extends mutable.Map[EntityPlayer, T] {
|
||||
var map = Map.empty[EntityPlayer, T]
|
||||
|
||||
BdLib.onServerStarting.listen(x => map = map.empty)
|
||||
BdLib.onServerStopping.listen(x => map = map.empty)
|
||||
FMLCommonHandler.instance().bus().register(this)
|
||||
|
||||
def updateIfNeeded(p: EntityPlayer, v: T): Boolean = {
|
||||
if (map.get(p).contains(v)) {
|
||||
false
|
||||
} else {
|
||||
map += p -> v
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
def reset(p: EntityPlayer) {
|
||||
if (map.contains(p)) map -= p
|
||||
}
|
||||
|
||||
override def get(p: EntityPlayer) = map.get(p)
|
||||
|
||||
override def +=(kv: (EntityPlayer, T)) = {
|
||||
map += kv
|
||||
this
|
||||
}
|
||||
override def -=(key: EntityPlayer) = {
|
||||
map -= key
|
||||
this
|
||||
}
|
||||
|
||||
override def iterator = map.iterator
|
||||
|
||||
@SubscribeEvent
|
||||
def hadlePlayerLogout(ev: PlayerLoggedOutEvent) = reset(ev.player)
|
||||
|
||||
@SubscribeEvent
|
||||
def hadlePlayerChangedDimension(ev: PlayerChangedDimensionEvent) = reset(ev.player)
|
||||
|
||||
@SubscribeEvent
|
||||
def hadlePlayerRespawn(ev: PlayerRespawnEvent) = reset(ev.player)
|
||||
}
|
||||
@@ -1,213 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) bdew, 2013 - 2014
|
||||
* 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
|
||||
|
||||
/**
|
||||
* Generic Referende
|
||||
* Syntax: S:{modid}:{name}
|
||||
* Parser: [[net.bdew.lib.recipes.RecipeParser.specGenericStack]]
|
||||
* @param mod modId of owner mod
|
||||
* @param name name of the stack
|
||||
*/
|
||||
case class StackGeneric(mod: String, name: String) extends StackRef
|
||||
|
||||
/**
|
||||
* Block reference
|
||||
* Syntax: B:[{modid}:]{name} [@ {meta}]
|
||||
* Parser: [[net.bdew.lib.recipes.RecipeParser.specBlock]]
|
||||
* @param mod modId of owner mod, default is "minecraft"
|
||||
* @param name Registered name
|
||||
* @param meta Metadata / Damage
|
||||
*/
|
||||
case class StackBlock(mod: String, name: String, meta: Int) extends StackRef
|
||||
|
||||
/**
|
||||
* Item reference
|
||||
* Syntax: I:[{modid}:]{name} [@ {meta}]
|
||||
* Parser: [[net.bdew.lib.recipes.RecipeParser.specItem]]
|
||||
* @param mod modId of owner mod, default is "minecraft"
|
||||
* @param name Registered name
|
||||
* @param meta Metadata / Damage
|
||||
*/
|
||||
case class StackItem(mod: String, 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
|
||||
|
||||
/**
|
||||
* Base class for delayed statements (executed after everything is parsed)
|
||||
* Actual processing is in [[net.bdew.lib.recipes.RecipeLoader.processDelayedStatements]]
|
||||
*/
|
||||
abstract class DelayedStatement extends 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 DelayedStatement
|
||||
|
||||
/**
|
||||
* 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 DelayedStatement
|
||||
|
||||
/**
|
||||
* 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 api is loaded
|
||||
* Syntax: ifAPI {string} { {statements} } [else { {statements} }]
|
||||
* Parser: [[net.bdew.lib.recipes.RecipeParser.ifApi]]
|
||||
* @param mod API modid
|
||||
* @param thn Statements to run if present
|
||||
* @param els Statements to run otherwise
|
||||
*/
|
||||
case class StIfHaveAPI(mod: String, thn: List[Statement], els: List[Statement]) extends Statement
|
||||
|
||||
/**
|
||||
* Conditional block - checks if mod is loaded
|
||||
* Can contain only delayed statements
|
||||
* 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[DelayedStatement], els: List[DelayedStatement]) extends DelayedStatement
|
||||
|
||||
/**
|
||||
* Removes previously defined recieps for a specific result
|
||||
* @param res Recipes that produce this result will be cleared
|
||||
*/
|
||||
case class StClearRecipes(res: StackRef) extends Statement
|
||||
|
||||
/**
|
||||
* Base class for staments that represent a crafting recipe
|
||||
*/
|
||||
abstract class CraftingStatement extends DelayedStatement {
|
||||
def result: StackRef
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 result Result reference
|
||||
* @param cnt Number of output items
|
||||
*/
|
||||
case class StRecipeShaped(rec: Seq[String], result: StackRef, cnt: Int) extends CraftingStatement
|
||||
|
||||
/**
|
||||
* Shapeless recipe definition
|
||||
* Syntax: shapeless: {characters} => {result} [* {count}]
|
||||
* Parser: [[net.bdew.lib.recipes.RecipeParser.recipeShapeless]]
|
||||
*
|
||||
* @param rec Recipe pattehrn
|
||||
* @param result Result reference
|
||||
* @param cnt Number of output items
|
||||
*/
|
||||
case class StRecipeShapeless(rec: String, result: StackRef, cnt: Int) extends CraftingStatement
|
||||
|
||||
/**
|
||||
* Smelting recipe definition
|
||||
* Syntax: smelt: {input} => {output}, {XP}
|
||||
* Parser [[net.bdew.lib.recipes.RecipeParser.recipeSmelting]]
|
||||
*
|
||||
* @param in Input Stack
|
||||
* @param result Output Stack
|
||||
* @param cnt Output Count
|
||||
* @param xp XP for smelting
|
||||
*/
|
||||
case class StSmeltRecipe(in: StackRef, result: StackRef, cnt: Int, xp: Float) extends CraftingStatement
|
||||
|
||||
/**
|
||||
* Used in statement processing to abort the current statement and show an error without a stack trace
|
||||
*/
|
||||
class StatementError(msg: String) extends Exception(msg)
|
||||
@@ -21,7 +21,7 @@ import net.minecraftforge.oredict.{OreDictionary, ShapelessOreRecipe}
|
||||
/**
|
||||
* 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
|
||||
* Into a list of [[net.bdew.lib.recipes.ConfigStatement]] subclasses
|
||||
* That are then executed here
|
||||
*/
|
||||
|
||||
@@ -49,9 +49,9 @@ class RecipeLoader {
|
||||
def error(msg: String, params: Any*) = throw new StatementError(msg.format(params: _*))
|
||||
|
||||
/**
|
||||
* List of unprocessed delayed statements
|
||||
* List of unprocessed recipe statements
|
||||
*/
|
||||
var delayedStatements = List.empty[DelayedStatement]
|
||||
var recipeStatements = List.empty[RecipeStatement]
|
||||
|
||||
/**
|
||||
* Looks up a recipe component
|
||||
@@ -67,11 +67,10 @@ class RecipeLoader {
|
||||
/**
|
||||
* Resolve class name if it's a macro
|
||||
*/
|
||||
def getRealClassName(s: String): String = {
|
||||
if (s.startsWith("$")) {
|
||||
return currClassMacros(s.stripPrefix("$"))
|
||||
}
|
||||
return s
|
||||
def getRealClassName(s: String) = {
|
||||
if (s.startsWith("$"))
|
||||
currClassMacros(s.stripPrefix("$"))
|
||||
else s
|
||||
}
|
||||
/**
|
||||
* Sanitize items from reflection
|
||||
@@ -207,62 +206,83 @@ class RecipeLoader {
|
||||
return (comp, needOd)
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to remove recipes from lists
|
||||
* @param list list to check
|
||||
* @param res crafting result to remove
|
||||
* @return cleaned list
|
||||
*/
|
||||
def clearStatements(list: List[RecipeStatement], res: StackRef): List[RecipeStatement] = {
|
||||
list flatMap {
|
||||
case x: CraftingStatement =>
|
||||
if (res == x.result) {
|
||||
BdLib.logInfo("Removing recipe %s", this)
|
||||
None
|
||||
} else Some(x)
|
||||
case RsRecipes(inner) =>
|
||||
Some(RsRecipes(clearStatements(inner, res)))
|
||||
case RsConditional(cnd, thn, els) =>
|
||||
Some(RsConditional(cnd, clearStatements(thn, res), clearStatements(els, res)))
|
||||
case x => Some(x)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks a condition and returns the result
|
||||
*/
|
||||
def resolveCondition(cond: Condition): Boolean = cond match {
|
||||
case CndHaveMod(mod) =>
|
||||
Misc.haveModVersion(mod)
|
||||
case CndHaveAPI(api) =>
|
||||
ModAPIManager.INSTANCE.hasAPI(api)
|
||||
case CndHaveOD(od) =>
|
||||
OreDictionary.getOres(od).size() > 0
|
||||
case CndNOT(cnd) => !resolveCondition(cnd)
|
||||
case CndAND(c1, c2) => resolveCondition(c1) && resolveCondition(c2)
|
||||
case CndOR(c1, c2) => resolveCondition(c1) || resolveCondition(c2)
|
||||
case x =>
|
||||
error("Can't process %s - this is a programing bug!", x)
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a single statement, override this to add more statements
|
||||
* @param s The statement
|
||||
*/
|
||||
def processStatement(s: Statement): Unit = s match {
|
||||
case StIfHaveMod(mod, thn, els) =>
|
||||
if (Misc.haveModVersion(mod)) {
|
||||
BdLib.logInfo("ifMod: %s found", mod)
|
||||
processStatementsSafe(thn)
|
||||
def processConfigStatement(s: ConfigStatement): Unit = s match {
|
||||
case CsConditionalConfig(cnd, thn, els) =>
|
||||
if (resolveCondition(cnd)) {
|
||||
BdLib.logInfo("Condition %s - TRUE", cnd)
|
||||
processConfigStatementsSafe(thn)
|
||||
} else {
|
||||
BdLib.logInfo("ifMod: %s not found", mod)
|
||||
processStatementsSafe(els)
|
||||
BdLib.logInfo("Condition %s - FALSE", cnd)
|
||||
processConfigStatementsSafe(els)
|
||||
}
|
||||
|
||||
case StIfHaveAPI(mod, thn, els) =>
|
||||
if (ModAPIManager.INSTANCE.hasAPI(mod)) {
|
||||
BdLib.logInfo("ifAPI: %s found", mod)
|
||||
processStatementsSafe(thn)
|
||||
} else {
|
||||
BdLib.logInfo("ifAPI: %s not found", mod)
|
||||
processStatementsSafe(els)
|
||||
}
|
||||
|
||||
case StClearRecipes(res) =>
|
||||
case CsClearRecipes(res) =>
|
||||
BdLib.logInfo("Clearing recipes that produce %s", res)
|
||||
delayedStatements = delayedStatements.filter({
|
||||
x =>
|
||||
if (x.isInstanceOf[CraftingStatement])
|
||||
if (x.asInstanceOf[CraftingStatement].result == res) {
|
||||
BdLib.logInfo("Removing recipe %s", x)
|
||||
false
|
||||
} else true
|
||||
else true
|
||||
})
|
||||
recipeStatements = clearStatements(recipeStatements, res)
|
||||
|
||||
case x: DelayedStatement =>
|
||||
delayedStatements :+= x
|
||||
case CsRecipeBlock(lst) =>
|
||||
recipeStatements :+= RsRecipes(lst)
|
||||
|
||||
case x =>
|
||||
BdLib.logError("Can't process %s - this is a programing bug!", x)
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a single delayed statement
|
||||
* Process a single recipe statement
|
||||
* @param st The statement
|
||||
*/
|
||||
def processDelayedStatement(st: DelayedStatement) = st match {
|
||||
case StCharAssign(c, r) =>
|
||||
def processRecipeStatement(st: RecipeStatement) = st match {
|
||||
case RsCharAssign(c, r) =>
|
||||
currCharMap += (c -> r)
|
||||
BdLib.logInfo("Added %s = %s", c, r)
|
||||
|
||||
case StClassMacro(id, cls) =>
|
||||
case RsClassMacro(id, cls) =>
|
||||
currClassMacros += (id -> cls)
|
||||
BdLib.logInfo("Added def %s = %s", id, cls)
|
||||
|
||||
case StRecipeShaped(rec, res, cnt) =>
|
||||
case RsRecipeShaped(rec, res, cnt) =>
|
||||
BdLib.logInfo("Adding shaped recipe %s => %s * %d", rec, res, cnt)
|
||||
val (comp, needOd) = resolveRecipeComponents(rec.mkString(""))
|
||||
val resStack = getConcreteStack(res, cnt)
|
||||
@@ -279,7 +299,7 @@ class RecipeLoader {
|
||||
|
||||
BdLib.logInfo("Done... result=%s, od=%s", resStack, needOd)
|
||||
|
||||
case StRecipeShapeless(rec, res, cnt) =>
|
||||
case RsRecipeShapeless(rec, res, cnt) =>
|
||||
BdLib.logInfo("Adding shapeless recipe %s => %s * %d", rec, res, cnt)
|
||||
val (comp, needOd) = resolveRecipeComponents(rec)
|
||||
val resStack = getConcreteStack(res, cnt)
|
||||
@@ -297,7 +317,7 @@ class RecipeLoader {
|
||||
|
||||
BdLib.logInfo("Done... result=%s, od=%s", resStack, needOd)
|
||||
|
||||
case StSmeltRecipe(in, out, cnt, xp) =>
|
||||
case RsRecipeSmelting(in, out, cnt, xp) =>
|
||||
BdLib.logInfo("Adding smelting recipe %s => %s * %d (%f xp)", in, out, cnt, xp)
|
||||
val outStack = getConcreteStack(out, cnt)
|
||||
if (outStack.getItemDamage == OreDictionary.WILDCARD_VALUE) {
|
||||
@@ -309,36 +329,64 @@ class RecipeLoader {
|
||||
BdLib.logInfo("added %s -> %s", inStack, outStack)
|
||||
}
|
||||
|
||||
case StIfHaveOD(od, thn, els) =>
|
||||
if (OreDictionary.getOres(od).size() > 0) {
|
||||
BdLib.logInfo("ifOreDict: %s found".format(od))
|
||||
processDelayedStatementsSafe(thn)
|
||||
case RsConditional(cnd, thn, els) =>
|
||||
if (resolveCondition(cnd)) {
|
||||
BdLib.logInfo("Condition %s - TRUE", cnd)
|
||||
processRecipeStatementsInSubcontext(thn)
|
||||
} else {
|
||||
BdLib.logInfo("ifOreDict: %s not found".format(od))
|
||||
processDelayedStatementsSafe(els)
|
||||
BdLib.logInfo("Condition %s - FALSE", cnd)
|
||||
processRecipeStatementsInSubcontext(els)
|
||||
}
|
||||
|
||||
case RsRecipes(list) =>
|
||||
processRecipeStatementsInSubcontext(list)
|
||||
|
||||
case RsRegOredict(id, spec, wildcard) =>
|
||||
BdLib.logInfo("Registering ore dictionary entry: %s -> %s", spec, id)
|
||||
val stack = getConcreteStack(spec)
|
||||
if (wildcard) {
|
||||
BdLib.logInfo("Forcing wildcard damage (was %d)", stack.getItemDamage)
|
||||
stack.setItemDamage(OreDictionary.WILDCARD_VALUE)
|
||||
}
|
||||
BdLib.logInfo("Actual stack: %s", stack)
|
||||
OreDictionary.registerOre(id, stack)
|
||||
|
||||
case x =>
|
||||
BdLib.logError("Can't process %s - this is a programing bug!", x)
|
||||
}
|
||||
|
||||
/**
|
||||
* Process main delayed statements list, clear the list afterwards
|
||||
* Processes recipe statements in a new context
|
||||
* Any changes to mutable state will not persist when this method returns
|
||||
*/
|
||||
def processDelayedStatements() {
|
||||
BdLib.logInfo("Processing %d delayed statements", delayedStatements.size)
|
||||
processDelayedStatementsSafe(delayedStatements)
|
||||
delayedStatements = List.empty
|
||||
def processRecipeStatementsInSubcontext(list: List[RecipeStatement]) = {
|
||||
val oldCharMap = currCharMap
|
||||
val oldClassMacros = currClassMacros
|
||||
try {
|
||||
processRecipeStatementsSafe(list)
|
||||
} finally {
|
||||
currCharMap = oldCharMap
|
||||
currClassMacros = oldClassMacros
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a list of delayed statements and catch all exceptions
|
||||
* Process main recipe statements list, clear the list afterwards
|
||||
*/
|
||||
def processRecipeStatements() {
|
||||
BdLib.logInfo("Processing %d recipe statements", recipeStatements.size)
|
||||
processRecipeStatementsSafe(recipeStatements)
|
||||
recipeStatements = List.empty
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a list of recipe statements and catch all exceptions
|
||||
* @param list The list to process
|
||||
*/
|
||||
def processDelayedStatementsSafe(list: List[DelayedStatement]) {
|
||||
def processRecipeStatementsSafe(list: List[RecipeStatement]) {
|
||||
for (s <- list) {
|
||||
try {
|
||||
processDelayedStatement(s)
|
||||
processRecipeStatement(s)
|
||||
} catch {
|
||||
case e: StatementError =>
|
||||
BdLib.logError("Error while processing %s: %s", s, e.getMessage)
|
||||
@@ -349,13 +397,13 @@ class RecipeLoader {
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a list of statements and catch all exceptions
|
||||
* Process a list of config statements and catch all exceptions
|
||||
* @param r The list to process
|
||||
*/
|
||||
def processStatementsSafe(r: List[Statement]): Unit = {
|
||||
def processConfigStatementsSafe(r: List[ConfigStatement]): Unit = {
|
||||
for (s <- r) {
|
||||
try {
|
||||
processStatement(s)
|
||||
processConfigStatement(s)
|
||||
} catch {
|
||||
case e: StatementError =>
|
||||
BdLib.logError("Error while processing %s: %s", s, e.getMessage)
|
||||
@@ -369,7 +417,7 @@ class RecipeLoader {
|
||||
BdLib.logInfo("Starting parsing")
|
||||
val r = newParser().doParse(f)
|
||||
BdLib.logInfo("Processing %d statements", r.size)
|
||||
processStatementsSafe(r)
|
||||
processConfigStatementsSafe(r)
|
||||
BdLib.logInfo("Done")
|
||||
}
|
||||
}
|
||||
@@ -68,68 +68,95 @@ class RecipeParser extends JavaTokenParsers {
|
||||
// Spec with possible number of items
|
||||
def specWithCount = spec ~ ("*" ~> int).?
|
||||
|
||||
// === Conditions ===
|
||||
|
||||
def cndHaveMod = "HaveMod" ~> str ^^ CndHaveMod
|
||||
def cndHaveAPI = "HaveAPI" ~> str ^^ CndHaveAPI
|
||||
def cndHaveOD = "HaveOD" ~> str ^^ CndHaveOD
|
||||
|
||||
def cndNOT = "!" ~> condition ^^ CndNOT
|
||||
def cndOR = "(" ~> condition ~ "||" ~ condition <~ ")" ^^ { case c1 ~ or ~ c2 => CndOR(c1, c2) }
|
||||
def cndAND = "(" ~> condition ~ "&&" ~ condition <~ ")" ^^ { case c1 ~ and ~ c2 => CndAND(c1, c2) }
|
||||
|
||||
def condition: Parser[Condition] = cndHaveAPI | cndHaveMod | cndHaveOD | cndNOT | cndOR | cndAND
|
||||
|
||||
// === Blocks ===
|
||||
|
||||
def recipesSubBlock = "recipes" ~> ("{" ~> recipeStatements <~ "}") ^^ RsRecipes
|
||||
def recipesTopBlock = "recipes" ~> ("{" ~> recipeStatements <~ "}") ^^ CsRecipeBlock
|
||||
|
||||
def conditionRecipes = "if" ~> condition ~ ("{" ~> recipeStatements <~ "}") ~ ("else" ~> "{" ~> recipeStatements <~ "}").? ^^ {
|
||||
case cond ~ thn ~ els => new RsConditional(cond, thn, els.getOrElse(List.empty))
|
||||
}
|
||||
|
||||
def conditionConfig = "if" ~> condition ~ ("<<" ~> configStatements <~ ">>") ~ ("else" ~> "<<" ~> configStatements <~ ">>").? ^^ {
|
||||
case cond ~ thn ~ els => new CsConditionalConfig(cond, thn, els.getOrElse(List.empty))
|
||||
}
|
||||
|
||||
def conditionBridge = conditionRecipes ^^ { case cond => CsRecipeBlock(List(cond)) }
|
||||
|
||||
// === Statements ===
|
||||
|
||||
def charSpec = recipeChar ~ "=" ~ spec ^^ {
|
||||
case ch ~ eq ~ spec => new StCharAssign(ch, spec)
|
||||
case ch ~ eq ~ spec => new RsCharAssign(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 ifAPI = ("ifAPI" ~> str) ~ ("{" ~> statements <~ "}") ~ ("else" ~> "{" ~> statements <~ "}").? ^^ {
|
||||
case mod ~ thn ~ els => new StIfHaveAPI(mod, thn, els.getOrElse(List.empty[Statement]))
|
||||
}
|
||||
|
||||
def ifOreDict = ("ifOreDict" ~> str) ~ ("{" ~> delayedStatements <~ "}") ~ ("else" ~> "{" ~> delayedStatements <~ "}").? ^^ {
|
||||
case id ~ thn ~ els => new StIfHaveOD(id, thn, els.getOrElse(List.empty[DelayedStatement]))
|
||||
case id ~ (p ~ cl) => RsClassMacro(id, (p :+ cl).mkString("."))
|
||||
}
|
||||
|
||||
def recipeShaped3x3 = recipeTriplet ~ recipeTriplet ~ ("=>" ~> specWithCount) ~ recipeTriplet ^^ {
|
||||
case r1 ~ r2 ~ (res ~ n) ~ r3 => StRecipeShaped(Seq(r1, r2, r3), res, n.getOrElse(1))
|
||||
case r1 ~ r2 ~ (res ~ n) ~ r3 => RsRecipeShaped(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))
|
||||
case r1 ~ r2 ~ (res ~ n) => RsRecipeShaped(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))
|
||||
case r1 ~ r2 ~ r3 ~ (res ~ n) => RsRecipeShaped(Seq(r1, r2, r3), res, n.getOrElse(1))
|
||||
}
|
||||
|
||||
def recipeShapeless = "shapeless" ~> ":" ~> recipeChar.+ ~ ("=>" ~> specWithCount) ^^ {
|
||||
case r ~ (res ~ n) => StRecipeShapeless(r.mkString(""), res, n.getOrElse(1))
|
||||
case r ~ (res ~ n) => RsRecipeShapeless(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 recipeSmelting = "smelt" ~> ":" ~> spec ~ ("=>" ~> specWithCount) ~ ("+" ~> decimalNumber <~ "xp").? ^^ {
|
||||
case in ~ (out ~ n) ~ xp => RsRecipeSmelting(in, out, n.getOrElse(1), xp.getOrElse("0").toFloat)
|
||||
}
|
||||
|
||||
def clearRecipes = "clearRecipes" ~> ":" ~> spec ^^ { case sp => StClearRecipes(sp) }
|
||||
def regOreDict = "regOreDict" ~> ":" ~> spec ~ "@WILDCARD".? ~ ("=>" ~> str) ^^ {
|
||||
case spec ~ wildcard ~ id => RsRegOredict(id, spec, wildcard.isDefined)
|
||||
}
|
||||
|
||||
def delayedStatement: Parser[DelayedStatement] = (
|
||||
def clearRecipes = "clearRecipes" ~> ":" ~> spec ^^ { case sp => CsClearRecipes(sp) }
|
||||
|
||||
def recipeStatement: Parser[RecipeStatement] = (
|
||||
charSpec
|
||||
| classMacro
|
||||
| ifOreDict
|
||||
| recipesSubBlock
|
||||
| conditionRecipes
|
||||
| recipesSubBlock
|
||||
| recipeShaped3x3
|
||||
| recipeShaped2x2
|
||||
| recipeShaped9
|
||||
| recipeShapeless
|
||||
| recipeSmelting
|
||||
| regOreDict
|
||||
)
|
||||
|
||||
def statement: Parser[Statement] = delayedStatement | ifMod | ifAPI | clearRecipes
|
||||
def configStatement: Parser[ConfigStatement] = (
|
||||
recipesTopBlock
|
||||
| clearRecipes
|
||||
| conditionBridge
|
||||
| conditionConfig
|
||||
)
|
||||
|
||||
def statements = statement.*
|
||||
def delayedStatements = delayedStatement.*
|
||||
def configStatements = configStatement.*
|
||||
def recipeStatements = recipeStatement.*
|
||||
|
||||
def doParse(r: Reader): List[Statement] = {
|
||||
parseAll(statements, r) match {
|
||||
def doParse(r: Reader): List[ConfigStatement] = {
|
||||
parseAll(configStatements, r) match {
|
||||
case Success(res, next) => return res
|
||||
case NoSuccess(msg, next) => sys.error("Config parsing failed at %s: %s".format(next.pos, msg))
|
||||
}
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright (c) bdew, 2013 - 2014
|
||||
* 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
|
||||
* http://bdew.net/minecraft-mod-public-license/
|
||||
*/
|
||||
|
||||
package net.bdew.lib.recipes
|
||||
|
||||
import java.io._
|
||||
|
||||
import cpw.mods.fml.common.FMLCommonHandler
|
||||
import net.bdew.lib.BdLib
|
||||
|
||||
object RecipesHelper {
|
||||
/**
|
||||
* Perform full loading of a set of config
|
||||
* @param modName Name of the mod, used in logging an derrors
|
||||
* @param listResource Resource Name of the internal config list file
|
||||
* @param configDir Base path to user config giles
|
||||
* @param resBaseName Base resource name for internal config files
|
||||
* @param loader Loader instance
|
||||
*/
|
||||
def loadConfigs(modName: String, listResource: String, configDir: File, resBaseName: String, loader: RecipeLoader) {
|
||||
BdLib.logInfo("Loading internal config files for mod %s", modName)
|
||||
|
||||
val listReader = new BufferedReader(new InputStreamReader(getClass.getResourceAsStream(listResource)))
|
||||
val internals = Iterator.continually(listReader.readLine)
|
||||
.takeWhile(_ != null)
|
||||
.map(_.trim)
|
||||
.filterNot(_.startsWith("#"))
|
||||
.filterNot(_.isEmpty)
|
||||
.toList
|
||||
listReader.close()
|
||||
|
||||
|
||||
val overrideDir = new File(configDir, "overrides")
|
||||
if (!overrideDir.exists()) overrideDir.mkdir()
|
||||
|
||||
for (fileName <- internals) {
|
||||
val overrideFile = new File(overrideDir, fileName)
|
||||
if (overrideFile.exists()) {
|
||||
tryLoadConfig(new FileReader(overrideFile), overrideFile.getCanonicalPath, modName, loader)
|
||||
} else {
|
||||
val resname = resBaseName + fileName
|
||||
tryLoadConfig(new InputStreamReader(getClass.getResourceAsStream(resname)),
|
||||
getClass.getResource(resname).toString, modName, loader)
|
||||
}
|
||||
}
|
||||
|
||||
BdLib.logInfo("Loading user config files for mod %s", modName)
|
||||
|
||||
for (fileName <- configDir.list().sorted if fileName.endsWith(".cfg")) {
|
||||
val file = new File(configDir, fileName)
|
||||
if (file.canRead)
|
||||
tryLoadConfig(new FileReader(file), file.getCanonicalPath, modName, loader)
|
||||
}
|
||||
|
||||
BdLib.logInfo("Config loading for mod %s finished", modName)
|
||||
}
|
||||
|
||||
def tryLoadConfig(reader: Reader, path: String, modName: String, loader: RecipeLoader) {
|
||||
BdLib.logInfo("Loading config: %s", path)
|
||||
try {
|
||||
loader.load(reader)
|
||||
} catch {
|
||||
case e: Throwable =>
|
||||
FMLCommonHandler.instance().raiseException(e, "%s config loading failed in file %s: %s".format(modName, path, e.getMessage), true)
|
||||
} finally {
|
||||
reader.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
* Copyright (c) bdew, 2013 - 2014
|
||||
* 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
|
||||
|
||||
/**
|
||||
* Used in statement processing to abort the current statement and show an error without a stack trace
|
||||
*/
|
||||
class StatementError(msg: String) extends Exception(msg)
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) bdew, 2013 - 2014
|
||||
* 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.lang.reflect.Modifier
|
||||
|
||||
import net.minecraft.block.Block
|
||||
import net.minecraft.item.Item
|
||||
|
||||
import scala.reflect.ClassTag
|
||||
|
||||
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,62 @@
|
||||
/*
|
||||
* Copyright (c) bdew, 2013 - 2014
|
||||
* 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
|
||||
* http://bdew.net/minecraft-mod-public-license/
|
||||
*/
|
||||
|
||||
package net.bdew.lib.recipes
|
||||
|
||||
/**
|
||||
* Represents a condition, something that can be resolved to a boolean
|
||||
* Actual processing is in [[RecipeLoader.resolveCondition]]
|
||||
*
|
||||
* Naming convention: All subclasses are named CndFoo
|
||||
*/
|
||||
abstract class Condition
|
||||
|
||||
/**
|
||||
* True if mod is present
|
||||
* Syntax: HaveMod {string}
|
||||
* Parser: [[RecipeParser.cndHaveMod]]
|
||||
* @param mod mod id
|
||||
*/
|
||||
case class CndHaveMod(mod: String) extends Condition
|
||||
|
||||
/**
|
||||
* True if API is present
|
||||
* Syntax: HaveAPI {string}
|
||||
* Parser: [[RecipeParser.cndHaveAPI]]
|
||||
*/
|
||||
case class CndHaveAPI(api: String) extends Condition
|
||||
|
||||
/**
|
||||
* True if oredict entery is present
|
||||
* Syntax: HaveOD {string}
|
||||
* Parser: [[RecipeParser.cndHaveOD]]
|
||||
*/
|
||||
case class CndHaveOD(od: String) extends Condition
|
||||
|
||||
/**
|
||||
* Boolean NOT
|
||||
* Syntax: ! {condition}
|
||||
* Parser: [[RecipeParser.cndNOT]]
|
||||
*/
|
||||
case class CndNOT(cnd: Condition) extends Condition
|
||||
|
||||
/**
|
||||
* Boolean AND
|
||||
* Syntax: ( {condition} && {condition} )
|
||||
* Parser: [[RecipeParser.cndAND]]
|
||||
*/
|
||||
case class CndAND(c1: Condition, c2: Condition) extends Condition
|
||||
|
||||
/**
|
||||
* Boolean OR
|
||||
* Syntax: ( {condition} || {condition} )
|
||||
* Parser: [[RecipeParser.cndOR]]
|
||||
*/
|
||||
case class CndOR(c1: Condition, c2: Condition) extends Condition
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright (c) bdew, 2013 - 2014
|
||||
* 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
|
||||
* http://bdew.net/minecraft-mod-public-license/
|
||||
*/
|
||||
|
||||
package net.bdew.lib.recipes
|
||||
|
||||
/**
|
||||
* Represents something 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]]
|
||||
*
|
||||
* Naming convention: All subclasses are named StackFoo
|
||||
*/
|
||||
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
|
||||
|
||||
/**
|
||||
* Generic Referende
|
||||
* Syntax: S:{modid}:{name}
|
||||
* Parser: [[net.bdew.lib.recipes.RecipeParser.specGenericStack]]
|
||||
* @param mod modId of owner mod
|
||||
* @param name name of the stack
|
||||
*/
|
||||
case class StackGeneric(mod: String, name: String) extends StackRef
|
||||
|
||||
/**
|
||||
* Block reference
|
||||
* Syntax: B:[{modid}:]{name} [@ {meta}]
|
||||
* Parser: [[net.bdew.lib.recipes.RecipeParser.specBlock]]
|
||||
* @param mod modId of owner mod, default is "minecraft"
|
||||
* @param name Registered name
|
||||
* @param meta Metadata / Damage
|
||||
*/
|
||||
case class StackBlock(mod: String, name: String, meta: Int) extends StackRef
|
||||
|
||||
/**
|
||||
* Item reference
|
||||
* Syntax: I:[{modid}:]{name} [@ {meta}]
|
||||
* Parser: [[net.bdew.lib.recipes.RecipeParser.specItem]]
|
||||
* @param mod modId of owner mod, default is "minecraft"
|
||||
* @param name Registered name
|
||||
* @param meta Metadata / Damage
|
||||
*/
|
||||
case class StackItem(mod: String, 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
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (c) bdew, 2013 - 2014
|
||||
* 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
|
||||
* http://bdew.net/minecraft-mod-public-license/
|
||||
*/
|
||||
|
||||
package net.bdew.lib.recipes
|
||||
|
||||
/**
|
||||
* Base class for config statements
|
||||
* Actual processing is in [[RecipeLoader.processConfigStatement]]
|
||||
*/
|
||||
abstract class ConfigStatement
|
||||
|
||||
/**
|
||||
* Block of delayed statements, used to include recipe statements in config scope (which is always top level)
|
||||
* Syntax: recipes { {statements} }
|
||||
* Parser: [[RecipeParser.recipesTopBlock]]
|
||||
* Also used internally by the parser to bridge [[RsConditional]] to config scope in [[RecipeParser.conditionBridge]]
|
||||
* @param list Statements to run
|
||||
*/
|
||||
case class CsRecipeBlock(list: List[RecipeStatement]) extends ConfigStatement
|
||||
|
||||
/**
|
||||
* Conditional config block
|
||||
* Syntax: if {condition} << {statements} >> [else << {statements} >>]
|
||||
* Parser: [[RecipeParser.conditionConfig]]
|
||||
* @param cond Condition
|
||||
* @param thn Statements to run if true
|
||||
* @param els Statements to run otherwise
|
||||
*/
|
||||
case class CsConditionalConfig(cond: Condition, thn: List[ConfigStatement], els: List[ConfigStatement]) extends ConfigStatement
|
||||
|
||||
/**
|
||||
* Removes previously defined recieps for a specific result
|
||||
* Syntax: clearRecipes: {spec}
|
||||
* Parser: [[RecipeParser.clearRecipes]]
|
||||
* @param res Recipes that produce this result will be cleared
|
||||
*/
|
||||
case class CsClearRecipes(res: StackRef) extends ConfigStatement
|
||||
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Copyright (c) bdew, 2013 - 2014
|
||||
* 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
|
||||
* http://bdew.net/minecraft-mod-public-license/
|
||||
*/
|
||||
|
||||
package net.bdew.lib.recipes
|
||||
|
||||
/**
|
||||
* Base class for recipe statements
|
||||
* Actual processing is in [[net.bdew.lib.recipes.RecipeLoader.processRecipeStatements]]
|
||||
*
|
||||
* Naming convention: All subclasses are named RsFoo
|
||||
*/
|
||||
abstract class RecipeStatement
|
||||
|
||||
/**
|
||||
* Character assignment
|
||||
* Syntax: {char} = {ref}
|
||||
* Parser: [[net.bdew.lib.recipes.RecipeParser.charSpec]]
|
||||
* @param char Character to assign
|
||||
* @param spec ItemStack Reference
|
||||
*/
|
||||
case class RsCharAssign(char: Char, spec: StackRef) extends RecipeStatement
|
||||
|
||||
/**
|
||||
* Define class macro
|
||||
* Syntax: def {id} = {name}
|
||||
* Parser: [[net.bdew.lib.recipes.RecipeParser.classMacro]]
|
||||
* @param id Macro identifier
|
||||
* @param cls Class name
|
||||
*/
|
||||
case class RsClassMacro(id: String, cls: String) extends RecipeStatement
|
||||
|
||||
/**
|
||||
* Unconditional block - allows grouping and isolation of statements
|
||||
* Syntax: recipes { {statements} }
|
||||
* Parser: [[net.bdew.lib.recipes.RecipeParser.recipesSubBlock]]
|
||||
* @param list Statements to run
|
||||
*/
|
||||
case class RsRecipes(list: List[RecipeStatement]) extends RecipeStatement
|
||||
|
||||
/**
|
||||
* Conditional recipes block
|
||||
* Syntax: if {condition} recipes { {statements} } [else { {statements} }]
|
||||
* Parser: [[net.bdew.lib.recipes.RecipeParser.conditionRecipes]]
|
||||
* @param cond Condition
|
||||
* @param thn Statements to run if true
|
||||
* @param els Statements to run otherwise
|
||||
*/
|
||||
case class RsConditional(cond: Condition, thn: List[RecipeStatement], els: List[RecipeStatement]) extends RecipeStatement
|
||||
|
||||
/**
|
||||
* Base class for staments that represent a crafting recipe, that has a result
|
||||
*/
|
||||
abstract class CraftingStatement extends RecipeStatement {
|
||||
def result: StackRef
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 result Result reference
|
||||
* @param cnt Number of output items
|
||||
*/
|
||||
case class RsRecipeShaped(rec: Seq[String], result: StackRef, cnt: Int) extends CraftingStatement
|
||||
|
||||
/**
|
||||
* Shapeless recipe definition
|
||||
* Syntax: shapeless: {characters} => {result} [* {count}]
|
||||
* Parser: [[net.bdew.lib.recipes.RecipeParser.recipeShapeless]]
|
||||
*
|
||||
* @param rec Recipe pattehrn
|
||||
* @param result Result reference
|
||||
* @param cnt Number of output items
|
||||
*/
|
||||
case class RsRecipeShapeless(rec: String, result: StackRef, cnt: Int) extends CraftingStatement
|
||||
|
||||
/**
|
||||
* Smelting recipe definition
|
||||
* Syntax: smelt: {input} => {output}, {XP}
|
||||
* Parser [[net.bdew.lib.recipes.RecipeParser.recipeSmelting]]
|
||||
*
|
||||
* @param in Input Stack
|
||||
* @param result Output Stack
|
||||
* @param cnt Output Count
|
||||
* @param xp XP for smelting
|
||||
*/
|
||||
case class RsRecipeSmelting(in: StackRef, result: StackRef, cnt: Int, xp: Float) extends CraftingStatement
|
||||
|
||||
/**
|
||||
* Smelting recipe definition
|
||||
* Syntax: regOreDict: {reference} -> {name}
|
||||
* Parser [[net.bdew.lib.recipes.RecipeParser.regOreDict]]
|
||||
*/
|
||||
case class RsRegOredict(id: String, spec: StackRef, wildcard: Boolean) extends RecipeStatement
|
||||
|
||||
@@ -11,19 +11,19 @@ package net.bdew.lib.recipes.gencfg
|
||||
|
||||
import net.bdew.lib.gui.Color
|
||||
|
||||
abstract class CfgEntry
|
||||
abstract class ConfigEntry
|
||||
|
||||
case class EntryDouble(v: Double) extends CfgEntry
|
||||
case class EntryDouble(v: Double) extends ConfigEntry
|
||||
|
||||
case class EntryStr(v: String) extends CfgEntry
|
||||
case class EntryStr(v: String) extends ConfigEntry
|
||||
|
||||
case class EntryNumList(v: List[Double]) extends CfgEntry
|
||||
case class EntryNumList(v: List[Double]) extends ConfigEntry
|
||||
|
||||
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)))
|
||||
case class ConfigSection(pfx: String = "") extends ConfigEntry with Iterable[(String, ConfigEntry)] {
|
||||
var raw = Map.empty[String, ConfigEntry].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 iterator: Iterator[(String, ConfigEntry)] = raw.iterator
|
||||
def filterType[T <: ConfigEntry](cls: Class[T]): Iterable[(String, T)] = raw.filter(x => cls.isInstance(x._2)).map(x => x.asInstanceOf[(String, T)])
|
||||
|
||||
def keys = raw.keys
|
||||
|
||||
@@ -35,7 +35,7 @@ case class ConfigSection(pfx: String = "") extends CfgEntry with Iterable[(Strin
|
||||
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 set(id: String, v: ConfigEntry) = raw += id -> v
|
||||
|
||||
def getDouble(id: String) = rawget(id, classOf[EntryDouble]).v
|
||||
def getString(id: String) = rawget(id, classOf[EntryStr]).v
|
||||
|
||||
@@ -10,25 +10,26 @@
|
||||
package net.bdew.lib.recipes.gencfg
|
||||
|
||||
import net.bdew.lib.BdLib
|
||||
import net.bdew.lib.recipes.{RecipeLoader, Statement}
|
||||
import net.bdew.lib.recipes.{ConfigStatement, RecipeLoader}
|
||||
|
||||
trait GenericConfigLoader extends RecipeLoader {
|
||||
val cfgStore: ConfigSection
|
||||
|
||||
def processConfigStatement(section: ConfigSection, s: CfgStatement): Unit = s match {
|
||||
def processConfigStatement(section: ConfigSection, s: CfgEntry): Unit = s match {
|
||||
case CfgVal(id, v) =>
|
||||
BdLib.logInfo("Config: %s%s = %s", section.pfx, id, v)
|
||||
section.set(id, v)
|
||||
case CfgSub(id, st) => processConfigBlock(section.getOrAddSection(id), st)
|
||||
case CfgSection(id, st) => processConfigBlock(section.getOrAddSection(id), st)
|
||||
case x =>
|
||||
BdLib.logError("Can't process %s - this is a programing bug!", x)
|
||||
}
|
||||
|
||||
def processConfigBlock(view: ConfigSection, block: List[CfgStatement]) = for (s <- block) processConfigStatement(view, s)
|
||||
def processConfigBlock(view: ConfigSection, block: List[CfgEntry]): Unit =
|
||||
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)
|
||||
override def processConfigStatement(s: ConfigStatement) = s match {
|
||||
case CsCfgSection(id, st) => processConfigBlock(cfgStore.getOrAddSection(id), st)
|
||||
case _ => super.processConfigStatement(s)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ package net.bdew.lib.recipes.gencfg
|
||||
import net.bdew.lib.recipes.RecipeParser
|
||||
|
||||
trait GenericConfigParser extends RecipeParser {
|
||||
override def statement = statementCfg | super.statement
|
||||
override def configStatement = statementCfg | super.configStatement
|
||||
|
||||
// Hex variant must come before decimalNumber, otherwise the parser breaks
|
||||
def signedNumber = (
|
||||
@@ -21,17 +21,21 @@ trait GenericConfigParser extends RecipeParser {
|
||||
| ("-" ~> decimalNumber) ^^ { case x => -x.toDouble }
|
||||
)
|
||||
|
||||
def cfgStatementNum = str ~ "=" ~ signedNumber ^^ { case id ~ eq ~ n => CfgVal(id, EntryDouble(n.toDouble)) }
|
||||
def cfgStatementStr = str ~ "=" ~ str ^^ { case id ~ eq ~ s => CfgVal(id, EntryStr(s)) }
|
||||
def cfgStatementNumList = str ~ ("=" ~> "{" ~> signedNumber.* <~ "}") ^^ { case id ~ l => CfgVal(id, EntryNumList(l)) }
|
||||
def cfgStatementSub = cfgBlock ^^ { case (id, st) => CfgSub(id, st) }
|
||||
def cvNum = signedNumber ^^ EntryDouble
|
||||
def cvStr = str ^^ EntryStr
|
||||
def cvNumList = "=" ~> "{" ~> signedNumber.* <~ "}" ^^ EntryNumList
|
||||
|
||||
def cfgStatement = cfgStatementNum | cfgStatementStr | cfgStatementSub | cfgStatementNumList
|
||||
def cfgValue = cvNum | cvStr | cvNumList
|
||||
|
||||
def ceSub = cfgBlock ^^ { case (id, st) => CfgSection(id, st) }
|
||||
def ceAssign = str ~ "=" ~ cfgValue ^^ { case k ~ eq ~ v => CfgVal(k, v) }
|
||||
|
||||
def cfgEntry = ceSub | ceAssign
|
||||
|
||||
// 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" ~> str ~ ("{" ~> cfgStatement.* <~ "}") ^^ { case id ~ st => (id, st) }
|
||||
def cfgBlock: Parser[(String, List[CfgEntry])] =
|
||||
"cfg" ~> str ~ ("{" ~> cfgEntry.* <~ "}") ^^ { case id ~ st => (id, st) }
|
||||
|
||||
def statementCfg = cfgBlock ^^ { case (id, st) => StCfg(id, st) }
|
||||
def statementCfg = cfgBlock ^^ { case (id, st) => CsCfgSection(id, st) }
|
||||
}
|
||||
+5
-5
@@ -9,15 +9,15 @@
|
||||
|
||||
package net.bdew.lib.recipes.gencfg
|
||||
|
||||
import net.bdew.lib.recipes.Statement
|
||||
import net.bdew.lib.recipes.ConfigStatement
|
||||
|
||||
abstract class CfgStatement
|
||||
abstract class CfgEntry
|
||||
|
||||
case class CfgVal(id: String, value: CfgEntry) extends CfgStatement
|
||||
case class CfgVal(id: String, value: ConfigEntry) extends CfgEntry
|
||||
|
||||
case class CfgSub(id: String, vals: List[CfgStatement]) extends CfgStatement
|
||||
case class CfgSection(id: String, vals: List[CfgEntry]) extends CfgEntry
|
||||
|
||||
case class StCfg(id: String, vals: List[CfgStatement]) extends Statement
|
||||
case class CsCfgSection(id: String, vals: List[CfgEntry]) extends ConfigStatement
|
||||
|
||||
|
||||
|
||||
@@ -10,14 +10,14 @@
|
||||
package net.bdew.lib.recipes.lootlist
|
||||
|
||||
import net.bdew.lib.recipes.StackRef
|
||||
import net.bdew.lib.recipes.gencfg.CfgEntry
|
||||
import net.bdew.lib.recipes.gencfg.ConfigEntry
|
||||
|
||||
/**
|
||||
* Allos definition of random-weighted loot/drop lists in config sections
|
||||
* Allows definition of random-weighted loot/drop lists in config sections
|
||||
* @param list List on (chance percent, stack reference) pairs, resolve to
|
||||
* real ItemStacks with LootListLoader.resolveLootList
|
||||
*/
|
||||
case class EntryLootList(list: List[(Int, StackRef)]) extends CfgEntry
|
||||
case class EntryLootList(list: List[(Int, StackRef)]) extends ConfigEntry
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -9,17 +9,18 @@
|
||||
|
||||
package net.bdew.lib.recipes.lootlist
|
||||
|
||||
import net.bdew.lib.recipes.gencfg.{CfgVal, GenericConfigParser}
|
||||
import net.bdew.lib.recipes.gencfg.GenericConfigParser
|
||||
|
||||
/**
|
||||
* Parser mixin for loot lists
|
||||
* ident: DropsList(
|
||||
* ident = DropsList(
|
||||
* {chance}% {stackRef}
|
||||
* ...
|
||||
* )
|
||||
*/
|
||||
trait LootListParser extends GenericConfigParser {
|
||||
def dropsEntry = (wholeNumber <~ "%") ~ spec ^^ { case n ~ s => (n.toInt, s) }
|
||||
def cfgDrops = ident ~ (":" ~> "DropsList" ~> "(" ~> dropsEntry.* <~ ")") ^^ { case id ~ a => CfgVal(id, EntryLootList(a)) }
|
||||
override def cfgStatement = cfgDrops | super.cfgStatement
|
||||
def ceDrops = "DropsList" ~> "(" ~> dropsEntry.* <~ ")" ^^ EntryLootList
|
||||
override def cfgValue = ceDrops | super.cfgValue
|
||||
}
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright (c) bdew, 2013 - 2014
|
||||
* 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
|
||||
* http://bdew.net/minecraft-mod-public-license/
|
||||
*/
|
||||
|
||||
package net.bdew.lib.render
|
||||
|
||||
import cpw.mods.fml.client.registry.{ISimpleBlockRenderingHandler, RenderingRegistry}
|
||||
|
||||
abstract class BaseBlockRenderHandler extends ISimpleBlockRenderingHandler {
|
||||
val id = RenderingRegistry.getNextAvailableRenderId
|
||||
RenderingRegistry.registerBlockHandler(this)
|
||||
|
||||
override def shouldRender3DInInventory(modelId: Int) = true
|
||||
override def getRenderId = id
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (c) bdew, 2013 - 2014
|
||||
* 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
|
||||
* http://bdew.net/minecraft-mod-public-license/
|
||||
*/
|
||||
|
||||
package net.bdew.lib.render
|
||||
|
||||
import net.minecraft.block.Block
|
||||
import net.minecraft.client.renderer.{RenderBlocks, Tessellator}
|
||||
import net.minecraftforge.common.util.ForgeDirection
|
||||
import org.lwjgl.opengl.GL11
|
||||
|
||||
object RenderUtils {
|
||||
/**
|
||||
* Render a single item side
|
||||
*/
|
||||
def doRenderItemSide(d: ForgeDirection, r: RenderBlocks, block: Block, meta: Int) = {
|
||||
val icon = r.getBlockIconFromSideAndMetadata(block, d.ordinal(), meta)
|
||||
Tessellator.instance.setNormal(d.offsetX, d.offsetY, d.offsetZ)
|
||||
d match {
|
||||
case ForgeDirection.DOWN => r.renderFaceYNeg(block, 0.0D, 0.0D, 0.0D, icon)
|
||||
case ForgeDirection.UP => r.renderFaceYPos(block, 0.0D, 0.0D, 0.0D, icon)
|
||||
case ForgeDirection.NORTH => r.renderFaceZNeg(block, 0.0D, 0.0D, 0.0D, icon)
|
||||
case ForgeDirection.SOUTH => r.renderFaceZPos(block, 0.0D, 0.0D, 0.0D, icon)
|
||||
case ForgeDirection.WEST => r.renderFaceXNeg(block, 0.0D, 0.0D, 0.0D, icon)
|
||||
case ForgeDirection.EAST => r.renderFaceXPos(block, 0.0D, 0.0D, 0.0D, icon)
|
||||
case _ => sys.error("Invalid side")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a simple block as an item (for gui, item entities etc.)
|
||||
*/
|
||||
def renderSimpleBlockItem(block: Block, metadata: Int, renderer: RenderBlocks) {
|
||||
val T = Tessellator.instance
|
||||
GL11.glTranslatef(-0.5F, -0.5F, -0.5F)
|
||||
for (side <- ForgeDirection.VALID_DIRECTIONS) {
|
||||
T.startDrawingQuads()
|
||||
doRenderItemSide(side, renderer, block, metadata)
|
||||
T.draw()
|
||||
}
|
||||
GL11.glTranslatef(0.5F, 0.5F, 0.5F)
|
||||
}
|
||||
}
|
||||
@@ -9,32 +9,15 @@
|
||||
|
||||
package net.bdew.lib.render.connected
|
||||
|
||||
import cpw.mods.fml.client.registry.{ISimpleBlockRenderingHandler, RenderingRegistry}
|
||||
import net.bdew.lib.block.BlockRef
|
||||
import net.bdew.lib.render.{BaseBlockRenderHandler, RenderUtils}
|
||||
import net.minecraft.block.Block
|
||||
import net.minecraft.client.renderer.{RenderBlocks, Tessellator}
|
||||
import net.minecraft.world.IBlockAccess
|
||||
import net.minecraftforge.common.util.ForgeDirection
|
||||
import org.lwjgl.opengl.GL11
|
||||
|
||||
object ConnectedRenderer extends ISimpleBlockRenderingHandler {
|
||||
val id = RenderingRegistry.getNextAvailableRenderId
|
||||
RenderingRegistry.registerBlockHandler(this)
|
||||
|
||||
def doRenderItemSide(d: ForgeDirection, r: RenderBlocks, block: Block, meta: Int) = {
|
||||
val icon = r.getBlockIconFromSideAndMetadata(block, d.ordinal(), meta)
|
||||
Tessellator.instance.setNormal(d.offsetX, d.offsetY, d.offsetZ)
|
||||
d match {
|
||||
case ForgeDirection.DOWN => r.renderFaceYNeg(block, 0.0D, 0.0D, 0.0D, icon)
|
||||
case ForgeDirection.UP => r.renderFaceYPos(block, 0.0D, 0.0D, 0.0D, icon)
|
||||
case ForgeDirection.NORTH => r.renderFaceZNeg(block, 0.0D, 0.0D, 0.0D, icon)
|
||||
case ForgeDirection.SOUTH => r.renderFaceZPos(block, 0.0D, 0.0D, 0.0D, icon)
|
||||
case ForgeDirection.WEST => r.renderFaceXNeg(block, 0.0D, 0.0D, 0.0D, icon)
|
||||
case ForgeDirection.EAST => r.renderFaceXPos(block, 0.0D, 0.0D, 0.0D, icon)
|
||||
case _ => sys.error("Invalid side")
|
||||
}
|
||||
}
|
||||
|
||||
object ConnectedRenderer extends BaseBlockRenderHandler {
|
||||
override def renderInventoryBlock(block: Block, metadata: Int, modelID: Int, renderer: RenderBlocks) {
|
||||
val tessellator = Tessellator.instance
|
||||
GL11.glTranslatef(-0.5F, -0.5F, -0.5F)
|
||||
@@ -43,8 +26,7 @@ object ConnectedRenderer extends ISimpleBlockRenderingHandler {
|
||||
|
||||
for (side <- ForgeDirection.VALID_DIRECTIONS) {
|
||||
tessellator.startDrawingQuads()
|
||||
doRenderItemSide(side, renderer, block, metadata)
|
||||
val m = ConnectedHelper.brightnessMultiplier(side)
|
||||
RenderUtils.doRenderItemSide(side, renderer, block, metadata)
|
||||
ConnectedHelper.draw(side, 8).doDraw(ConnectedHelper.Vec3F(0, 0, 0), edge)
|
||||
tessellator.draw()
|
||||
}
|
||||
@@ -105,9 +87,6 @@ object ConnectedRenderer extends ISimpleBlockRenderingHandler {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override def shouldRender3DInInventory(modelId: Int) = true
|
||||
override def getRenderId = id
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user