Preparing for public release

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

No files matched your search

+9
View File
@@ -0,0 +1,9 @@
/.gradle
/build
/deps
/eclipse
/out
*.ipr
*.iml
*.iws
+87
View File
@@ -0,0 +1,87 @@
Minecraft Mod Public License
============================
Version 1.0.1
0. Definitions
--------------
Minecraft: Denotes a copy of the Minecraft game licensed by Mojang AB
User: Anybody that interacts with the software in one of the following ways:
- play
- decompile
- recompile or compile
- modify
- distribute
Mod: The mod code designated by the present license, in source form, binary
form, as obtained standalone, as part of a wider distribution or resulting from
the compilation of the original or modified sources.
Dependency: Code required for the mod to work properly. This includes
dependencies required to compile the code as well as any file or modification
that is explicitely or implicitely required for the mod to be working.
1. Scope
--------
The present license is granted to any user of the mod. As a prerequisite,
a user must own a legally acquired copy of Minecraft
2. Liability
------------
This mod is provided 'as is' with no warranties, implied or otherwise. The owner
of this mod takes no responsibility for any damages incurred from the use of
this mod. This mod alters fundamental parts of the Minecraft game, parts of
Minecraft may not work with this mod installed. All damages caused from the use
or misuse of this mad fall on the user.
3. Play rights
--------------
The user is allowed to install this mod on a client or a server and to play
without restriction.
4. Modification rights
----------------------
The user has the right to decompile the source code, look at either the
decompiled version or the original source code, and to modify it.
5. Derivation rights
--------------------
The user has the rights to derive code from this mod, that is to say to
write code that extends or instanciate the mod classes or interfaces, refer to
its objects, or calls its functions. This code is known as "derived" code, and
can be licensed under a license different from this mod.
6. Distribution of original or modified copy rights
---------------------------------------------------
Is subject to distribution rights this entire mod in its various forms. This
include:
- original binary or source forms of this mod files
- modified versions of these binaries or source files, as well as binaries
resulting from source modifications
- patch to its source or binary files
- any copy of a portion of its binary source files
The user is allowed to redistribute this mod partially, in totality, or
included in a distribution.
When distributing binary files, the user must provide means to obtain its
entire set of sources or modified sources at no costs.
All distributions of this mod must remain licensed under the MMPL.
All dependencies that this mod have on other mods or classes must be licensed
under conditions comparable to this version of MMPL, with the exception of the
Minecraft code and the mod loading framework (e.g. ModLoader, ModLoaderMP or
Bukkit).
Modified version of binaries and sources, as well as files containing sections
copied from this mod, should be distributed under the terms of the present
license.
+112
View File
@@ -0,0 +1,112 @@
buildscript {
repositories {
mavenCentral()
maven {
name = "bdew"
url = "http://jenkins.bdew.net/maven"
}
maven {
name = "forge"
url = "http://files.minecraftforge.net/maven"
}
}
dependencies {
classpath 'net.minecraftforge.gradle:ForgeGradle:1.0-SNAPSHOT'
}
}
apply plugin: 'forge'
apply plugin: 'scala'
version = "0.9.0"
if (project.hasProperty('buildnum')) {
project.version = project.version + '.' + project.buildnum
} else {
project.version = project.version + '-dev'
}
group = "net.bdew"
archivesBaseName = "bdlib"
minecraft {
version = "1.6.4-9.11.1.964"
}
import org.apache.tools.ant.filters.ReplaceTokens
def myTokens = [BdLibVer: project.version]
sourceSets {
main {
scala {
srcDir 'src'
}
resources {
srcDir 'resources'
}
}
processed {
scala {
srcDir 'build/stage'
}
}
}
task stage(type: Sync) {
from sourceSets.main.scala
into 'build/stage'
filter(ReplaceTokens, tokens: myTokens)
}
compileScala {
source = sourceSets.processed.scala
dependsOn stage
}
processResources {
from(sourceSets.main.resources.srcDirs) {
include 'mcmod.info'
filter(ReplaceTokens, tokens: myTokens)
}
from(sourceSets.main.resources.srcDirs) {
exclude 'mcmod.info'
}
}
task sourceJar(type: Jar) {
from sourceSets.main.allSource
}
task deobfJar(type: Jar) {
from sourceSets.main.output
}
jar {
appendix = 'universal'
}
artifacts {
archives sourceJar
archives deobfJar
}
apply plugin: 'maven-publish'
publishing {
publications {
maven(MavenPublication) {
artifact deobfJar
artifact sourceJar {
classifier "sources"
}
}
}
repositories {
maven {
url "file://var/www/maven"
}
}
}
Binary file not shown.
+6
View File
@@ -0,0 +1,6 @@
#Thu Nov 28 11:30:59 IST 2013
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=http\://services.gradle.org/distributions/gradle-1.9-bin.zip
Vendored
+164
View File
@@ -0,0 +1,164 @@
#!/usr/bin/env bash
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn ( ) {
echo "$*"
}
die ( ) {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
esac
# For Cygwin, ensure paths are in UNIX format before anything is touched.
if $cygwin ; then
[ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
fi
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >&-
APP_HOME="`pwd -P`"
cd "$SAVED" >&-
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
function splitJvmOpts() {
JVM_OPTS=("$@")
}
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
Vendored
+90
View File
@@ -0,0 +1,90 @@
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windowz variants
if not "%OS%" == "Windows_NT" goto win9xME_args
if "%@eval[2+2]" == "4" goto 4NT_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
goto execute
:4NT_args
@rem Get arguments from the 4NT Shell from JP Software
set CMD_LINE_ARGS=%$
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega
+20
View File
@@ -0,0 +1,20 @@
[
{
"modid": "bdlib",
"name": "BD Lib",
"description": "",
"version": "@BdLibVer@",
"url": "bdew.net/mods/",
"updateUrl": "",
"authorList": [
"bdew"
],
"credits": "",
"logoFile": "",
"screenshots": [
],
"parent":"",
"dependencies": [
]
}
]
+11
View File
@@ -0,0 +1,11 @@
package net.bdew.lib
import cpw.mods.fml.common.Mod
import cpw.mods.fml.common.event.FMLPreInitializationEvent
@Mod(modid = "bdlib", version = "@BdLibVer@", modLanguage = "scala")
object BdLib {
def preInit(ev: FMLPreInitializationEvent) {
ev.getModLog.info("bdlib @BdLibVer@ loaded")
}
}
+34
View File
@@ -0,0 +1,34 @@
/*
* Copyright (c) bdew, 2013
* https://github.com/bdew/bdlib
*
* This mod is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt
*/
package net.bdew.lib
class EventBase[T] extends {
var listeners = Seq.empty[T]
def listen(x: T) = listeners :+= x
def hasListeners = listeners.size > 0
}
class Event0 extends EventBase[() => Unit] {
def trigger() = for (x <- listeners) x()
}
class Event1[T] extends EventBase[(T) => Unit] {
def trigger(p1: T) = for (x <- listeners) x(p1)
}
class Event2[T, R] extends EventBase[(T, R) => Unit] {
def trigger(p1: T, p2: R) = for (x <- listeners) x(p1, p2)
}
object Event {
def apply(t: Unit) = new Event0
def apply[T] = new Event1[T]
def apply[T, R] = new Event2[T, R]
}
+66
View File
@@ -0,0 +1,66 @@
/*
* Copyright (c) bdew, 2013
* https://github.com/bdew/bdlib
*
* This mod is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt
*/
package net.bdew.lib
import cpw.mods.fml.common.registry.GameRegistry
import net.minecraft.nbt.{NBTTagCompound, NBTTagList}
import net.minecraft.util.StatCollector
import net.minecraft.item.ItemStack
import cpw.mods.fml.common.versioning.{ArtifactVersion, VersionParser}
import cpw.mods.fml.common.Loader
import net.minecraftforge.oredict.ShapedOreRecipe
object Misc {
def iterNbtList[X](list: NBTTagList) =
for (i <- 0 until list.tagCount()) yield list.tagAt(i).asInstanceOf[X]
def toLocal(s: String) = StatCollector.translateToLocal(s)
def toLocalF(s: String, params: Any*) = StatCollector.translateToLocal(s).format(params: _*)
def flattenRecipe(pattern: Seq[String], items: Map[Char, AnyRef]) =
pattern ++ items.map {
case (k, v) => Seq(new Character(k), v)
}.flatten
def wrapTag(n: String, f: (NBTTagCompound) => Any)(t: NBTTagCompound) {
val p = t.getCompoundTag(n)
f(p)
t.setCompoundTag(n, p)
}
def addRecipe(result: ItemStack, pattern: Seq[String], items: Map[Char, AnyRef]) =
GameRegistry.addRecipe(result, flattenRecipe(pattern, items): _*)
def addRecipeOD(result: ItemStack, pattern: Seq[String], items: Map[Char, AnyRef]) =
GameRegistry.addRecipe(new ShapedOreRecipe(result, flattenRecipe(pattern, items): _*))
def min[T](vals: T*)(implicit o: Ordering[T]): T = vals.min(o)
def max[T](vals: T*)(implicit o: Ordering[T]): T = vals.max(o)
def clamp[T](value: T, min: T, max: T)(implicit o: Ordering[T]): T = if (o.gt(value,max)) max else if (o.lt(value,min)) min else value
def iterSome[T](list: Seq[T], indexes: Iterable[Int]): Iterable[T] = for (i <- indexes) yield list(i)
def iterSomeEnum[T](list: Seq[T], indexes: Iterable[Int]): Iterable[(Int, T)] = for (i <- indexes) yield i -> list(i)
def filterType[T](from: Iterable[_], cls: Class[T]) = from.filter(cls.isInstance).asInstanceOf[Iterable[T]]
def haveModVersion(spec: String): Boolean = {
val req = VersionParser.parseVersionReference(spec)
val modid = req.getLabel
if (!Loader.instance.getIndexedModList.containsKey(modid)) return false
val found: ArtifactVersion = Loader.instance.getIndexedModList.get(modid).getProcessedVersion
if (found == null || !req.containsVersion(found)) return false
return true
}
}
+34
View File
@@ -0,0 +1,34 @@
/*
* Copyright (c) bdew, 2013
* https://github.com/bdew/bdlib
*
* This mod is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt
*/
package net.bdew.lib.block
import net.minecraft.block.{ITileEntityProvider, Block}
import net.minecraft.world.{IBlockAccess, World}
import net.minecraft.tileentity.TileEntity
import cpw.mods.fml.common.FMLCommonHandler
trait HasTE[T] extends Block with ITileEntityProvider {
val TEClass: Class[_ <: TileEntity]
def createNewTileEntity(world: World): TileEntity = TEClass.newInstance()
def getTE(w: IBlockAccess, x: Int, y: Int, z: Int): T = {
var t = w.getBlockTileEntity(x, y, z)
if ((t == null) || !TEClass.isInstance(t)) {
FMLCommonHandler.instance().getFMLLogger.severe("Tile entity for block %s at (%d,%d,%d) is corrupt or missing - recreating".format(this, x, y, z))
w match {
case ww: World =>
t = createNewTileEntity(ww)
ww.setBlockTileEntity(x, y, z, t)
case _ =>
sys.error("Unable to recreate TE")
}
}
return t.asInstanceOf[T]
}
}
@@ -0,0 +1,19 @@
/*
* Copyright (c) bdew, 2013
* https://github.com/bdew/bdlib
*
* This mod is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt
*/
package net.bdew.lib.data
import net.minecraft.nbt.NBTTagCompound
import net.bdew.lib.data.base.{UpdateKind, TileDataSlots, DataSlotVal}
case class DataSlotBoolean(name: String, parent: TileDataSlots, default: Boolean = false) extends DataSlotVal[Boolean] {
var cval = default
def save(t: NBTTagCompound, kind: UpdateKind.Value) = t.setBoolean(name, cval)
def load(t: NBTTagCompound, kind: UpdateKind.Value) = cval = t.getBoolean(name)
}
@@ -0,0 +1,20 @@
/*
* Copyright (c) bdew, 2013
* https://github.com/bdew/bdlib
*
* This mod is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt
*/
package net.bdew.lib.data
import net.bdew.lib.data.base.{TileDataSlots, UpdateKind, DataSlotVal}
import net.minecraftforge.common.ForgeDirection
import net.minecraft.nbt.NBTTagCompound
case class DataSlotDirection(name: String, parent: TileDataSlots) extends DataSlotVal[ForgeDirection] {
var cval = ForgeDirection.UP
def save(t: NBTTagCompound, kind: UpdateKind.Value) = t.setByte(name, cval.ordinal().toByte)
def load(t: NBTTagCompound, kind: UpdateKind.Value) = cval = ForgeDirection.getOrientation(t.getByte(name))
}
+18
View File
@@ -0,0 +1,18 @@
/*
* Copyright (c) bdew, 2013
* https://github.com/bdew/bdlib
*
* This mod is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt
*/
package net.bdew.lib.data
import net.minecraft.nbt.NBTTagCompound
import net.bdew.lib.data.base.{UpdateKind, TileDataSlots, DataSlotNumeric}
case class DataSlotFloat(name: String, parent: TileDataSlots, default: Float = 0) extends DataSlotNumeric[Float](default) {
def save(t: NBTTagCompound, kind: UpdateKind.Value) = t.setFloat(name, cval)
def load(t: NBTTagCompound, kind: UpdateKind.Value) = cval = t.getFloat(name)
}
+18
View File
@@ -0,0 +1,18 @@
/*
* Copyright (c) bdew, 2013
* https://github.com/bdew/bdlib
*
* This mod is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt
*/
package net.bdew.lib.data
import net.minecraft.nbt.NBTTagCompound
import net.bdew.lib.data.base.{UpdateKind, TileDataSlots, DataSlotNumeric}
case class DataSlotInt(name: String, parent: TileDataSlots, default: Int = 0) extends DataSlotNumeric[Int](default) {
def save(t: NBTTagCompound, kind: UpdateKind.Value) = t.setInteger(name, cval)
def load(t: NBTTagCompound, kind: UpdateKind.Value) = cval = t.getInteger(name)
}
@@ -0,0 +1,32 @@
/*
* Copyright (c) bdew, 2013
* https://github.com/bdew/bdlib
*
* This mod is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt
*/
package net.bdew.lib.data
import net.bdew.lib.data.base.{TileDataSlots, UpdateKind, DataSlotVal}
import net.minecraft.nbt.NBTTagCompound
import net.minecraft.item.ItemStack
case class DataSlotItemStack(name: String, parent: TileDataSlots) extends DataSlotVal[ItemStack] {
var cval: ItemStack = null
override def update(v: ItemStack) = {
if (!ItemStack.areItemStacksEqual(v, cval)) {
cval = if (v == null) null else v.copy()
parent.dataSlotChanged(this)
}
}
def save(t: NBTTagCompound, kind: UpdateKind.Value) = {
val tag = new NBTTagCompound()
if (cval != null) cval.writeToNBT(tag)
t.setCompoundTag(name, tag)
}
def load(t: NBTTagCompound, kind: UpdateKind.Value) = cval = ItemStack.loadItemStackFromNBT(t.getCompoundTag(name))
}
@@ -0,0 +1,19 @@
/*
* Copyright (c) bdew, 2013
* https://github.com/bdew/bdlib
*
* This mod is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt
*/
package net.bdew.lib.data
import net.minecraft.nbt.NBTTagCompound
import net.bdew.lib.data.base.{UpdateKind, TileDataSlots, DataSlotVal}
case class DataSlotString(name: String, parent: TileDataSlots, default: String = null) extends DataSlotVal[String] {
var cval: String = default
def save(t: NBTTagCompound, kind: UpdateKind.Value) = if (cval != null) t.setString(name, cval)
def load(t: NBTTagCompound, kind: UpdateKind.Value) = cval = if (t.hasKey(name)) t.getString(name) else null
}
+62
View File
@@ -0,0 +1,62 @@
/*
* Copyright (c) bdew, 2013
* https://github.com/bdew/bdlib
*
* This mod is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt
*/
package net.bdew.lib.data
import net.minecraftforge.fluids.{IFluidTank, FluidTank, FluidStack}
import net.minecraft.nbt.NBTTagCompound
import net.bdew.lib.data.base.{UpdateKind, TileDataSlots, DataSlot}
abstract class DataSlotTankBase(sz: Int) extends FluidTank(sz) with IFluidTank with DataSlot {
var oldStack: FluidStack = null
var size: Int
parent.serverTick.listen(checkUpdate)
updateKind = Set(UpdateKind.GUI, UpdateKind.SAVE)
def checkUpdate() {
if (!isSame(oldStack, fluid)) {
oldStack = if (fluid == null) null else fluid.copy()
parent.dataSlotChanged(this)
}
}
def isSame(v1: FluidStack, v2: FluidStack): Boolean = {
if (v1 == null && v2 == null) return true
if (v1 == null || v2 == null) return false
return v1.isFluidStackIdentical(v2)
}
def save(t: NBTTagCompound, k: UpdateKind.Value) {
val tag = new NBTTagCompound()
writeToNBT(tag)
if (k == UpdateKind.GUI)
tag.setInteger("size", size)
t.setCompoundTag(name, tag)
}
def load(t: NBTTagCompound, k: UpdateKind.Value) {
val tag = t.getCompoundTag(name)
readFromNBT(tag)
if (k == UpdateKind.GUI)
size = tag.getInteger("size")
}
}
case class DataSlotTank(name: String, parent: TileDataSlots, var size: Int) extends DataSlotTankBase(size)
case class DataSlotTankRestricted(name: String, parent: TileDataSlots, var size: Int, fluidID: Int) extends DataSlotTankBase(size) {
def fill(amount: Int, doFill: Boolean) = super.fill(new FluidStack(fluidID, amount), doFill)
override def fill(resource: FluidStack, doFill: Boolean): Int = {
if ((resource != null) && (resource.fluidID != fluidID)) return 0
return super.fill(resource, doFill)
}
}
@@ -0,0 +1,39 @@
/*
* Copyright (c) bdew, 2013
* https://github.com/bdew/bdlib
*
* This mod is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt
*/
package net.bdew.lib.data.base
import net.minecraft.entity.player.EntityPlayerMP
import net.bdew.lib.gui.BaseContainer
import net.minecraft.inventory.ICrafting
trait ContainerDataSlots extends BaseContainer {
val dataSource: TileDataSlots
var lastSentChange = dataSource.lastChange
override def addCraftingToCrafters(crafter: ICrafting) {
super.addCraftingToCrafters(crafter)
if (crafter.isInstanceOf[EntityPlayerMP]) {
val pkt = dataSource.getDataSlotPacket
crafter.asInstanceOf[EntityPlayerMP].playerNetServerHandler.sendPacketToPlayer(pkt)
}
}
override def detectAndSendChanges() {
super.detectAndSendChanges()
// only send updates every 10 ticks
if (dataSource.lastChange >= lastSentChange + 10 || (dataSource.lastChange > lastSentChange && lastSentChange + 10 < dataSource.worldObj.getTotalWorldTime)) {
lastSentChange = dataSource.lastChange
val pkt = dataSource.getDataSlotPacket
for (player <- players)
player.playerNetServerHandler.sendPacketToPlayer(pkt)
}
}
}
+42
View File
@@ -0,0 +1,42 @@
/*
* Copyright (c) bdew, 2013
* https://github.com/bdew/bdlib
*
* This mod is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt
*/
package net.bdew.lib.data.base
import net.minecraft.nbt.NBTTagCompound
/**
* Base trait for all data slots
*/
trait DataSlot {
/**
* Tile Entity that owns this slot
* Accessed in constructor, so should be in parameters or a lazy val, otherwise will crash
*/
val parent: TileDataSlots
/**
* Unique name
* Accessed in constructor, so should be in parameters or a lazy val, otherwise will crash
*/
val name: String
parent.dataSlots += (name -> this)
// Where should it sync
var updateKind = Set(UpdateKind.GUI)
def save(t: NBTTagCompound, kind: UpdateKind.Value)
def load(t: NBTTagCompound, kind: UpdateKind.Value)
def setUpdate(vals: UpdateKind.Value*): this.type = {
updateKind = vals.toSet
return this
}
}
@@ -0,0 +1,22 @@
/*
* Copyright (c) bdew, 2013
* https://github.com/bdew/bdlib
*
* This mod is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt
*/
package net.bdew.lib.data.base
/**
* Base class for data slots that hold numeric values
* adds convinience operators to modify the value
*/
abstract class DataSlotNumeric[T](default: T)(implicit n: Numeric[T]) extends DataSlotVal[T] {
var cval = default
def +=(that: T) = update(n.plus(cval, that))
def -=(that: T) = update(n.minus(cval, that))
def *=(that: T) = update(n.times(cval, that))
}
@@ -0,0 +1,21 @@
/*
* Copyright (c) bdew, 2013
* https://github.com/bdew/bdlib
*
* This mod is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt
*/
package net.bdew.lib.data.base
/**
* Base class for data slots that hold values with ordering operators, adds more convinience operators
* TODO: Do i need this? normal operators can be used with the implicit conversion
*/
abstract class DataSlotOrdered[T](implicit n: Ordering[T]) extends DataSlotVal[T] {
def :>(that: T) = n.compare(cval, that) > 0
def :<(that: T) = n.compare(cval, that) < 0
def :>=(that: T) = n.compare(cval, that) >= 0
def :<=(that: T) = n.compare(cval, that) <= 0
}
@@ -0,0 +1,39 @@
/*
* Copyright (c) bdew, 2013
* https://github.com/bdew/bdlib
*
* This mod is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt
*/
package net.bdew.lib.data.base
import language.implicitConversions
/**
* Base trait for data slots that hold primitive values
* Defines some convinience operators to access the value and an implicit conversion to the value
*/
trait DataSlotVal[T] extends DataSlot {
var cval: T
def isSame(v: T) = v == cval
def :=(that: T) = update(that)
def :!=(that: T) = cval != that
def :==(that: T) = cval == that
def update(v: T) {
if (!isSame(v)) {
cval = v
parent.dataSlotChanged(this)
}
}
}
object DataSlotVal {
implicit def slot2val[T](slot: DataSlotVal[T]): T = slot.cval
}
@@ -0,0 +1,64 @@
/*
* Copyright (c) bdew, 2013
* https://github.com/bdew/bdlib
*
* This mod is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt
*/
package net.bdew.lib.data.base
import net.minecraft.network.packet.Packet132TileEntityData
import scala.collection.mutable
import net.minecraft.nbt.NBTTagCompound
import net.bdew.lib.tile.TileExtended
trait TileDataSlots extends TileExtended {
val dataSlots = mutable.HashMap.empty[String, DataSlot]
var lastChange = 0L
final val TRACE = true
def doSave(kind: UpdateKind.Value, t: NBTTagCompound) {
for ((n, s) <- dataSlots if s.updateKind.contains(kind)) {
s.save(t, kind)
if (TRACE) printf("%s: %s S=> %s\n".format(kind, n, t.getTag(n)))
}
}
def doLoad(kind: UpdateKind.Value, t: NBTTagCompound) {
for ((n, s) <- dataSlots if s.updateKind.contains(kind)) {
if (TRACE) printf("%s: %s L<= %s\n".format(kind, n, t.getTag(n)))
s.load(t, kind)
}
}
persistSave.listen(doSave(UpdateKind.SAVE, _))
persistLoad.listen(doLoad(UpdateKind.SAVE, _))
sendClientUpdate.listen(doSave(UpdateKind.WORLD, _))
handleClientUpdate.listen(doLoad(UpdateKind.WORLD, _))
def dataSlotChanged(slot: DataSlot) {
if (worldObj != null) {
if (slot.updateKind.contains(UpdateKind.GUI))
lastChange = worldObj.getTotalWorldTime
if (slot.updateKind.contains(UpdateKind.WORLD))
worldObj.markBlockForUpdate(xCoord, yCoord, zCoord)
if (slot.updateKind.contains(UpdateKind.SAVE))
worldObj.markTileEntityChunkModified(xCoord, yCoord, zCoord, this)
}
}
def getDataSlotPacket: Packet132TileEntityData = {
val tag = new NBTTagCompound()
doSave(UpdateKind.GUI, tag)
return new Packet132TileEntityData(this.xCoord, this.yCoord, this.zCoord, ACT_GUI, tag)
}
override protected def extDataPacket(id: Int, data: NBTTagCompound) {
if (id == ACT_GUI)
doLoad(UpdateKind.GUI, data)
super.extDataPacket(id, data)
}
}
@@ -0,0 +1,16 @@
/*
* Copyright (c) bdew, 2013
* https://github.com/bdew/bdlib
*
* This mod is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt
*/
package net.bdew.lib.data.base
object UpdateKind extends Enumeration {
val WORLD = Value("WORLD")
val GUI = Value("GUI")
val SAVE = Value("SAVE")
}
+46
View File
@@ -0,0 +1,46 @@
/*
* Copyright (c) bdew, 2013
* https://github.com/bdew/bdlib
*
* This mod is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt
*/
package net.bdew.lib.gui
import net.minecraft.inventory.{IInventory, Slot, Container}
import net.minecraft.entity.player.{EntityPlayerMP, EntityPlayer, InventoryPlayer}
import net.minecraft.item.ItemStack
import net.bdew.lib.items.ItemUtils
import net.bdew.lib.Misc
abstract class BaseContainer(te: IInventory) extends Container {
import scala.collection.JavaConversions._
def players = Misc.filterType(crafters, classOf[EntityPlayerMP])
protected def bindPlayerInventory(inv: InventoryPlayer, xOffs: Int, yOffsInv: Int, yOffsHotbar: Int) {
for (i <- 0 until 3; j <- 0 until 9)
addSlotToContainer(new Slot(inv, j + i * 9 + 9, xOffs + j * 18, yOffsInv + i * 18))
for (i <- 0 until 9)
addSlotToContainer(new Slot(inv, i, xOffs + i * 18, yOffsHotbar))
}
override def transferStackInSlot(player: EntityPlayer, slot: Int): ItemStack = {
var stack = getSlot(slot).getStack
if (getSlot(slot).inventory == player.inventory) {
stack = ItemUtils.addStackToSlots(stack, te, 0 until te.getSizeInventory, true)
} else {
stack = ItemUtils.addStackToSlots(stack, player.inventory, 9 until player.inventory.mainInventory.length, true)
// Only put in hotbar if the rest is full
if (stack != null)
stack = ItemUtils.addStackToSlots(stack, player.inventory, 0 until 9, true)
}
getSlot(slot).putStack(stack)
return null
}
}
+89
View File
@@ -0,0 +1,89 @@
/*
* Copyright (c) bdew, 2013
* https://github.com/bdew/bdlib
*
* This mod is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt
*/
package net.bdew.lib.gui
import net.minecraft.client.gui.inventory.GuiContainer
import net.minecraft.inventory.Container
import scala.collection.mutable
import net.minecraft.client.gui.GuiButton
import net.bdew.lib.gui.widgets.Widget
import net.minecraft.util.ResourceLocation
import org.lwjgl.opengl.GL11
abstract class BaseScreen(cont: Container, xSz: Int, ySz: Int) extends GuiContainer(cont) {
xSize = xSz
ySize = ySz
val widgets = mutable.MutableList.empty[Widget]
val texture: ResourceLocation
def rect = new Rect(guiLeft, guiTop, xSize, ySize)
def getFontRenderer = fontRenderer
override def initGui() {
super.initGui()
widgets.clear()
buttonList.clear()
}
def addButton[T <: GuiButton](w: T): T = {
buttonList.asInstanceOf[java.util.ArrayList[GuiButton]].add(w)
return w
}
def addWidget[T <: Widget](w: T): T = {
widgets += w
w.parent = this
return w
}
protected override def keyTyped(c: Char, i: Int) {
for (w <- widgets)
if (w.keyTyped(c, i))
return
super.keyTyped(c, i)
}
protected override def mouseClicked(x: Int, y: Int, bt: Int) {
super.mouseClicked(x, y, bt)
val p = new Point(x, y) - rect.origin
for (w <- widgets if w.rect.contains(p))
w.mouseClicked(p - w.rect.origin, bt)
}
protected override def drawGuiContainerForegroundLayer(x: Int, y: Int) {
for (w <- widgets)
w.draw()
}
protected override def drawScreen(x: Int, y: Int, f: Float) {
super.drawScreen(x, y, f)
val tip = mutable.MutableList.empty[String]
val p = new Point(x, y) - rect.origin
for (w <- widgets if w.rect.contains(p))
w.handleTooltip(p - w.rect.origin, tip)
import collection.JavaConversions._
if (tip.size > 0)
drawHoveringText(tip, x, y, fontRenderer)
}
protected def drawGuiContainerBackgroundLayer(f: Float, i: Int, j: Int) {
GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F)
mc.renderEngine.bindTexture(texture)
val x = (width - xSize) / 2
val y = (height - ySize) / 2
this.drawTexturedModalRect(x, y, 0, 0, xSize, ySize)
}
}
+18
View File
@@ -0,0 +1,18 @@
/*
* Copyright (c) bdew, 2013
* https://github.com/bdew/bdlib
*
* This mod is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt
*/
package net.bdew.lib.gui
object Direction extends Enumeration {
type Direction = Value
val UP = Value("UP")
val DOWN = Value("UP")
val LEFT = Value("UP")
val RIGHT = Value("UP")
}
+16
View File
@@ -0,0 +1,16 @@
/*
* Copyright (c) bdew, 2013
* https://github.com/bdew/bdlib
*
* This mod is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt
*/
package net.bdew.lib.gui
class Point(val x: Int, val y: Int) {
def this(p: Point) = this(p.x, p.y)
def +(that: Point) = new Point(this.x + that.x, this.y + that.y)
def -(that: Point) = new Point(this.x - that.x, this.y - that.y)
}
+16
View File
@@ -0,0 +1,16 @@
/*
* Copyright (c) bdew, 2013
* https://github.com/bdew/bdlib
*
* This mod is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt
*/
package net.bdew.lib.gui
class Rect(val x: Int, val y: Int, val w: Int, val h: Int) {
def this(p: Point, w: Int, h: Int) = this(p.x, p.y, w, h)
def contains(p: Point) = p.x >= x && p.y >= y && p.x <= x + w && p.y <= y + h
def origin = new Point(x, y)
}
+18
View File
@@ -0,0 +1,18 @@
/*
* Copyright (c) bdew, 2013
* https://github.com/bdew/bdlib
*
* This mod is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt
*/
package net.bdew.lib.gui
import net.minecraft.inventory.IInventory
import net.minecraft.inventory.Slot
import net.minecraft.item.ItemStack
class SlotValidating(inv: IInventory, slot: Int, x: Int, y: Int) extends Slot(inv, slot, x, y) {
override def isItemValid(stack: ItemStack) = inventory.isItemValidForSlot(getSlotIndex, stack)
}
@@ -0,0 +1,16 @@
/*
* Copyright (c) bdew, 2013
* https://github.com/bdew/bdlib
*
* This mod is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt
*/
package net.bdew.lib.gui
import net.minecraft.util.ResourceLocation
class TextureLocation(val resource: ResourceLocation, val p: Point) extends Point(p.x, p.y) {
def this(resource: ResourceLocation, x: Int, y: Int) = this(resource, new Point(x, y))
}
+26
View File
@@ -0,0 +1,26 @@
/*
* Copyright (c) bdew, 2013
* https://github.com/bdew/bdlib
*
* This mod is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt
*/
package net.bdew.lib.gui.widgets
import scala.collection.mutable
import net.bdew.lib.gui.{Point, BaseScreen, Rect}
import net.minecraft.util.ResourceLocation
import net.minecraft.client.Minecraft
trait Widget {
val rect: Rect
var parent: BaseScreen = null
def handleTooltip(p: Point, tip: mutable.MutableList[String]) {}
def mouseClicked(p: Point, button: Int) {}
def keyTyped(c: Char, i: Int): Boolean = false
def draw() {}
def bindTexture(res: ResourceLocation) = Minecraft.getMinecraft.renderEngine.bindTexture(res)
}
@@ -0,0 +1,39 @@
/*
* Copyright (c) bdew, 2013
* https://github.com/bdew/bdlib
*
* This mod is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt
*/
package net.bdew.lib.gui.widgets
import net.bdew.lib.gui.{TextureLocation, Rect}
import net.bdew.lib.gui.Direction
import net.bdew.lib.data.base.DataSlotNumeric
class WidgetFillDataslot[T](val rect: Rect, val texture: TextureLocation, dir: Direction.Direction, dslot: DataSlotNumeric[T], maxval: T)(implicit num: Numeric[T]) extends Widget {
def getFillArea(max: Int): Int = (num.toFloat(dslot) / num.toFloat(maxval) * max).round
override def draw() {
bindTexture(texture.resource)
dir match {
case Direction.UP =>
val fill = getFillArea(rect.h)
parent.drawTexturedModalRect(rect.x, rect.y + rect.h - fill, texture.x, texture.y + rect.h - fill, rect.w, fill)
case Direction.DOWN =>
val fill = getFillArea(rect.h)
parent.drawTexturedModalRect(rect.x, rect.y, texture.x, texture.y, rect.w, fill)
case Direction.LEFT =>
val fill = getFillArea(rect.w)
parent.drawTexturedModalRect(rect.x + rect.w - fill, rect.y, texture.x + rect.w - fill, texture.y, fill, rect.h)
case Direction.RIGHT =>
val fill = getFillArea(rect.w)
parent.drawTexturedModalRect(rect.x, rect.y, texture.x, texture.y, fill, rect.h)
}
}
}
@@ -0,0 +1,60 @@
/*
* Copyright (c) bdew, 2013
* https://github.com/bdew/bdlib
*
* This mod is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt
*/
package net.bdew.lib.gui.widgets
import net.bdew.lib.gui.{Point, TextureLocation, Rect}
import net.bdew.lib.data.DataSlotTankBase
import scala.collection.mutable
import net.minecraft.client.renderer.texture.TextureMap
import java.text.DecimalFormat
import net.bdew.lib.Misc
import org.lwjgl.opengl.GL11
class WidgetFluidGauge(val rect: Rect, overlay: TextureLocation, dslot: DataSlotTankBase) extends Widget {
val formater = new DecimalFormat("#,###")
override def handleTooltip(p: Point, tip: mutable.MutableList[String]) {
if (dslot.getFluid != null) {
tip += dslot.getFluid.getFluid.getLocalizedName
tip += "%s/%s mB".format(formater.format(dslot.getFluidAmount), formater.format(dslot.getCapacity))
} else {
tip += Misc.toLocal("gendustry.label.empty")
}
}
override def draw() {
GL11.glEnable(GL11.GL_BLEND)
GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA)
val fstack = dslot.getFluid
if (fstack != null && fstack.getFluid.getStillIcon != null) {
val icon = fstack.getFluid.getStillIcon
bindTexture(TextureMap.locationBlocksTexture)
var fillHeight: Int = (rect.h * fstack.amount / dslot.getCapacity).round
var yStart: Int = 0
while (fillHeight > 0) {
if (fillHeight > 16) {
parent.drawTexturedModelRectFromIcon(rect.x, rect.y + rect.h - 16 - yStart, icon, 16, 16)
fillHeight -= 16
} else {
parent.drawTexturedModelRectFromIcon(rect.x, rect.y + rect.h - fillHeight - yStart, icon, 16, fillHeight)
fillHeight = 0
}
yStart = yStart + 16
}
}
GL11.glDisable(GL11.GL_BLEND)
bindTexture(overlay.resource)
parent.drawTexturedModalRect(rect.x, rect.y, overlay.x, overlay.y, rect.w, rect.h)
}
}
@@ -0,0 +1,19 @@
/*
* Copyright (c) bdew, 2013
* https://github.com/bdew/bdlib
*
* This mod is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt
*/
package net.bdew.lib.gui.widgets
import net.bdew.lib.gui.Rect
class WidgetLabel(text: String, x: Int, y: Int, color: Int) extends Widget {
val rect: Rect = new Rect(x, y, 0, 0)
override def draw() {
parent.getFontRenderer.drawString(text, x, y, color)
}
}
@@ -0,0 +1,18 @@
/*
* Copyright (c) bdew, 2013
* https://github.com/bdew/bdlib
*
* This mod is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt
*/
package net.bdew.lib.gui.widgets
import net.bdew.lib.gui.{Point, Direction, TextureLocation, Rect}
import net.bdew.lib.data.DataSlotFloat
import scala.collection.mutable
class WidgetProgressBar(rect: Rect, texture: TextureLocation, dslot: DataSlotFloat) extends WidgetFillDataslot[Float](rect, texture, Direction.RIGHT, dslot, 1) {
override def handleTooltip(p: Point, tip: mutable.MutableList[String]) = tip += "%.0f".format(dslot.cval * 100) + "%"
}
@@ -0,0 +1,19 @@
/*
* Copyright (c) bdew, 2013
* https://github.com/bdew/bdlib
*
* This mod is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt
*/
package net.bdew.lib.gui.widgets
import net.minecraft.client.gui.{FontRenderer, GuiTextField}
import net.bdew.lib.gui.{Point, Rect}
class WidgetTextEdit(val rect: Rect, fr: FontRenderer) extends GuiTextField(fr, rect.x, rect.y, rect.w, rect.h) with Widget {
override def mouseClicked(p: Point, button: Int) = super.mouseClicked(p.x + rect.x, p.y + rect.y, button)
override def keyTyped(c: Char, i: Int): Boolean = super.textboxKeyTyped(c, i)
override def draw() = super.drawTextBox()
}
+79
View File
@@ -0,0 +1,79 @@
/*
* Copyright (c) bdew, 2013
* https://github.com/bdew/bdlib
*
* This mod is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt
*/
package net.bdew.lib.items
import net.minecraft.entity.item.EntityItem
import net.minecraft.item.ItemStack
import net.minecraft.world.World
import net.minecraft.entity.player.EntityPlayer
import net.minecraft.inventory.IInventory
import net.bdew.lib.Misc
object ItemUtils {
def throwItemAt(world: World, x: Int, y: Int, z: Int, stack: ItemStack) {
if ((stack == null) || world.isRemote) return
val dx = world.rand.nextFloat * 0.8
val dy = world.rand.nextFloat * 0.8
val dz = world.rand.nextFloat * 0.8
val entityitem: EntityItem = new EntityItem(world, x + dx, y + dy, z + dz, stack)
entityitem.motionX = world.rand.nextGaussian * 0.05
entityitem.motionY = world.rand.nextGaussian * 0.05 + 0.2
entityitem.motionZ = world.rand.nextGaussian * 0.05
world.spawnEntityInWorld(entityitem)
}
def dropItemToPlayer(world: World, player: EntityPlayer, stack: ItemStack) {
if ((stack == null) || world.isRemote) return
world.spawnEntityInWorld(new EntityItem(world, player.posX, player.posY, player.posZ, stack))
}
def isSameItem(stack1: ItemStack, stack2: ItemStack): Boolean = {
if (stack1 == null || stack2 == null)
return stack1 == stack2
if (stack1.itemID != stack2.itemID)
return false
if (stack1.getHasSubtypes && stack2.getItemDamage != stack1.getItemDamage)
return false
return ItemStack.areItemStackTagsEqual(stack2, stack1)
}
def addStackToSlots(stack: ItemStack, inv: IInventory, slots: Iterable[Int], checkvalid: Boolean): ItemStack = {
if (stack == null) return null
// Try merging into existing slots
for (slot <- slots if (!checkvalid || inv.isItemValidForSlot(slot, stack)) && isSameItem(stack, inv.getStackInSlot(slot))) {
val target = inv.getStackInSlot(slot)
val toAdd = Misc.min(target.getMaxStackSize - target.stackSize, inv.getInventoryStackLimit - target.stackSize, stack.stackSize)
if (toAdd >= stack.stackSize) {
target.stackSize += stack.stackSize
stack.stackSize = 0
inv.onInventoryChanged()
return null
} else if (toAdd > 0) {
target.stackSize += toAdd
stack.stackSize -= toAdd
inv.onInventoryChanged()
}
}
// Now find empty slots and stick any leftovers there
for (slot <- slots if (!checkvalid || inv.isItemValidForSlot(slot, stack)) && inv.getStackInSlot(slot) == null) {
if (inv.getInventoryStackLimit < stack.stackSize) {
inv.setInventorySlotContents(slot, stack.splitStack(inv.getInventoryStackLimit))
} else {
inv.setInventorySlotContents(slot, stack.copy())
stack.stackSize = 0
return null
}
}
return stack
}
}
+181
View File
@@ -0,0 +1,181 @@
/*
* Copyright (c) bdew, 2013
* https://github.com/bdew/bdlib
*
* This mod is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt
*/
package net.bdew.lib.recipes
/**
* Base class for everything that can be resolved to ItemStack or recipe component
* Actual processing is in:
* * [[net.bdew.lib.recipes.RecipeLoader.getRecipeComponent]]
* * [[net.bdew.lib.recipes.RecipeLoader.getConcreteStack]]
* * [[net.bdew.lib.recipes.RecipeLoader.getAllConcreteStacks]]
*
*/
abstract class StackRef
/**
* Ore Dictionary reference
* Syntax: OD:{identifier}
* Parser: [[net.bdew.lib.recipes.RecipeParser.specOD]]
* @param id OD entry name
*/
case class StackOreDict(id: String) extends StackRef
/**
* Mod item reference [[cpw.mods.fml.common.registry.GameRegistry.findItemStack]]
* Syntax: {modID}:{name}
* Parser: [[net.bdew.lib.recipes.RecipeParser.specModStack]]
* @param mod modId of owner mod
* @param id name of the stack
*/
case class StackMod(mod: String, id: String) extends StackRef
/**
* Vanilla block reference
* Syntax: B:{name} [@ {meta}]
* Parser: [[net.bdew.lib.recipes.RecipeParser.specMcBlock]]
* @param name Unlocalized name (without "tile.")
* @param meta Metadata / Damage
*/
case class StackMCBlock(name: String, meta: Int) extends StackRef
/**
* Vanilla item reference
* Syntax: I:{name} [@ {meta}]
* Parser: [[net.bdew.lib.recipes.RecipeParser.specMcItem]]
* @param name Unlocalized name (without "item.")
* @param meta Metadata / Damage
*/
case class StackMCItem(name: String, meta: Int) extends StackRef
/**
* Reference to an Item/Block/ItemStack pulic static field
* Syntax: {path}.{to}.{class}[{field}] [@ {meta}]
* Parser: [[net.bdew.lib.recipes.RecipeParser.specReflect]]
* @param cls Class name
* @param field Field name
* @param meta Metadata / Damage (Ignored for ItemStacks)
*/
case class StackReflect(cls: String, field: String, meta: Int) extends StackRef
/**
* Reference to an Item/Block/ItemStack pulic static getter
* Syntax: {path}.{to}.{class}.{method}({string}) [@ {meta}]
* Parser: [[net.bdew.lib.recipes.RecipeParser.specGetter]]
* @param cls Class name
* @param method Method name
* @param name Parameter to getter
* @param meta Metadata / Damage (Ignored for ItemStacks)
*/
case class StackGetter(cls: String, method: String, name: String, meta: Int) extends StackRef
/**
* Macro reference to a previous definition
* Syntax: ${char}
* Parser: [[net.bdew.lib.recipes.RecipeParser.specMacro]]
* @param id The underlying character
*/
case class StackMacro(id: Char) extends StackRef
/**
* Base class for statements
* Actual processing is in [[net.bdew.lib.recipes.RecipeLoader.processStatement]]
*/
abstract class Statement
/**
* Character assignment
* Syntax: {char} = {ref}
* Parser: [[net.bdew.lib.recipes.RecipeParser.charSpec]]
* @param char Character to assign
* @param spec ItemStack Reference
*/
case class StCharAssign(char: Char, spec: StackRef) extends Statement
/**
* Define class macro
* Syntax: def {id} = {name}
* Parser: [[net.bdew.lib.recipes.RecipeParser.classMacro]]
* @param id Macro identifier
* @param cls Class name
*/
case class StClassMacro(id: String, cls: String) extends Statement
/**
* Conditional block - checks if mod is loaded
* Syntax: ifMod {string} { {statements} } [else { {statements} }]
* Parser: [[net.bdew.lib.recipes.RecipeParser.ifMod]]
* @param mod mod and version to check [[cpw.mods.fml.common.versioning.VersionParser]]
* @param thn Statements to run if present
* @param els Statements to run otherwise
*/
case class StIfHaveMod(mod: String, thn: List[Statement], els: List[Statement]) extends Statement
/**
* Conditional block - checks if mod is loaded
* Syntax: ifOreDict {string} { {statements} } [else { {statements} }]
* Parser: [[net.bdew.lib.recipes.RecipeParser.ifOreDict]]
* @param id Ore Dictionary Entry
* @param thn Statements to run if present
* @param els Statements to run otherwise
*/
case class StIfHaveOD(id: String, thn: List[Statement], els: List[Statement]) extends Statement
/**
* Shaped recipe definition
*
* Syntax:
* XXX
* XXX => {result} [* {count}]
* XXX
*
* Parser: [[net.bdew.lib.recipes.RecipeParser.recipeShaped3x3]]
*
* Syntax:
* XX
* XX => {result} [* {count}]
*
* Parser: [[net.bdew.lib.recipes.RecipeParser.recipeShaped2x2]]
*
* Syntax: XXX XXX XXX => {result} [* {count}]
* Parser: [[net.bdew.lib.recipes.RecipeParser.recipeShaped9]]
*
* @param rec Recipe pattern
* @param res Result reference
* @param cnt Number of output items
*/
case class StRecipeShaped(rec: Seq[String], res: StackRef, cnt: Int) extends Statement
/**
* Shapeless recipe definition
* Syntax: shapeless: {characters} => {result} [* {count}]
* Parser: [[net.bdew.lib.recipes.RecipeParser.recipeShapeless]]
*
* @param rec Recipe pattehrn
* @param res Result reference
* @param cnt Number of output items
*/
case class StRecipeShapeless(rec: String, res: StackRef, cnt: Int) extends Statement
/**
* Smelting recipe definition
* Syntax: smelt: {input} => {output}, {XP}
* Parser [[net.bdew.lib.recipes.RecipeParser.recipeSmelting]]
*
* @param in Input Stack
* @param out Output Stack
* @param cnt Output Count
* @param xp XP for smelting
*/
case class StSmeltRecipe(in: StackRef, out: StackRef, cnt: Int, xp: Float) extends Statement
/**
* Used in statement processing to abort the current statement and show an error without a stack trace
*/
class StatementError(msg: String) extends Exception(msg)
+319
View File
@@ -0,0 +1,319 @@
/*
* Copyright (c) bdew, 2013
* https://github.com/bdew/bdlib
*
* This mod is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt
*/
package net.bdew.lib.recipes
import java.io.Reader
import net.minecraft.item.{Item, ItemStack}
import net.bdew.lib.Misc
import net.minecraft.block.Block
import cpw.mods.fml.common.registry.GameRegistry
import net.minecraftforge.oredict.{ShapelessOreRecipe, OreDictionary}
import java.util.logging.Logger
import cpw.mods.fml.common.FMLLog
import net.minecraft.item.crafting.FurnaceRecipes
/**
* Main recipe loader class
* The input file is parsed by [[net.bdew.lib.recipes.RecipeParser]]
* Into a list of [[net.bdew.lib.recipes.Statement]] subclasses
* That are then executed here
*/
class RecipeLoader {
/**
* Create a new parser, override in subclasses to use an extended parser
* @return New ConfigParser (or subclass) instance
*/
def newParser() = new RecipeParser()
val log: Logger = Logger.getLogger("RecipeLoader")
log.setParent(FMLLog.getLogger)
/**
* Current map of recipe characters to parser item references
*/
val currCharMap = collection.mutable.Map.empty[Char, StackRef].withDefault(x => error("Undefined recipe character '%s'", x))
/**
* Current map of class macros
*/
val currClassMacros = collection.mutable.Map.empty[String, String].withDefault(x => error("Undefined class macro '%s'", x))
/**
* Triggers an error with formatted string
*/
def error(msg: String, params: Any*) = throw new StatementError(msg.format(params: _*))
/**
* Looks up a recipe component
* @param s Parser ItemStack reference
* @return ItemStack or String that can be used as recipe components in MC functions
*/
def getRecipeComponent(s: StackRef): AnyRef = s match {
case StackOreDict(id) => id
case StackMacro(ch) => getRecipeComponent(currCharMap(ch))
case _ => getConcreteStack(s)
}
/**
* Resolve class name if it's a macro
*/
def getRealClassName(s: String): String = {
if (s.startsWith("$")) {
return currClassMacros(s.stripPrefix("$"))
}
return s
}
/**
* Sanitize items from reflection
* @param x The item
* @param source Human readable source (used in errors and warnings)
* @param meta Metadata or damage
* @param cnt Stack size
* @return
*/
def sanitizeReflectedItem(x: AnyRef, source: String, meta: Int, cnt: Int): ItemStack = x match {
case x: ItemStack =>
val l = x.copy()
l.stackSize = cnt
if (meta != OreDictionary.WILDCARD_VALUE && meta != l.getItemDamage) {
log.warning("%s requested with meta %d but specifies %d".format(source, meta, l.getItemDamage))
l.setItemDamage(meta)
}
return l
case x: Item =>
return new ItemStack(x, cnt, meta)
case x: Block =>
return new ItemStack(x, cnt, meta)
case _ =>
error("%s is %s which cannot be translated to an ItemStack", source, x.getClass.getName)
}
/**
* Fetches an ItemStack using reflection from static fields
* Item and Block instaces are converted to ItemStacks
* @param clsName Name of class to fetch from (can be a class macro)
* @param fldName Field name
* @param meta Metadata or damage
* @param cnt Stack size
* @return Matching itemstack
*/
def reflectStack(clsName: String, fldName: String, meta: Int, cnt: Int): ItemStack = {
val realName = getRealClassName(clsName)
val cls = Class.forName(realName)
val fld = cls.getField(fldName).get(null)
return sanitizeReflectedItem(fld, "%s.%s".format(realName, fldName), meta, cnt)
}
/**
* Fetches an ItemStack using reflection from static getters
* Item and Block instaces are converted to ItemStacks
* @param clsName Name of class to fetch from (can be a class macro)
* @param method Method name
* @param param Parameter to method
* @param meta Metadata or damage
* @param cnt Stack size
* @return Matching itemstack
*/
def reflectStackGetter(clsName: String, method: String, param: String, meta: Int, cnt: Int): ItemStack = {
var realName: String = clsName
var realMethod: String = method
//Some acrobatics to allow use with macros, even bare ones like $foo(bar)
if ((realName.length == 0) && realMethod.startsWith("$")) {
val v = getRealClassName(realMethod).split('.').reverse
realName = v.tail.reverse.mkString(".")
realMethod = v.head
}
if (realName.startsWith("$")) {
realName = getRealClassName(clsName)
}
val cls = Class.forName(realName)
val meth = cls.getMethod(realMethod, classOf[String])
val res = meth.invoke(null, param)
return sanitizeReflectedItem(res, "%s.%s(%s)".format(realName, realMethod, param), meta, cnt)
}
/**
* Returns all possible ItemStacks that match a reference
* Currently everything except OreDictionary references just returns one item
* @param s Parser ItemStack reference
* @param cnt Stack size
* @return List of matching ItemStacks
*/
def getAllConcreteStacks(s: StackRef, cnt: Int = 1): Iterable[ItemStack] = s match {
case StackOreDict(id) =>
import scala.collection.JavaConversions._
val c = OreDictionary.getOres(id).map(_.copy())
c.foreach(_.stackSize = cnt)
return c
case _ => Seq(getConcreteStack(s))
}
/**
* Returns an ItemStack that match a reference
* This is the main StackRef resolution method
* @param s Parser ItemStack reference
* @param cnt Stack size
* @return A matching ItemStack
*/
def getConcreteStack(s: StackRef, cnt: Int = 1): ItemStack = s match {
case StackOreDict(id) =>
val l = OreDictionary.getOres(id)
if (l.size == 0) error("Concrete ItemStack requested for OD entry '%s' that is empty", id)
val s = l.get(0).copy()
s.stackSize = cnt
log.info("Concrete ItemStack for OD entry '%s' -> %s".format(id, s))
return s
case StackMacro(ch) => getConcreteStack(currCharMap(ch), cnt)
case StackMod(mod, id) =>
val i = GameRegistry.findItemStack(mod, id, cnt)
if (i == null) error("Item %s:%s not found", mod, id)
i
case StackMCBlock(id, meta) => new ItemStack(Vanilla.blocks(id), cnt, meta)
case StackMCItem(id, meta) => new ItemStack(Vanilla.items(id), cnt, meta)
case StackReflect(cls, field, meta) => reflectStack(cls, field, meta, cnt)
case StackGetter(cls, method, param, meta) => reflectStackGetter(cls, method, param, meta, cnt)
}
/**
* Looks up all characters used in the recipe
* @param s The pattern
* @return Map from character to recipe components and a boolean that means OD-aware methods should be used
*/
def resolveRecipeComponents(s: Iterable[Char]): (Map[Char, AnyRef], Boolean) = {
var comp = Map.empty[Char, AnyRef]
var needOd = false
for (x <- s if !comp.contains(x) && x != '_') {
if (!currCharMap.contains(x)) error("Character %s is undefined", x)
val r = getRecipeComponent(currCharMap(x))
if (r.isInstanceOf[String]) needOd = true
log.info("%s -> %s".format(x, r))
comp += (x -> r)
}
return (comp, needOd)
}
/**
* Process a single statement, override this to add more statements
* @param s The statement
*/
def processStatement(s: Statement): Unit = s match {
case StCharAssign(c, r) =>
currCharMap(c) = r
log.info("Added %s = %s".format(c, r))
case StClassMacro(id, cls) =>
currClassMacros(id) = cls
log.info("Added def %s = %s".format(id, cls))
case StIfHaveMod(mod, thn, els) =>
if (Misc.haveModVersion(mod)) {
log.info("ifMod: %s found".format(mod))
processStatementsSafe(thn)
} else {
log.info("ifMod: %s not found".format(mod))
processStatementsSafe(els)
}
case StIfHaveOD(od, thn, els) =>
if (OreDictionary.getOres(od).size() > 0) {
log.info("ifOreDict: %s found".format(od))
processStatementsSafe(thn)
} else {
log.info("ifOreDict: %s not found".format(od))
processStatementsSafe(els)
}
case StRecipeShaped(rec, res, cnt) =>
log.info("Adding shaped recipe %s => %s * %d".format(rec, res, cnt))
val (comp, needOd) = resolveRecipeComponents(rec.mkString(""))
val resStack = getConcreteStack(res, cnt)
if (resStack.getItemDamage == OreDictionary.WILDCARD_VALUE) {
log.info("Result meta is unset, defaulting to 0")
resStack.setItemDamage(0)
}
if (needOd)
Misc.addRecipeOD(resStack, rec, comp)
else
Misc.addRecipe(resStack, rec, comp)
log.info("Done... result=%s, od=%s".format(resStack, needOd))
case StRecipeShapeless(rec, res, cnt) =>
log.info("Adding shapeless recipe %s => %s * %d".format(rec, res, cnt))
val (comp, needOd) = resolveRecipeComponents(rec)
val resStack = getConcreteStack(res, cnt)
val recTrans = rec.toCharArray.map(comp(_))
if (resStack.getItemDamage == OreDictionary.WILDCARD_VALUE) {
log.info("Result meta is unset, defaulting to 0")
resStack.setItemDamage(0)
}
if (needOd)
GameRegistry.addRecipe(new ShapelessOreRecipe(resStack, recTrans: _*))
else
GameRegistry.addShapelessRecipe(resStack, recTrans: _*)
log.info("Done... result=%s, od=%s".format(resStack, needOd))
case StSmeltRecipe(in, out, cnt, xp) =>
log.info("Adding smelting recipe %s => %s * %d (%f xp)".format(in, out, cnt, xp))
val outStack = getConcreteStack(out, cnt)
if (outStack.getItemDamage == OreDictionary.WILDCARD_VALUE) {
log.info("Result meta is unset, defaulting to 0")
outStack.setItemDamage(0)
}
for (inStack <- getAllConcreteStacks(in, 1)) {
if (inStack.getItemDamage == OreDictionary.WILDCARD_VALUE) {
FurnaceRecipes.smelting.addSmelting(inStack.itemID, outStack, xp)
log.info("added %d -> %s".format(inStack.itemID, outStack))
} else {
FurnaceRecipes.smelting.addSmelting(inStack.itemID, inStack.getItemDamage, outStack, xp)
log.info("added %d@%d -> %s".format(inStack.itemID, inStack.getItemDamage, outStack))
}
}
case x =>
log.severe("Can't process %s - this is a programing bug!".format(x))
}
/**
* Process a list of statements and catch all exceptions
* @param r The list to process
*/
def processStatementsSafe(r: List[Statement]): Unit = {
for (s <- r) {
try {
processStatement(s)
} catch {
case e: StatementError =>
log.severe("Error while processing %s: %s".format(s, e.getMessage))
case e: Throwable =>
log.severe("Error while processing %s: %s".format(s, e))
e.printStackTrace()
}
}
}
def load(f: Reader) {
log.info("Starting parsing")
val r = newParser().doParse(f)
log.info("Processing %d statements".format(r.size))
processStatementsSafe(r)
log.info("Done")
}
}
+124
View File
@@ -0,0 +1,124 @@
/*
* Copyright (c) bdew, 2013
* https://github.com/bdew/bdlib
*
* This mod is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt
*/
package net.bdew.lib.recipes
import java.io.Reader
import scala.util.parsing.combinator._
import org.apache.commons.lang3.StringEscapeUtils
import net.minecraftforge.oredict.OreDictionary
class RecipeParser extends JavaTokenParsers {
// Allows C-style comments
protected override val whiteSpace = """(\s|//.*|(?m)/\*(\*(?!/)|[^*])*\*/)+""".r
// Simple integer without signs
def int = "\\d+".r ^^ (_.toInt)
// Possible metadata suffix (defaults to wildcard value)
def maybeMeta = ("@" ~> int).? ^^ (_.getOrElse(OreDictionary.WILDCARD_VALUE))
// Qualified class name
def clsPath = (ident <~ ".").* ~ ident
// Single character usable in recipes (this could be extended)
def recipeChar = "[a-zA-Z0-9]".r ^^ (_.charAt(0))
// Set of 3 characters for 3x3 recipes (underscore = empty)
def recipeTriplet = repN(3, recipeChar | "_") ^^ (_.mkString(""))
// Set of 2 characters for 2x2 recipes
def recipeDuplet = repN(2, recipeChar | "_") ^^ (_.mkString(""))
// Quoted string with escape characters
def unescapeStr = stringLiteral ^^ { case x => StringEscapeUtils.unescapeJava(x.substring(1, x.length - 1)) }
// Identifier or quoted string
def str = ident | unescapeStr
// === Item references ===
def specOD = "OD" ~> ":" ~> ident ^^ StackOreDict
def specMcBlock = "B" ~> ":" ~> ident ~ maybeMeta ^^ { case b ~ m => StackMCBlock(b, m) }
def specMcItem = "I" ~> ":" ~> ident ~ maybeMeta ^^ { case b ~ m => StackMCItem(b, m) }
def specModStack = str ~ ":" ~ str ^^ { case m ~ c ~ n => StackMod(m, n) }
def specMacro = "$" ~> recipeChar ^^ StackMacro
def specReflect = clsPath ~ ("[" ~> ident <~ "]") ~ maybeMeta ^^ {
case (p ~ cl) ~ id ~ m => StackReflect((p :+ cl).mkString("."), id, m)
}
def specGetter = clsPath ~ ("(" ~> str <~ ")") ~ maybeMeta ^^ {
case (p ~ cl) ~ n ~ m => StackGetter(p.mkString("."), cl, n, m)
}
def spec = specMcBlock | specMcItem | specOD | specModStack | specGetter | specReflect | specMacro
// Spec with possible number of items
def specWithCount = spec ~ ("*" ~> int).?
// === Statements ===
def charSpec = recipeChar ~ "=" ~ spec ^^ {
case ch ~ eq ~ spec => new StCharAssign(ch, spec)
}
def classMacro = ("def" ~> ident <~ "=") ~ clsPath ^^ {
case id ~ (p ~ cl) => StClassMacro(id, (p :+ cl).mkString("."))
}
def ifMod = ("ifMod" ~> str) ~ ("{" ~> statements <~ "}") ~ ("else" ~> "{" ~> statements <~ "}").? ^^ {
case mod ~ thn ~ els => new StIfHaveMod(mod, thn, els.getOrElse(List.empty[Statement]))
}
def ifOreDict = ("ifOreDict" ~> str) ~ ("{" ~> statements <~ "}") ~ ("else" ~> "{" ~> statements <~ "}").? ^^ {
case id ~ thn ~ els => new StIfHaveOD(id, thn, els.getOrElse(List.empty[Statement]))
}
def recipeShaped3x3 = recipeTriplet ~ recipeTriplet ~ ("=>" ~> specWithCount) ~ recipeTriplet ^^ {
case r1 ~ r2 ~ (res ~ n) ~ r3 => StRecipeShaped(Seq(r1, r2, r3), res, n.getOrElse(1))
}
def recipeShaped2x2 = recipeDuplet ~ recipeDuplet ~ ("=>" ~> specWithCount) ^^ {
case r1 ~ r2 ~ (res ~ n) => StRecipeShaped(Seq(r1, r2), res, n.getOrElse(1))
}
def recipeShaped9 = recipeTriplet ~ recipeTriplet ~ recipeTriplet ~ ("=>" ~> specWithCount) ^^ {
case r1 ~ r2 ~ r3 ~ (res ~ n) => StRecipeShaped(Seq(r1, r2, r3), res, n.getOrElse(1))
}
def recipeShapeless = "shapeless" ~> ":" ~> recipeChar.+ ~ ("=>" ~> specWithCount) ^^ {
case r ~ (res ~ n) => StRecipeShapeless(r.mkString(""), res, n.getOrElse(1))
}
def recipeSmelting = "smelt" ~> ":" ~> spec ~ ("=>" ~> specWithCount) ~ ("," ~> decimalNumber).? ^^ {
case in ~ (out ~ n) ~ xp => StSmeltRecipe(in, out, n.getOrElse(1), xp.getOrElse("0").toFloat)
}
def statement: Parser[Statement] = (
charSpec
| classMacro
| ifMod
| recipeShaped3x3
| recipeShaped2x2
| recipeShaped9
| recipeShapeless
| recipeSmelting
)
def statements = statement.*
def doParse(r: Reader): List[Statement] = {
parseAll(statements, r) match {
case Success(res, next) => return res
case NoSuccess(msg, next) => sys.error("Config parsing failed at %s: %s".format(next.pos, msg))
}
}
}
+42
View File
@@ -0,0 +1,42 @@
/*
* Copyright (c) bdew, 2013
* https://github.com/bdew/bdlib
*
* This mod is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt
*/
package net.bdew.lib.recipes
import net.minecraft.block.Block
import net.minecraft.item.Item
import scala.reflect.ClassTag
import java.lang.reflect.Modifier
object Vanilla {
// Maps of vanilla blocks and items (without tile. / item. prefixes)
lazy val blocks = mkMap[Block](_.getUnlocalizedName.stripPrefix("tile.")).withDefault(x => throw new StatementError("Block %s not found".format(x)))
lazy val items = mkMap[Item](_.getUnlocalizedName.stripPrefix("item.")).withDefault(x => throw new StatementError("Item %s not found".format(x)))
/**
* Generates the maps
* @tparam T The base class
* @param namer A function that converts objects to names
*/
private def mkMap[T](namer: T => String)(implicit t: ClassTag[T]) = {
val c = t.runtimeClass
// Grab all the fields
c.getFields.filter(x => {
// Keep only static fields that match the base Class
c.isAssignableFrom(x.getType) && Modifier.isStatic(x.getModifiers)
}).map(x => {
// Retrieve the static value
val f = x.get(null).asInstanceOf[T]
// Convert to name -> object tuples
namer(f) -> f
}).toMap // and finally to a map
}
}
@@ -0,0 +1,56 @@
/*
* Copyright (c) bdew, 2013
* https://github.com/bdew/bdlib
*
* This mod is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt
*/
package net.bdew.lib.recipes.gencfg
abstract class CfgEntry
case class EntryDouble(v: Double) extends CfgEntry
case class EntryStr(v: String) extends CfgEntry
case class ConfigSection(pfx: String = "") extends CfgEntry with Iterable[(String, CfgEntry)] {
var raw = Map.empty[String, CfgEntry].withDefault(x => sys.error("Config value '%s%s' is missing".format(pfx,x)))
def iterator: Iterator[(String, CfgEntry)] = raw.iterator
def filterType[T<:CfgEntry](cls: Class[T]): Iterable[(String,T)] = raw.filter(x=>cls.isInstance(x._2)).map(x=>x.asInstanceOf[(String,T)])
def rawget[T](id: String, t: Class[T]): T = {
val v = raw(id)
if (t.isInstance(v))
return v.asInstanceOf[T]
else
sys.error("Config value '%s%s' is of the wrong type, expected %s, got %s".format(pfx, id, t.getName, v.getClass.getName))
}
def set(id: String, v: CfgEntry) = raw += id -> v
def getDouble(id: String) = rawget(id, classOf[EntryDouble]).v
def getString(id: String) = rawget(id, classOf[EntryStr]).v
def getSection(id: String) = rawget(id, classOf[ConfigSection])
final val trueVals = Set("y", "true", "yes", "on")
def getBoolean(id: String) = trueVals.contains(getString(id).toLowerCase)
def getOrAddSection(id: String) = {
if (raw.isDefinedAt(id)) {
rawget(id, classOf[ConfigSection])
} else {
val newSection = new ConfigSection(pfx + id + ".")
set(id, newSection)
newSection
}
}
def getInt(id: String) = getDouble(id).round.toInt
def getFloat(id: String) = getDouble(id).toFloat
}
@@ -0,0 +1,24 @@
/*
* Copyright (c) bdew, 2013
* https://github.com/bdew/bdlib
*
* This mod is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt
*/
package net.bdew.lib.recipes.gencfg
import net.bdew.lib.recipes.Statement
abstract class CfgStatement
case class CfgVal(id: String, value: CfgEntry) extends CfgStatement
case class CfgSub(id: String, vals: List[CfgStatement]) extends CfgStatement
case class StCfg(id: String, vals: List[CfgStatement]) extends Statement
@@ -0,0 +1,33 @@
/*
* Copyright (c) bdew, 2013
* https://github.com/bdew/bdlib
*
* This mod is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt
*/
package net.bdew.lib.recipes.gencfg
import net.bdew.lib.recipes.{Statement, RecipeLoader}
trait GenericConfigLoader extends RecipeLoader {
val cfgStore: ConfigSection
def processConfigStatement(section: ConfigSection, s: CfgStatement): Unit = s match {
case CfgVal(id, v) =>
log.info("Config: %s%s = %s".format(section.pfx, id, v))
section.set(id, v)
case CfgSub(id, st) => processConfigBlock(section.getOrAddSection(id), st)
case x =>
log.severe("Can't process %s - this is a programing bug!".format(x))
}
def processConfigBlock(view: ConfigSection, block: List[CfgStatement]) = for (s <- block) processConfigStatement(view, s)
override def processStatement(s: Statement) = s match {
case StCfg(id, st) => processConfigBlock(cfgStore.getOrAddSection(id), st)
case _ => super.processStatement(s)
}
}
@@ -0,0 +1,26 @@
/*
* Copyright (c) bdew, 2013
* https://github.com/bdew/bdlib
*
* This mod is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt
*/
package net.bdew.lib.recipes.gencfg
import net.bdew.lib.recipes.RecipeParser
trait GenericConfigParser extends RecipeParser {
override def statement = statementCfg | super.statement
def cfgStatementNum = ident ~ "=" ~ decimalNumber ^^ { case id ~ eq ~ n => CfgVal(id, EntryDouble(n.toDouble)) }
def cfgStatementStr = ident ~ "=" ~ str ^^ { case id ~ eq ~ s => CfgVal(id, EntryStr(s)) }
def cfgStatementSub = cfgBlock ^^ { case (id, st) => CfgSub(id, st) }
def cfgStatement = cfgStatementNum | cfgStatementStr | cfgStatementSub
// A bit of type acrobatics because this is recursive (via cfgStatementSub), the tuple is translated into the proper class in either cfgStatementSub or cfg
def cfgBlock: Parser[(String, List[CfgStatement])] = "cfg" ~> ident ~ ("{" ~> cfgStatement.* <~ "}") ^^ { case id ~ st => (id, st) }
def statementCfg = cfgBlock ^^ { case (id, st) => StCfg(id, st) }
}
@@ -0,0 +1,92 @@
/*
* Copyright (c) bdew, 2013
* https://github.com/bdew/bdlib
*
* This mod is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt
*/
package net.bdew.lib.rotate
import cpw.mods.fml.relauncher.Side
import cpw.mods.fml.relauncher.SideOnly
import net.minecraft.block.Block
import net.minecraft.entity.EntityLivingBase
import net.minecraft.item.ItemStack
import net.minecraft.util.Icon
import net.minecraft.util.MathHelper
import net.minecraft.world.IBlockAccess
import net.minecraft.world.World
import net.minecraftforge.common.ForgeDirection
import java.util.EnumSet
/**
* Basic logic for block rotatation
*/
trait BaseRotateableBlock extends Block {
/**
* Override this method to provide your textures, also called when rendering as item
*/
def getIcon(meta: Int, kind: IconType.Value): Icon
/**
* Override this method to provide your textures, if you need to check other state
*/
def getIcon(world: IBlockAccess, x: Int, y: Int, z: Int, kind: IconType.Value): Icon = getIcon(world.getBlockMetadata(x, y, z), kind)
/**
* Set of valid rotations, default is all of them
*/
def getValidFacings: EnumSet[ForgeDirection] = {
return EnumSet.allOf(classOf[ForgeDirection])
}
/**
* Rotation to show when it's unavailable (like rendering item in inventory)
*/
def getDefaultFacing: ForgeDirection = ForgeDirection.UP
/**
* Those will be overrided to provide concrete storage
*/
def setFacing(world: World, x: Int, y: Int, z: Int, facing: ForgeDirection)
def getFacing(world: IBlockAccess, x: Int, y: Int, z: Int): ForgeDirection
override def rotateBlock(worldObj: World, x: Int, y: Int, z: Int, axis: ForgeDirection): Boolean = {
if (getValidFacings.contains(axis)) {
setFacing(worldObj, x, y, z, axis)
return true
}
return false
}
@SideOnly(Side.CLIENT)
override def getIcon(side: Int, meta: Int): Icon = getIcon(meta, IconType.fromSideAndDir(side, getDefaultFacing))
@SideOnly(Side.CLIENT)
override def getBlockTexture(world: IBlockAccess, x: Int, y: Int, z: Int, side: Int): Icon = getIcon(world, x, y, z, IconType.fromSideAndDir(side, getFacing(world, x, y, z)))
override def getValidRotations(worldObj: World, x: Int, y: Int, z: Int): Array[ForgeDirection] = getValidFacings.toArray(Array.empty[ForgeDirection])
override def onBlockPlacedBy(world: World, x: Int, y: Int, z: Int, ent: EntityLivingBase, stack: ItemStack) {
val validRotations = getValidFacings
var dir = getDefaultFacing
if (ent != null) {
val pitch: Int = Math.round(ent.rotationPitch)
val yaw: Int = MathHelper.floor_double(ent.rotationYaw * 4.0F / 360.0F + 0.5D) & 3
dir = yaw match {
case _ if pitch >= 50 && validRotations.contains(ForgeDirection.UP) => ForgeDirection.UP
case _ if pitch <= -50 && validRotations.contains(ForgeDirection.DOWN) => ForgeDirection.DOWN
case 0 if validRotations.contains(ForgeDirection.NORTH) => ForgeDirection.NORTH
case 1 if validRotations.contains(ForgeDirection.EAST) => ForgeDirection.EAST
case 2 if validRotations.contains(ForgeDirection.SOUTH) => ForgeDirection.SOUTH
case 3 if validRotations.contains(ForgeDirection.WEST) => ForgeDirection.WEST
case _ => dir
}
}
setFacing(world, x, y, z, dir)
super.onBlockPlacedBy(world, x, y, z, ent, stack)
}
}
+28
View File
@@ -0,0 +1,28 @@
/*
* Copyright (c) bdew, 2013
* https://github.com/bdew/bdlib
*
* This mod is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt
*/
package net.bdew.lib.rotate
import net.minecraftforge.common.ForgeDirection
object IconType extends Enumeration {
val BACK = Value(0, "BACK")
val FRONT = Value(1, "FRONT")
val SIDE = Value(2, "SIDE")
def fromSideAndDir(side: Int, facing: ForgeDirection) = this(metaSideMap(side)(facing.ordinal))
val metaSideMap = Array(
Array(1, 0, 2, 2, 2, 2),
Array(0, 1, 2, 2, 2, 2),
Array(2, 2, 1, 0, 2, 2),
Array(2, 2, 0, 1, 2, 2),
Array(2, 2, 2, 2, 1, 0),
Array(2, 2, 2, 2, 0, 1))
}
@@ -0,0 +1,17 @@
/*
* Copyright (c) bdew, 2013
* https://github.com/bdew/bdlib
*
* This mod is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt
*/
package net.bdew.lib.rotate
import net.bdew.lib.data.base.{UpdateKind, TileDataSlots}
import net.bdew.lib.data.DataSlotDirection
trait RotateableTile extends TileDataSlots {
var rotation = DataSlotDirection("rotation", this).setUpdate(UpdateKind.SAVE, UpdateKind.WORLD)
}
@@ -0,0 +1,34 @@
/*
* Copyright (c) bdew, 2013
* https://github.com/bdew/bdlib
*
* This mod is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt
*/
package net.bdew.lib.rotate
import net.minecraft.block.ITileEntityProvider
import net.minecraft.world.IBlockAccess
import net.minecraft.world.World
import net.minecraftforge.common.ForgeDirection
import cpw.mods.fml.common.FMLCommonHandler
/**
* Stores rotation data in tile entity. The TE should implement {@link RotateableTile}
*/
trait RotateableTileBlock extends BaseRotateableBlock with ITileEntityProvider {
def setFacing(world: World, x: Int, y: Int, z: Int, facing: ForgeDirection) {
world.getBlockTileEntity(x, y, z).asInstanceOf[RotateableTile].rotation := facing
}
def getFacing(world: IBlockAccess, x: Int, y: Int, z: Int): ForgeDirection = {
val te: RotateableTile = world.getBlockTileEntity(x, y, z).asInstanceOf[RotateableTile]
if (te == null || te.rotation == null) {
FMLCommonHandler.instance().getFMLLogger.warning("Failed gettig rocation for block at %d, %d, %d".format(x, y, z))
return getDefaultFacing
}
return te.rotation
}
}
+14
View File
@@ -0,0 +1,14 @@
/*
* Copyright (c) bdew, 2013
* https://github.com/bdew/bdlib
*
* This mod is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt
*/
package net.bdew.lib.tile
trait Component {
def added(p: TileExtended, name: String)
}
+46
View File
@@ -0,0 +1,46 @@
/*
* Copyright (c) bdew, 2013
* https://github.com/bdew/bdlib
*
* This mod is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt
*/
package net.bdew.lib.tile
import net.minecraft.tileentity.TileEntity
import net.minecraftforge.fluids._
import net.minecraftforge.common.ForgeDirection
trait ExposeTank extends TileEntity with IFluidHandler {
def getTankFromDirection(dir: ForgeDirection): IFluidTank
def fill(from: ForgeDirection, resource: FluidStack, doFill: Boolean): Int = {
val tank = getTankFromDirection(from)
if (tank == null) return 0
return tank.fill(resource, doFill)
}
def drain(from: ForgeDirection, resource: FluidStack, doDrain: Boolean): FluidStack = {
val tank = getTankFromDirection(from)
if (tank == null || resource == null || !resource.isFluidEqual(tank.getFluid)) return null
return tank.drain(resource.amount, doDrain)
}
def drain(from: ForgeDirection, maxDrain: Int, doDrain: Boolean): FluidStack = {
val tank = getTankFromDirection(from)
if (tank == null) return null
getTankFromDirection(from).drain(maxDrain, doDrain)
}
def canFill(from: ForgeDirection, fluid: Fluid): Boolean = getTankFromDirection(from) != null
def canDrain(from: ForgeDirection, fluid: Fluid): Boolean = getTankFromDirection(from) != null
def getTankInfo(from: ForgeDirection): Array[FluidTankInfo] = {
val tank = getTankFromDirection(from)
if (tank == null) return Array.empty[FluidTankInfo]
return Array(tank.getInfo)
}
}
+69
View File
@@ -0,0 +1,69 @@
/*
* Copyright (c) bdew, 2013
* https://github.com/bdew/bdlib
*
* This mod is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt
*/
package net.bdew.lib.tile
import net.minecraft.tileentity.TileEntity
import net.minecraft.nbt.NBTTagCompound
import net.minecraft.network.INetworkManager
import net.minecraft.network.packet.Packet132TileEntityData
import net.bdew.lib.Event
class TileExtended extends TileEntity {
final val ACT_CLIENT = 1
final val ACT_GUI = 2
var clientTick = Event()
var serverTick = Event()
var persistSave = Event[NBTTagCompound]
var persistLoad = Event[NBTTagCompound]
var sendClientUpdate = Event[NBTTagCompound]
var handleClientUpdate = Event[NBTTagCompound]
def tickClient() {}
def tickServer() {}
override final def writeToNBT(tag: NBTTagCompound) = {
super.writeToNBT(tag)
persistSave.trigger(tag)
}
override final def readFromNBT(tag: NBTTagCompound) = {
super.readFromNBT(tag)
persistLoad.trigger(tag)
}
override final def getDescriptionPacket: Packet132TileEntityData = {
if (!sendClientUpdate.hasListeners) return null
val tag = new NBTTagCompound
sendClientUpdate.trigger(tag)
return new Packet132TileEntityData(this.xCoord, this.yCoord, this.zCoord, ACT_CLIENT, tag)
}
override final def onDataPacket(net: INetworkManager, pkt: Packet132TileEntityData) {
if (pkt.actionType == ACT_CLIENT)
handleClientUpdate.trigger(pkt.data)
else
extDataPacket(pkt.actionType, pkt.data)
}
override final def updateEntity() {
if (worldObj != null) {
if (worldObj.isRemote) {
tickClient()
clientTick.trigger()
} else {
tickServer()
serverTick.trigger()
}
}
}
protected def extDataPacket(id: Int, data: NBTTagCompound) {}
}
@@ -0,0 +1,66 @@
/*
* Copyright (c) bdew, 2013
* https://github.com/bdew/bdlib
*
* This mod is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt
*/
package net.bdew.lib.tile.inventory
import net.minecraft.inventory.IInventory
import net.minecraft.item.ItemStack
import net.minecraft.entity.player.EntityPlayer
trait BaseInventory extends IInventory {
var inv: Array[ItemStack] = new Array(getSizeInventory)
def getStackInSlot(i: Int): ItemStack = inv(i)
def getInvName = ""
def isInvNameLocalized = false
def getInventoryStackLimit = 64
def isUseableByPlayer(player: EntityPlayer) = true
def openChest() = Unit
def closeChest() = Unit
def isItemValidForSlot(slot: Int, stack: ItemStack) = true
def decrStackSize(slot: Int, n: Int): ItemStack = {
var item = inv(slot)
if (item != null) {
if (item.stackSize <= n) {
inv(slot) = null
onInventoryChanged()
return item
} else {
var newstack = item.splitStack(n)
if (item.stackSize == 0) {
inv(slot) = null
}
onInventoryChanged()
return newstack
}
} else {
return null
}
}
def getStackInSlotOnClosing(slot: Int): ItemStack = {
var tmp = inv(slot)
inv(slot) = null
onInventoryChanged()
return tmp
}
def setInventorySlotContents(slot: Int, stack: ItemStack) = {
inv(slot) = stack
onInventoryChanged()
}
}
@@ -0,0 +1,25 @@
/*
* Copyright (c) bdew, 2013
* https://github.com/bdew/bdlib
*
* This mod is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt
*/
package net.bdew.lib.tile.inventory
import net.minecraft.block.Block
import net.minecraft.world.World
trait BreakableInventoryBlock extends Block {
override def breakBlock(world: World, x: Int, y: Int, z: Int, blockId: Int, meta: Int) {
if (!world.isRemote) {
val te = world.getBlockTileEntity(x, y, z).asInstanceOf[BreakableInventoryTile]
if (te != null) {
te.dropItems()
}
}
super.breakBlock(world, x, y, z, blockId, meta)
}
}
@@ -0,0 +1,25 @@
/*
* Copyright (c) bdew, 2013
* https://github.com/bdew/bdlib
*
* This mod is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt
*/
package net.bdew.lib.tile.inventory
import net.minecraft.tileentity.TileEntity
import net.minecraft.item.ItemStack
import net.bdew.lib.items.ItemUtils
trait BreakableInventoryTile extends TileEntity with BaseInventory {
def dropItems() {
if (worldObj != null && !worldObj.isRemote) {
for (stack <- inv if stack != null) {
ItemUtils.throwItemAt(worldObj, xCoord, yCoord, zCoord, stack)
}
inv = new Array[ItemStack](inv.size)
}
}
}
@@ -0,0 +1,38 @@
/*
* Copyright (c) bdew, 2013
* https://github.com/bdew/bdlib
*
* This mod is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt
*/
package net.bdew.lib.tile.inventory
import net.minecraft.item.ItemStack
import net.minecraft.nbt.{NBTTagList, NBTTagCompound}
import net.bdew.lib.Misc
import net.bdew.lib.tile.TileExtended
trait PersistentInventoryTile extends TileExtended with BaseInventory {
persistLoad.listen((tag: NBTTagCompound) => {
inv = new Array[ItemStack](getSizeInventory)
for (nbtItem <- Misc.iterNbtList[NBTTagCompound](tag.getTagList("Items"))) {
val slot = nbtItem.getByte("Slot")
if (slot >= 0 && slot < inv.size) {
inv(slot) = ItemStack.loadItemStackFromNBT(nbtItem)
}
}
})
persistSave.listen((tag: NBTTagCompound) => {
val itemList = new NBTTagList
for ((item, i) <- inv.view.zipWithIndex if item != null) {
val itemNbt: NBTTagCompound = new NBTTagCompound
itemNbt.setByte("Slot", i.asInstanceOf[Byte])
item.writeToNBT(itemNbt)
itemList.appendTag(itemNbt)
}
tag.setTag("Items", itemList)
})
}
@@ -0,0 +1,23 @@
/*
* Copyright (c) bdew, 2013
* https://github.com/bdew/bdlib
*
* This mod is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt
*/
package net.bdew.lib.tile.inventory
import net.minecraft.inventory.ISidedInventory
import net.minecraft.item.ItemStack
trait SidedInventory extends BaseInventory with ISidedInventory {
var allowSided = false
def getAccessibleSlotsFromSide(side: Int): Array[Int] = (0 until inv.size).toArray
def canInsertItem(slot: Int, stack: ItemStack, side: Int) = allowSided && isItemValidForSlot(slot, stack)
def canExtractItem(slot: Int, stack: ItemStack, side: Int) = allowSided
}