Compare commits

...
74 Commits
Author SHA1 Message Date
bdew a6eb495fe1 bump version 2015-10-02 15:31:08 +03:00
bdew 2d539e8013 Don't try to open GUIs of nonexistant TEs if crap is passed to the gui handler 2015-10-01 00:11:05 +03:00
bdew c44729536c Replace NBSP with space in number formatting (for those locales that use it) - minecraft doesn't render NBSP correctly. 2015-09-18 17:32:36 +03:00
bdew 35def010a3 Merge pull request #19 from Mazdallier/patch-2
Update fr_FR.lang
2015-09-01 14:18:36 +03:00
Mazdallier 911f7aa159 Update fr_FR.lang
before other mod updates
2015-09-01 09:38:27 +02:00
bdew 3aef519c25 Added some hooks to cover system, fixed rendering covers when breaking blocks 2015-08-25 15:52:45 +03:00
bdew 6c59b25e2c Force US locale on all upper/lower case conversions + normalized icon registration across all mods. 2015-08-09 15:03:21 +03:00
bdew 014c1c5e6e Fixed rotatable blocks not always triggering chunk update when rotated 2015-08-05 02:08:26 +03:00
bdew 7fd040e65a Added detailed tooltips to multiblock controllers/modules 2015-08-02 16:34:28 +03:00
bdew ece84599f9 Added misc.withAutoClose - Provides something like java try-with-resources in scala 2015-07-30 15:50:53 +03:00
bdew 174af254e8 Added ChatHelper - allows building chat message with less boilerplate 2015-07-30 14:30:59 +03:00
bdew 71185838f6 Added WidgetInfoMulti 2015-07-23 15:06:50 +03:00
bdew f2cdba7800 Prevent fractional charge leftovers in capacitors (bdew/generators#43) 2015-07-19 22:56:14 +03:00
bdew 89b54300e3 Added tooltip handler system 2015-07-16 12:37:06 +03:00
bdew 9ee12091e6 Modules dataslot in multiblock controlers should not trigger render updates 2015-06-27 19:00:12 +03:00
bdew 08ccf07dfb Don't trigger chunk updates if somethings changes UpdateKind.WORLD dataslot on client. 2015-06-27 18:59:35 +03:00
bdew 382c21f732 Added KeepData mixins for blocks that keep their stuff when broken. 2015-06-24 15:50:23 +03:00
bdew 17e4bf3a2f BlockTooltip will now use the new HasItemBlock trait 2015-06-24 15:50:09 +03:00
bdew ebe2c1f34a Added HasItemBlock - trait that tells BlockManager and Machine to register custom ItemBlocks. Replaces old itemClass parameter. Version bumped to 1.9.0 2015-06-24 15:49:00 +03:00
bdew fae2825e7b Added RichNBTTagCompound.toItemStack 2015-06-24 12:05:48 +03:00
bdew b2e138f3cd TileBaseProcessor shouldn't include BreakableInventoryTile 2015-06-24 12:05:02 +03:00
bdew 9d897d0663 getActiveModId will return <unknown> instead of null 2015-06-24 12:03:58 +03:00
bdew 497917185c BreakableInventoryBlock now checks that the TileEntity extends BreakableInventoryTile at compile time 2015-06-23 11:19:03 +03:00
bdew 9ff7a75604 Build against forge 10.13.4.1448, updated to gradle 2.4 2015-06-10 11:24:27 +03:00
bdew f8bb1e8fbb Added a way to manually run ServerTickExecutionContext 2015-06-08 15:44:16 +03:00
bdew a530c66680 Added ItemBlock with tooltip 2015-06-02 16:45:22 +03:00
bdew 26af828491 Added BlockManager.registerLegacyTileEntity 2015-06-02 14:37:27 +03:00
bdew 1c0913d674 Code cleanup 2015-06-02 13:52:51 +03:00
bdew 895cfd9cb6 Improved NBT constructor 2015-05-31 15:40:08 +03:00
bdew f43dd28e03 Added easy NBT constructor - see https://gist.github.com/bdew/0a44363dcac4be85415c 2015-05-25 15:29:31 +03:00
bdew 289f8f7120 derp 2015-05-24 04:03:23 +03:00
bdew e7787fb9ca bumped version to 1.8.0, removed deprecated methods 2015-05-24 04:01:36 +03:00
bdew 58e336f8a9 Misc.haveModVersion should check APIs too, added getModVersion 2015-05-24 04:00:23 +03:00
bdew bea6a13896 Added async helpers and ServerTickExecutionContext (executes futures in server thread using tick event) 2015-05-21 18:05:33 +03:00
bdew 793ceb0024 Merge pull request #16 from Mazdallier/patch-1
Create fr_FR.lang
2015-05-13 12:07:16 +03:00
Yves 66d9be58c8 Update fr_FR.lang
--file return back
2015-05-12 17:13:57 +02:00
Yves 87d64208c8 Create fr_FR.lang 2015-05-12 15:59:10 +02:00
bdew 6f6496c1e3 /oredistribution - added dense ore support 2015-05-12 16:04:44 +03:00
bdew 934e984abf /oredistribution - Added option to dump to file 2015-05-12 16:02:03 +03:00
bdew 4900537a82 /oredistribution - Fixed meta detection with some ores (e.g. lapis) 2015-05-12 10:19:37 +03:00
bdew 31b5ab9d52 Added /oredistribution command 2015-05-10 22:37:04 +03:00
bdew 8a4ccf7d81 Prevent build failure when CF api key is not available 2015-05-10 15:49:37 +03:00
bdew 429107215f Allow fractional chances in config lootlists 2015-05-10 15:36:31 +03:00
bdew 0c60d596b6 Jenkins will now upload builds to curseforge 2015-05-10 15:35:45 +03:00
bdew da35094895 Merge pull request #14 from theelixzammuto/mc1710
Added Italian Localization
2015-04-27 23:30:19 +03:00
theelixzammuto 83d30f12c2 Added Italian Localization 2015-04-26 21:42:29 +02:00
bdew 8d4484ca18 DataSlotTankRestricted now takes fluid object instead of fluid ID 2015-04-20 14:53:25 +03:00
bdew 624df87299 Updated to grade 2.3, reworked build script to use properties file, changed version format to include MC version 2015-04-20 14:37:23 +03:00
bdew 18b4f19dab Compatibility fix for forge 10.13.3.x 2015-04-14 19:29:13 +03:00
bdew 00b32712a0 Added TankEmulator 2015-04-02 11:22:47 +03:00
bdew 2a008aa093 Refactored nbt helper 2015-04-02 10:29:28 +03:00
bdew 745170415e changed SimpleGenericSensor.parameters back to GenericSensorParameter for greater flexibility 2015-03-30 14:50:48 +03:00
bdew 69b8e80c5f Removed unused field from DataSlotResource and fixed warning 2015-03-30 14:49:54 +03:00
bdew 93ccc42429 Refactored some common code into bdlib, added ability for modules to decide if they can connect to a controller 2015-03-25 17:34:13 +02:00
bdew dc567bd1be More work on sensors 2015-03-25 16:34:46 +02:00
bdew 516133ee0a Fixed multiple derps in 61ba86d451 2015-03-25 16:18:54 +02:00
bdew 28de3620a2 Added human readable errors to NBTTypes 2015-03-25 13:28:18 +02:00
bdew 61ba86d451 Added NBTHelper, changed OutputConfigFluid to use moving average 2015-03-25 13:11:52 +02:00
bdew 8e65772cae More work on sensor system 2015-03-25 10:46:18 +02:00
bdew 284cdfc970 Fixed crash on dedicated servers (bdew/generators#29) 2015-03-24 13:47:58 +02:00
bdew bae688c366 More sensor changes 2015-03-23 17:42:36 +02:00
bdew d3952b69d0 More work on sensor system 2015-03-22 16:14:29 +02:00
bdew 399abf1054 Attempt to Fix getWorldObj reobfuscation shenanigans 2015-03-18 10:40:16 +02:00
bdew f66b97d0cc Refactored TileDataSlots into a base trait DataSlotContainer that can be implemented by other things 2015-03-15 10:20:19 +02:00
bdew 13778072c0 derp 2015-03-12 17:03:39 +02:00
bdew 7dc95fcce1 Give a sensible error if trying to use a Block with no matching ItemBlock in recipes 2015-03-12 17:01:11 +02:00
bdew b71db73b11 Allowed custom ItemBlock registration in BlockManager 2015-03-11 18:00:58 +02:00
bdew 530d5add82 Moved block rotation from player camera logic into a separate object 2015-03-11 18:00:32 +02:00
bdew 3dd917b2a0 Added BlockAccessProxy 2015-03-11 17:06:53 +02:00
bdew 8f44111b4c Fixed item rendering for rotated blocks 2015-03-06 20:56:23 +02:00
bdew 8415ee7a00 Added slot types for sensors 2015-03-04 11:03:06 +02:00
bdew 6439ef8f08 Added Misc.prevInSeq, Added SimpleInventory 2015-03-04 11:02:37 +02:00
bdew dc59ee3d31 Added RotatedBlockRenderer and support for rotated blocks to ConnectedRenderer 2015-03-03 17:47:32 +02:00
bdew 9ae4935fd9 Added sensor system
Bump version
2015-03-03 17:46:45 +02:00
116 changed files with 2399 additions and 299 deletions

No files matched your search

+35 -13
View File
@@ -21,21 +21,30 @@ buildscript {
apply plugin: 'scala'
apply plugin: 'forge'
version = "1.6.5"
file "build.properties" withReader {
def prop = new Properties()
prop.load(it)
ext.config = new ConfigSlurper().parse prop
}
if (project.hasProperty('forgeOverride')) {
config.forge.version = forgeOverride
}
if (project.hasProperty('buildnum')) {
project.version = project.version + '.' + project.buildnum
ext.simpleVersion = "${config.bdlib.version}.${project.buildnum}"
} else {
project.version = "0-SNAPSHOT"
ext.simpleVersion = "${config.bdlib.version}-DEV"
}
version = simpleVersion + '-mc' + config.minecraft.version
group = "net.bdew"
archivesBaseName = "bdlib"
ext.versuffix = "mc1710"
minecraft {
version = "1.7.10-10.13.2.1291"
replace("BDLIB_VER", project.version)
version = "${config.minecraft.version}-${config.forge.version}"
replace("BDLIB_VER", simpleVersion.toString())
}
import org.apache.tools.ant.filters.ReplaceTokens
@@ -66,16 +75,18 @@ processResources {
}
task sourceJar(type: Jar) {
from sourceSets.main.allSource
classifier "sources"
}
task deobfJar(type: Jar) {
from sourceSets.main.output
classifier "dev"
duplicatesStrategy "exclude"
}
jar {
appendix = project.versuffix
afterEvaluate { project ->
// Fudge the inputs of source jars so we get the version after replacements
tasks.getByPath(":sourceJar").from(tasks.getByPath(":sourceMainScala").outputs.files)
}
artifacts {
@@ -89,10 +100,7 @@ publishing {
publications {
maven(MavenPublication) {
artifact deobfJar
artifact sourceJar {
classifier "sources"
}
artifact sourceJar
}
}
repositories {
@@ -100,4 +108,18 @@ publishing {
url "file://var/www/maven"
}
}
}
apply plugin: 'curseforge'
curse {
projectId = config.curseforge.id
apiKey = project.hasProperty("curseForgeApiKey") ? project.curseForgeApiKey : ""
releaseType = 'alpha'
artifact = jar
changelog = project.hasProperty("changelog") ? project.changelog : "No changelog available"
additionalArtifact deobfJar
additionalArtifact sourceJar
}
+5
View File
@@ -0,0 +1,5 @@
bdlib.version=1.9.3
curseforge.id=70496
minecraft.version=1.7.10
forge.version=10.13.4.1448-1.7.10
+1 -1
View File
@@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-2.0-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-2.4-bin.zip
Vendored Regular → Executable
View File
File mode changed.
+11
View File
@@ -9,6 +9,10 @@ bdlib.multiblock.disabled=Disabled
bdlib.multiblock.incomplete=This machine is incomplete, it requires at least:
bdlib.multiblock.notconnected=Not connected to a valid machine
bdlib.multiblock.toomanyoutputs=Too many outputs connected, unable to attach new connection
bdlib.multiblock.tip.module=Can be installed in:
bdlib.multiblock.tip.controller=Possible modules:
bdlib.multiblock.tip.module.range= * %s (%s - %s)
bdlib.multiblock.tip.module.max= * %s (up to %s)
bdlib.rsmode.always=Always ON
bdlib.rsmode.never=Disabled
@@ -17,3 +21,10 @@ bdlib.rsmode.rs_off=Disable on redstone
bdlib.label.empty=Empty
bdlib.oredistribution.usage=/oredistribution <radius> [<min height>] [<max height>] [--file]
bdlib.oredistribution.start1=Checking ore distribution in (%s,%s,%s) to (%s,%s,%s) dim %s
bdlib.oredistribution.start2=Server may lag for a while
bdlib.oredistribution.entry=%s %s - %s (%s%%)
bdlib.oredistribution.warn=%s Warning: %s has multiple variants generated:
bdlib.oredistribution.saved=Ore distribution dumped to %s
bdlib.oredistribution.error=Failed to save ore distribution dump: %s
+30
View File
@@ -0,0 +1,30 @@
bdlib.multiblock.face.north=Nord
bdlib.multiblock.face.south=Sud
bdlib.multiblock.face.east=Est
bdlib.multiblock.face.west=Ouest
bdlib.multiblock.face.up=Dessus
bdlib.multiblock.face.down=Dessous
bdlib.multiblock.disabled=Désactivé
bdlib.multiblock.incomplete=Cette machine est incomplète, elle exige au moins :
bdlib.multiblock.notconnected=Pas connecté à une machine valide
bdlib.multiblock.toomanyoutputs=Trop de sorties connectées, impossible d'ajouter une nouvelle connexion
bdlib.multiblock.tip.module=Peut être installé dans :
bdlib.multiblock.tip.controller=Modules possibles:
bdlib.multiblock.tip.module.range= * %s (%s - %s)
bdlib.multiblock.tip.module.max= * %s (plus de %s)
bdlib.rsmode.always=Toujours actif
bdlib.rsmode.never=Désactivé
bdlib.rsmode.rs_on=Activé par redstone
bdlib.rsmode.rs_off=Désactivé par redstone
bdlib.label.empty=Vide
bdlib.oredistribution.usage=/oredistribution <rayon> [<hauteur mini>] [<hauteur maxi>] [--file]
bdlib.oredistribution.start1=Valide la distribution de minerai entre (%s,%s,%s) et (%s,%s,%s) dim %s
bdlib.oredistribution.start2=Le server peut ralentir pendantun certain temps
bdlib.oredistribution.entry=%s %s - %s (%s%%)
bdlib.oredistribution.warn=%s Attention: %s fait produire des variantes multiples :
bdlib.oredistribution.saved=Distribution de minerai déposée dans %s
bdlib.oredistribution.error=Impossible d'enregistrer la distribution de minerai : %s
+18
View File
@@ -0,0 +1,18 @@
bdlib.multiblock.face.north=Nord
bdlib.multiblock.face.south=Sud
bdlib.multiblock.face.east=Est
bdlib.multiblock.face.west=Ovest
bdlib.multiblock.face.up=Sopra
bdlib.multiblock.face.down=Sotto
bdlib.multiblock.disabled=Disattivo
bdlib.multiblock.incomplete=Questa macchina è incompleta, richiede almeno:
bdlib.multiblock.notconnected=Non connesso ad una macchina valida
bdlib.multiblock.toomanyoutputs=Troppi Output collegati,impossibile inserire una nuova connessione
bdlib.rsmode.always=Sempre Attivo
bdlib.rsmode.never=Disattivo
bdlib.rsmode.rs_on=Attivo su Impulso di Pietrarossa
bdlib.rsmode.rs_off=Disattivo su Impulso di Pietrarossa
bdlib.label.empty=Vuoto
+2 -1
View File
@@ -10,6 +10,7 @@
package net.bdew.lib
import java.util
import java.util.Locale
import cpw.mods.fml.common.{ICrashCallable, ModAPIManager, ModContainer}
@@ -20,7 +21,7 @@ object ApiReporter extends ICrashCallable {
val mods = new util.ArrayList[ModContainer]
val nameLookup = new util.HashMap[String, ModContainer]
ModAPIManager.INSTANCE.injectAPIModContainers(mods, nameLookup)
(for (mod <- mods.sortBy(_.getModId.toLowerCase)) yield
(for (mod <- mods.sortBy(_.getModId.toLowerCase(Locale.US))) yield
"\t\t* %s (%s) from %s".format(mod.getModId, mod.getVersion,
if (mod.getSource.isDirectory)
mod.getSource
+6 -1
View File
@@ -13,6 +13,7 @@ import cpw.mods.fml.common.Mod.EventHandler
import cpw.mods.fml.common.event.{FMLPreInitializationEvent, FMLServerStartingEvent, FMLServerStoppingEvent}
import cpw.mods.fml.common.{FMLCommonHandler, Mod}
import net.bdew.lib.multiblock.network.NetHandler
import net.bdew.lib.tooltip.TooltipHandler
import net.minecraft.command.CommandHandler
import org.apache.logging.log4j.Logger
@@ -37,12 +38,16 @@ object BdLib {
log.debug("List of loaded APIs: " + ApiReporter.APIs)
FMLCommonHandler.instance().registerCrashCallable(ApiReporter)
NetHandler.init()
if (ev.getSide.isClient) {
TooltipHandler.init()
}
}
@EventHandler
def serverStarting(event: FMLServerStartingEvent) {
val commandHandler = event.getServer.getCommandManager.asInstanceOf[CommandHandler]
commandHandler.registerCommand(new CommandDumpRegistry)
commandHandler.registerCommand(CommandDumpRegistry)
commandHandler.registerCommand(CommandOreDistribution)
onServerStarting.trigger(event)
}
+1 -1
View File
@@ -19,7 +19,7 @@ import net.minecraft.item.ItemStack
import net.minecraftforge.fluids.FluidRegistry
import net.minecraftforge.oredict.OreDictionary
class CommandDumpRegistry extends CommandBase {
object CommandDumpRegistry extends CommandBase {
def getCommandName = "dumpregistry"
override def getRequiredPermissionLevel = 2
def getCommandUsage(c: ICommandSender) = "dumpregistry"
@@ -0,0 +1,148 @@
/*
* 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
import java.io.{BufferedWriter, File, FileWriter}
import cpw.mods.fml.common.registry.GameData
import cpw.mods.fml.relauncher.FMLInjectionData
import net.minecraft.command.{CommandBase, ICommandSender, WrongUsageException}
import net.minecraft.entity.player.EntityPlayerMP
import net.minecraft.item.Item
import net.minecraft.util.EnumChatFormatting
import net.minecraftforge.oredict.OreDictionary
import scala.collection.mutable
object CommandOreDistribution extends CommandBase {
def getCommandName = "oredistribution"
override def getRequiredPermissionLevel = 2
def getCommandUsage(c: ICommandSender) = "bdlib.oredistribution.usage"
def safeInt(s: String) =
try {
s.toInt
} catch {
case e: NumberFormatException => throw new WrongUsageException("bdlib.oredistribution.usage")
}
def wrapColor(s: String, c: EnumChatFormatting) = c + s + EnumChatFormatting.RESET
def processCommand(sender: ICommandSender, baseParams: Array[String]) {
val (flags, params) = baseParams.partition(_.startsWith("--"))
if (params.length < 1 || params.length > 3)
throw new WrongUsageException(getCommandUsage(sender))
val (startX, startZ, world) =
sender match {
case p: EntityPlayerMP => (p.posX.toInt, p.posZ.toInt, p.worldObj)
case _ => (0, 0, sender.getEntityWorld)
}
val radius = safeInt(params.head)
val minY = if (params.length >= 2) safeInt(params(1)) else 0
val maxY = if (params.length >= 3) safeInt(params(2)) else world.getHeight - 1
if (minY < 0 || radius <= 0 || minY > maxY || maxY > world.getHeight - 1)
throw new WrongUsageException(getCommandUsage(sender))
val toFile = flags.contains("--file")
// why java, WHY?
CommandBase.func_152373_a(sender, this, "bdlib.oredistribution.start1",
Array[Integer](startX - radius, minY, startZ - radius, startX + radius, maxY, startZ + radius, world.provider.dimensionId): _*)
CommandBase.func_152373_a(sender, this, "bdlib.oredistribution.start2")
import scala.collection.JavaConversions._
val ores = (OreDictionary.getOreNames.filter(x => x.startsWith("ore") || x.startsWith("denseore")) flatMap { name =>
val fixedName =
if (name.startsWith("ore"))
name.substring(3)
else if (name.startsWith("denseore"))
"Dense " + name.substring(8)
else name
for (s <- OreDictionary.getOres(name)) yield (s.getItem, s.getItemDamage) -> fixedName
}).toMap
val distribution = mutable.Map.empty[String, Int].withDefaultValue(0)
val kinds = mutable.Map.empty[String, Set[(Item, Int)]].withDefaultValue(Set.empty)
for {
x <- startX - radius to startX + radius
y <- minY to maxY
z <- startZ - radius to startZ + radius
if !world.isAirBlock(x, y, z)
} {
val key = (Item.getItemFromBlock(world.getBlock(x, y, z)), world.getBlockMetadata(x, y, z))
for (ore <- ores.get(key)) {
distribution(ore) += 1
kinds(ore) += key
}
}
val total = distribution.values.sum
val warnings = kinds.filter(_._2.size > 1)
if (toFile) {
// === OUTPUT TO FILE ===
val mcHome = FMLInjectionData.data()(6).asInstanceOf[File] //is there a better way to get this?
val dumpFile = new File(mcHome, "ore_distribution.txt")
val dumpWriter = new BufferedWriter(new FileWriter(dumpFile))
try {
dumpWriter.write("Ore distribution report - (%d,%d,%d) to (%d,%d,%d) dim %d".format(
startX - radius, minY, startZ - radius, startX + radius, maxY, startZ + radius, world.provider.dimensionId
))
dumpWriter.newLine()
dumpWriter.newLine()
if (warnings.nonEmpty) {
for ((id, types) <- warnings.toList.sortBy(_._1)) {
dumpWriter.write("Warning: %s has multiple variants generated:".format(id))
dumpWriter.newLine()
for ((item, dmg) <- types) {
dumpWriter.write(" - %s@%s".format(GameData.getItemRegistry.getNameForObject(item), dmg))
dumpWriter.newLine()
}
dumpWriter.newLine()
}
dumpWriter.write("=================")
dumpWriter.newLine()
dumpWriter.newLine()
}
for ((id, num) <- distribution.filter(_._2 > 0).toList.sortBy(-_._2)) {
dumpWriter.write("%s - %s (%s%%)".format(id, DecFormat.round(num), DecFormat.short(100F * num / total)))
dumpWriter.newLine()
}
CommandBase.func_152373_a(sender, this, "bdlib.oredistribution.saved", dumpFile.getCanonicalPath)
} catch {
case e: Throwable =>
CommandBase.func_152373_a(sender, this, "bdlib.oredistribution.error", e.toString)
BdLib.logErrorException("Failed to save ore distribution dump", e)
} finally {
dumpWriter.close()
}
} else {
// === OUTPUT TO CHAT ===
for ((id, types) <- warnings.toList.sortBy(_._1)) {
CommandBase.func_152373_a(sender, this, "bdlib.oredistribution.warn",
wrapColor(" !", EnumChatFormatting.RED), wrapColor(id, EnumChatFormatting.RED))
for ((item, dmg) <- types)
CommandBase.func_152373_a(sender, this, wrapColor(" - ", EnumChatFormatting.RED) + GameData.getItemRegistry.getNameForObject(item) + "@" + dmg)
}
for ((id, num) <- distribution.filter(_._2 > 0).toList.sortBy(-_._2)) {
CommandBase.func_152373_a(sender, this, "bdlib.oredistribution.entry",
" *", wrapColor(id, EnumChatFormatting.YELLOW),
DecFormat.round(num), DecFormat.short(100F * num / total))
}
}
}
}
+6 -6
View File
@@ -16,13 +16,13 @@ object DecFormat {
val dec2Fmt = new DecimalFormat("#,##0.00")
val dec1Fmt = new DecimalFormat("#,##0.0")
def round(x: Double) = thousandsFmt.format(x)
def round(x: Float) = thousandsFmt.format(x)
def round(x: Int) = thousandsFmt.format(x)
def round(x: Double) = thousandsFmt.format(x).replace('\u00A0', ' ')
def round(x: Float) = thousandsFmt.format(x).replace('\u00A0', ' ')
def round(x: Int) = thousandsFmt.format(x).replace('\u00A0', ' ')
def dec2(x: Double) = dec2Fmt.format(x)
def dec2(x: Float) = dec2Fmt.format(x)
def dec2(x: Int) = dec2Fmt.format(x)
def dec2(x: Double) = dec2Fmt.format(x).replace('\u00A0', ' ')
def dec2(x: Float) = dec2Fmt.format(x).replace('\u00A0', ' ')
def dec2(x: Int) = dec2Fmt.format(x).replace('\u00A0', ' ')
def short(x: Double) = if (x > 10) thousandsFmt.format(x) else if (x > 1) dec1Fmt.format(x) else dec2Fmt.format(x)
def short(x: Float) = if (x > 10) thousandsFmt.format(x) else if (x > 1) dec1Fmt.format(x) else dec2Fmt.format(x)
+1 -1
View File
@@ -12,7 +12,7 @@ package net.bdew.lib
class EventBase[T] extends {
var listeners = Seq.empty[T]
def listen(x: T) = listeners :+= x
def hasListeners = listeners.size > 0
def hasListeners = listeners.nonEmpty
}
class Event0 extends EventBase[() => Unit] {
+65 -23
View File
@@ -9,9 +9,12 @@
package net.bdew.lib
import cpw.mods.fml.common.Loader
import java.util
import java.util.Locale
import cpw.mods.fml.common.registry.GameRegistry
import cpw.mods.fml.common.versioning.{ArtifactVersion, VersionParser}
import cpw.mods.fml.common.versioning.VersionParser
import cpw.mods.fml.common.{Loader, ModAPIManager, ModContainer}
import net.minecraft.item.ItemStack
import net.minecraft.nbt.NBTTagCompound
import net.minecraft.tileentity.TileEntity
@@ -22,26 +25,16 @@ import net.minecraftforge.fluids.{Fluid, FluidStack}
import net.minecraftforge.oredict.ShapedOreRecipe
object Misc {
def iterNbtCompoundList(parent: NBTTagCompound, name: String): Iterable[NBTTagCompound] = {
val list = parent.getTagList(name, 10)
for (i <- 0 until list.tagCount()) yield list.getCompoundTagAt(i)
}
def iterNbtIntArray(parent: NBTTagCompound, name: String): Iterable[Array[Int]] = {
val list = parent.getTagList(name, 11)
for (i <- 0 until list.tagCount()) yield list.func_150306_c(i)
}
def getActiveModId = Loader.instance().activeModContainer().getModId
def getActiveModId = Option(Loader.instance().activeModContainer().getModId) getOrElse "<UNKNOWN>"
def toLocal(s: String) = StatCollector.translateToLocal(s)
def toLocalF(s: String, params: Any*) = StatCollector.translateToLocal(s).format(params: _*)
def hasLocal(s: String) = StatCollector.canTranslate(s)
def flattenRecipe(pattern: Seq[String], items: Map[Char, AnyRef]) =
pattern ++ items.map {
pattern ++ items.flatMap {
case (k, v) => Seq(new Character(k), v)
}.flatten
}
def wrapTag(n: String, f: (NBTTagCompound) => Any)(t: NBTTagCompound) {
val p = t.getCompoundTag(n)
@@ -67,17 +60,28 @@ object Misc {
def getBiomeByName(name: String) = BiomeGenBase.getBiomeGenArray.find(x => x != null && x.biomeName == name).orNull
def haveModVersion(spec: String): Boolean = {
val req = VersionParser.parseVersionReference(spec)
val modId = req.getLabel
private lazy val modLookup = {
val mods = new util.ArrayList[ModContainer]
val nameLookup = new util.HashMap[String, ModContainer]
if (!Loader.instance.getIndexedModList.containsKey(modId)) return false
nameLookup.putAll(Loader.instance().getIndexedModList)
ModAPIManager.INSTANCE.injectAPIModContainers(mods, nameLookup)
val found: ArtifactVersion = Loader.instance.getIndexedModList.get(modId).getProcessedVersion
import scala.collection.JavaConverters._
nameLookup.asScala
}
if (found == null || !req.containsVersion(found)) return false
def haveModVersion(modId: String) = {
val spec = VersionParser.parseVersionReference(modId)
modLookup.contains(spec.getLabel) && spec.containsVersion(modLookup(spec.getLabel).getProcessedVersion)
}
return true
def getModVersion(modId: String) =
modLookup.get(modId) map (_.getVersion)
def getModVersionString(modId: String): String = {
val cont = modLookup.getOrElse(modId, return "NOT FOUND")
cont.getModId + " " + cont.getVersion
}
// Because writing this every time is awkward
@@ -108,11 +112,19 @@ object Misc {
def nextInSeq[T](seq: Seq[T], elem: T) = {
val pos = seq.indexOf(elem)
if (pos < 0 || pos == seq.size - 1)
seq(0)
seq.head
else
seq(pos + 1)
}
def prevInSeq[T](seq: Seq[T], elem: T) = {
val pos = seq.indexOf(elem)
if (pos <= 0)
seq.last
else
seq(pos - 1)
}
def getFluidIcon(fs: FluidStack): IIcon =
if (fs != null && fs.getFluid != null && fs.getFluid.getIcon != null)
fs.getFluid.getIcon(fs)
@@ -129,5 +141,35 @@ object Misc {
if (f != null) getFluidColor(new FluidStack(f, 1)) else 0xFFFFFF
lazy val lineSeparator = System.getProperty("line.separator")
/**
* Provides something like java try-with-resources in scala
*/
def withAutoClose[T <: AutoCloseable, R](o: T)(f: T => R): R = {
val res = try {
f(o)
} catch {
case t1: Throwable =>
if (o != null) {
try {
o.close()
} catch {
case t2: Throwable =>
t1.addSuppressed(t2)
}
}
throw t1
}
if (o != null)
o.close()
res
}
def iconName(domain: String, name: String, path: String*) =
if (path.isEmpty)
"%s:%s".format(domain, name).toLowerCase(Locale.US)
else
"%s:%s/%s".format(domain, name, path.mkString("/")).toLowerCase(Locale.US)
}
+30
View File
@@ -0,0 +1,30 @@
/*
* Copyright (c) bdew, 2013 - 2015
* 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.async
import scala.concurrent.{Future, Promise}
object Async {
def inOtherThread[T](f: => T) = {
val p = Promise[T]()
val t = new Thread(new Runnable {
override def run(): Unit =
try {
p.success(f)
} catch {
case t: Throwable => p.failure(t)
}
})
t.start()
p.future
}
def inServerThread[T](f: => T) = Future(f)(ServerTickExecutionContext)
}
@@ -0,0 +1,55 @@
/*
* Copyright (c) bdew, 2013 - 2015
* 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.async
import cpw.mods.fml.common.FMLCommonHandler
import cpw.mods.fml.common.eventhandler.SubscribeEvent
import cpw.mods.fml.common.gameevent.TickEvent.ServerTickEvent
import net.bdew.lib.BdLib
import scala.collection.mutable
import scala.concurrent.ExecutionContext
object ServerTickExecutionContext extends ExecutionContext {
private val queue = mutable.Queue.empty[Runnable]
FMLCommonHandler.instance.bus.register(this)
BdLib.logDebug("Installed ServerTickExecutionContext")
private def getNextBatch = this.synchronized {
if (queue.nonEmpty) {
val res = queue.toList
queue.clear()
res
} else List.empty
}
override def execute(runnable: Runnable): Unit =
this.synchronized {
queue += runnable
}
override def reportFailure(cause: Throwable): Unit =
BdLib.logErrorException("Error in execution context", cause)
def doSingleLoop(): Unit = {
for (r <- getNextBatch) {
try {
r.run()
} catch {
case t: Throwable => reportFailure(t)
}
}
}
@SubscribeEvent
def onTick(ev: ServerTickEvent): Unit = doSingleLoop()
}
+21
View File
@@ -0,0 +1,21 @@
/*
* Copyright (c) bdew, 2013 - 2015
* 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.block
import net.minecraft.block.Block
import net.minecraft.item.ItemBlock
/**
* If defined on a block - defines a custom ItemBlock class that will be used when registering
* Supported by BlockManager and Machine
*/
trait HasItemBlock extends Block {
def ItemBlockClass: Class[_ <: ItemBlock]
}
@@ -0,0 +1,29 @@
/*
* Copyright (c) bdew, 2013 - 2015
* 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.block
import java.util
import net.minecraft.block.Block
import net.minecraft.entity.player.EntityPlayer
import net.minecraft.item.{ItemBlock, ItemStack}
trait BlockTooltip extends Block with HasItemBlock {
override val ItemBlockClass: Class[_ <: ItemBlock] = classOf[ItemBlockTooltip]
def getTooltip(stack: ItemStack, player: EntityPlayer, advanced: Boolean): List[String]
}
class ItemBlockTooltip(b: Block) extends ItemBlock(b) {
override def addInformation(stack: ItemStack, player: EntityPlayer, list: util.List[_], advanced: Boolean): Unit = {
import scala.collection.JavaConversions._
if (b.isInstanceOf[BlockTooltip])
list.asInstanceOf[util.List[String]].addAll(b.asInstanceOf[BlockTooltip].getTooltip(stack, player, advanced))
}
}
+110
View File
@@ -0,0 +1,110 @@
/*
* Copyright (c) bdew, 2013 - 2015
* 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.block
import java.util
import net.bdew.lib.nbt.NBT
import net.bdew.lib.tile.TileExtended
import net.minecraft.block.Block
import net.minecraft.entity.player.EntityPlayer
import net.minecraft.item.ItemStack
import net.minecraft.nbt.NBTTagCompound
import net.minecraft.util.MovingObjectPosition
import net.minecraft.world.World
/**
* Mixin for blocks to keep their data when broken
* Must have a TileEntity that extends TileKeepData
*/
trait BlockKeepData extends Block with HasItemBlock {
this: HasTE[_ <: TileKeepData] =>
override val ItemBlockClass: Class[_ <: ItemBlockKeepData] = classOf[ItemBlockKeepData]
def getSavedBlock(world: World, x: Int, y: Int, z: Int, metadata: Int) = {
val stack = new ItemStack(getItemDropped(metadata, world.rand, 0), 1, damageDropped(metadata))
getTE(world, x, y, z).saveToItem(stack)
stack
}
override def getDrops(world: World, x: Int, y: Int, z: Int, metadata: Int, fortune: Int): util.ArrayList[ItemStack] = {
val drops = new util.ArrayList[ItemStack]()
drops.add(getSavedBlock(world, x, y, z, metadata))
drops
}
override def removedByPlayer(world: World, player: EntityPlayer, x: Int, y: Int, z: Int, willHarvest: Boolean): Boolean =
if (willHarvest)
true
else
super.removedByPlayer(world, player, x, y, z, willHarvest)
override def harvestBlock(world: World, player: EntityPlayer, x: Int, y: Int, z: Int, meta: Int): Unit = {
super.harvestBlock(world, player, x, y, z, meta)
world.setBlockToAir(x, y, z)
}
override def getPickBlock(target: MovingObjectPosition, world: World, x: Int, y: Int, z: Int, player: EntityPlayer): ItemStack = {
getSavedBlock(world, x, y, z, world.getBlockMetadata(x, y, z))
}
/**
* Override for special actions on placing
* ItemStack might or might not contain actual data
* Called with the TE created and added to world, after onBlockPlacedBy & co
*/
def restoreTileEntity(world: World, x: Int, y: Int, z: Int, is: ItemStack, player: EntityPlayer) = getTE(world, x, y, z).loadFromItem(is)
}
/**
* Mixin for tile entities to keep their data when broken
* Block class has to extend BlockKeepData
*/
trait TileKeepData extends TileExtended {
/**
* Override to modify data that will be stored in an item
* @param t Automatically serialized data
* @return Modified serialized data
*/
def afterTileBreakSave(t: NBTTagCompound) = t
/**
* Override to modify data that will be load from an item
* After the tile entity is fully constructed and added to world
* @param t Automatically serialized data
* @return Modified serialized data
*/
def beforeTileBreakLoad(t: NBTTagCompound) = t
final def saveToItem(is: ItemStack): Unit = {
if (!is.hasTagCompound) is.setTagCompound(new NBTTagCompound)
is.getTagCompound.setTag("data", afterTileBreakSave(NBT.from(persistSave.trigger)))
}
final def loadFromItem(is: ItemStack): Unit = {
if (is.hasTagCompound && is.getTagCompound.hasKey("data")) {
persistLoad.trigger(beforeTileBreakLoad(is.getTagCompound.getCompoundTag("data")))
}
}
}
/**
* Custom ItemBlock that handles loading data to the Tile Entity
*/
class ItemBlockKeepData(b: Block) extends ItemBlockTooltip(b) {
override def placeBlockAt(stack: ItemStack, player: EntityPlayer, world: World, x: Int, y: Int, z: Int, side: Int, hitX: Float, hitY: Float, hitZ: Float, metadata: Int): Boolean = {
if (super.placeBlockAt(stack, player, world, x, y, z, side, hitX, hitY, hitZ, metadata)) {
if (!world.isRemote && b.isInstanceOf[BlockKeepData])
b.asInstanceOf[BlockKeepData].restoreTileEntity(world, x, y, z, stack, player)
true
} else false
}
}
+3 -1
View File
@@ -15,6 +15,8 @@ import net.minecraft.block.Block
import net.minecraft.block.material.Material
import net.minecraft.client.renderer.texture.IIconRegister
import scala.language.implicitConversions
trait NamedBlock extends Block {
def name: String
}
@@ -25,6 +27,6 @@ class SimpleBlock(val name: String, material: Material) extends Block(material)
@SideOnly(Side.CLIENT)
override def registerBlockIcons(reg: IIconRegister) {
blockIcon = reg.registerIcon(modId + ":" + name.toLowerCase)
blockIcon = reg.registerIcon(Misc.iconName(modId, name))
}
}
+24 -5
View File
@@ -9,30 +9,49 @@
package net.bdew.lib.config
import cpw.mods.fml.common.ObfuscationReflectionHelper
import cpw.mods.fml.common.registry.GameRegistry
import net.bdew.lib.Misc
import net.bdew.lib.block.{HasTE, NamedBlock}
import net.bdew.lib.block.{HasItemBlock, HasTE, NamedBlock}
import net.minecraft.block.Block
import net.minecraft.creativetab.CreativeTabs
import net.minecraft.item.ItemStack
import net.minecraft.item.{ItemBlock, ItemStack}
import net.minecraft.tileentity.TileEntity
class BlockManager(creativeTab: CreativeTabs) {
def regBlock[T <: NamedBlock](block: T): T = regBlock(block, block.name)
def regBlock[T <: Block](block: T, name: String, addStack: Boolean = false): T = {
GameRegistry.registerBlock(block, name)
def regSpecial[T <: NamedBlock](block: T, addStack: Boolean = false, skipTileEntityReg: Boolean = false): T =
regBlock(block, block.name, addStack, skipTileEntityReg)
def regBlock[T <: Block](block: T, name: String, addStack: Boolean = false, skipTileEntityReg: Boolean = false): T = {
val itemClass: Class[_ <: ItemBlock] = if (block.isInstanceOf[HasItemBlock])
block.asInstanceOf[HasItemBlock].ItemBlockClass
else
classOf[ItemBlock]
GameRegistry.registerBlock(block, itemClass, name)
block.setCreativeTab(creativeTab)
if (addStack)
GameRegistry.registerCustomItemStack(name, new ItemStack(block))
if (block.isInstanceOf[HasTE[_]])
if (block.isInstanceOf[HasTE[_]] && !skipTileEntityReg)
GameRegistry.registerTileEntity(block.asInstanceOf[HasTE[_]].TEClass,
"%s.%s".format(Misc.getActiveModId, name))
return block
}
/**
* Registers a legacy TE name->class mapping. Stolen from GameRegistry.registerTileEntityWithAlternatives
*/
def registerLegacyTileEntity(name: String, cls: Class[_ <: TileEntity]): Unit = {
val teMappings: java.util.Map[String, Class[_]] = ObfuscationReflectionHelper.getPrivateValue(classOf[TileEntity], null, "field_" + "145855_i", "nameToClassMap")
if (!teMappings.containsKey(name))
teMappings.put(name, cls)
}
def load() {}
}
@@ -9,8 +9,11 @@
package net.bdew.lib.config
import net.bdew.lib.Misc
import net.bdew.lib.gui.{GuiHandler, GuiProvider}
import net.bdew.lib.machine.Machine
import net.bdew.lib.multiblock.MachineCore
import net.bdew.lib.multiblock.block.BlockModule
import net.bdew.lib.recipes.gencfg.ConfigSection
import net.minecraft.creativetab.CreativeTabs
@@ -25,5 +28,27 @@ class MachineManager(val tuning: ConfigSection, guiHandler: GuiHandler, creative
}
return machine
}
def load() {}
}
trait MachineManagerMultiblock extends MachineManager {
var controllers = Set.empty[MachineCore]
override def registerMachine[R <: Machine[_]](machine: R): R = {
super.registerMachine(machine)
if (machine.enabled) {
Misc.asInstanceOpt(machine, classOf[MachineCore]) foreach { controllerMachine =>
controllers += controllerMachine
controllerMachine.getController.machine = controllerMachine
}
}
machine
}
def getMachinesForBlock(b: BlockModule[_]): Map[MachineCore, (Int, Int)] = {
(for (machine <- controllers; max <- machine.modules.get(b.kind)) yield {
machine ->(machine.required.getOrElse(b.kind, 0), max)
}).toMap
}
}
+66 -17
View File
@@ -11,10 +11,11 @@ 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.block.{BlockRef, HasTE}
import net.bdew.lib.items.ItemUtils
import net.minecraft.block.Block
import net.minecraft.entity.player.EntityPlayer
import net.minecraft.entity.player.{EntityPlayer, EntityPlayerMP}
import net.minecraft.item.ItemStack
import net.minecraft.util.IIcon
import net.minecraft.world.{IBlockAccess, World}
import net.minecraftforge.common.util.ForgeDirection
@@ -23,53 +24,101 @@ trait BlockCoverable[T <: TileCoverable] extends HasTE[T] {
@SideOnly(Side.CLIENT)
override def getRenderType = CoverRenderer.id
private def getCoverItem(w: IBlockAccess, x: Int, y: Int, z: Int, side: ForgeDirection): Option[(ItemCover, ItemStack, TileCoverable)] = {
val te = getTE(w, x, y, z)
for {
coverStack <- Option(te.covers(side).value)
coverItemMaybe <- Option(coverStack.getItem)
coverItem <- Misc.asInstanceOpt(coverItemMaybe, classOf[ItemCover])
} yield (coverItem, coverStack, te)
}
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)
// Shift+RightClick with empty hand should remove cover
if (player.getCurrentEquippedItem == null && player.isSneaking) {
for (cover <- Option(te.covers(side).value)) {
for {
cover <- Option(te.covers(side).value)
coverItem <- Misc.asInstanceOpt(cover.getItem, classOf[ItemCover])
} {
if (!world.isRemote) {
te.covers(side) := null
te.onCoversChanged()
ItemUtils.dropItemToPlayer(world, player, cover)
coverChanged(world, x, y, z, side)
ItemUtils.dropItemToPlayer(world, player, coverItem.onRemove(cover))
}
return true
}
}
// If held item is cover - try to install it
for {
activeStack <- Option(player.getCurrentEquippedItem)
activeItem <- Option(activeStack.getItem)
coverItem <- Misc.asInstanceOpt(activeItem, classOf[ItemCover])
if te.isValidCover(side, activeStack) && coverItem.isValidTile(te, activeStack)
} {
if (!world.isRemote) {
for (cover <- Option(te.covers(side).value))
ItemUtils.throwItemAt(world, te.xCoord + side.offsetX, te.yCoord + side.offsetY, te.zCoord + side.offsetZ, cover.copy())
if (!world.isRemote && player.isInstanceOf[EntityPlayerMP]) {
for {
oldCover <- Option(te.covers(side).value)
oldItem <- Misc.asInstanceOpt(oldCover.getItem, classOf[ItemCover])
} {
ItemUtils.throwItemAt(world, te.xCoord + side.offsetX, te.yCoord + side.offsetY, te.zCoord + side.offsetZ, oldItem.onRemove(oldCover))
}
te.covers(side) := activeStack.splitStack(1)
te.covers(side) := coverItem.onInstall(te, side, activeStack.splitStack(1), player.asInstanceOf[EntityPlayerMP])
if (activeStack.stackSize <= 0)
player.inventory.setInventorySlotContents(player.inventory.currentItem, null)
if (activeStack.stackSize <= 0) player.inventory.setInventorySlotContents(player.inventory.currentItem, null)
te.onCoversChanged()
coverChanged(world, x, y, z, side)
}
return true
}
// If has cover - let it handle the click
for ((item, stack, te) <- getCoverItem(world, x, y, z, side)) {
if (item.clickCover(te, side, stack, player)) return true
}
super.onBlockActivated(world, x, y, z, player, face, xOffs, yOffs, zOffs)
}
override def canProvidePower = true
override def isProvidingWeakPower(w: IBlockAccess, x: Int, y: Int, z: Int, side: Int): Int = {
val direction = Misc.forgeDirection(side).getOpposite
for ((item, stack, te) <- getCoverItem(w, x, y, z, direction)) {
if (item.isEmittingSignal(te, direction, stack)) return 15
}
0
}
def coverChanged(w: World, x: Int, y: Int, z: Int, side: ForgeDirection): Unit = {
val pos = BlockRef(x, y, z).neighbour(side)
w.notifyBlockOfNeighborChange(pos.x, pos.y, pos.z, pos.block(w).orNull)
}
def getCoverIcon(w: IBlockAccess, x: Int, y: Int, z: Int, side: ForgeDirection): Option[IIcon] =
for {
coverStack <- Option(getTE(w, x, y, z).covers(side).value)
coverItemMaybe <- Option(coverStack.getItem)
coverItem <- Misc.asInstanceOpt(coverItemMaybe, classOf[ItemCover])
} yield coverItem.getCoverIcon(coverStack)
for ((item, stack, te) <- getCoverItem(w, x, y, z, side))
yield item.getCoverIcon(te, side, stack)
override def breakBlock(world: World, x: Int, y: Int, z: Int, block: Block, meta: Int) {
if (!world.isRemote)
for ((dir, covOpt) <- getTE(world, x, y, z).covers; cover <- Option(covOpt.value))
ItemUtils.throwItemAt(world, x, y, z, cover)
if (!world.isRemote) {
val te = getTE(world, x, y, z)
for {
(dir, covOpt) <- te.covers
cover <- Option(covOpt.value)
item <- Misc.asInstanceOpt(cover.getItem, classOf[ItemCover])
} {
te.covers(dir) := null
ItemUtils.throwItemAt(world, x, y, z, item.onRemove(cover))
coverChanged(world, x, y, z, dir)
}
}
super.breakBlock(world, x, y, z, block, meta)
}
}
+7 -6
View File
@@ -23,12 +23,13 @@ object CoverRenderer extends BaseBlockRenderHandler {
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)
if (!renderer.hasOverrideBlockTexture)
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
}
}
+54 -3
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) bdew, 2013 - 2014
* Copyright (c) bdew, 2013 - 2015
* https://github.com/bdew/bdlib
*
* This mod is distributed under the terms of the Minecraft Mod Public
@@ -9,23 +9,74 @@
package net.bdew.lib.covers
import net.minecraft.entity.player.{EntityPlayer, EntityPlayerMP}
import net.minecraft.item.{Item, ItemStack}
import net.minecraft.util.IIcon
import net.minecraftforge.common.util.ForgeDirection
trait ItemCover extends Item {
/**
* @return true if tickCover should be called
*/
def isCoverTicking: Boolean
/**
* @param te Host TileEntity
* @param side Side the cover is installed on
* @param cover Cover ItemStack
* @return Icon to render, MUST be on terrain sprite sheet (0), not item!
*/
def getCoverIcon(stack: ItemStack): IIcon
def getCoverIcon(te: TileCoverable, side: ForgeDirection, cover: ItemStack): IIcon
/**
* Perform tick, called on server only
* @param te Host TileEntity
* @param side Side the cover is installed on
* @param cover Cover ItemStack
*/
def tickCover(te: TileCoverable, side: ForgeDirection, cover: ItemStack)
def tickCover(te: TileCoverable, side: ForgeDirection, cover: ItemStack): Unit = {}
/**
* Checks if this cover can be installed on a specific TE
* @param te Potential host TileEntity
* @param cover Cover ItemStack
* @return true if can be installed
*/
def isValidTile(te: TileCoverable, cover: ItemStack): Boolean
/**
* Handle click on covered side - called on both client and server
* @param te Host TileEntity
* @param side Side the cover is installed on
* @param cover Cover ItemStack
* @param player Player clicking the cover
* @return true if click was handled by cover
*/
def clickCover(te: TileCoverable, side: ForgeDirection, cover: ItemStack, player: EntityPlayer): Boolean = false
/**
* Check if cover is emitting RS signal
* @param te Host TileEntity
* @param side Side the cover is installed on
* @param cover Cover ItemStack
* @return true if cover is emitting RS signal
*/
def isEmittingSignal(te: TileCoverable, side: ForgeDirection, cover: ItemStack): Boolean = false
/**
* Called when cover is installed on a block - called only on server
* @param te Host TileEntity
* @param side Side the cover is installed on
* @param cover Cover ItemStack - do not modify!
* @param player Player entity doing the installation
* @return cover ItemStack - copy if modified
*/
def onInstall(te:TileCoverable, side: ForgeDirection, cover: ItemStack, player: EntityPlayerMP): ItemStack = cover
/**
* Called when cover is removed from block or block is destroyed - called only on server
* @param cover Cover ItemStack - do not modify!
* @return cover ItemStack - copy if modified
*/
def onRemove(cover: ItemStack): ItemStack = cover
}
+3 -1
View File
@@ -9,6 +9,8 @@
package net.bdew.lib.covers
import java.util.Locale
import net.bdew.lib.Misc
import net.bdew.lib.data.DataSlotItemStack
import net.bdew.lib.data.base.{TileDataSlots, UpdateKind}
@@ -17,7 +19,7 @@ import net.minecraftforge.common.util.ForgeDirection
trait TileCoverable extends TileDataSlots {
val covers = (ForgeDirection.VALID_DIRECTIONS map { x =>
x -> DataSlotItemStack("cover_" + x.toString.toLowerCase, this).setUpdate(UpdateKind.SAVE, UpdateKind.WORLD, UpdateKind.RENDER)
x -> DataSlotItemStack("cover_" + x.toString.toLowerCase(Locale.US), this).setUpdate(UpdateKind.SAVE, UpdateKind.WORLD, UpdateKind.RENDER)
}).toMap
/**
+2 -2
View File
@@ -9,10 +9,10 @@
package net.bdew.lib.data
import net.bdew.lib.data.base.{DataSlotVal, TileDataSlots, UpdateKind}
import net.bdew.lib.data.base.{DataSlotContainer, DataSlotVal, UpdateKind}
import net.minecraft.nbt.NBTTagCompound
case class DataSlotBoolean(name: String, parent: TileDataSlots, default: Boolean = false) extends DataSlotVal[Boolean] {
case class DataSlotBoolean(name: String, parent: DataSlotContainer, default: Boolean = false) extends DataSlotVal[Boolean] {
var value = default
def save(t: NBTTagCompound, kind: UpdateKind.Value) = t.setBoolean(name, value)
def load(t: NBTTagCompound, kind: UpdateKind.Value) = value = t.getBoolean(name)
@@ -9,11 +9,11 @@
package net.bdew.lib.data
import net.bdew.lib.data.base.{DataSlotVal, TileDataSlots, UpdateKind}
import net.bdew.lib.data.base.{DataSlotContainer, DataSlotVal, UpdateKind}
import net.minecraft.nbt.NBTTagCompound
import net.minecraftforge.common.util.ForgeDirection
case class DataSlotDirection(name: String, parent: TileDataSlots) extends DataSlotVal[ForgeDirection] {
case class DataSlotDirection(name: String, parent: DataSlotContainer) extends DataSlotVal[ForgeDirection] {
var value = ForgeDirection.UP
def save(t: NBTTagCompound, kind: UpdateKind.Value) = t.setByte(name, value.ordinal().toByte)
def load(t: NBTTagCompound, kind: UpdateKind.Value) = value = ForgeDirection.getOrientation(t.getByte(name))
+2 -2
View File
@@ -9,10 +9,10 @@
package net.bdew.lib.data
import net.bdew.lib.data.base.{DataSlotNumeric, TileDataSlots, UpdateKind}
import net.bdew.lib.data.base.{DataSlotContainer, DataSlotNumeric, UpdateKind}
import net.minecraft.nbt.NBTTagCompound
case class DataSlotDouble(name: String, parent: TileDataSlots, default: Double = 0) extends DataSlotNumeric[Double](default) {
case class DataSlotDouble(name: String, parent: DataSlotContainer, default: Double = 0) extends DataSlotNumeric[Double](default) {
def save(t: NBTTagCompound, kind: UpdateKind.Value) = t.setDouble(name, value)
def load(t: NBTTagCompound, kind: UpdateKind.Value) = value = t.getDouble(name)
}
+2 -2
View File
@@ -9,10 +9,10 @@
package net.bdew.lib.data
import net.bdew.lib.data.base.{DataSlotNumeric, TileDataSlots, UpdateKind}
import net.bdew.lib.data.base.{DataSlotContainer, DataSlotNumeric, UpdateKind}
import net.minecraft.nbt.NBTTagCompound
case class DataSlotFloat(name: String, parent: TileDataSlots, default: Float = 0) extends DataSlotNumeric[Float](default) {
case class DataSlotFloat(name: String, parent: DataSlotContainer, default: Float = 0) extends DataSlotNumeric[Float](default) {
def save(t: NBTTagCompound, kind: UpdateKind.Value) = t.setFloat(name, value)
def load(t: NBTTagCompound, kind: UpdateKind.Value) = value = t.getFloat(name)
}
@@ -9,15 +9,15 @@
package net.bdew.lib.data
import net.bdew.lib.data.base.{TileDataSlots, UpdateKind}
import net.bdew.lib.data.base.{DataSlotContainer, UpdateKind}
import net.minecraft.nbt.NBTTagCompound
import net.minecraftforge.fluids.{Fluid, FluidRegistry}
case class DataSlotFluidOption(name: String, parent: TileDataSlots) extends DataSlotOption[Fluid] {
case class DataSlotFluidOption(name: String, parent: DataSlotContainer) extends DataSlotOption[Fluid] {
setUpdate(UpdateKind.SAVE, UpdateKind.GUI)
override def save(t: NBTTagCompound, kind: UpdateKind.Value) {
value map { x => t.setString(name, x.getName) }
value foreach { x => t.setString(name, x.getName) }
}
override def load(t: NBTTagCompound, kind: UpdateKind.Value): Unit = {
@@ -12,11 +12,11 @@ package net.bdew.lib.data
import java.util.UUID
import com.mojang.authlib.GameProfile
import net.bdew.lib.data.base.{DataSlotVal, TileDataSlots, UpdateKind}
import net.bdew.lib.data.base.{DataSlotContainer, DataSlotVal, UpdateKind}
import net.minecraft.nbt.NBTTagCompound
import org.apache.commons.lang3.StringUtils
case class DataSlotGameProfile(name: String, parent: TileDataSlots) extends DataSlotVal[GameProfile] {
case class DataSlotGameProfile(name: String, parent: DataSlotContainer) extends DataSlotVal[GameProfile] {
override var value: GameProfile = null
override def load(t: NBTTagCompound, kind: UpdateKind.Value) = {
@@ -29,8 +29,8 @@ case class DataSlotGameProfile(name: String, parent: TileDataSlots) extends Data
override def save(t: NBTTagCompound, kind: UpdateKind.Value) = {
if (value != null) {
Option(value.getId) map (id => t.setString(name + "_uid", id.toString))
Option(value.getName) filterNot (name => StringUtils.isBlank(name)) map (name => t.setString(name + "_name", name))
Option(value.getId) foreach (id => t.setString(name + "_uid", id.toString))
Option(value.getName) filterNot (name => StringUtils.isBlank(name)) foreach (name => t.setString(name + "_name", name))
}
}
}
+2 -2
View File
@@ -9,10 +9,10 @@
package net.bdew.lib.data
import net.bdew.lib.data.base.{DataSlotNumeric, TileDataSlots, UpdateKind}
import net.bdew.lib.data.base.{DataSlotContainer, DataSlotNumeric, UpdateKind}
import net.minecraft.nbt.NBTTagCompound
case class DataSlotInt(name: String, parent: TileDataSlots, default: Int = 0) extends DataSlotNumeric[Int](default) {
case class DataSlotInt(name: String, parent: DataSlotContainer, default: Int = 0) extends DataSlotNumeric[Int](default) {
def save(t: NBTTagCompound, kind: UpdateKind.Value) = t.setInteger(name, value)
def load(t: NBTTagCompound, kind: UpdateKind.Value) = value = t.getInteger(name)
}
@@ -9,13 +9,12 @@
package net.bdew.lib.data
import net.bdew.lib.Misc
import net.bdew.lib.data.base.{DataSlot, TileDataSlots, UpdateKind}
import net.bdew.lib.data.base.{DataSlot, DataSlotContainer, UpdateKind}
import net.bdew.lib.tile.inventory.BaseInventory
import net.minecraft.item.ItemStack
import net.minecraft.nbt.{NBTTagCompound, NBTTagList}
case class DataSlotInventory(name: String, parent: TileDataSlots, size: Int) extends DataSlot with BaseInventory {
case class DataSlotInventory(name: String, parent: DataSlotContainer, size: Int) extends DataSlot with BaseInventory {
setUpdate(UpdateKind.SAVE)
override def getSizeInventory = size
@@ -23,9 +22,10 @@ case class DataSlotInventory(name: String, parent: TileDataSlots, size: Int) ext
override def load(t: NBTTagCompound, kind: UpdateKind.Value) {
inv = new Array[ItemStack](getSizeInventory)
for (nbtItem <- Misc.iterNbtCompoundList(t, name)) {
import net.bdew.lib.nbt._
for (nbtItem <- t.getList[NBTTagCompound](name)) {
val slot = nbtItem.getByte("Slot")
if (slot >= 0 && slot < inv.size) {
if (slot >= 0 && slot < inv.length) {
inv(slot) = ItemStack.loadItemStackFromNBT(nbtItem)
}
}
@@ -9,11 +9,11 @@
package net.bdew.lib.data
import net.bdew.lib.data.base.{DataSlotVal, TileDataSlots, UpdateKind}
import net.bdew.lib.data.base.{DataSlotContainer, DataSlotVal, UpdateKind}
import net.minecraft.item.ItemStack
import net.minecraft.nbt.NBTTagCompound
case class DataSlotItemStack(name: String, parent: TileDataSlots) extends DataSlotVal[ItemStack] {
case class DataSlotItemStack(name: String, parent: DataSlotContainer) extends DataSlotVal[ItemStack] {
var value: ItemStack = null
override def update(v: ItemStack) = {
@@ -11,12 +11,12 @@ package net.bdew.lib.data
import java.io.{ByteArrayInputStream, ByteArrayOutputStream, DataInputStream, DataOutputStream}
import net.bdew.lib.data.base.{DataSlot, TileDataSlots, UpdateKind}
import net.bdew.lib.data.base.{DataSlot, DataSlotContainer, UpdateKind}
import net.minecraft.nbt.NBTTagCompound
import scala.collection.mutable
case class DataSlotMovingAverage(name: String, parent: TileDataSlots, size: Int) extends DataSlot {
case class DataSlotMovingAverage(name: String, parent: DataSlotContainer, size: Int) extends DataSlot {
val values = mutable.Queue.empty[Double]
var average: Double = 0
+2 -2
View File
@@ -9,10 +9,10 @@
package net.bdew.lib.data
import net.bdew.lib.data.base.{DataSlotVal, TileDataSlots, UpdateKind}
import net.bdew.lib.data.base.{DataSlotContainer, DataSlotVal, UpdateKind}
import net.minecraft.nbt.NBTTagCompound
case class DataSlotString(name: String, parent: TileDataSlots, default: String = null) extends DataSlotVal[String] {
case class DataSlotString(name: String, parent: DataSlotContainer, default: String = null) extends DataSlotVal[String] {
var value: String = default
def save(t: NBTTagCompound, kind: UpdateKind.Value) = if (value != null) t.setString(name, value)
def load(t: NBTTagCompound, kind: UpdateKind.Value) = value = if (t.hasKey(name)) t.getString(name) else null
+7 -7
View File
@@ -9,14 +9,14 @@
package net.bdew.lib.data
import net.bdew.lib.data.base.{DataSlot, TileDataSlots, UpdateKind}
import net.bdew.lib.data.base.{DataSlot, DataSlotContainer, UpdateKind}
import net.minecraft.nbt.NBTTagCompound
import net.minecraftforge.fluids.{FluidStack, FluidTank, IFluidTank}
import net.minecraftforge.fluids._
abstract class DataSlotTankBase(sz: Int) extends FluidTank(sz) with IFluidTank with DataSlot {
var oldStack: FluidStack = null
parent.serverTick.listen(checkUpdate)
parent.onServerTick(checkUpdate)
updateKind = Set(UpdateKind.GUI, UpdateKind.SAVE)
@@ -67,13 +67,13 @@ abstract class DataSlotTankBase(sz: Int) extends FluidTank(sz) with IFluidTank w
super.fill(resource, false)
}
case class DataSlotTank(name: String, parent: TileDataSlots, size: Int) extends DataSlotTankBase(size)
case class DataSlotTank(name: String, parent: DataSlotContainer, 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)
case class DataSlotTankRestricted(name: String, parent: DataSlotContainer, var size: Int, filterFluid: Fluid) extends DataSlotTankBase(size) {
def fill(amount: Int, doFill: Boolean) = super.fill(new FluidStack(filterFluid, amount), doFill)
override def fill(resource: FluidStack, doFill: Boolean): Int = {
if ((resource != null) && (resource.fluidID != fluidID)) return 0
if ((resource != null) && (resource.getFluid != filterFluid)) return 0
return super.fill(resource, doFill)
}
}
+1 -1
View File
@@ -19,7 +19,7 @@ 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
val parent: DataSlotContainer
/**
* Unique name
@@ -0,0 +1,77 @@
/*
* 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.data.base
import net.minecraft.nbt.NBTTagCompound
import net.minecraft.world.World
import scala.collection.mutable
/**
* Base Trait for objects that can contain Data Slots, this allows implementing them on things that aren't TEs
*/
trait DataSlotContainer {
// Can't use getWorldObj - it fails to get remapped and stuff breaks in obfuscated environment
def getWorldObject: World
/**
* Called when a dataslot value changes
*/
def dataSlotChanged(slot: DataSlot): Unit
/**
* Register a function to run on every server tick
*/
def onServerTick(f: () => Unit): Unit
/**
* List of dataslots in this container
*/
val dataSlots = mutable.HashMap.empty[String, DataSlot]
/**
* The value of getTotalWorldTime when the last change happened
*/
var lastChange = 0L
/**
* The value of getTotalWorldTime when the last GUI packet was sent happened
*/
var lastGuiPacket = 0L
final val TRACE = false
def doSave(kind: UpdateKind.Value, t: NBTTagCompound) {
if (kind == UpdateKind.GUI)
t.setLong("BDLib_TS", getWorldObject.getTotalWorldTime)
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) {
if (kind == UpdateKind.GUI) {
val ts = t.getLong("BDLib_TS")
if (ts > lastGuiPacket) {
lastGuiPacket = ts
} else {
return
}
}
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)
}
}
}
@@ -19,4 +19,9 @@ abstract class DataSlotNumeric[T](default: T)(implicit n: Numeric[T]) extends Da
def +=(that: T) = update(n.plus(value, that))
def -=(that: T) = update(n.minus(value, that))
def *=(that: T) = update(n.times(value, that))
/* Special Int versions, using the conversion from numeric */
def +=(that: Int) = update(n.plus(value, n.fromInt(that)))
def -=(that: Int) = update(n.minus(value, n.fromInt(that)))
def *=(that: Int) = update(n.times(value, n.fromInt(that)))
}
+14 -40
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) bdew, 2013 - 2014
* Copyright (c) bdew, 2013 - 2015
* https://github.com/bdew/bdlib
*
* This mod is distributed under the terms of the Minecraft Mod Public
@@ -14,51 +14,25 @@ import net.minecraft.nbt.NBTTagCompound
import net.minecraft.network.Packet
import net.minecraft.network.play.server.S35PacketUpdateTileEntity
import scala.collection.mutable
trait TileDataSlots extends TileExtended {
val dataSlots = mutable.HashMap.empty[String, DataSlot]
var lastChange = 0L
var lastGuiPacket = 0L
final val TRACE = false
def doSave(kind: UpdateKind.Value, t: NBTTagCompound) {
if (kind == UpdateKind.GUI)
t.setLong("BDLib_TS", getWorldObj.getTotalWorldTime)
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) {
if (kind == UpdateKind.GUI) {
val ts = t.getLong("BDLib_TS")
if (ts > lastGuiPacket) {
lastGuiPacket = ts
} else {
return
}
}
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)
if (kind == UpdateKind.WORLD && s.updateKind.contains(UpdateKind.RENDER))
getWorldObj.markBlockRangeForRenderUpdate(xCoord, yCoord, zCoord, xCoord, yCoord, zCoord)
}
}
trait TileDataSlots extends TileExtended with DataSlotContainer {
persistSave.listen(doSave(UpdateKind.SAVE, _))
persistLoad.listen(doLoad(UpdateKind.SAVE, _))
sendClientUpdate.listen(doSave(UpdateKind.WORLD, _))
handleClientUpdate.listen(doLoad(UpdateKind.WORLD, _))
handleClientUpdate.listen { tag =>
doLoad(UpdateKind.WORLD, tag)
if (dataSlots.values.exists(_.updateKind.contains(UpdateKind.RENDER)))
getWorldObj.markBlockRangeForRenderUpdate(xCoord, yCoord, zCoord, xCoord, yCoord, zCoord)
}
def dataSlotChanged(slot: DataSlot) {
override def getWorldObject = getWorldObj
override def onServerTick(f: () => Unit) = serverTick.listen(f)
override def dataSlotChanged(slot: DataSlot) = {
if (getWorldObj != null) {
if (slot.updateKind.contains(UpdateKind.GUI))
lastChange = getWorldObj.getTotalWorldTime
if (slot.updateKind.contains(UpdateKind.WORLD))
if (!getWorldObj.isRemote && slot.updateKind.contains(UpdateKind.WORLD))
getWorldObj.markBlockForUpdate(xCoord, yCoord, zCoord)
if (slot.updateKind.contains(UpdateKind.SAVE))
getWorldObj.markTileEntityChunkModified(xCoord, yCoord, zCoord, this)
@@ -68,7 +42,7 @@ trait TileDataSlots extends TileExtended {
def getDataSlotPacket: Packet = {
val tag = new NBTTagCompound()
doSave(UpdateKind.GUI, tag)
return new S35PacketUpdateTileEntity(this.xCoord, this.yCoord, this.zCoord, ACT_GUI, tag)
return new S35PacketUpdateTileEntity(xCoord, yCoord, zCoord, ACT_GUI, tag)
}
override protected def extDataPacket(id: Int, data: NBTTagCompound) {
+1 -1
View File
@@ -56,7 +56,7 @@ abstract class BaseScreen(cont: Container, xSz: Int, ySz: Int) extends GuiContai
import scala.collection.JavaConversions._
if (tip.size > 0)
if (tip.nonEmpty)
drawHoveringText(tip, x, y, getFontRenderer)
}
+9 -2
View File
@@ -23,6 +23,13 @@ trait GuiProvider {
def getContainer(te: TEClass, player: EntityPlayer): AnyRef
@SideOnly(Side.CLIENT)
def getGui(te: TileEntity, player: EntityPlayer): AnyRef = getGui(te.asInstanceOf[TEClass], player)
def getContainer(te: TileEntity, player: EntityPlayer): AnyRef = getContainer(te.asInstanceOf[TEClass], player)
def getGui(te: TileEntity, player: EntityPlayer): AnyRef =
if (te != null)
getGui(te.asInstanceOf[TEClass], player)
else null
def getContainer(te: TileEntity, player: EntityPlayer): AnyRef =
if (te != null)
getContainer(te.asInstanceOf[TEClass], player)
else null
}
+60
View File
@@ -0,0 +1,60 @@
/*
* Copyright (c) bdew, 2013 - 2015
* 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.helpers
import net.minecraft.util._
import scala.language.implicitConversions
class RichChatComponent(v: IChatComponent) {
def &(that: IChatComponent) = v.appendSibling(that)
private def applyStyle(f: ChatStyle => Unit) = {
f(v.getChatStyle)
v
}
def setColor(c: EnumChatFormatting) = applyStyle(_.setColor(c))
def setBold(b: Boolean) = applyStyle(_.setBold(b))
def setItalic(b: Boolean) = applyStyle(_.setItalic(b))
def setObfuscated(b: Boolean) = applyStyle(_.setObfuscated(b))
def setStrikethrough(b: Boolean) = applyStyle(_.setStrikethrough(b))
def setUnderlined(b: Boolean) = applyStyle(_.setUnderlined(b))
}
object ChatHelper {
object Color {
val BLACK = EnumChatFormatting.BLACK
val DARK_BLUE = EnumChatFormatting.DARK_BLUE
val DARK_GREEN = EnumChatFormatting.DARK_GREEN
val DARK_AQUA = EnumChatFormatting.DARK_AQUA
val DARK_RED = EnumChatFormatting.DARK_RED
val DARK_PURPLE = EnumChatFormatting.DARK_PURPLE
val GOLD = EnumChatFormatting.GOLD
val GRAY = EnumChatFormatting.GRAY
val DARK_GRAY = EnumChatFormatting.DARK_GRAY
val BLUE = EnumChatFormatting.BLUE
val GREEN = EnumChatFormatting.GREEN
val AQUA = EnumChatFormatting.AQUA
val RED = EnumChatFormatting.RED
val LIGHT_PURPLE = EnumChatFormatting.LIGHT_PURPLE
val YELLOW = EnumChatFormatting.YELLOW
val WHITE = EnumChatFormatting.WHITE
}
implicit def str2chat(s: String): ChatComponentText = new ChatComponentText(s)
implicit def str2rich(s: String): RichChatComponent = new RichChatComponent(new ChatComponentText(s))
implicit def pimpIChatComponent(v: IChatComponent): RichChatComponent = new RichChatComponent(v)
def C(s: String) = new ChatComponentText(s)
def L(s: String, params: IChatComponent*) = new ChatComponentTranslation(s, params: _*)
}
+1 -1
View File
@@ -24,6 +24,6 @@ class SimpleItem(val name: String) extends Item with NamedItem {
@SideOnly(Side.CLIENT)
override def registerIcons(reg: IIconRegister) {
itemIcon = reg.registerIcon(modId + ":" + name.toLowerCase)
itemIcon = reg.registerIcon(Misc.iconName(modId, name))
}
}
@@ -9,7 +9,6 @@
package net.bdew.lib.items.inventory
import net.bdew.lib.Misc
import net.bdew.lib.tile.inventory.BaseInventory
import net.minecraft.entity.player.EntityPlayer
import net.minecraft.item.ItemStack
@@ -23,10 +22,11 @@ class InventoryItemAdapter(val player: EntityPlayer, val slot: Int, val size: In
load()
def load() {
import net.bdew.lib.nbt._
val tag = getStack.getTagCompound
for (nbtItem <- Misc.iterNbtCompoundList(tag, tagName)) {
for (nbtItem <- tag.getList[NBTTagCompound](tagName)) {
val slot = nbtItem.getByte("Slot")
if (slot >= 0 && slot < inv.size) {
if (slot >= 0 && slot < inv.length) {
inv(slot) = ItemStack.loadItemStackFromNBT(nbtItem)
}
}
+10 -2
View File
@@ -11,10 +11,11 @@ package net.bdew.lib.machine
import cpw.mods.fml.common.registry.GameRegistry
import net.bdew.lib.Misc
import net.bdew.lib.block.HasTE
import net.bdew.lib.block.{HasItemBlock, HasTE}
import net.bdew.lib.recipes.gencfg.ConfigSection
import net.minecraft.block.Block
import net.minecraft.creativetab.CreativeTabs
import net.minecraft.item.ItemBlock
abstract class Machine[T <: Block](val name: String, blockConstruct: => T) {
var block: T = null.asInstanceOf[T]
@@ -24,7 +25,14 @@ abstract class Machine[T <: Block](val name: String, blockConstruct: => T) {
def regBlock(creativeTab: CreativeTabs) {
block = blockConstruct
GameRegistry.registerBlock(block, name)
val itemClass: Class[_ <: ItemBlock] = if (block.isInstanceOf[HasItemBlock])
block.asInstanceOf[HasItemBlock].ItemBlockClass
else
classOf[ItemBlock]
GameRegistry.registerBlock(block, itemClass, name)
block.setCreativeTab(creativeTab)
if (block.isInstanceOf[HasTE[_]]) {
GameRegistry.registerTileEntity(block.asInstanceOf[HasTE[_]].TEClass, "%s.%s".format(modId, name))
@@ -9,11 +9,16 @@
package net.bdew.lib.multiblock
import net.bdew.lib.machine.Machine
import net.bdew.lib.multiblock.block.BlockController
import net.bdew.lib.recipes.gencfg.{ConfigSection, EntryDouble}
trait MachineCore {
trait MachineCore extends {
this: Machine[_ <: BlockController[_]] =>
var tuning: ConfigSection
def getController: BlockController[_] = block
def cfgSectionToMap(name: String) = tuning.getSection(name).map({
case (n, EntryDouble(v)) => n -> v.toInt
case (n, x) => sys.error("Invalid config value in section %s%s.%s = %s".format(tuning.pfx, name, n, x))
+1 -1
View File
@@ -41,7 +41,7 @@ object Tools {
val seen = mutable.Set.empty[BlockRef]
val queue = mutable.Queue.empty[BlockRef]
queue ++= getConnectedNeighbours(world, core, core, seen)
while (queue.size > 0) {
while (queue.nonEmpty) {
val current = queue.dequeue()
seen.add(current)
queue ++= getConnectedNeighbours(world, core, current, seen)
@@ -9,17 +9,22 @@
package net.bdew.lib.multiblock.block
import net.bdew.lib.block.{BlockRef, HasTE}
import net.bdew.lib.multiblock.ResourceProvider
import net.bdew.lib.Misc
import net.bdew.lib.block.{BlockRef, BlockTooltip, HasTE}
import net.bdew.lib.multiblock.tile.TileController
import net.bdew.lib.multiblock.{MachineCore, ResourceProvider}
import net.bdew.lib.render.connected.ConnectedTextureBlock
import net.minecraft.block.Block
import net.minecraft.block.material.Material
import net.minecraft.entity.player.EntityPlayer
import net.minecraft.item.ItemStack
import net.minecraft.util.EnumChatFormatting
import net.minecraft.world.{IBlockAccess, World}
abstract class BlockController[T <: TileController](val name: String, material: Material, val TEClass: Class[T])
extends Block(material) with HasTE[T] with ConnectedTextureBlock {
extends Block(material) with HasTE[T] with ConnectedTextureBlock with BlockTooltip {
var machine: MachineCore = null
def resources: ResourceProvider
@@ -39,6 +44,23 @@ abstract class BlockController[T <: TileController](val name: String, material:
getTE(world, x, y, z).onClick(player)
return true
}
override def getTooltip(stack: ItemStack, player: EntityPlayer, advanced: Boolean): List[String] = {
List(Misc.toLocal("bdlib.multiblock.tip.controller")) ++ (
for ((kind, max) <- machine.modules) yield {
val name = Misc.toLocalF(resources.getModuleName(kind))
if (machine.required.getOrElse(kind, 0) > 0) {
Misc.toLocalF("bdlib.multiblock.tip.module.range",
EnumChatFormatting.YELLOW + name + EnumChatFormatting.RESET,
EnumChatFormatting.YELLOW + machine.required(kind).toString + EnumChatFormatting.RESET,
EnumChatFormatting.YELLOW + max.toString + EnumChatFormatting.RESET)
} else {
Misc.toLocalF("bdlib.multiblock.tip.module.max",
EnumChatFormatting.YELLOW + name + EnumChatFormatting.RESET,
EnumChatFormatting.YELLOW + max.toString + EnumChatFormatting.RESET)
}
})
}
}
@@ -9,7 +9,9 @@
package net.bdew.lib.multiblock.block
import net.bdew.lib.block.{BlockRef, HasTE}
import net.bdew.lib.Misc
import net.bdew.lib.block.{BlockRef, BlockTooltip, HasTE}
import net.bdew.lib.config.MachineManagerMultiblock
import net.bdew.lib.multiblock.tile.TileModule
import net.bdew.lib.multiblock.{ResourceProvider, Tools}
import net.bdew.lib.render.connected.ConnectedTextureBlock
@@ -18,11 +20,11 @@ import net.minecraft.block.material.Material
import net.minecraft.entity.EntityLivingBase
import net.minecraft.entity.player.EntityPlayer
import net.minecraft.item.ItemStack
import net.minecraft.util.ChatComponentTranslation
import net.minecraft.util.{ChatComponentTranslation, EnumChatFormatting}
import net.minecraft.world.{IBlockAccess, World}
abstract class BlockModule[T <: TileModule](val name: String, val kind: String, material: Material, val TEClass: Class[T])
extends Block(material) with HasTE[T] with ConnectedTextureBlock {
abstract class BlockModule[T <: TileModule](val name: String, val kind: String, material: Material, val TEClass: Class[T], val machines: MachineManagerMultiblock)
extends Block(material) with HasTE[T] with ConnectedTextureBlock with BlockTooltip {
def resources: ResourceProvider
@@ -60,10 +62,27 @@ abstract class BlockModule[T <: TileModule](val name: String, val kind: String,
p <- te.connected.value
bl <- p.block(world)
} yield {
bl.onBlockActivated(world, p.x, p.y, p.z, player, meta, 0, 0, 0)
}) getOrElse {
bl.onBlockActivated(world, p.x, p.y, p.z, player, meta, 0, 0, 0)
}) getOrElse {
player.addChatMessage(new ChatComponentTranslation("bdlib.multiblock.notconnected"))
}
true
}
override def getTooltip(stack: ItemStack, player: EntityPlayer, advanced: Boolean): List[String] = {
List(Misc.toLocal("bdlib.multiblock.tip.module")) ++ (
for ((machine, (min, max)) <- machines.getMachinesForBlock(this)) yield {
val name = machine.getController.getLocalizedName
if (min > 0) {
Misc.toLocalF("bdlib.multiblock.tip.module.range",
EnumChatFormatting.YELLOW + name + EnumChatFormatting.RESET,
EnumChatFormatting.YELLOW + min.toString + EnumChatFormatting.RESET,
EnumChatFormatting.YELLOW + max.toString + EnumChatFormatting.RESET)
} else {
Misc.toLocalF("bdlib.multiblock.tip.module.max",
EnumChatFormatting.YELLOW + name + EnumChatFormatting.RESET,
EnumChatFormatting.YELLOW + max.toString + EnumChatFormatting.RESET)
}
})
}
}
@@ -28,7 +28,7 @@ trait BlockOutput[T <: TileOutput[_]] extends BlockModule[T] with BlockAdditiona
def getFaceOverlays(world: IBlockAccess, x: Int, y: Int, z: Int, face: ForgeDirection): List[FaceOverlay] = {
var result = List.empty[FaceOverlay]
Option(getTE(world, x, y, z)) flatMap (_.getCore) map { core =>
Option(getTE(world, x, y, z)) flatMap (_.getCore) foreach { core =>
val bf = BlockFace(x, y, z, face)
if (core.outputFaces.contains(bf))
result :+= FaceOverlay(resources.output, resources.outputColors(core.outputFaces(bf)))
@@ -9,15 +9,14 @@
package net.bdew.lib.multiblock.data
import net.bdew.lib.Misc
import net.bdew.lib.block.BlockFace
import net.bdew.lib.data.base.{DataSlot, TileDataSlots, UpdateKind}
import net.minecraft.nbt.{NBTTagCompound, NBTTagIntArray, NBTTagList}
import net.bdew.lib.data.base.{DataSlot, DataSlotContainer, UpdateKind}
import net.minecraft.nbt.NBTTagCompound
import net.minecraftforge.common.util.ForgeDirection
import scala.collection.mutable
case class DataSlotBlockFaceMap(name: String, parent: TileDataSlots) extends DataSlot {
case class DataSlotBlockFaceMap(name: String, parent: DataSlotContainer) extends DataSlot {
val map = collection.mutable.Map.empty[BlockFace, Int]
setUpdate(UpdateKind.SAVE, UpdateKind.WORLD)
@@ -27,15 +26,15 @@ case class DataSlotBlockFaceMap(name: String, parent: TileDataSlots) extends Dat
def ent2arr(x: (BlockFace, Int)) = Array(x._2, x._1.x, x._1.y, x._1.z, x._1.face.ordinal())
def arr2ent(x: Array[Int]) = BlockFace(x(1), x(2), x(3), ForgeDirection.values()(x(4))) -> x(0)
import net.bdew.lib.nbt._
def save(t: NBTTagCompound, kind: UpdateKind.Value) {
val lst = new NBTTagList()
for (x <- map) lst.appendTag(new NBTTagIntArray(ent2arr(x)))
t.setTag(name, lst)
t.setList(name, map.map(ent2arr))
}
def load(t: NBTTagCompound, kind: UpdateKind.Value) {
map.clear()
map ++= Misc.iterNbtIntArray(t, name) map arr2ent
map ++= t.getList[Array[Int]](name) map arr2ent
}
def updated() = parent.dataSlotChanged(this)
@@ -9,12 +9,12 @@
package net.bdew.lib.multiblock.data
import net.bdew.lib.data.base.{DataSlot, TileDataSlots, UpdateKind}
import net.bdew.lib.data.base.{DataSlot, DataSlotContainer, UpdateKind}
import net.minecraft.nbt.NBTTagCompound
import scala.collection.mutable
case class DataSlotOutputConfig(name: String, parent: TileDataSlots, slots: Int) extends DataSlot {
case class DataSlotOutputConfig(name: String, parent: DataSlotContainer, slots: Int) extends DataSlot {
val map = collection.mutable.Map.empty[Int, OutputConfig]
setUpdate(UpdateKind.SAVE, UpdateKind.GUI)
@@ -12,14 +12,14 @@ package net.bdew.lib.multiblock.data
import net.bdew.lib.Misc
import net.bdew.lib.block.BlockRef
import net.bdew.lib.data.DataSlotOption
import net.bdew.lib.data.base.{TileDataSlots, UpdateKind}
import net.bdew.lib.data.base.{DataSlotContainer, UpdateKind}
import net.minecraft.nbt.NBTTagCompound
case class DataSlotPos(name: String, parent: TileDataSlots) extends DataSlotOption[BlockRef] {
case class DataSlotPos(name: String, parent: DataSlotContainer) extends DataSlotOption[BlockRef] {
setUpdate(UpdateKind.SAVE, UpdateKind.WORLD)
def save(t: NBTTagCompound, kind: UpdateKind.Value) {
value map (x => t.setTag(name, Misc.applyMutator(x.writeToNBT, new NBTTagCompound)))
value foreach (x => t.setTag(name, Misc.applyMutator(x.writeToNBT, new NBTTagCompound)))
}
def load(t: NBTTagCompound, kind: UpdateKind.Value) {
@@ -11,29 +11,28 @@ package net.bdew.lib.multiblock.data
import net.bdew.lib.Misc
import net.bdew.lib.block.BlockRef
import net.bdew.lib.data.base.{DataSlot, TileDataSlots, UpdateKind}
import net.minecraft.nbt.{NBTTagCompound, NBTTagList}
import net.bdew.lib.data.base.{DataSlot, DataSlotContainer, UpdateKind}
import net.minecraft.nbt.NBTTagCompound
import scala.collection.mutable
case class DataSlotPosSet(name: String, parent: TileDataSlots) extends DataSlot {
case class DataSlotPosSet(name: String, parent: DataSlotContainer) extends DataSlot {
val set = collection.mutable.Set.empty[BlockRef]
setUpdate(UpdateKind.SAVE, UpdateKind.WORLD)
import net.bdew.lib.nbt._
def save(t: NBTTagCompound, kind: UpdateKind.Value) {
val lst = new NBTTagList()
for (x <- set) lst.appendTag(Misc.applyMutator(x.writeToNBT, new NBTTagCompound))
t.setTag(name, lst)
t.setList(name, set.map(x => Misc.applyMutator(x.writeToNBT, new NBTTagCompound)))
}
def load(t: NBTTagCompound, kind: UpdateKind.Value) {
set.clear()
set ++= Misc.iterNbtCompoundList(t, name) map BlockRef.fromNBT
set ++= t.getList[NBTTagCompound](name) map BlockRef.fromNBT
}
def updated() = parent.dataSlotChanged(this)
}
object DataSlotPosSet {
@@ -10,26 +10,36 @@
package net.bdew.lib.multiblock.data
import net.bdew.lib.multiblock.network.MsgOutputCfg
import net.minecraft.nbt.NBTTagCompound
import net.minecraft.nbt.{NBTTagCompound, NBTTagList}
import scala.collection.mutable
class OutputConfigFluid extends OutputConfig with OutputConfigRSControllable {
override def id = "fluid"
var avg = 0.0
val values = mutable.Queue.empty[Double]
var rsMode = RSMode.ALWAYS
final val decay = 0.5
final val ticks = 20
import net.bdew.lib.nbt._
def avg = values.sum / values.size
def updateAvg(v: Double) {
avg = avg * decay + (1 - decay) * v
values += v
if (values.size > ticks)
values.dequeue()
}
def read(t: NBTTagCompound) {
avg = t.getDouble("avg")
values.clear()
values ++= t.getList[Double]("values")
rsMode = RSMode(t.getInteger("rsMode"))
}
def write(t: NBTTagCompound) {
t.setDouble("avg", avg)
val l = new NBTTagList
t.setList("values", values)
t.setInteger("rsMode", rsMode.id)
}
@@ -14,11 +14,11 @@ import net.bdew.lib.gui.{Color, Point, Rect, Texture}
import scala.collection.mutable
class WidgetInfo(val rect: Rect, icon: Texture, text: => String, tooltip: => String) extends Widget {
class WidgetInfoMulti(val rect: Rect, icon: Texture, text: => String, tooltip: => List[String]) extends Widget {
final val iconRect = Rect(1, 1, 8, 8)
override def handleTooltip(p: Point, tip: mutable.MutableList[String]) {
if (iconRect.contains(p) && tooltip != null) tip += tooltip
if (iconRect.contains(p) && tooltip != null) tip ++= tooltip
}
override def draw(mouse: Point) {
@@ -26,3 +26,5 @@ class WidgetInfo(val rect: Rect, icon: Texture, text: => String, tooltip: => Str
parent.drawText(text, rect.origin +(12, 1), Color.darkGray, false)
}
}
class WidgetInfo(rect: Rect, icon: Texture, text: => String, tooltip: => String) extends WidgetInfoMulti(rect, icon, text, List(tooltip))
@@ -9,6 +9,8 @@
package net.bdew.lib.multiblock.gui
import java.util.Locale
import net.bdew.lib.Misc
import net.bdew.lib.gui.widgets.Widget
import net.bdew.lib.gui.{Point, Rect, Texture}
@@ -24,7 +26,7 @@ class WidgetOutputIcon(p: Point, te: CIOutputFaces, output: Int) extends Widget
val faces = te.outputFaces.inverted
if (faces.isDefinedAt(output)) {
val bf = faces(output)
bf.origin.block(te.getWorldObj) map { block =>
bf.origin.block(te.getWorldObj) foreach { block =>
parent.drawTexture(rect, Texture(Texture.BLOCKS, block.getIcon(te.getWorldObj, bf.origin.x, bf.origin.y, bf.origin.z, bf.face.ordinal())))
if (block.isInstanceOf[BlockAdditionalRender]) {
for (over <- block.asInstanceOf[BlockAdditionalRender].getFaceOverlays(te.getWorldObj, bf.origin.x, bf.origin.y, bf.origin.z, bf.face))
@@ -43,7 +45,7 @@ class WidgetOutputIcon(p: Point, te: CIOutputFaces, output: Int) extends Widget
val bf = faces(output)
bf.origin.block(te.getWorldObj) map { block =>
tip += block.getLocalizedName
tip += "%d, %d, %d - %s".format(bf.x, bf.y, bf.z, Misc.toLocal("bdlib.multiblock.face." + bf.face.toString.toLowerCase))
tip += "%d, %d, %d - %s".format(bf.x, bf.y, bf.z, Misc.toLocal("bdlib.multiblock.face." + bf.face.toString.toLowerCase(Locale.US)))
}
} else {
tip += Misc.toLocal("bdlib.multiblock.disabled")
@@ -9,6 +9,8 @@
package net.bdew.lib.multiblock.gui
import java.util.Locale
import net.bdew.lib.Misc
import net.bdew.lib.gui.widgets.{WidgetButtonIcon, WidgetSubContainer}
import net.bdew.lib.gui.{Point, Rect}
@@ -37,7 +39,7 @@ class WidgetRSConfig(te: CIOutputFaces, output: Int, p: Point) extends WidgetSub
override def draw(mouse: Point) {
bt.icon = icons(cfg.rsMode)
bt.hover = Misc.toLocal("bdlib.rsmode." + cfg.rsMode.toString.toLowerCase)
bt.hover = Misc.toLocal("bdlib.rsmode." + cfg.rsMode.toString.toLowerCase(Locale.US))
super.draw(mouse)
}
@@ -18,7 +18,7 @@ import net.bdew.lib.multiblock.{MachineCore, ResourceProvider, Tools}
import net.minecraft.entity.player.EntityPlayer
trait TileController extends TileDataSlots {
val modules = new DataSlotPosSet("modules", this).setUpdate(UpdateKind.WORLD, UpdateKind.SAVE, UpdateKind.RENDER)
val modules = new DataSlotPosSet("modules", this).setUpdate(UpdateKind.WORLD, UpdateKind.SAVE)
def resources: ResourceProvider
def cfg: MachineCore
@@ -29,7 +29,7 @@ trait TileController extends TileDataSlots {
lazy val myPos = BlockRef(xCoord, yCoord, zCoord)
def getNumOfModules(kind: String) = modules.map(_.getTile[TileModule](getWorldObj)).flatten.count(_.kind == kind)
def getNumOfModules(kind: String) = modules.flatMap(_.getTile[TileModule](getWorldObj)).count(_.kind == kind)
def onModulesChanged()
def onClick(player: EntityPlayer)
@@ -59,7 +59,7 @@ trait TileController extends TileDataSlots {
def validateModules() {
modules.filter(x => {
!x.getTile[TileModule](getWorldObj).isDefined || !x.getBlock[BlockModule[TileModule]](getWorldObj).isDefined
x.getTile[TileModule](getWorldObj).isEmpty || x.getBlock[BlockModule[TileModule]](getWorldObj).isEmpty
}).foreach(x => {
BdLib.logWarn("Block at %s is not a valid module, removing from machine %s at %d,%d,%d", x, this.getClass.getSimpleName, xCoord, yCoord, zCoord)
modules.remove(x)
@@ -10,21 +10,17 @@
package net.bdew.lib.multiblock.tile
import net.minecraft.entity.player.EntityPlayer
import net.minecraft.util.{ChatComponentTranslation, ChatStyle, EnumChatFormatting}
abstract class TileControllerGui extends TileController {
def openGui(player: EntityPlayer)
def onClick(player: EntityPlayer) = {
import net.bdew.lib.helpers.ChatHelper._
val missing = cfg.required.filter({ case (mod, cnt) => getNumOfModules(mod) < cnt })
if (missing.size > 0) {
player.addChatMessage(new ChatComponentTranslation("bdlib.multiblock.incomplete")
.setChatStyle(new ChatStyle().setColor(EnumChatFormatting.RED)))
if (missing.nonEmpty) {
player.addChatMessage(L("bdlib.multiblock.incomplete").setColor(Color.RED))
for ((mod, cnt) <- missing)
player.addChatMessage(
new ChatComponentTranslation("- %s %s", Integer.valueOf(cnt),
new ChatComponentTranslation(resources.getModuleName(mod)))
.setChatStyle(new ChatStyle().setColor(EnumChatFormatting.RED)))
player.addChatMessage(L("- %s %s", cnt.toString, L(resources.getModuleName(mod))).setColor(Color.RED))
} else openGui(player)
}
@@ -41,13 +41,15 @@ trait TileModule extends TileDataSlots {
}
def onBreak() {
getCore map (_.moduleRemoved(this))
getCore foreach (_.moduleRemoved(this))
}
def canConnectToCore(br: BlockRef) = true
def tryConnect() {
if (getCore.isEmpty) {
for {
conn <- Tools.findConnections(getWorldObj, myPos, kind).headOption
conn <- Tools.findConnections(getWorldObj, myPos, kind).headOption if canConnectToCore(conn)
core <- conn.getTile[TileController](getWorldObj)
} {
connect(core)
@@ -47,7 +47,7 @@ abstract class TileOutput[T <: OutputConfig] extends TileModule with MIOutput[T]
def onConnectionsChanged(added: Set[ForgeDirection], removed: Set[ForgeDirection]) {}
def doRescanFaces() {
getCore map { core =>
getCore foreach { core =>
val connections = (
ForgeDirection.VALID_DIRECTIONS
filterNot { dir => core.modules.contains(myPos.neighbour(dir)) }
@@ -58,7 +58,7 @@ abstract class TileOutput[T <: OutputConfig] extends TileModule with MIOutput[T]
val toRemove = known -- connections
toRemove.foreach(x => core.removeOutput(myPos, x))
toAdd.foreach(x => core.newOutput(myPos, x, makeCfgObject(x)))
if (toAdd.size > 0 || toRemove.size > 0) {
if (toAdd.nonEmpty || toRemove.nonEmpty) {
onConnectionsChanged(toAdd, toRemove)
getWorldObj.markBlockForUpdate(xCoord, yCoord, zCoord)
}
+29
View File
@@ -0,0 +1,29 @@
/*
* Copyright (c) bdew, 2013 - 2015
* 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.nbt
import net.minecraft.nbt.NBTTagList
import scala.annotation.implicitNotFound
@implicitNotFound("Type ${R} can't currently be retrieved from NBT lists")
case class ListElement[R](definition: Type[R], fromList: (NBTTagList, Int) => R)
object ListElement {
def apply[R: ListElement] = implicitly[ListElement[R]]
import Type._
implicit val stringInList = ListElement(TString, _.getStringTagAt(_))
implicit val compoundInList = ListElement(TCompound, _.getCompoundTagAt(_))
implicit val intArrayInList = ListElement(TIntArray, _.func_150306_c(_))
implicit val doubleInList = ListElement(TDouble, _.func_150309_d(_))
implicit val floatInList = ListElement(TFloat, _.func_150308_e(_))
}
+50
View File
@@ -0,0 +1,50 @@
/*
* Copyright (c) bdew, 2013 - 2015
* 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.nbt
import net.minecraft.item.ItemStack
import net.minecraft.nbt.{NBTBase, NBTTagByte, NBTTagCompound, NBTTagList}
import scala.language.implicitConversions
object NBT {
class NBTSerialized(val value: NBTBase) extends AnyVal
object NBTSerialized {
implicit def serializeNbtPrimitive[T: Type](v: T): NBTSerialized = new NBTSerialized(Type[T].toNBT(v))
implicit def serializeNbtList[T: Type](v: Traversable[T]): NBTSerialized = {
val list = new NBTTagList
for (x <- v) list.appendTag(Type[T].toNBT(x))
new NBTSerialized(list)
}
// Boolean is special because it's represented as a byte in NBT
implicit def serializeBoolean(v: Boolean): NBTSerialized = new NBTSerialized(new NBTTagByte(if (v) 1 else 0))
// Itemstack serialization helpers
implicit def serializeItemStack(v: ItemStack): NBTSerialized = new NBTSerialized(NBT.from(v.writeToNBT _))
implicit def serializeItemStackList(v: Traversable[ItemStack]): NBTSerialized = serializeNbtList(v map (x => NBT.from(x.writeToNBT _)))
}
def apply(pairs: (String, NBTSerialized)*): NBTTagCompound = {
val tag = new NBTTagCompound()
for ((k, v) <- pairs)
tag.setTag(k, v.value)
tag
}
def from(f: (NBTTagCompound) => _) = {
val v = new NBTTagCompound
f(v)
v
}
}
@@ -0,0 +1,32 @@
/*
* Copyright (c) bdew, 2013 - 2015
* 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.nbt
import net.minecraft.item.ItemStack
import net.minecraft.nbt.{NBTTagCompound, NBTTagList}
import scala.language.implicitConversions
class RichNBTTagCompound(tag: NBTTagCompound) {
def getList[T: ListElement](name: String): Iterable[T] = {
val tDef = ListElement[T]
val list = tag.getTagList(name, tDef.definition.id)
for (i <- 0 until list.tagCount()) yield tDef.fromList(list, i)
}
def setList[T: Type](name: String, v: Iterable[T]): Unit = {
val list = new NBTTagList
for (x <- v) list.appendTag(Type[T].toNBT(x))
tag.setTag(name, list)
}
def toItemStack = Option(ItemStack.loadItemStackFromNBT(tag))
}
+77
View File
@@ -0,0 +1,77 @@
/*
* Copyright (c) bdew, 2013 - 2015
* 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.nbt
import net.minecraft.nbt._
import scala.annotation.implicitNotFound
@implicitNotFound("Type ${R} is not supported by NBT")
trait Type[R] {
def id: Int
def toNBT(p: R): NBTBase
def fromCompound(t: NBTTagCompound, n: String): Option[R]
}
object Type {
def apply[R: Type] = implicitly[Type[R]]
implicit object TByte extends TypeDef(1, classOf[NBTTagByte], classOf[Byte]) {
override def toVal(p: NBTTagByte): Byte = p.func_150290_f()
override def toNBT(p: Byte): NBTTagByte = new NBTTagByte(p)
}
implicit object TShort extends TypeDef(2, classOf[NBTTagShort], classOf[Short]) {
override def toVal(p: NBTTagShort): Short = p.func_150289_e()
override def toNBT(p: Short): NBTTagShort = new NBTTagShort(p)
}
implicit object TInt extends TypeDef(3, classOf[NBTTagInt], classOf[Int]) {
override def toVal(p: NBTTagInt): Int = p.func_150287_d()
override def toNBT(p: Int): NBTTagInt = new NBTTagInt(p)
}
implicit object TLong extends TypeDef(4, classOf[NBTTagLong], classOf[Long]) {
override def toVal(p: NBTTagLong): Long = p.func_150291_c()
override def toNBT(p: Long): NBTTagLong = new NBTTagLong(p)
}
implicit object TFloat extends TypeDef(5, classOf[NBTTagFloat], classOf[Float]) {
override def toVal(p: NBTTagFloat): Float = p.func_150288_h()
override def toNBT(p: Float): NBTTagFloat = new NBTTagFloat(p)
}
implicit object TDouble extends TypeDef(6, classOf[NBTTagDouble], classOf[Double]) {
override def toVal(p: NBTTagDouble): Double = p.func_150286_g()
override def toNBT(p: Double): NBTTagDouble = new NBTTagDouble(p)
}
implicit object TByteArray extends TypeDef(7, classOf[NBTTagByteArray], classOf[Array[Byte]]) {
override def toVal(p: NBTTagByteArray): Array[Byte] = p.func_150292_c()
override def toNBT(p: Array[Byte]): NBTTagByteArray = new NBTTagByteArray(p)
}
implicit object TString extends TypeDef(8, classOf[NBTTagString], classOf[String]) {
override def toVal(p: NBTTagString): String = p.func_150285_a_()
override def toNBT(p: String): NBTTagString = new NBTTagString(p)
}
implicit object TList extends TypeDefSimple(9, classOf[NBTTagList])
implicit object TCompound extends TypeDefSimple(10, classOf[NBTTagCompound])
implicit object TIntArray extends TypeDef(11, classOf[NBTTagIntArray], classOf[Array[Int]]) {
override def toVal(p: NBTTagIntArray): Array[Int] = p.func_150302_c()
override def toNBT(p: Array[Int]): NBTTagIntArray = new NBTTagIntArray(p)
}
}
+32
View File
@@ -0,0 +1,32 @@
/*
* Copyright (c) bdew, 2013 - 2015
* 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.nbt
import net.minecraft.nbt.{NBTBase, NBTTagCompound}
import scala.annotation.implicitNotFound
@implicitNotFound("Type ${R} is not supported by NBT")
abstract class TypeDef[T <: NBTBase, R](val id: Int, val cls: Class[T], val valueClass: Class[R]) extends Type[R] {
TypeDef.map += id -> this
def toVal(p: T): R
def toNBT(p: R): T
override def fromCompound(t: NBTTagCompound, n: String): Option[R] =
if (t.hasKey(n, id)) Some(toVal(t.getTag(n).asInstanceOf[T])) else None
}
object TypeDef {
var map = Map.empty[Int, TypeDef[_, _]]
}
class TypeDefSimple[T <: NBTBase](id: Int, cls: Class[T]) extends TypeDef[T, T](id, cls, cls) {
override def toVal(p: T): T = p
override def toNBT(p: T): T = p
}
+18
View File
@@ -0,0 +1,18 @@
/*
* Copyright (c) bdew, 2013 - 2015
* 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
import net.minecraft.nbt.NBTTagCompound
import scala.language.implicitConversions
package object nbt {
implicit def compound2rich(p: NBTTagCompound): RichNBTTagCompound = new RichNBTTagCompound(p)
}
+3 -2
View File
@@ -10,11 +10,11 @@
package net.bdew.lib.power
import net.bdew.lib.Misc
import net.bdew.lib.data.base.{DataSlot, TileDataSlots, UpdateKind}
import net.bdew.lib.data.base.{DataSlot, DataSlotContainer, UpdateKind}
import net.bdew.lib.machine.PoweredMachine
import net.minecraft.nbt.NBTTagCompound
case class DataSlotPower(name: String, parent: TileDataSlots) extends DataSlot {
case class DataSlotPower(name: String, parent: DataSlotContainer) extends DataSlot {
updateKind = Set(UpdateKind.GUI, UpdateKind.SAVE)
var stored = 0F
@@ -34,6 +34,7 @@ case class DataSlotPower(name: String, parent: TileDataSlots) extends DataSlot {
val canExtract = Misc.clamp(v, 0F, stored)
if ((canExtract > 0) && !simulate) {
stored -= canExtract
if (stored < 1) stored = 0
parent.dataSlotChanged(this)
}
return canExtract
@@ -13,12 +13,11 @@ import net.bdew.lib.data.DataSlotFloat
import net.bdew.lib.data.base.{TileDataSlots, UpdateKind}
import net.bdew.lib.machine.ProcessorMachine
import net.bdew.lib.tile.TileExtended
import net.bdew.lib.tile.inventory.{BreakableInventoryTile, PersistentInventoryTile, SidedInventory}
import net.bdew.lib.tile.inventory.{PersistentInventoryTile, SidedInventory}
abstract class TileBaseProcessor extends TileExtended
with TileDataSlots
with PersistentInventoryTile
with BreakableInventoryTile
with SidedInventory
with TilePoweredBase {
def cfg: ProcessorMachine
+4 -1
View File
@@ -178,7 +178,10 @@ class RecipeLoader {
case StackGeneric(mod, id) =>
notNull(GameRegistry.findItemStack(mod, id, cnt), "Stack not found %s:%s".format(mod, id))
case StackBlock(mod, id, meta) =>
new ItemStack(notNull(GameRegistry.findBlock(mod, id), "Block not found %s:%s".format(mod, id)), cnt, meta)
val block = notNull(GameRegistry.findBlock(mod, id), "Block not found %s:%s".format(mod, id))
if (Item.getItemFromBlock(block) == null)
error("The block '%s:%s' does not have a valid matching item registered and thus can't be used in recipes", mod, id)
new ItemStack(block, cnt, meta)
case StackItem(mod, id, meta) =>
new ItemStack(notNull(GameRegistry.findItem(mod, id), "Item not found %s:%s".format(mod, id)), cnt, meta)
case StackReflect(cls, field, meta) => reflectStack(cls, field, meta, cnt)
+13 -13
View File
@@ -12,7 +12,7 @@ package net.bdew.lib.recipes
import java.io._
import cpw.mods.fml.common.FMLCommonHandler
import net.bdew.lib.BdLib
import net.bdew.lib.{BdLib, Misc}
object RecipesHelper {
/**
@@ -26,15 +26,14 @@ object RecipesHelper {
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 internals = Misc.withAutoClose(new BufferedReader(new InputStreamReader(getClass.getResourceAsStream(listResource)))) { listReader =>
Iterator.continually(listReader.readLine)
.takeWhile(_ != null)
.map(_.trim)
.filterNot(_.startsWith("#"))
.filterNot(_.isEmpty)
.toList
}
val overrideDir = new File(configDir, "overrides")
if (!overrideDir.exists()) overrideDir.mkdir()
@@ -44,9 +43,10 @@ object RecipesHelper {
if (overrideFile.exists()) {
tryLoadConfig(new FileReader(overrideFile), overrideFile.getCanonicalPath, modName, loader)
} else {
val resource = resBaseName + fileName
tryLoadConfig(new InputStreamReader(getClass.getResourceAsStream(resource)),
getClass.getResource(resource).toString, modName, loader)
val url = getClass.getResource(resBaseName + fileName)
Misc.withAutoClose(url.openStream()) { stream =>
tryLoadConfig(new InputStreamReader(stream), url.toString, modName, loader)
}
}
}
@@ -9,6 +9,8 @@
package net.bdew.lib.recipes.gencfg
import java.util.Locale
import net.bdew.lib.gui.Color
abstract class ConfigEntry
@@ -43,7 +45,7 @@ case class ConfigSection(pfx: String = "") extends ConfigEntry with Iterable[(St
def getSection(id: String) = getRaw(id, classOf[ConfigSection])
final val trueVals = Set("y", "true", "yes", "on")
def getBoolean(id: String) = trueVals.contains(getString(id).toLowerCase)
def getBoolean(id: String) = trueVals.contains(getString(id).toLowerCase(Locale.US))
def hasValue(id: String) = raw.isDefinedAt(id)
@@ -59,8 +61,8 @@ case class ConfigSection(pfx: String = "") extends ConfigEntry with Iterable[(St
def getInt(id: String) = getDouble(id).round.toInt
def getFloat(id: String) = getDouble(id).toFloat
def getIntList(id: String) = getDoubleList(id).map(_.round.toInt).toList
def getFloatList(id: String) = getDoubleList(id).map(_.toFloat).toList
def getIntList(id: String) = getDoubleList(id).map(_.round.toInt)
def getFloatList(id: String) = getDoubleList(id).map(_.toFloat)
def getColor(id: String) =
raw(id) match {
@@ -14,10 +14,10 @@ import net.bdew.lib.recipes.gencfg.ConfigEntry
/**
* Allows definition of random-weighted loot/drop lists in config sections
* @param list List on (chance percent, stack reference) pairs, resolve to
* @param list List of (chance percent, stack reference) pairs, resolve to
* real ItemStacks with LootListLoader.resolveLootList
*/
case class EntryLootList(list: List[(Int, StackRef)]) extends ConfigEntry
case class EntryLootList(list: List[(Double, StackRef)]) extends ConfigEntry
@@ -19,8 +19,8 @@ import net.minecraftforge.oredict.OreDictionary
* Loader mixin for loot lists
*/
trait LootListLoader extends GenericConfigLoader {
def resolveLootList(entry: EntryLootList): List[(Int, ItemStack)] = resolveLootList(entry.list)
def resolveLootList(list: List[(Int, StackRef)]) =
def resolveLootList(entry: EntryLootList): List[(Double, ItemStack)] = resolveLootList(entry.list)
def resolveLootList(list: List[(Double, StackRef)]) =
(for ((chance, ref) <- list) yield {
try {
val itemStack = getConcreteStack(ref)
@@ -19,7 +19,7 @@ import net.bdew.lib.recipes.gencfg.GenericConfigParser
* )
*/
trait LootListParser extends GenericConfigParser {
def dropsEntry = (wholeNumber <~ "%") ~ spec ^^ { case n ~ s => (n.toInt, s) }
def dropsEntry = (decimalNumber <~ "%") ~ spec ^^ { case n ~ s => (n.toDouble, s) }
def ceDrops = "DropsList" ~> "(" ~> dropsEntry.* <~ ")" ^^ EntryLootList
override def cfgValue = ceDrops | super.cfgValue
}
@@ -10,6 +10,7 @@
package net.bdew.lib.render
import cpw.mods.fml.common.eventhandler.SubscribeEvent
import net.bdew.lib.Misc
import net.bdew.lib.gui.{IconWrapper, Texture}
import net.minecraft.client.renderer.texture.IIconRegister
import net.minecraft.util.IIcon
@@ -21,6 +22,13 @@ import net.minecraftforge.common.MinecraftForge
* @param kind 0=Blocks / 1=Items
*/
class IconPreloader(kind: Int) {
lazy val map = {
(for {
method <- getClass.getMethods if method.getParameterTypes.isEmpty && classOf[TextureLoc].isAssignableFrom(method.getReturnType)
value <- Misc.asInstanceOpt(method.invoke(this), classOf[TextureLoc])
} yield method.getName -> value).toMap
}
var icons = Set.empty[TextureLoc]
val sheet = kind match {
@@ -36,6 +36,8 @@ object RenderUtils {
* Render a simple block as an item (for gui, item entities etc.)
*/
def renderSimpleBlockItem(block: Block, metadata: Int, renderer: RenderBlocks) {
block.setBlockBoundsForItemRender()
renderer.setRenderBoundsFromBlock(block)
val T = Tessellator.instance
GL11.glTranslatef(-0.5F, -0.5F, -0.5F)
for (side <- ForgeDirection.VALID_DIRECTIONS) {
@@ -0,0 +1,74 @@
/*
* Copyright (c) bdew, 2013 - 2015
* 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.bdew.lib.render.connected.ConnectedHelper.{EdgeDraw, RectF}
import net.bdew.lib.rotate.BaseRotatableBlock
import net.minecraft.block.Block
import net.minecraft.client.renderer.RenderBlocks
import net.minecraft.world.IBlockAccess
import net.minecraftforge.common.util.ForgeDirection
object RotatedBlockRenderer extends BaseBlockRenderHandler {
val filterIconDraw =
(for (dir <- ForgeDirection.VALID_DIRECTIONS)
yield (dir, new EdgeDraw(RectF(0.35F, 0.35F, 0.65F, 0.65F), dir))).toMap
def setRenderRotation(renderer: RenderBlocks, side: ForgeDirection): Unit = {
side.ordinal() match {
case 0 =>
renderer.uvRotateEast = 3
renderer.uvRotateWest = 3
renderer.uvRotateSouth = 3
renderer.uvRotateNorth = 3
case 2 =>
renderer.uvRotateSouth = 1
renderer.uvRotateNorth = 2
case 3 =>
renderer.uvRotateSouth = 2
renderer.uvRotateNorth = 1
renderer.uvRotateTop = 3
renderer.uvRotateBottom = 3
case 4 =>
renderer.uvRotateEast = 1
renderer.uvRotateWest = 2
renderer.uvRotateTop = 2
renderer.uvRotateBottom = 1
case 5 =>
renderer.uvRotateEast = 2
renderer.uvRotateWest = 1
renderer.uvRotateTop = 1
renderer.uvRotateBottom = 2
case _ =>
}
}
def clearRenderRotation(renderer: RenderBlocks): Unit = {
renderer.uvRotateEast = 0
renderer.uvRotateWest = 0
renderer.uvRotateSouth = 0
renderer.uvRotateNorth = 0
renderer.uvRotateTop = 0
renderer.uvRotateBottom = 0
}
override def renderInventoryBlock(block: Block, metadata: Int, modelID: Int, renderer: RenderBlocks) {
setRenderRotation(renderer, block.asInstanceOf[BaseRotatableBlock].getDefaultFacing)
RenderUtils.renderSimpleBlockItem(block, metadata, renderer)
clearRenderRotation(renderer)
}
override def renderWorldBlock(world: IBlockAccess, x: Int, y: Int, z: Int, block: Block, modelId: Int, renderer: RenderBlocks): Boolean = {
setRenderRotation(renderer, block.asInstanceOf[BaseRotatableBlock].getFacing(world, x, y, z))
renderer.renderStandardBlock(block, x, y, z)
clearRenderRotation(renderer)
true
}
}
@@ -1,5 +1,5 @@
/*
* Copyright (c) bdew, 2013 - 2014
* Copyright (c) bdew, 2013 - 2015
* https://github.com/bdew/bdlib
*
* This mod is distributed under the terms of the Minecraft Mod Public
@@ -10,7 +10,8 @@
package net.bdew.lib.render.connected
import net.bdew.lib.block.BlockRef
import net.bdew.lib.render.{BaseBlockRenderHandler, RenderUtils}
import net.bdew.lib.render.{BaseBlockRenderHandler, RenderUtils, RotatedBlockRenderer}
import net.bdew.lib.rotate.BaseRotatableBlock
import net.minecraft.block.Block
import net.minecraft.client.renderer.{RenderBlocks, Tessellator}
import net.minecraft.world.IBlockAccess
@@ -35,7 +36,10 @@ object ConnectedRenderer extends BaseBlockRenderHandler {
}
override def renderWorldBlock(world: IBlockAccess, x: Int, y: Int, z: Int, block: Block, modelId: Int, renderer: RenderBlocks): Boolean = {
renderer.renderStandardBlock(block, x, y, z)
if (block.isInstanceOf[BaseRotatableBlock])
RotatedBlockRenderer.renderWorldBlock(world, x, y, z, block, modelId, renderer)
else
renderer.renderStandardBlock(block, x, y, z)
val pos = ConnectedHelper.Vec3F(x, y, z)
for (face <- ForgeDirection.VALID_DIRECTIONS)
@@ -10,13 +10,12 @@
package net.bdew.lib.resource
import net.bdew.lib.Misc
import net.bdew.lib.data.base.{DataSlot, TileDataSlots, UpdateKind}
import net.bdew.lib.data.base.{DataSlot, DataSlotContainer, UpdateKind}
import net.minecraft.nbt.NBTTagCompound
import net.minecraftforge.fluids.{FluidStack, FluidTankInfo}
class DataSlotResource(val name: String, val parent: TileDataSlots, initCapacity: Int) extends DataSlot {
class DataSlotResource(val name: String, val parent: DataSlotContainer, initCapacity: Int) extends DataSlot {
var resource: Option[Resource] = None
var amount = 0D
var capacity = initCapacity
val sendCapacityOnUpdateKind = Set(UpdateKind.GUI)
@@ -101,7 +100,7 @@ class DataSlotResource(val name: String, val parent: TileDataSlots, initCapacity
override def save(t: NBTTagCompound, kind: UpdateKind.Value) {
val tag = new NBTTagCompound()
resource map { res => tag.setTag("resource", ResourceManager.saveToNBT(res)) }
resource foreach { res => tag.setTag("resource", ResourceManager.saveToNBT(res)) }
if (sendCapacityOnUpdateKind.contains(kind))
tag.setInteger("capacity", capacity)
@@ -11,14 +11,14 @@ package net.bdew.lib.resource
import net.bdew.lib.Misc
import net.bdew.lib.data.DataSlotOption
import net.bdew.lib.data.base.{TileDataSlots, UpdateKind}
import net.bdew.lib.data.base.{DataSlotContainer, UpdateKind}
import net.minecraft.nbt.NBTTagCompound
case class DataSlotResourceKindOption(name: String, parent: TileDataSlots) extends DataSlotOption[ResourceKind] {
case class DataSlotResourceKindOption(name: String, parent: DataSlotContainer) extends DataSlotOption[ResourceKind] {
setUpdate(UpdateKind.SAVE, UpdateKind.GUI)
override def save(t: NBTTagCompound, kind: UpdateKind.Value) {
value map { r =>
value foreach { r =>
t.setTag(name,
Misc.applyMutator(new NBTTagCompound) { tag =>
r.helperObject.saveToNBT(tag, r)
@@ -69,21 +69,7 @@ trait BaseRotatableBlock extends Block {
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
}
}
val dir = RotatedHelper.getFacingFromEntity(ent, getValidFacings, getDefaultFacing)
setFacing(world, x, y, z, dir)
super.onBlockPlacedBy(world, x, y, z, ent, stack)
}
+1 -1
View File
@@ -13,5 +13,5 @@ import net.bdew.lib.data.DataSlotDirection
import net.bdew.lib.data.base.{TileDataSlots, UpdateKind}
trait RotatableTile extends TileDataSlots {
var rotation = DataSlotDirection("rotation", this).setUpdate(UpdateKind.SAVE, UpdateKind.WORLD)
var rotation = DataSlotDirection("rotation", this).setUpdate(UpdateKind.SAVE, UpdateKind.WORLD, UpdateKind.RENDER)
}
@@ -0,0 +1,32 @@
/*
* Copyright (c) bdew, 2013 - 2015
* 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.rotate
import java.util
import net.minecraft.entity.EntityLivingBase
import net.minecraft.util.MathHelper
import net.minecraftforge.common.util.ForgeDirection
object RotatedHelper {
def getFacingFromEntity(ent: EntityLivingBase, validRotations: util.EnumSet[ForgeDirection], default: ForgeDirection): ForgeDirection = {
val pitch = Math.round(ent.rotationPitch)
val yaw = MathHelper.floor_double(ent.rotationYaw * 4.0F / 360.0F + 0.5D) & 3
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 _ => default
}
}
}
@@ -0,0 +1,39 @@
/*
* Copyright (c) bdew, 2013 - 2015
* 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.sensors
import net.bdew.lib.Misc
import net.bdew.lib.data.base.{DataSlotVal, UpdateKind}
import net.bdew.lib.sensors.multiblock.TileRedstoneSensorModule
import net.minecraft.nbt.NBTTagCompound
case class DataSlotSensor[T, R](registry: SensorSystem[T, R], name: String, parent: TileRedstoneSensorModule, default: GenericSensorType[T, R]) extends DataSlotVal[SensorPair[T, R]] {
override var value = SensorPair(default, default.defaultParameter)
setUpdate(UpdateKind.SAVE, UpdateKind.GUI)
override def save(t: NBTTagCompound, kind: UpdateKind.Value) = {
t.setTag(name, Misc.applyMutator(new NBTTagCompound) { tag =>
tag.setString("uid", value.sensor.uid)
value.sensor.saveParameter(value.param, tag)
})
}
override def load(t: NBTTagCompound, kind: UpdateKind.Value) = {
value = registry.get(t.getCompoundTag(name).getString("uid"))
.map(x => SensorPair(x, x.loadParameter(t.getCompoundTag(name))))
.getOrElse(SensorPair(default, default.defaultParameter))
}
def ensureValid(obj: T): Unit = {
if (!value.sensor.isValidParameter(value.param, obj))
update(value.copy(param = value.sensor.defaultParameter))
}
}
@@ -0,0 +1,18 @@
/*
* Copyright (c) bdew, 2013 - 2015
* 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.sensors
import net.bdew.lib.Misc
abstract class GenericSensorParameter(system: SensorSystem[_, _]) {
val uid: String
def localizedName = Misc.toLocal(system.localizationPrefix + ".param." + uid)
}
@@ -0,0 +1,43 @@
/*
* Copyright (c) bdew, 2013 - 2015
* 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.sensors
import cpw.mods.fml.relauncher.{Side, SideOnly}
import net.bdew.lib.Misc
import net.bdew.lib.gui.{DrawTarget, Rect}
import net.minecraft.item.ItemStack
import net.minecraft.nbt.NBTTagCompound
abstract class GenericSensorType[-T, +R](system: SensorSystem[T, R]) {
def uid: String
system.register(this)
def getTooltip(obj: T): List[String] = List(localizedName)
def getParamTooltip(obj: T, param: GenericSensorParameter): List[String] = List(param.localizedName)
def localizedName = Misc.toLocal(system.localizationPrefix + "." + uid)
def defaultParameter: GenericSensorParameter
def paramClicked(current: GenericSensorParameter, item: ItemStack, button: Int, mod: Int, obj: T): GenericSensorParameter
def saveParameter(p: GenericSensorParameter, tag: NBTTagCompound)
def loadParameter(tag: NBTTagCompound): GenericSensorParameter
def isValidParameter(p: GenericSensorParameter, obj: T): Boolean
def getResult(param: GenericSensorParameter, obj: T): R
@SideOnly(Side.CLIENT)
def drawSensor(rect: Rect, target: DrawTarget, obj: T): Unit
@SideOnly(Side.CLIENT)
def drawParameter(rect: Rect, target: DrawTarget, obj: T, param: GenericSensorParameter): Unit
}
@@ -0,0 +1,35 @@
/*
* Copyright (c) bdew, 2013 - 2015
* 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.sensors
import cpw.mods.fml.relauncher.{Side, SideOnly}
import net.bdew.lib.Misc
import net.bdew.lib.gui.{DrawTarget, IconWrapper, Rect, Texture}
import net.minecraft.init.Blocks
abstract class RedstoneSensors[T] extends SensorSystem[T, Boolean](false) {
lazy val rsOn = new IconWrapper(Texture.BLOCKS, Blocks.redstone_torch.getIcon(0, 0))
lazy val rsOff = new IconWrapper(Texture.BLOCKS, Blocks.unlit_redstone_torch.getIcon(0, 0))
@SideOnly(Side.CLIENT)
override def drawResult(result: Boolean, rect: Rect, target: DrawTarget): Unit = {
if (result)
target.drawTexture(rect, rsOn)
else
target.drawTexture(rect, rsOff)
}
@SideOnly(Side.CLIENT)
override def getLocalizedResultText(result: Boolean): String =
if (result)
Misc.toLocal(localizationPrefix + ".on")
else
Misc.toLocal(localizationPrefix + ".off")
}
+14
View File
@@ -0,0 +1,14 @@
/*
* Copyright (c) bdew, 2013 - 2015
* 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.sensors
case class SensorPair[-T, +R](sensor: GenericSensorType[T, R], param: GenericSensorParameter) {
def getResult(obj: T) = sensor.getResult(param, obj)
}
@@ -0,0 +1,76 @@
/*
* Copyright (c) bdew, 2013 - 2015
* 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.sensors
import cpw.mods.fml.relauncher.{Side, SideOnly}
import net.bdew.lib.gui._
import net.bdew.lib.{BdLib, Misc}
import net.minecraft.item.ItemStack
abstract class SensorSystem[T, R](defaultResult: R) {
val map = collection.mutable.Map.empty[String, GenericSensorType[T, R]]
def get(uid: String) = map.get(uid)
def register[Z <: GenericSensorType[T, R]](s: Z): Z = {
if (map.isDefinedAt(s.uid))
sys.error("Duplicate sensor ID: %s (%s / %s)".format(s.uid, map(s.uid), s))
map += s.uid -> s
s
}
@SideOnly(Side.CLIENT)
def disabledTexture: Texture
def localizationPrefix: String
@SideOnly(Side.CLIENT)
def drawResult(result: R, rect: Rect, target: DrawTarget): Unit
@SideOnly(Side.CLIENT)
def getLocalizedResultText(result: R): String
abstract class SensorType extends GenericSensorType(this)
abstract class SensorParameter extends GenericSensorParameter(this)
abstract class SimpleSensor extends SimpleGenericSensor(this)
abstract class SimpleParameter extends SimpleGenericParameter(this)
object DisabledParameter extends SimpleParameter {
override val uid = "disabled"
@SideOnly(Side.CLIENT)
override def texture = disabledTexture
}
object DisabledSensor extends SimpleSensor {
override def parameters = Vector(DisabledParameter)
override def uid = "disabled"
override def paramClicked(current: GenericSensorParameter, item: ItemStack, button: Int, mod: Int, obj: T): GenericSensorParameter = DisabledParameter
override def getResult(param: GenericSensorParameter, obj: T): R = defaultResult
@SideOnly(Side.CLIENT)
override def texture = disabledTexture
}
object DisabledSensorPair extends SensorPair(DisabledSensor, DisabledParameter)
def init(): Unit = {
BdLib.logDebug("Initialized sensor system %s for mod %s", this.getClass.getName, Misc.getActiveModId)
}
}
@@ -0,0 +1,65 @@
/*
* Copyright (c) bdew, 2013 - 2015
* 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.sensors
import cpw.mods.fml.relauncher.{Side, SideOnly}
import net.bdew.lib.Misc
import net.bdew.lib.gui._
import net.minecraft.item.ItemStack
import net.minecraft.nbt.NBTTagCompound
abstract class SimpleGenericParameter(system: SensorSystem[_, _]) extends GenericSensorParameter(system) {
@SideOnly(Side.CLIENT)
def texture: Texture
@SideOnly(Side.CLIENT)
def textureColor = Color.white
}
abstract class SimpleGenericSensor[-T, +R](system: SensorSystem[T, R]) extends GenericSensorType[T, R](system) {
def parameters: IndexedSeq[GenericSensorParameter]
override lazy val defaultParameter = parameters.headOption.getOrElse(system.DisabledParameter)
lazy val parameterMap = (parameters map (x => x.uid -> x)).toMap
override def paramClicked(current: GenericSensorParameter, item: ItemStack, button: Int, mod: Int, obj: T) =
if (item == null && button == 0 && mod == 0)
Misc.nextInSeq(parameters, current)
else if (item == null && button == 1 && mod == 0)
Misc.prevInSeq(parameters, current)
else
current
override def saveParameter(p: GenericSensorParameter, tag: NBTTagCompound) = tag.setString("param", p.uid)
override def loadParameter(tag: NBTTagCompound) = parameterMap.getOrElse(tag.getString("param"), system.DisabledParameter)
override def isValidParameter(p: GenericSensorParameter, obj: T) = parameters.contains(p)
@SideOnly(Side.CLIENT)
def texture: Texture
@SideOnly(Side.CLIENT)
def textureColor = Color.white
@SideOnly(Side.CLIENT)
override def drawSensor(rect: Rect, target: DrawTarget, obj: T): Unit = {
target.drawTexture(rect, texture, textureColor)
}
@SideOnly(Side.CLIENT)
override def drawParameter(rect: Rect, target: DrawTarget, obj: T, param: GenericSensorParameter): Unit = {
param match {
case x: SimpleGenericParameter => target.drawTexture(rect, x.texture, x.textureColor)
case _ => target.drawTexture(rect, system.DisabledParameter.texture, system.DisabledParameter.textureColor)
}
}
}
@@ -0,0 +1,24 @@
/*
* Copyright (c) bdew, 2013 - 2015
* 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.sensors
import net.bdew.lib.gui.SlotClickable
import net.minecraft.entity.player.EntityPlayer
import net.minecraft.inventory.{IInventory, Slot}
class SlotSensorParameter[T, R](inv: IInventory, index: Int, x: Int, y: Int, ds: DataSlotSensor[T, R], obj: => Option[T]) extends Slot(inv, index, x, y) with SlotClickable {
override def onClick(button: Int, mods: Int, player: EntityPlayer) = {
obj foreach { x =>
val newParam = ds.sensor.paramClicked(ds.param, player.inventory.getItemStack, button, mods, x)
ds := ds.value.copy(param = newParam)
}
player.inventory.getItemStack
}
}
@@ -0,0 +1,29 @@
/*
* Copyright (c) bdew, 2013 - 2015
* 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.sensors
import net.bdew.lib.Misc
import net.bdew.lib.gui.SlotClickable
import net.minecraft.entity.player.EntityPlayer
import net.minecraft.inventory.{IInventory, Slot}
class SlotSensorType[T, R](inv: IInventory, index: Int, x: Int, y: Int, ds: DataSlotSensor[T, R], types: => Seq[GenericSensorType[T, R]]) extends Slot(inv, index, x, y) with SlotClickable {
override def onClick(button: Int, mods: Int, player: EntityPlayer) = {
if (mods == 0 && (button == 0 || button == 1) && types.nonEmpty && player.inventory.getItemStack == null) {
val newSensor =
if (button == 0)
Misc.nextInSeq(types, ds.sensor)
else
Misc.prevInSeq(types, ds.sensor)
ds := SensorPair(newSensor, newSensor.defaultParameter)
}
player.inventory.getItemStack
}
}
@@ -0,0 +1,84 @@
/*
* Copyright (c) bdew, 2013 - 2015
* 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.sensors.multiblock
import net.bdew.lib.Misc
import net.bdew.lib.block.BlockRef
import net.bdew.lib.gui.GuiProvider
import net.bdew.lib.multiblock.block.BlockModule
import net.bdew.lib.rotate.{BaseRotatableBlock, IconType}
import net.minecraft.entity.player.EntityPlayer
import net.minecraft.util.{ChatComponentTranslation, IIcon}
import net.minecraft.world.{IBlockAccess, World}
import net.minecraftforge.common.util.ForgeDirection
trait BlockRedstoneSensorModule[T <: TileRedstoneSensorModule] extends BlockModule[T] with BaseRotatableBlock with GuiProvider {
override def onBlockActivated(world: World, x: Int, y: Int, z: Int, player: EntityPlayer, meta: Int, xOffs: Float, yOffs: Float, zOffs: Float): Boolean = {
if (player.isSneaking) return false
if (world.isRemote) return true
val te = getTE(world, x, y, z)
if (te.getCore.isDefined) {
te.config.ensureValid(te.getCore.get)
doOpenGui(world, x, y, z, player)
} else {
player.addChatMessage(new ChatComponentTranslation("bdlib.multiblock.notconnected"))
}
true
}
def doOpenGui(world: World, x: Int, y: Int, z: Int, player: EntityPlayer)
def notifyTarget(w: World, x: Int, y: Int, z: Int): Unit = {
val bp = BlockRef(x, y, z).neighbour(getFacing(w, x, y, z))
w.notifyBlocksOfNeighborChange(bp.x, bp.y, bp.z, this)
}
override def getFacing(world: IBlockAccess, x: Int, y: Int, z: Int) =
Misc.forgeDirection(world.getBlockMetadata(x, y, z) & 7)
override def setFacing(world: World, x: Int, y: Int, z: Int, facing: ForgeDirection) = {
val m = world.getBlockMetadata(x, y, z) & 8
world.setBlockMetadataWithNotify(x, y, z, m | facing.ordinal(), 3)
notifyTarget(world, x, y, z)
}
def isSignalOn(world: IBlockAccess, x: Int, y: Int, z: Int) =
(world.getBlockMetadata(x, y, z) & 8) == 8
def setSignal(world: World, x: Int, y: Int, z: Int, signal: Boolean): Unit = {
val m = world.getBlockMetadata(x, y, z) & 7
world.setBlockMetadataWithNotify(x, y, z, m | (if (signal) 8 else 0), 3)
notifyTarget(world, x, y, z)
}
override def getIcon(meta: Int, kind: IconType.Value) = kind match {
case IconType.BACK => bottomIcon
case IconType.FRONT => if ((meta & 8) == 8) frontIconOn else frontIcon
case IconType.SIDE => if ((meta & 8) == 8) sideIconOn else sideIcon
}
override def canProvidePower = true
override def isSideSolid(world: IBlockAccess, x: Int, y: Int, z: Int, side: ForgeDirection) = true
override def isProvidingWeakPower(w: IBlockAccess, x: Int, y: Int, z: Int, side: Int) = {
val m = w.getBlockMetadata(x, y, z)
if (((m & 7) == Misc.forgeDirection(side).getOpposite.ordinal()) && ((m & 8) == 8))
15
else
0
}
var frontIcon: IIcon = null
var bottomIcon: IIcon = null
var frontIconOn: IIcon = null
var sideIconOn: IIcon = null
var sideIcon: IIcon = null
}
@@ -0,0 +1,19 @@
/*
* Copyright (c) bdew, 2013 - 2015
* 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.sensors.multiblock
import net.bdew.lib.multiblock.tile.TileController
import net.bdew.lib.sensors.{GenericSensorType, SensorSystem}
import net.minecraft.tileentity.TileEntity
trait CIRedstoneSensors extends TileController {
def redstoneSensorsType: Seq[GenericSensorType[TileEntity, Boolean]]
def redstoneSensorSystem: SensorSystem[TileEntity, Boolean]
}
@@ -0,0 +1,113 @@
/*
* Copyright (c) bdew, 2013 - 2015
* 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.sensors.multiblock
import java.util.Locale
import cpw.mods.fml.relauncher.{Side, SideOnly}
import net.bdew.lib.Misc
import net.bdew.lib.gui._
import net.bdew.lib.multiblock.interact.CIOutputFaces
import net.bdew.lib.render.connected.BlockAdditionalRender
import net.bdew.lib.sensors.{GenericSensorParameter, GenericSensorType, SensorSystem}
import net.minecraft.item.ItemStack
import net.minecraft.nbt.NBTTagCompound
import net.minecraft.tileentity.TileEntity
trait SensorOutput extends GenericSensorType[TileEntity, Boolean] {
def system: SensorSystem[TileEntity, Boolean]
override def defaultParameter = system.DisabledParameter
case class SensorOutputFlowParameter(output: Int) extends GenericSensorParameter(system) {
override val uid: String = "output." + output
}
def getResultFromOutput(te: CIOutputFaces, output: Int): Boolean
override def loadParameter(tag: NBTTagCompound) = {
if (tag.hasKey("output"))
SensorOutputFlowParameter(tag.getInteger("output"))
else
system.DisabledParameter
}
override def saveParameter(p: GenericSensorParameter, tag: NBTTagCompound): Unit = p match {
case SensorOutputFlowParameter(n) => tag.setInteger("output", n)
case _ =>
}
override def isValidParameter(p: GenericSensorParameter, obj: TileEntity): Boolean = (p, obj) match {
case (SensorOutputFlowParameter(n), x: CIOutputFaces) => x.outputFaces.inverted.isDefinedAt(n)
case (param, _) if param == system.DisabledParameter => true
case _ => false
}
override def getResult(param: GenericSensorParameter, obj: TileEntity): Boolean = (param, obj) match {
case (SensorOutputFlowParameter(n), x: CIOutputFaces) => getResultFromOutput(x, n)
case _ => false
}
override def paramClicked(current: GenericSensorParameter, item: ItemStack, button: Int, mod: Int, obj: TileEntity) =
if (mod == 0 && (button == 0 || button == 1) && item == null)
(current, obj) match {
case (SensorOutputFlowParameter(n), x: CIOutputFaces) =>
val outputs = x.outputFaces.map.values.toList.sorted
if (outputs.nonEmpty)
if (button == 0)
SensorOutputFlowParameter(Misc.nextInSeq(outputs, n))
else
SensorOutputFlowParameter(Misc.prevInSeq(outputs, n))
else
system.DisabledParameter
case (_, x: CIOutputFaces) =>
if (button == 0)
x.outputFaces.map.values.toList.sorted.headOption map SensorOutputFlowParameter getOrElse system.DisabledParameter
else
x.outputFaces.map.values.toList.sorted.reverse.headOption map SensorOutputFlowParameter getOrElse system.DisabledParameter
case _ =>
system.DisabledParameter
}
else current
@SideOnly(Side.CLIENT)
override def drawParameter(rect: Rect, target: DrawTarget, obj: TileEntity, param: GenericSensorParameter): Unit = (param, obj) match {
case (SensorOutputFlowParameter(output), te: CIOutputFaces) =>
val faces = te.outputFaces.inverted
if (faces.isDefinedAt(output)) {
val bf = faces(output)
bf.origin.block(te.getWorldObj) foreach { block =>
target.drawTexture(rect, Texture(Texture.BLOCKS, block.getIcon(te.getWorldObj, bf.origin.x, bf.origin.y, bf.origin.z, bf.face.ordinal())))
if (block.isInstanceOf[BlockAdditionalRender]) {
for (over <- block.asInstanceOf[BlockAdditionalRender].getFaceOverlays(te.getWorldObj, bf.origin.x, bf.origin.y, bf.origin.z, bf.face))
target.drawTexture(rect, Texture(Texture.BLOCKS, over.icon), over.color)
}
}
}
case _ => target.drawTexture(rect, system.DisabledParameter.texture, system.DisabledParameter.textureColor)
}
override def getParamTooltip(obj: TileEntity, param: GenericSensorParameter) = (param, obj) match {
case (SensorOutputFlowParameter(output), te: CIOutputFaces) =>
val faces = te.outputFaces.inverted
var list = List.empty[String]
list :+= Misc.toLocal(te.resources.unlocalizedOutputName(output))
if (faces.isDefinedAt(output)) {
val bf = faces(output)
bf.origin.block(te.getWorldObj) foreach { block =>
list :+= block.getLocalizedName
list :+= "%d, %d, %d - %s".format(bf.x, bf.y, bf.z, Misc.toLocal("bdlib.multiblock.face." + bf.face.toString.toLowerCase(Locale.US)))
}
}
list
case _ => super.getParamTooltip(obj, param)
}
}
Loaded 100 of 116 files, more files were not shown because too many files have changed in this diff. Show more