Compare commits

...
15 Commits
Author SHA1 Message Date
bdew 8bbab862ab Added RecipesHelper with some shared code for config system loading 2014-10-19 17:16:59 +03:00
bdew 9e83d04487 Build with newer forge 2014-10-19 17:16:15 +03:00
bdew 9202b27340 Added renderer for covers (to allow partially showing the underlying texture) - bdew/gendustry#57 2014-10-15 12:09:08 +03:00
bdew 70ee9fabd6 Added BaseBlockRenderHandler and RenderUtils (some common code moved there) 2014-10-15 12:09:08 +03:00
bdew 78d9bed924 Merge pull request #7 from nalimleinad/mc1710
Create cs_CZ.lang
2014-10-14 13:44:19 +03:00
nalimleinad 92517cdcec Create cs_CZ.lang 2014-10-13 15:30:59 +02:00
bdew bcb8edc8a5 Improved handling of missing icons of fluids and in Texture class 2014-10-08 12:11:53 +03:00
bdew 9a837361e7 /dumpregistry will now show actual items registered in OD 2014-10-06 13:51:40 +03:00
bdew 5ae0461f10 Recipe parser/loader rework, see http://bdew.net/bacon/ for description of new format 2014-10-06 13:51:38 +03:00
bdew b3f8fb3c56 Added PlayerCache - a generic player->whatever map that auto-clears on server restart, logoff, respawn, etc. 2014-09-23 14:12:13 +03:00
bdew 023ae4d77f Added another version of Misc.asInstanceOpt that's easier to use with map, etc. 2014-09-23 14:12:13 +03:00
bdew b1e0e70fc4 Added WidgetSimpleIcon 2014-09-23 14:12:13 +03:00
bdew 5f01716310 Made network message type bound to a specific channel, this should give compile-time errors for sending messages on the wrong channel. Messages should now inherit from YourChannelObject.Message 2014-09-23 14:12:13 +03:00
bdew 0976fb4acc Merge pull request #5 from ViKaleidoscope/patch-1
Create zh_CN.lang
2014-09-19 09:25:35 +03:00
∑( ° △ °|||) 4effeafbb7 Create zh_CN.lang 2014-09-19 12:54:59 +08:00
38 changed files with 932 additions and 485 deletions

No files matched your search

+2 -2
View File
@@ -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)
}
+19
View File
@@ -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ý
+18
View File
@@ -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=空
+10 -1
View File
@@ -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)
}
}
+5
View File
@@ -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)
+6 -1
View File
@@ -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")
+21 -1
View File
@@ -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
}
+11 -5
View File
@@ -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
}
}
+8 -1
View File
@@ -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
+35 -4
View File
@@ -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)
+61
View File
@@ -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)
}
-213
View File
@@ -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)
+109 -61
View File
@@ -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")
}
}
+55 -28
View File
@@ -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)
-44
View File
@@ -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) }
}
@@ -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
}
+48
View File
@@ -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
}