1.15: Initial port.

This commit is contained in:
stfwi 2019-12-19 18:26:00 +01:00
parent 7055adf985
commit a733e39c51
1028 changed files with 31668 additions and 3 deletions

View file

@ -4,4 +4,4 @@ org.gradle.jvmargs=-Xmx8G
version_minecraft=1.12.2
version_forge=14.23.5.2768
version_jei=4.10.0.198
version_engineersdecor=1.0.17-b2
version_engineersdecor=1.0.17-b3

View file

@ -10,6 +10,8 @@ Mod sources for Minecraft version 1.12.2.
----
## Version history
~ v1.0.17-b3 [A]
- v1.0.17-b2 [A] Reverse recipes for slabs and slab slices added.
[M] Inset Floor Edge Light slightly thinner, looks better.

View file

@ -5,4 +5,4 @@ version_minecraft=1.14.4
version_forge_minecraft=1.14.4-28.1.104
version_fml_mappings=20190719-1.14.3
version_jei=1.14.4:6.0.0.10
version_engineersdecor=1.0.17-b2
version_engineersdecor=1.0.17-b3

View file

@ -11,6 +11,8 @@ Mod sources for Minecraft version 1.14.4.
## Version history
~ v1.0.17-b3 [A]
- v1.0.17-b2 [A] Reverse recipes for slabs and slab slices added.
[M] Inset Floor Edge Light slightly thinner, looks better.

37
1.15/.gitignore vendored Normal file
View file

@ -0,0 +1,37 @@
bin
*.launch
.settings
.metadata
.classpath
.project
out
*.ipr
*.iws
*.iml
.idea
build
.gradle
*.tmp
*.log
*.jks
eclipse
run
tests
/dist
signing.*
src/main/java/archive
src/main/resources/assets/minecraft
.vscode
/classes
/dev
/tmp
/archive
/assets-src
.gimp
*.xcf
desktop.ini
.DS_Store
Thumbs.db
forge*changelog.txt
/*.txt
mcmodsrepo

92
1.15/Makefile Normal file
View file

@ -0,0 +1,92 @@
# @file Makefile
# @author Stefan Wilhelm (wile)
# @license MIT
#
# GNU Make makefile based build relay.
# Note for reviewers/clones: This file is a auxiliary script for my setup.
# It's not needed to build the mod.
#
MOD_JAR_PREFIX=engineersdecor-
MOD_JAR=$(filter-out %-sources.jar,$(wildcard build/libs/${MOD_JAR_PREFIX}*.jar))
ifeq ($(OS),Windows_NT)
GRADLE=gradlew.bat --no-daemon
GRADLE_STOP=gradlew.bat --stop
DJS=djs
else
GRADLE=./gradlew --no-daemon
GRADLE_STOP=./gradlew --stop
DJS=djs
endif
wildcardr=$(foreach d,$(wildcard $1*),$(call wildcardr,$d/,$2) $(filter $(subst *,%,$2),$d))
#
# Targets
#
.PHONY: default mod data init clean clean-all mrproper all run install sanatize dist-check dist start-server assets
default: mod
all: clean clean-all mod | install
mod: data
@echo "[1.14] Building mod using gradle ..."
@$(GRADLE) build $(GRADLE_OPTS)
data:
@echo "[1.14] Running data generators ..."
@djs tasks.js datagen
clean:
@echo "[1.14] Cleaning ..."
@rm -rf src/generated
@rm -rf mcmodsrepo
@rm -f build/libs/*
@$(GRADLE) clean
clean-all:
@echo "[1.14] Cleaning using gradle ..."
@rm -rf mcmodsrepo
@rm -f dist/*
@rm -rf run/logs/
@rm -rf run/crash-reports/
@$(GRADLE) clean
mrproper: clean-all
@rm -f meta/*.*
@rm -rf run/
@rm -rf out/
@rm -f .project
@rm -f .classpath
init:
@echo "[1.14] Initialising eclipse workspace using gradle ..."
@$(GRADLE) eclipse
sanatize:
@echo "[1.14] Running sanatising tasks ..."
@djs tasks.js trailing-whitespaces
@djs tasks.js tabs-to-spaces
@djs tasks.js sync-languages
@djs tasks.js version-check
@djs tasks.js update-json
@git status -s .
dist-check:
@echo "[1.14] Running dist checks ..."
@djs tasks.js dist-check
dist-files: clean-all init mod
@echo "[1.14] Distribution files ..."
@mkdir -p dist
@cp build/libs/$(MOD_JAR_PREFIX)* dist/
@djs tasks.js dist
dist: sanatize dist-check dist-files
assets:
@echo "[1.14] Running asset generators ..."
@djs tasks.js create-slab-assets
@djs tasks.js create-half-slab-assets
@djs tasks.js assets

102
1.15/build.gradle Normal file
View file

@ -0,0 +1,102 @@
// @file build.gradle
// Engineer's decor mod gradle build relay (mc1.15.1)
buildscript {
repositories {
maven { url = 'https://files.minecraftforge.net/maven' }
jcenter()
mavenCentral()
}
dependencies {
classpath group: 'net.minecraftforge.gradle', name: 'ForgeGradle', version: '3.+', changing: true
}
}
apply plugin: 'net.minecraftforge.gradle'
apply plugin: 'eclipse'
apply plugin: 'maven-publish'
sourceCompatibility = targetCompatibility = compileJava.sourceCompatibility = compileJava.targetCompatibility = '1.8'
//-----------------------------------------------------------------------------
version = "${version_engineersdecor}"
group = "wile.engineersdecor"
archivesBaseName = "engineersdecor-${version_minecraft}"
def signingData = { ->
def sp = new Properties()
if(file("signing.properties").exists()) file("signing.properties").withInputStream { sp.load(it) }
return sp
}()
repositories {
maven { name = "Progwml6 maven"; url = "https://dvs1.progwml6.com/files/maven/" } // JEI files
maven { name = "ModMaven"; url = "modmaven.k-4u.nl" } // JEI files, fallback
}
minecraft {
mappings channel: 'snapshot', version: "${version_fml_mappings}"
// accessTransformer = file('build/resources/main/META-INF/accesstransformer.cfg')
runs {
client {
workingDirectory project.file('run')
property 'forge.logging.markers', 'SCAN,REGISTRIES,REGISTRYDUMP'
property 'forge.logging.console.level', 'debug'
mods {
engineersdecor {
source sourceSets.main
}
}
}
server {
workingDirectory project.file('run')
property 'forge.logging.markers', 'SCAN,REGISTRIES,REGISTRYDUMP'
property 'forge.logging.console.level', 'debug'
mods {
engineersdecor {
source sourceSets.main
}
}
}
data {
workingDirectory project.file('run')
property 'forge.logging.markers', 'SCAN,REGISTRIES,REGISTRYDUMP'
property 'forge.logging.console.level', 'debug'
args '--mod', 'engineersdecor', '--all', '--output', file('src/generated/resources/')
mods {
engineersdecor {
source sourceSets.main
}
}
}
}
}
dependencies {
minecraft "net.minecraftforge:forge:${version_forge_minecraft}"
//compileOnly fg.deobf("mezz.jei:jei-${version_jei}:api")
//runtimeOnly fg.deobf("mezz.jei:jei-${version_jei}")
}
processResources {
outputs.upToDateWhen { false } // thx to @tterrag for this hint
doLast { file("${sourceSets.main.output.resourcesDir}/.gitversion").text = 'git log "-1" "--format=%h"'.execute().in.text.trim() }
}
jar {
manifest {
attributes([
"Specification-Title": "engineersdecor",
"Specification-Vendor": "wilechaote",
"Specification-Version": "1", // We are version 1 of ourselves
"Implementation-Title": project.name,
"Implementation-Version": "${version_engineersdecor}",
"Implementation-Vendor" :"wilechaote",
"Implementation-Timestamp": new Date().format("yyyy-MM-dd'T'HH:mm:ssZ")
])
}
}
def reobfFile = file("$buildDir/reobfJar/output.jar")
def reobfArtifact = artifacts.add('default', reobfFile) { type 'jar'; builtBy 'reobfJar'; }
publishing {
publications { mavenJava(MavenPublication) { artifact reobfArtifact } }
repositories { maven { url "file:///${project.projectDir}/mcmodsrepo" } }
}

8
1.15/gradle.properties Normal file
View file

@ -0,0 +1,8 @@
# @file gradle.properties
org.gradle.daemon=false
org.gradle.jvmargs=-Xmx8G
version_minecraft=1.15.1
version_forge_minecraft=1.15.1-30.0.11
version_fml_mappings=20190719-1.14.3
version_jei=1.14.4:6.0.0.10
version_engineersdecor=1.0.17-b2

BIN
1.15/gradle/wrapper/gradle-wrapper.jar vendored Normal file

Binary file not shown.

View file

@ -0,0 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.9-bin.zip

172
1.15/gradlew vendored Normal file
View file

@ -0,0 +1,172 @@
#!/usr/bin/env sh
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn () {
echo "$*"
}
die () {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=$(save "$@")
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
cd "$(dirname "$0")"
fi
exec "$JAVACMD" "$@"

84
1.15/gradlew.bat vendored Normal file
View file

@ -0,0 +1,84 @@
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

View file

@ -0,0 +1,61 @@
#!/usr/bin/djs
// run from tasks.js directory
"use strict";
(function(constants, libassets){
const me = {};
const modid = constants.mod_registry_name();
const assets_root = constants.local_assets_root();
const hexchar = ['0','1','2','3','4','5','6','7','8','9','a','b','c','d','e']; // ('a'+parts) won't work so here we go
const create_item_model = function(prefix, texture) {
const model = {
parent: modid+":block/slab/generic/halfslab_inventory_model",
textures: { all: texture }
}
const path = "models/item/halfslab_"+prefix+".json";
if(!fs.writefile(path, JSON.stringify(model))) {
throw new Error("Failed to write item model file '"+ path +"'");
}
};
const create_block_models = function(prefix, texture) {
for(var parts=0; parts<15; ++parts) {
const model = {
parent: modid+":block/slab/generic/halfslab_s"+hexchar[parts]+"_model",
textures: { all:texture }
}
const path = "models/block/slab/specific/halfslab_"+prefix+"_s"+hexchar[parts]+"_model.json";
if(!fs.writefile(path, JSON.stringify(model))) {
throw new Error("Failed to write model file '"+ path +"'");
}
}
};
const create_blockstate = function(prefix) {
var variants = {};
for(var parts=0; parts<15; ++parts) {
variants[ ("parts="+parts).replace(/[\s]/g,"") ] = {
model: (modid+":block/slab/specific/halfslab_"+prefix+"_s"+hexchar[parts]+"_model").replace(/[\s]/g,"")
}
}
const path = "blockstates/halfslab_"+prefix+".json";
if(!fs.writefile(path, JSON.stringify({variants:variants},null,1))) throw new Error("Failed to write blockstate '"+path+"'");
return path;
};
me.create = function(data) {
const here = fs.cwd()
const registry_name_prefix = data.name_prefix;
const texture = data.texture;
if(!fs.chdir(assets_root)) throw new Error("Could not switch to assets root folder: '" + assets_root + "'");
try {
create_block_models(registry_name_prefix, texture);
create_item_model(registry_name_prefix, texture);
create_blockstate(registry_name_prefix, texture);
} finally {
fs.chdir(here);
}
}
Object.freeze(me);
return me;
});

View file

@ -0,0 +1,64 @@
#!/usr/bin/djs
// run from tasks.js directory
"use strict";
(function(constants, libassets){
const me = {};
const modid = constants.mod_registry_name();
const assets_root = constants.local_assets_root();
const create_item_model = function(prefix, texture_prefix) {
const model = {
parent: modid+":block/slab/generic/slab_inventory_model",
textures: { all: modid+":block/"+texture_prefix+"0" }
}
const path = "models/item/"+prefix+"_slab.json";
if(!fs.writefile(path, JSON.stringify(model))) {
throw new Error("Failed to write item model file '"+ path +"'");
}
};
const create_block_models = function(prefix, texture_prefix) {
for(var parts=0; parts<3; ++parts) {
for(var tvariant=0; tvariant<4; ++tvariant) {
const model = {
parent: modid+":block/slab/generic/slab_s"+parts+"_model",
textures: { all: modid+":block/"+texture_prefix+tvariant }
}
const path = "models/block/slab/specific/"+prefix+"_slab_s"+parts+"v"+tvariant+"_model.json";
if(!fs.writefile(path, JSON.stringify(model))) {
throw new Error("Failed to write model file '"+ path +"'");
}
}
}
};
const create_blockstate = function(prefix) {
var variants = {};
for(var parts=0; parts<3; ++parts) {
for(var tvariant=0; tvariant<4; ++tvariant) {
variants[ ("parts="+parts+",tvariant="+tvariant).replace(/[\s]/g,"") ] = {
model: (modid+":block/slab/specific/"+prefix+"_slab_s"+parts+"v"+tvariant+"_model").replace(/[\s]/g,"")
}
}
}
const path = "blockstates/"+prefix+"_slab.json";
if(!fs.writefile(path, JSON.stringify({variants:variants},null,1))) throw new Error("Failed to write blockstate '"+path+"'");
return path;
};
me.create = function(prefixes) {
const here = fs.cwd()
const registry_name_prefix = prefixes.name_prefix;
const texture_prefix = prefixes.texture_prefix;
if(!fs.chdir(assets_root)) throw new Error("Could not switch to assets root folder: '" + assets_root + "'");
try {
create_block_models(registry_name_prefix, texture_prefix);
create_item_model(registry_name_prefix, texture_prefix);
create_blockstate(registry_name_prefix, texture_prefix);
} finally {
fs.chdir(here);
}
}
Object.freeze(me);
return me;
});

10
1.15/meta/update.json Normal file
View file

@ -0,0 +1,10 @@
{
"homepage": "https://www.curseforge.com/minecraft/mc-mods/engineers-decor/",
"1.15.1": {
"1.0.17-b2": "[A] Initial port."
},
"promos": {
"1.15.1-recommended": "",
"1.15.1-latest": "1.0.17-b2"
}
}

16
1.15/readme.md Normal file
View file

@ -0,0 +1,16 @@
## Engineer's Decor (MC1.15.1)
Mod sources for Minecraft version 1.15.1.
- Description, credits, and features: Please see the readme in the repository root.
- Compiled mod distribution channel is curseforge: https://www.curseforge.com/minecraft/mc-mods/engineers-decor/files.
----
## Version history
- v1.0.17-b2 [A] Initial port.
----

View file

@ -0,0 +1,18 @@
/*
* BluSunrize
* Copyright (c) 2017
*
* This code is licensed under "Blu's License of Common Sense"
* Details can be found in the license file in the root folder of this project
*/
package blusunrize.immersiveengineering.api.fluid;
import net.minecraft.util.Direction;
public interface IFluidPipe
{
boolean canOutputPressurized(boolean consumePower);
boolean hasOutputConnection(Direction side);
}

View file

@ -0,0 +1,903 @@
/*
* @file ModContent.java
* @author Stefan Wilhelm (wile)
* @copyright (C) 2018 Stefan Wilhelm
* @license MIT (see https://opensource.org/licenses/MIT)
*
* Definition and initialisation of blocks of this
* module, along with their tile entities if applicable.
*
* Note: Straight forward definition of different blocks/entities
* to make recipes, models and texture definitions easier.
*/
package wile.engineersdecor;
import wile.engineersdecor.blocks.*;
import wile.engineersdecor.detail.ModAuxiliaries;
import net.minecraft.block.material.MaterialColor;
import net.minecraft.block.Block;
import net.minecraft.block.SoundType;
import net.minecraft.block.material.Material;
import net.minecraft.tileentity.TileEntityType;
import net.minecraft.item.Item;
import net.minecraft.item.BlockItem;
import net.minecraft.entity.EntityClassification;
import net.minecraft.entity.EntityType;
import net.minecraft.inventory.container.ContainerType;
import net.minecraft.util.ResourceLocation;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.RenderTypeLookup;
import net.minecraft.client.gui.ScreenManager;
import net.minecraftforge.event.RegistryEvent;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.fml.client.registry.RenderingRegistry;
import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent;
import org.apache.commons.lang3.ArrayUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.Collections;
import javax.annotation.Nonnull;
@SuppressWarnings("unused")
public class ModContent
{
//--------------------------------------------------------------------------------------------------------------------
// Blocks
//--------------------------------------------------------------------------------------------------------------------
public static final BlockDecor CLINKER_BRICK_BLOCK = (BlockDecor)(new BlockDecor(
BlockDecor.CFG_DEFAULT,
Block.Properties.create(Material.ROCK, MaterialColor.STONE).hardnessAndResistance(3f, 50f).sound(SoundType.STONE)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "clinker_brick_block"));
public static final BlockDecorSlab CLINKER_BRICK_SLAB = (BlockDecorSlab)(new BlockDecorSlab(
BlockDecor.CFG_DEFAULT,
Block.Properties.create(Material.ROCK, MaterialColor.STONE).hardnessAndResistance(3f, 50f).sound(SoundType.STONE)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "clinker_brick_slab"));
public static final BlockDecorStairs CLINKER_BRICK_STAIRS = (BlockDecorStairs)(new BlockDecorStairs(
BlockDecor.CFG_DEFAULT,
CLINKER_BRICK_BLOCK.getDefaultState(),
Block.Properties.create(Material.ROCK, MaterialColor.STONE).hardnessAndResistance(3f, 50f).sound(SoundType.STONE)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "clinker_brick_stairs"));
public static final BlockDecorWall CLINKER_BRICK_WALL = (BlockDecorWall)(new BlockDecorWall(
BlockDecor.CFG_DEFAULT,
Block.Properties.create(Material.ROCK, MaterialColor.STONE).hardnessAndResistance(3f, 50f).sound(SoundType.STONE)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "clinker_brick_wall"));
// -------------------------------------------------------------------------------------------------------------------
public static final BlockDecor CLINKER_BRICK_STAINED_BLOCK = (BlockDecor)(new BlockDecor(
BlockDecor.CFG_DEFAULT,
Block.Properties.create(Material.ROCK, MaterialColor.STONE).hardnessAndResistance(3f, 50f).sound(SoundType.STONE)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "clinker_brick_stained_block"));
public static final BlockDecorSlab CLINKER_BRICK_STAINED_SLAB = (BlockDecorSlab)(new BlockDecorSlab(
BlockDecor.CFG_DEFAULT,
Block.Properties.create(Material.ROCK, MaterialColor.STONE).hardnessAndResistance(3f, 50f).sound(SoundType.STONE)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "clinker_brick_stained_slab"));
public static final BlockDecorStairs CLINKER_BRICK_STAINED_STAIRS = (BlockDecorStairs)(new BlockDecorStairs(
BlockDecor.CFG_DEFAULT,
CLINKER_BRICK_BLOCK.getDefaultState(),
Block.Properties.create(Material.ROCK, MaterialColor.STONE).hardnessAndResistance(3f, 50f).sound(SoundType.STONE)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "clinker_brick_stained_stairs"));
// -------------------------------------------------------------------------------------------------------------------
public static final BlockDecor SLAG_BRICK_BLOCK = (BlockDecor)(new BlockDecor(
BlockDecor.CFG_DEFAULT,
Block.Properties.create(Material.ROCK, MaterialColor.STONE).hardnessAndResistance(3f, 50f).sound(SoundType.STONE)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "slag_brick_block"));
public static final BlockDecorSlab SLAG_BRICK_SLAB = (BlockDecorSlab)(new BlockDecorSlab(
BlockDecor.CFG_DEFAULT,
Block.Properties.create(Material.ROCK, MaterialColor.STONE).hardnessAndResistance(3f, 50f).sound(SoundType.STONE)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "slag_brick_slab"));
public static final BlockDecorStairs SLAG_BRICK_STAIRS = (BlockDecorStairs)(new BlockDecorStairs(
BlockDecor.CFG_DEFAULT,
SLAG_BRICK_BLOCK.getDefaultState(),
Block.Properties.create(Material.ROCK, MaterialColor.STONE).hardnessAndResistance(3f, 50f).sound(SoundType.STONE)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "slag_brick_stairs"));
public static final BlockDecorWall SLAG_BRICK_WALL = (BlockDecorWall)(new BlockDecorWall(
BlockDecor.CFG_DEFAULT,
Block.Properties.create(Material.ROCK, MaterialColor.STONE).hardnessAndResistance(3f, 50f).sound(SoundType.STONE)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "slag_brick_wall"));
// -------------------------------------------------------------------------------------------------------------------
public static final BlockDecor REBAR_CONCRETE_BLOCK = (BlockDecor)(new BlockDecor(
BlockDecor.CFG_DEFAULT,
Block.Properties.create(Material.ROCK, MaterialColor.STONE).hardnessAndResistance(5f, 2000f).sound(SoundType.STONE)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "rebar_concrete"));
public static final BlockDecorSlab REBAR_CONCRETE_SLAB = (BlockDecorSlab)(new BlockDecorSlab(
BlockDecor.CFG_DEFAULT,
Block.Properties.create(Material.ROCK, MaterialColor.STONE).hardnessAndResistance(5f, 2000f).sound(SoundType.STONE)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "rebar_concrete_slab"));
public static final BlockDecorStairs REBAR_CONCRETE_STAIRS = (BlockDecorStairs)(new BlockDecorStairs(
BlockDecor.CFG_DEFAULT,
REBAR_CONCRETE_BLOCK.getDefaultState(),
Block.Properties.create(Material.ROCK, MaterialColor.STONE).hardnessAndResistance(5f, 2000f).sound(SoundType.STONE)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "rebar_concrete_stairs"));
public static final BlockDecorWall REBAR_CONCRETE_WALL = (BlockDecorWall)(new BlockDecorWall(
BlockDecor.CFG_DEFAULT,
Block.Properties.create(Material.ROCK, MaterialColor.STONE).hardnessAndResistance(5f, 2000f).sound(SoundType.STONE)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "rebar_concrete_wall"));
public static final BlockDecorHalfSlab HALFSLAB_REBARCONCRETE = (BlockDecorHalfSlab)(new BlockDecorHalfSlab(
BlockDecor.CFG_CUTOUT,
Block.Properties.create(Material.ROCK, MaterialColor.STONE).hardnessAndResistance(5f, 2000f).sound(SoundType.STONE)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "halfslab_rebar_concrete"));
// -------------------------------------------------------------------------------------------------------------------
public static final BlockDecor GAS_CONCRETE_BLOCK = (BlockDecor)(new BlockDecor(
BlockDecor.CFG_DEFAULT,
Block.Properties.create(Material.ROCK, MaterialColor.STONE).hardnessAndResistance(1.5f, 10f).sound(SoundType.STONE)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "gas_concrete"));
public static final BlockDecorSlab GAS_CONCRETE_SLAB = (BlockDecorSlab)(new BlockDecorSlab(
BlockDecor.CFG_DEFAULT,
Block.Properties.create(Material.ROCK, MaterialColor.STONE).hardnessAndResistance(1.5f, 10f).sound(SoundType.STONE)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "gas_concrete_slab"));
public static final BlockDecorStairs GAS_CONCRETE_STAIRS = (BlockDecorStairs)(new BlockDecorStairs(
BlockDecor.CFG_DEFAULT,
REBAR_CONCRETE_BLOCK.getDefaultState(),
Block.Properties.create(Material.ROCK, MaterialColor.STONE).hardnessAndResistance(1.5f, 10f).sound(SoundType.STONE)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "gas_concrete_stairs"));
public static final BlockDecorWall GAS_CONCRETE_WALL = (BlockDecorWall)(new BlockDecorWall(
BlockDecor.CFG_DEFAULT,
Block.Properties.create(Material.ROCK, MaterialColor.STONE).hardnessAndResistance(1.5f, 10f).sound(SoundType.STONE)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "gas_concrete_wall"));
public static final BlockDecorHalfSlab HALFSLAB_GASCONCRETE = (BlockDecorHalfSlab)(new BlockDecorHalfSlab(
BlockDecor.CFG_CUTOUT,
Block.Properties.create(Material.ROCK, MaterialColor.STONE).hardnessAndResistance(1.5f, 10f).sound(SoundType.STONE)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "halfslab_gas_concrete"));
// -------------------------------------------------------------------------------------------------------------------
public static final BlockDecor REBAR_CONCRETE_TILE = (BlockDecor)(new BlockDecor(
BlockDecor.CFG_DEFAULT,
Block.Properties.create(Material.ROCK, MaterialColor.STONE).hardnessAndResistance(5f, 2000f).sound(SoundType.STONE)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "rebar_concrete_tile"));
public static final BlockDecorSlab REBAR_CONCRETE_TILE_SLAB = (BlockDecorSlab)(new BlockDecorSlab(
BlockDecor.CFG_DEFAULT,
Block.Properties.create(Material.ROCK, MaterialColor.STONE).hardnessAndResistance(5f, 2000f).sound(SoundType.STONE)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "rebar_concrete_tile_slab"));
public static final BlockDecorStairs REBAR_CONCRETE_TILE_STAIRS = (BlockDecorStairs)(new BlockDecorStairs(
BlockDecor.CFG_DEFAULT,
REBAR_CONCRETE_TILE.getDefaultState(),
Block.Properties.create(Material.ROCK, MaterialColor.STONE).hardnessAndResistance(5f, 2000f).sound(SoundType.STONE)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "rebar_concrete_tile_stairs"));
// -------------------------------------------------------------------------------------------------------------------
public static final BlockDecorGlassBlock PANZERGLASS_BLOCK = (BlockDecorGlassBlock)(new BlockDecorGlassBlock(
BlockDecor.CFG_TRANSLUCENT,
Block.Properties.create(Material.GLASS, MaterialColor.AIR).hardnessAndResistance(5f, 2000f).sound(SoundType.METAL).func_226896_b_()
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "panzerglass_block"));
public static final BlockDecorSlab PANZERGLASS_SLAB = (BlockDecorSlab)(new BlockDecorSlab(
BlockDecor.CFG_TRANSLUCENT,
Block.Properties.create(Material.IRON, MaterialColor.IRON).hardnessAndResistance(5f, 2000f).sound(SoundType.METAL).func_226896_b_()
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "panzerglass_slab"));
// -------------------------------------------------------------------------------------------------------------------
public static final BlockDecorLadder METAL_RUNG_LADDER = (BlockDecorLadder)(new BlockDecorLadder(
BlockDecor.CFG_DEFAULT,
Block.Properties.create(Material.IRON, MaterialColor.IRON).hardnessAndResistance(1.0f, 25f).sound(SoundType.METAL).func_226896_b_()
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "metal_rung_ladder"));
public static final BlockDecorLadder METAL_RUNG_STEPS = (BlockDecorLadder)(new BlockDecorLadder(
BlockDecor.CFG_DEFAULT,
Block.Properties.create(Material.IRON, MaterialColor.IRON).hardnessAndResistance(1.0f, 25f).sound(SoundType.METAL).func_226896_b_()
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "metal_rung_steps"));
public static final BlockDecorLadder TREATED_WOOD_LADDER = (BlockDecorLadder)(new BlockDecorLadder(
BlockDecor.CFG_DEFAULT,
Block.Properties.create(Material.WOOD, MaterialColor.WOOD).hardnessAndResistance(1.0f, 25f).sound(SoundType.WOOD).func_226896_b_()
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "treated_wood_ladder"));
// -------------------------------------------------------------------------------------------------------------------
public static final BlockDecor.WaterLoggable TREATED_WOOD_TABLE = (BlockDecor.WaterLoggable)(new BlockDecor.WaterLoggable(
BlockDecor.CFG_CUTOUT,
Block.Properties.create(Material.WOOD, MaterialColor.WOOD).hardnessAndResistance(2f, 15f).sound(SoundType.WOOD),
ModAuxiliaries.getPixeledAABB(1,0,1, 15,15.9,15)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "treated_wood_table"));
public static final BlockDecorChair TREATED_WOOD_STOOL = (BlockDecorChair)(new BlockDecorChair(
BlockDecor.CFG_CUTOUT|BlockDecor.CFG_HORIZIONTAL|BlockDecor.CFG_LOOK_PLACEMENT,
Block.Properties.create(Material.WOOD, MaterialColor.WOOD).hardnessAndResistance(2f, 15f).sound(SoundType.WOOD),
ModAuxiliaries.getPixeledAABB(4.1,0,4.1, 11.8,8.8,11.8)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "treated_wood_stool"));
public static final BlockDecor.WaterLoggable TREATED_WOOD_SIDE_TABLE = (BlockDecor.WaterLoggable)(new BlockDecor.WaterLoggable(
BlockDecor.CFG_CUTOUT|BlockDecor.CFG_HORIZIONTAL|BlockDecor.CFG_LOOK_PLACEMENT,
Block.Properties.create(Material.WOOD, MaterialColor.WOOD).hardnessAndResistance(2f, 15f).sound(SoundType.WOOD),
ModAuxiliaries.getPixeledAABB(2,0,2, 14,15.9,14)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "treated_wood_side_table"));
public static final BlockDecorDirected.WaterLoggable TREATED_WOOD_WINDOWSILL = (BlockDecorDirected.WaterLoggable)(new BlockDecorDirected.WaterLoggable(
BlockDecor.CFG_CUTOUT|BlockDecor.CFG_HORIZIONTAL|BlockDecor.CFG_FACING_PLACEMENT,
Block.Properties.create(Material.WOOD, MaterialColor.WOOD).hardnessAndResistance(2f, 15f).sound(SoundType.WOOD),
ModAuxiliaries.getPixeledAABB(0.5,15,10.5, 15.5,16,16)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "treated_wood_windowsill"));
public static final BlockDecorDirected.WaterLoggable TREATED_WOOD_BROAD_WINDOWSILL = (BlockDecorDirected.WaterLoggable)(new BlockDecorDirected.WaterLoggable(
BlockDecor.CFG_CUTOUT|BlockDecor.CFG_HORIZIONTAL|BlockDecor.CFG_FACING_PLACEMENT,
Block.Properties.create(Material.WOOD, MaterialColor.WOOD).hardnessAndResistance(2f, 15f).sound(SoundType.WOOD),
ModAuxiliaries.getPixeledAABB(0,14.5,4, 16,16,16)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "treated_wood_broad_windowsill"));
public static final BlockDecorDirected.WaterLoggable INSET_LIGHT_IRON = (BlockDecorDirected.WaterLoggable)(new BlockDecorDirected.WaterLoggable(
BlockDecor.CFG_CUTOUT|BlockDecor.CFG_OPPOSITE_PLACEMENT,
Block.Properties.create(Material.IRON, MaterialColor.IRON).hardnessAndResistance(2f, 15f).sound(SoundType.METAL).lightValue(15),
ModAuxiliaries.getPixeledAABB(5.2,5.2,15.7, 10.8,10.8,16.0)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "iron_inset_light"));
public static final BlockDecorDirected.WaterLoggable FLOOR_EDGE_LIGHT_IRON = (BlockDecorDirected.WaterLoggable)(new BlockDecorDirected.WaterLoggable(
BlockDecor.CFG_CUTOUT|BlockDecor.CFG_LOOK_PLACEMENT|BlockDecor.CFG_HORIZIONTAL,
Block.Properties.create(Material.IRON, MaterialColor.IRON).hardnessAndResistance(2f, 15f).sound(SoundType.METAL).lightValue(15),
ModAuxiliaries.getPixeledAABB(5,0,0, 11,2,1)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "iron_floor_edge_light"));
public static final BlockDecor.WaterLoggable STEEL_TABLE = (BlockDecor.WaterLoggable)(new BlockDecor.WaterLoggable(
BlockDecor.CFG_CUTOUT|BlockDecor.CFG_HORIZIONTAL|BlockDecor.CFG_LOOK_PLACEMENT,
Block.Properties.create(Material.WOOD, MaterialColor.WOOD).hardnessAndResistance(2f, 15f).sound(SoundType.WOOD),
ModAuxiliaries.getPixeledAABB(0,0,0, 16,16,16)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "steel_table"));
public static final BlockDecor STEEL_FLOOR_GRATING = (BlockDecorFloorGrating)(new BlockDecorFloorGrating(
BlockDecor.CFG_CUTOUT,
Block.Properties.create(Material.IRON, MaterialColor.IRON).hardnessAndResistance(2f, 15f).sound(SoundType.METAL).func_226896_b_(),
ModAuxiliaries.getPixeledAABB(0,14,0, 16,16,16)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "steel_floor_grating"));
// -------------------------------------------------------------------------------------------------------------------
public static final BlockDecorWindow TREATED_WOOD_WINDOW = (BlockDecorWindow)(new BlockDecorWindow(
BlockDecor.CFG_LOOK_PLACEMENT,
Block.Properties.create(Material.WOOD, MaterialColor.WOOD).hardnessAndResistance(2f, 15f).sound(SoundType.GLASS),
ModAuxiliaries.getPixeledAABB(0,0,7, 16,16,9)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "treated_wood_window"));
public static final BlockDecorWindow STEEL_FRAMED_WINDOW = (BlockDecorWindow)(new BlockDecorWindow(
BlockDecor.CFG_LOOK_PLACEMENT,
Block.Properties.create(Material.IRON, MaterialColor.IRON).hardnessAndResistance(2f, 15f).sound(SoundType.GLASS),
ModAuxiliaries.getPixeledAABB(0,0,7.5, 16,16,8.5)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "steel_framed_window"));
// -------------------------------------------------------------------------------------------------------------------
public static final BlockDecorStraightPole TREATED_WOOD_POLE = (BlockDecorStraightPole)(new BlockDecorStraightPole(
BlockDecor.CFG_CUTOUT|BlockDecor.CFG_FACING_PLACEMENT|BlockDecor.CFG_FLIP_PLACEMENT_IF_SAME,
Block.Properties.create(Material.WOOD, MaterialColor.WOOD).hardnessAndResistance(2f, 15f).sound(SoundType.WOOD),
ModAuxiliaries.getPixeledAABB(5.8,5.8,0, 10.2,10.2,16)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "treated_wood_pole"));
public static final BlockDecorStraightPole TREATED_WOOD_POLE_HEAD = (BlockDecorStraightPole)(new BlockDecorStraightPole(
BlockDecor.CFG_CUTOUT|BlockDecor.CFG_FACING_PLACEMENT|BlockDecor.CFG_FLIP_PLACEMENT_IF_SAME,
Block.Properties.create(Material.WOOD, MaterialColor.WOOD).hardnessAndResistance(2f, 15f).sound(SoundType.WOOD),
ModAuxiliaries.getPixeledAABB(5.8,5.8,0, 10.2,10.2,16)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "treated_wood_pole_head"));
public static final BlockDecorStraightPole TREATED_WOOD_POLE_SUPPORT = (BlockDecorStraightPole)(new BlockDecorStraightPole(
BlockDecor.CFG_CUTOUT|BlockDecor.CFG_FACING_PLACEMENT|BlockDecor.CFG_FLIP_PLACEMENT_IF_SAME,
Block.Properties.create(Material.WOOD, MaterialColor.WOOD).hardnessAndResistance(2f, 15f).sound(SoundType.WOOD),
ModAuxiliaries.getPixeledAABB(5.8,5.8,0, 10.2,10.2,16)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "treated_wood_pole_support"));
public static final BlockDecorStraightPole THIN_STEEL_POLE = (BlockDecorStraightPole)(new BlockDecorStraightPole(
BlockDecor.CFG_CUTOUT|BlockDecor.CFG_FACING_PLACEMENT,
Block.Properties.create(Material.IRON, MaterialColor.IRON).hardnessAndResistance(2f, 15f).sound(SoundType.METAL),
ModAuxiliaries.getPixeledAABB(6,6,0, 10,10,16)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "thin_steel_pole"));
public static final BlockDecorStraightPole THIN_STEEL_POLE_HEAD = (BlockDecorStraightPole)(new BlockDecorStraightPole(
BlockDecor.CFG_CUTOUT|BlockDecor.CFG_FACING_PLACEMENT|BlockDecor.CFG_FLIP_PLACEMENT_IF_SAME,
Block.Properties.create(Material.IRON, MaterialColor.IRON).hardnessAndResistance(2f, 15f).sound(SoundType.METAL).func_226896_b_(),
ModAuxiliaries.getPixeledAABB(6,6,0, 10,10,16)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "thin_steel_pole_head"));
public static final BlockDecorStraightPole THICK_STEEL_POLE = (BlockDecorStraightPole)(new BlockDecorStraightPole(
BlockDecor.CFG_CUTOUT|BlockDecor.CFG_FACING_PLACEMENT,
Block.Properties.create(Material.IRON, MaterialColor.IRON).hardnessAndResistance(2f, 15f).sound(SoundType.METAL),
ModAuxiliaries.getPixeledAABB(5,5,0, 11,11,16)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "thick_steel_pole"));
public static final BlockDecorStraightPole THICK_STEEL_POLE_HEAD = (BlockDecorStraightPole)(new BlockDecorStraightPole(
BlockDecor.CFG_CUTOUT|BlockDecor.CFG_FACING_PLACEMENT|BlockDecor.CFG_FLIP_PLACEMENT_IF_SAME,
Block.Properties.create(Material.IRON, MaterialColor.IRON).hardnessAndResistance(2f, 15f).sound(SoundType.METAL).func_226896_b_(),
ModAuxiliaries.getPixeledAABB(5,5,0, 11,11,16)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "thick_steel_pole_head"));
public static final BlockDecorHorizontalSupport STEEL_DOUBLE_T_SUPPORT = (BlockDecorHorizontalSupport)(new BlockDecorHorizontalSupport(
BlockDecor.CFG_CUTOUT|BlockDecor.CFG_HORIZIONTAL|BlockDecor.CFG_LOOK_PLACEMENT,
Block.Properties.create(Material.IRON, MaterialColor.IRON).hardnessAndResistance(2f, 15f).sound(SoundType.METAL),
ModAuxiliaries.getPixeledAABB(5,11,0, 11,16,16)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "steel_double_t_support"));
// -------------------------------------------------------------------------------------------------------------------
public static final BlockDecorDirected.WaterLoggable SIGN_MODLOGO = (BlockDecorDirected.WaterLoggable)(new BlockDecorDirected.WaterLoggable(
BlockDecor.CFG_CUTOUT|BlockDecor.CFG_FACING_PLACEMENT|BlockDecor.CFG_HORIZIONTAL,
Block.Properties.create(Material.WOOD, MaterialColor.WOOD).hardnessAndResistance(1f, 1000f).sound(SoundType.WOOD).lightValue(1),
ModAuxiliaries.getPixeledAABB(0,0,15.6, 16,16,16.0)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "sign_decor"));
public static final BlockDecorDirected.WaterLoggable SIGN_HOTWIRE = (BlockDecorDirected.WaterLoggable)(new BlockDecorDirected.WaterLoggable(
BlockDecor.CFG_CUTOUT|BlockDecor.CFG_FACING_PLACEMENT|BlockDecor.CFG_HORIZIONTAL,
Block.Properties.create(Material.WOOD, MaterialColor.WOOD).hardnessAndResistance(1f, 1f).sound(SoundType.WOOD),
ModAuxiliaries.getPixeledAABB(2,2,15.6, 14,14,16)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "sign_hotwire"));
public static final BlockDecorDirected.WaterLoggable SIGN_DANGER = (BlockDecorDirected.WaterLoggable)(new BlockDecorDirected.WaterLoggable(
BlockDecor.CFG_CUTOUT|BlockDecor.CFG_FACING_PLACEMENT|BlockDecor.CFG_HORIZIONTAL,
Block.Properties.create(Material.WOOD, MaterialColor.WOOD).hardnessAndResistance(1f, 1f).sound(SoundType.WOOD),
ModAuxiliaries.getPixeledAABB(2,2,15.6, 14,14,16)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "sign_danger"));
public static final BlockDecorDirected.WaterLoggable SIGN_DEFENSE = (BlockDecorDirected.WaterLoggable)(new BlockDecorDirected.WaterLoggable(
BlockDecor.CFG_CUTOUT|BlockDecor.CFG_FACING_PLACEMENT|BlockDecor.CFG_HORIZIONTAL,
Block.Properties.create(Material.WOOD, MaterialColor.WOOD).hardnessAndResistance(1f, 1f).sound(SoundType.WOOD),
ModAuxiliaries.getPixeledAABB(2,2,15.6, 14,14,16)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "sign_defense"));
public static final BlockDecorDirected.WaterLoggable SIGN_FACTORY_AREA = (BlockDecorDirected.WaterLoggable)(new BlockDecorDirected.WaterLoggable(
BlockDecor.CFG_CUTOUT|BlockDecor.CFG_FACING_PLACEMENT|BlockDecor.CFG_HORIZIONTAL,
Block.Properties.create(Material.WOOD, MaterialColor.WOOD).hardnessAndResistance(1f, 1f).sound(SoundType.WOOD),
ModAuxiliaries.getPixeledAABB(2,2,15.6, 14,14,16)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "sign_factoryarea"));
public static final BlockDecorDirected.WaterLoggable SIGN_EXIT = (BlockDecorDirected.WaterLoggable)(new BlockDecorDirected.WaterLoggable(
BlockDecor.CFG_CUTOUT|BlockDecor.CFG_FACING_PLACEMENT|BlockDecor.CFG_HORIZIONTAL,
Block.Properties.create(Material.WOOD, MaterialColor.WOOD).hardnessAndResistance(1f, 1f).sound(SoundType.WOOD),
ModAuxiliaries.getPixeledAABB(3,7,15.6, 13,13,16)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "sign_exit"));
// -------------------------------------------------------------------------------------------------------------------
public static final BlockDecorCraftingTable TREATED_WOOD_CRAFTING_TABLE = (BlockDecorCraftingTable)(new BlockDecorCraftingTable(
BlockDecor.CFG_CUTOUT|BlockDecor.CFG_HORIZIONTAL|BlockDecor.CFG_LOOK_PLACEMENT|BlockDecor.CFG_OPPOSITE_PLACEMENT,
Block.Properties.create(Material.WOOD, MaterialColor.WOOD).hardnessAndResistance(1f, 15f).sound(SoundType.WOOD),
ModAuxiliaries.getPixeledAABB(1,0,1, 15,15.9,15)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "treated_wood_crafting_table"));
public static final BlockDecorFurnace SMALL_LAB_FURNACE = (BlockDecorFurnace)(new BlockDecorFurnace(
BlockDecor.CFG_CUTOUT|BlockDecor.CFG_HORIZIONTAL|BlockDecor.CFG_LOOK_PLACEMENT,
Block.Properties.create(Material.IRON, MaterialColor.IRON).hardnessAndResistance(1f, 15f).sound(SoundType.METAL).func_226896_b_(),
ModAuxiliaries.getPixeledAABB(1,0,1, 15,15,16.0)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "small_lab_furnace"));
public static final BlockDecorFurnaceElectrical SMALL_ELECTRICAL_FURNACE = (BlockDecorFurnaceElectrical)(new BlockDecorFurnaceElectrical(
BlockDecor.CFG_CUTOUT|BlockDecor.CFG_HORIZIONTAL|BlockDecor.CFG_LOOK_PLACEMENT|BlockDecor.CFG_ELECTRICAL,
Block.Properties.create(Material.IRON, MaterialColor.IRON).hardnessAndResistance(2f, 15f).sound(SoundType.METAL).func_226896_b_(),
ModAuxiliaries.getPixeledAABB(0,0,0, 16,16,16)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "small_electrical_furnace"));
public static final BlockDecorDropper FACTORY_DROPPER = (BlockDecorDropper)(new BlockDecorDropper(
BlockDecor.CFG_LOOK_PLACEMENT|BlockDecor.CFG_OPPOSITE_PLACEMENT|BlockDecor.CFG_REDSTONE_CONTROLLED,
Block.Properties.create(Material.IRON, MaterialColor.IRON).hardnessAndResistance(2f, 15f).sound(SoundType.METAL).func_226896_b_(),
ModAuxiliaries.getPixeledAABB(0,0,0, 16,16,15)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "factory_dropper"));
public static final BlockDecorPlacer FACTORY_PLACER = (BlockDecorPlacer)(new BlockDecorPlacer(
BlockDecor.CFG_LOOK_PLACEMENT|BlockDecor.CFG_FLIP_PLACEMENT_SHIFTCLICK|BlockDecor.CFG_OPPOSITE_PLACEMENT|BlockDecor.CFG_REDSTONE_CONTROLLED,
Block.Properties.create(Material.IRON, MaterialColor.IRON).hardnessAndResistance(2f, 15f).sound(SoundType.METAL).func_226896_b_(),
ModAuxiliaries.getPixeledAABB(2,2,2, 14,14,14)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "factory_placer"));
public static final BlockDecorBreaker SMALL_BLOCK_BREAKER = (BlockDecorBreaker)(new BlockDecorBreaker(
BlockDecor.CFG_HORIZIONTAL|BlockDecor.CFG_LOOK_PLACEMENT|BlockDecor.CFG_OPPOSITE_PLACEMENT|BlockDecor.CFG_FLIP_PLACEMENT_SHIFTCLICK,
Block.Properties.create(Material.IRON, MaterialColor.IRON).hardnessAndResistance(2f, 15f).sound(SoundType.METAL).func_226896_b_(),
ModAuxiliaries.getPixeledAABB(0,0,0, 16,12,16)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "small_block_breaker"));
public static final BlockDecorHopper FACTORY_HOPPER = (BlockDecorHopper)(new BlockDecorHopper(
BlockDecor.CFG_CUTOUT|BlockDecor.CFG_FACING_PLACEMENT|BlockDecor.CFG_OPPOSITE_PLACEMENT|BlockDecor.CFG_REDSTONE_CONTROLLED,
Block.Properties.create(Material.IRON, MaterialColor.IRON).hardnessAndResistance(2f, 15f).sound(SoundType.METAL).func_226896_b_(),
ModAuxiliaries.getPixeledAABB(0,0,0, 16,16,16)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "factory_hopper"));
public static final BlockDecorWasteIncinerator SMALL_WASTE_INCINERATOR = (BlockDecorWasteIncinerator)(new BlockDecorWasteIncinerator(
BlockDecor.CFG_DEFAULT|BlockDecor.CFG_ELECTRICAL,
Block.Properties.create(Material.IRON, MaterialColor.IRON).hardnessAndResistance(2f, 15f).sound(SoundType.METAL),
ModAuxiliaries.getPixeledAABB(0,0,0, 16,16,16)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "small_waste_incinerator"));
public static final BlockDecorMineralSmelter SMALL_MINERAL_SMELTER = (BlockDecorMineralSmelter)(new BlockDecorMineralSmelter(
BlockDecor.CFG_CUTOUT|BlockDecor.CFG_HORIZIONTAL|BlockDecor.CFG_LOOK_PLACEMENT|BlockDecor.CFG_ELECTRICAL,
Block.Properties.create(Material.IRON, MaterialColor.IRON).hardnessAndResistance(2f, 15f).sound(SoundType.METAL).func_226896_b_(),
ModAuxiliaries.getPixeledAABB(1.1,0,1.1, 14.9,16,14.9)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "small_mineral_smelter"));
public static final BlockDecorSolarPanel SMALL_SOLAR_PANEL = (BlockDecorSolarPanel)(new BlockDecorSolarPanel(
BlockDecor.CFG_CUTOUT|BlockDecor.CFG_HORIZIONTAL|BlockDecor.CFG_LOOK_PLACEMENT|BlockDecor.CFG_ELECTRICAL,
Block.Properties.create(Material.IRON, MaterialColor.IRON).hardnessAndResistance(2f, 15f).sound(SoundType.METAL).func_226896_b_(),
ModAuxiliaries.getPixeledAABB(0,0,0, 16,11.5,16)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "small_solar_panel"));
public static final BlockDecorMilker SMALL_MILKING_MACHINE = (BlockDecorMilker)(new BlockDecorMilker(
BlockDecor.CFG_LOOK_PLACEMENT|BlockDecor.CFG_HORIZIONTAL|BlockDecor.CFG_CUTOUT|BlockDecor.CFG_ELECTRICAL,
Block.Properties.create(Material.IRON, MaterialColor.IRON).hardnessAndResistance(2f, 15f).sound(SoundType.METAL).func_226896_b_(),
ModAuxiliaries.getPixeledAABB(0,0,0, 16,16,13)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "small_milking_machine"));
public static final BlockDecorTreeCutter SMALL_TREE_CUTTER = (BlockDecorTreeCutter)(new BlockDecorTreeCutter(
BlockDecor.CFG_CUTOUT|BlockDecor.CFG_HORIZIONTAL|BlockDecor.CFG_LOOK_PLACEMENT|BlockDecor.CFG_FLIP_PLACEMENT_SHIFTCLICK,
Block.Properties.create(Material.IRON, MaterialColor.IRON).hardnessAndResistance(2f, 15f).sound(SoundType.METAL).func_226896_b_(),
ModAuxiliaries.getPixeledAABB(0,0,0, 16,8,16)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "small_tree_cutter"));
public static final BlockDecorPipeValve STRAIGHT_CHECK_VALVE = (BlockDecorPipeValve)(new BlockDecorPipeValve(
BlockDecor.CFG_FACING_PLACEMENT|BlockDecor.CFG_OPPOSITE_PLACEMENT|BlockDecor.CFG_FLIP_PLACEMENT_SHIFTCLICK|BlockDecor.CFG_CUTOUT,
Block.Properties.create(Material.IRON, MaterialColor.IRON).hardnessAndResistance(2f, 15f).sound(SoundType.METAL).func_226896_b_(),
ModAuxiliaries.getPixeledAABB(4,4,0, 12,12,16)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "straight_pipe_valve"));
public static final BlockDecorPipeValve STRAIGHT_REDSTONE_VALVE = (BlockDecorPipeValve)(new BlockDecorPipeValve(
BlockDecor.CFG_FACING_PLACEMENT|BlockDecor.CFG_OPPOSITE_PLACEMENT|BlockDecor.CFG_FLIP_PLACEMENT_SHIFTCLICK|BlockDecor.CFG_CUTOUT|BlockDecor.CFG_REDSTONE_CONTROLLED,
Block.Properties.create(Material.IRON, MaterialColor.IRON).hardnessAndResistance(2f, 15f).sound(SoundType.METAL).func_226896_b_(),
ModAuxiliaries.getPixeledAABB(4,4,0, 12,12,16)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "straight_pipe_valve_redstone"));
public static final BlockDecorPipeValve STRAIGHT_REDSTONE_ANALOG_VALVE = (BlockDecorPipeValve)(new BlockDecorPipeValve(
BlockDecor.CFG_FACING_PLACEMENT|BlockDecor.CFG_OPPOSITE_PLACEMENT|BlockDecor.CFG_FLIP_PLACEMENT_SHIFTCLICK|BlockDecor.CFG_CUTOUT|BlockDecor.CFG_REDSTONE_CONTROLLED|BlockDecor.CFG_ANALOG,
Block.Properties.create(Material.IRON, MaterialColor.IRON).hardnessAndResistance(2f, 15f).sound(SoundType.METAL).func_226896_b_(),
ModAuxiliaries.getPixeledAABB(4,4,0, 12,12,16)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "straight_pipe_valve_redstone_analog"));
public static final BlockDecorPassiveFluidAccumulator PASSIVE_FLUID_ACCUMULATOR = (BlockDecorPassiveFluidAccumulator)(new BlockDecorPassiveFluidAccumulator(
BlockDecor.CFG_FACING_PLACEMENT|BlockDecor.CFG_OPPOSITE_PLACEMENT|BlockDecor.CFG_FLIP_PLACEMENT_SHIFTCLICK|BlockDecor.CFG_CUTOUT,
Block.Properties.create(Material.IRON, MaterialColor.IRON).hardnessAndResistance(2f, 15f).sound(SoundType.METAL).func_226896_b_(),
ModAuxiliaries.getPixeledAABB(0,0,0, 16,16,16)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "passive_fluid_accumulator"));
public static final BlockDecorFluidFunnel SMALL_FLUID_FUNNEL = (BlockDecorFluidFunnel)(new BlockDecorFluidFunnel(
BlockDecor.CFG_CUTOUT|BlockDecor.CFG_REDSTONE_CONTROLLED,
Block.Properties.create(Material.IRON, MaterialColor.IRON).hardnessAndResistance(2f, 15f).sound(SoundType.METAL).func_226896_b_(),
ModAuxiliaries.getPixeledAABB(0,0,0, 16,16,16)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "small_fluid_funnel"));
// -------------------------------------------------------------------------------------------------------------------
public static final BlockDecorWall CONCRETE_WALL = (BlockDecorWall)(new BlockDecorWall(
BlockDecor.CFG_CUTOUT|BlockDecor.CFG_HARD_IE_DEPENDENT,
Block.Properties.create(Material.ROCK, MaterialColor.STONE).hardnessAndResistance(2f, 50f).sound(SoundType.STONE)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "concrete_wall"));
public static final BlockDecorHalfSlab HALFSLAB_CONCRETE = (BlockDecorHalfSlab)(new BlockDecorHalfSlab(
BlockDecor.CFG_CUTOUT|BlockDecor.CFG_HARD_IE_DEPENDENT,
Block.Properties.create(Material.ROCK, MaterialColor.STONE).hardnessAndResistance(1f, 10f).sound(SoundType.STONE)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "halfslab_concrete"));
public static final BlockDecorHalfSlab HALFSLAB_TREATEDWOOD = (BlockDecorHalfSlab)(new BlockDecorHalfSlab(
BlockDecor.CFG_CUTOUT|BlockDecor.CFG_HARD_IE_DEPENDENT,
Block.Properties.create(Material.WOOD, MaterialColor.WOOD).hardnessAndResistance(1f, 4f).sound(SoundType.WOOD)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "halfslab_treated_wood"));
public static final BlockDecorHalfSlab HALFSLAB_SHEETMETALIRON = (BlockDecorHalfSlab)(new BlockDecorHalfSlab(
BlockDecor.CFG_CUTOUT|BlockDecor.CFG_HARD_IE_DEPENDENT,
Block.Properties.create(Material.IRON, MaterialColor.IRON).hardnessAndResistance(1f, 10f).sound(SoundType.METAL)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "halfslab_sheetmetal_iron"));
public static final BlockDecorHalfSlab HALFSLAB_SHEETMETALSTEEL = (BlockDecorHalfSlab)(new BlockDecorHalfSlab(
BlockDecor.CFG_CUTOUT|BlockDecor.CFG_HARD_IE_DEPENDENT,
Block.Properties.create(Material.IRON, MaterialColor.IRON).hardnessAndResistance(1f, 10f).sound(SoundType.METAL)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "halfslab_sheetmetal_steel"));
public static final BlockDecorHalfSlab HALFSLAB_SHEETMETALCOPPER = (BlockDecorHalfSlab)(new BlockDecorHalfSlab(
BlockDecor.CFG_CUTOUT|BlockDecor.CFG_HARD_IE_DEPENDENT,
Block.Properties.create(Material.IRON, MaterialColor.IRON).hardnessAndResistance(1f, 10f).sound(SoundType.METAL)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "halfslab_sheetmetal_copper"));
public static final BlockDecorHalfSlab HALFSLAB_SHEETMETALGOLD = (BlockDecorHalfSlab)(new BlockDecorHalfSlab(
BlockDecor.CFG_CUTOUT|BlockDecor.CFG_HARD_IE_DEPENDENT,
Block.Properties.create(Material.IRON, MaterialColor.IRON).hardnessAndResistance(1f, 10f).sound(SoundType.METAL)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "halfslab_sheetmetal_gold"));
public static final BlockDecorHalfSlab HALFSLAB_SHEETMETALALUMINIUM = (BlockDecorHalfSlab)(new BlockDecorHalfSlab(
BlockDecor.CFG_CUTOUT|BlockDecor.CFG_HARD_IE_DEPENDENT,
Block.Properties.create(Material.IRON, MaterialColor.IRON).hardnessAndResistance(1f, 10f).sound(SoundType.METAL)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "halfslab_sheetmetal_aluminum"));
// -------------------------------------------------------------------------------------------------------------------
public static final BlockDecorFence STEEL_MESH_FENCE = (BlockDecorFence)(new BlockDecorFence(
BlockDecor.CFG_CUTOUT,
Block.Properties.create(Material.IRON, MaterialColor.IRON).hardnessAndResistance(2f, 15f).sound(SoundType.METAL)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "steel_mesh_fence"));
// -------------------------------------------------------------------------------------------------------------------
public static final BlockDecorTest TEST_BLOCK = (BlockDecorTest)(new BlockDecorTest(
BlockDecor.CFG_LOOK_PLACEMENT|BlockDecor.CFG_FLIP_PLACEMENT_SHIFTCLICK|BlockDecor.CFG_ELECTRICAL|BlockDecor.CFG_REDSTONE_CONTROLLED,
Block.Properties.create(Material.IRON, MaterialColor.IRON).hardnessAndResistance(0f, 32000f).sound(SoundType.METAL),
ModAuxiliaries.getPixeledAABB(0,0,0, 16,16,16)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "test_block"));
// -------------------------------------------------------------------------------------------------------------------
private static final Block modBlocks[] = {
TREATED_WOOD_CRAFTING_TABLE,
SMALL_LAB_FURNACE,
SMALL_ELECTRICAL_FURNACE,
FACTORY_HOPPER,
FACTORY_DROPPER,
FACTORY_PLACER,
SMALL_BLOCK_BREAKER,
SMALL_TREE_CUTTER,
SMALL_SOLAR_PANEL,
SMALL_WASTE_INCINERATOR,
SMALL_MINERAL_SMELTER,
SMALL_MILKING_MACHINE,
STRAIGHT_CHECK_VALVE,
STRAIGHT_REDSTONE_VALVE,
STRAIGHT_REDSTONE_ANALOG_VALVE,
PASSIVE_FLUID_ACCUMULATOR,
SMALL_FLUID_FUNNEL,
CLINKER_BRICK_BLOCK,
CLINKER_BRICK_SLAB,
CLINKER_BRICK_STAIRS,
CLINKER_BRICK_WALL,
CLINKER_BRICK_STAINED_BLOCK,
CLINKER_BRICK_STAINED_SLAB,
CLINKER_BRICK_STAINED_STAIRS,
SLAG_BRICK_BLOCK,
SLAG_BRICK_SLAB,
SLAG_BRICK_STAIRS,
SLAG_BRICK_WALL,
REBAR_CONCRETE_BLOCK,
REBAR_CONCRETE_SLAB,
REBAR_CONCRETE_STAIRS,
REBAR_CONCRETE_WALL,
REBAR_CONCRETE_TILE,
REBAR_CONCRETE_TILE_SLAB,
REBAR_CONCRETE_TILE_STAIRS,
GAS_CONCRETE_BLOCK,
GAS_CONCRETE_SLAB,
GAS_CONCRETE_STAIRS,
GAS_CONCRETE_WALL,
HALFSLAB_REBARCONCRETE,
HALFSLAB_GASCONCRETE,
HALFSLAB_CONCRETE,
//HALFSLAB_TREATEDWOOD,
//HALFSLAB_SHEETMETALIRON
//HALFSLAB_SHEETMETALSTEEL,
//HALFSLAB_SHEETMETALCOPPER,
//HALFSLAB_SHEETMETALGOLD,
//HALFSLAB_SHEETMETALALUMINIUM,
CONCRETE_WALL,
PANZERGLASS_BLOCK,
PANZERGLASS_SLAB,
METAL_RUNG_LADDER,
METAL_RUNG_STEPS,
TREATED_WOOD_LADDER,
TREATED_WOOD_TABLE,
TREATED_WOOD_STOOL,
TREATED_WOOD_SIDE_TABLE,
TREATED_WOOD_WINDOWSILL,
TREATED_WOOD_BROAD_WINDOWSILL,
TREATED_WOOD_WINDOW,
STEEL_FRAMED_WINDOW,
STEEL_TABLE,
INSET_LIGHT_IRON,
FLOOR_EDGE_LIGHT_IRON,
STEEL_FLOOR_GRATING,
STEEL_MESH_FENCE,
TREATED_WOOD_POLE,
TREATED_WOOD_POLE_HEAD,
TREATED_WOOD_POLE_SUPPORT,
THIN_STEEL_POLE,
THIN_STEEL_POLE_HEAD,
THICK_STEEL_POLE,
THICK_STEEL_POLE_HEAD,
STEEL_DOUBLE_T_SUPPORT,
SIGN_HOTWIRE,
SIGN_DANGER,
SIGN_DEFENSE,
SIGN_FACTORY_AREA,
SIGN_EXIT,
SIGN_MODLOGO,
};
private static final Block devBlocks[] = {
//TEST_BLOCK
};
//--------------------------------------------------------------------------------------------------------------------
// Tile entities bound exclusively to the blocks above
//--------------------------------------------------------------------------------------------------------------------
public static final TileEntityType<?> TET_TREATED_WOOD_CRAFTING_TABLE = TileEntityType.Builder
.create(BlockDecorCraftingTable.BTileEntity::new, TREATED_WOOD_CRAFTING_TABLE)
.build(null)
.setRegistryName(ModEngineersDecor.MODID, "te_treated_wood_crafting_table");
public static final TileEntityType<?> TET_SMALL_LAB_FURNACE = TileEntityType.Builder
.create(BlockDecorFurnace.BTileEntity::new, SMALL_LAB_FURNACE)
.build(null)
.setRegistryName(ModEngineersDecor.MODID, "te_small_lab_furnace");
public static final TileEntityType<?> TET_SMALL_ELECTRICAL_FURNACE = TileEntityType.Builder
.create(BlockDecorFurnaceElectrical.BTileEntity::new, SMALL_ELECTRICAL_FURNACE)
.build(null)
.setRegistryName(ModEngineersDecor.MODID, "te_small_electrical_furnace");
public static final TileEntityType<?> TET_FACTORY_DROPPER = TileEntityType.Builder
.create(BlockDecorDropper.BTileEntity::new, FACTORY_DROPPER)
.build(null)
.setRegistryName(ModEngineersDecor.MODID, "te_factory_dropper");
public static final TileEntityType<?> TET_FACTORY_PLACER = TileEntityType.Builder
.create(BlockDecorPlacer.BTileEntity::new, FACTORY_PLACER)
.build(null)
.setRegistryName(ModEngineersDecor.MODID, "te_factory_placer");
public static final TileEntityType<?> TET_SMALL_BLOCK_BREAKER = TileEntityType.Builder
.create(BlockDecorBreaker.BTileEntity::new, SMALL_BLOCK_BREAKER)
.build(null)
.setRegistryName(ModEngineersDecor.MODID, "te_small_block_breaker");
public static final TileEntityType<?> TET_FACTORY_HOPPER = TileEntityType.Builder
.create(BlockDecorHopper.BTileEntity::new, FACTORY_HOPPER)
.build(null)
.setRegistryName(ModEngineersDecor.MODID, "te_factory_hopper");
public static final TileEntityType<?> TET_WASTE_INCINERATOR = TileEntityType.Builder
.create(BlockDecorWasteIncinerator.BTileEntity::new, SMALL_WASTE_INCINERATOR)
.build(null)
.setRegistryName(ModEngineersDecor.MODID, "te_small_waste_incinerator");
public static final TileEntityType<?> TET_STRAIGHT_PIPE_VALVE = TileEntityType.Builder
.create(BlockDecorPipeValve.BTileEntity::new, STRAIGHT_CHECK_VALVE, STRAIGHT_REDSTONE_VALVE, STRAIGHT_REDSTONE_ANALOG_VALVE)
.build(null)
.setRegistryName(ModEngineersDecor.MODID, "te_pipe_valve");
public static final TileEntityType<?> TET_PASSIVE_FLUID_ACCUMULATOR = TileEntityType.Builder
.create(BlockDecorPassiveFluidAccumulator.BTileEntity::new, PASSIVE_FLUID_ACCUMULATOR)
.build(null)
.setRegistryName(ModEngineersDecor.MODID, "te_passive_fluid_accumulator");
public static final TileEntityType<?> TET_SMALL_FLUID_FUNNEL = TileEntityType.Builder
.create(BlockDecorFluidFunnel.BTileEntity::new, SMALL_FLUID_FUNNEL)
.build(null)
.setRegistryName(ModEngineersDecor.MODID, "te_small_fluid_funnel");
public static final TileEntityType<?> TET_MINERAL_SMELTER = TileEntityType.Builder
.create(BlockDecorMineralSmelter.BTileEntity::new, SMALL_MINERAL_SMELTER)
.build(null)
.setRegistryName(ModEngineersDecor.MODID, "te_small_mineral_smelter");
public static final TileEntityType<?> TET_SMALL_SOLAR_PANEL = TileEntityType.Builder
.create(BlockDecorSolarPanel.BTileEntity::new, SMALL_SOLAR_PANEL)
.build(null)
.setRegistryName(ModEngineersDecor.MODID, "te_small_solar_panel");
public static final TileEntityType<?> TET_SMALL_MILKING_MACHINE = TileEntityType.Builder
.create(BlockDecorMilker.BTileEntity::new, SMALL_MILKING_MACHINE)
.build(null)
.setRegistryName(ModEngineersDecor.MODID, "te_small_milking_machine");
public static final TileEntityType<?> TET_SMALL_TREE_CUTTER = TileEntityType.Builder
.create(BlockDecorTreeCutter.BTileEntity::new, SMALL_TREE_CUTTER)
.build(null)
.setRegistryName(ModEngineersDecor.MODID, "te_small_tree_cutter");
public static final TileEntityType<?> TET_TEST_BLOCK = TileEntityType.Builder
.create(BlockDecorPipeValve.BTileEntity::new, TEST_BLOCK)
.build(null)
.setRegistryName(ModEngineersDecor.MODID, "te_test_block");
private static final TileEntityType<?> tile_entity_types[] = {
TET_TREATED_WOOD_CRAFTING_TABLE,
TET_SMALL_LAB_FURNACE,
TET_SMALL_ELECTRICAL_FURNACE,
TET_FACTORY_HOPPER,
TET_FACTORY_DROPPER,
TET_FACTORY_PLACER,
TET_SMALL_BLOCK_BREAKER,
TET_SMALL_TREE_CUTTER,
TET_WASTE_INCINERATOR,
TET_MINERAL_SMELTER,
TET_SMALL_SOLAR_PANEL,
TET_SMALL_MILKING_MACHINE,
TET_STRAIGHT_PIPE_VALVE,
TET_PASSIVE_FLUID_ACCUMULATOR,
TET_SMALL_FLUID_FUNNEL,
TET_TEST_BLOCK
};
//--------------------------------------------------------------------------------------------------------------------
// Entities bound exclusively to the blocks above
//--------------------------------------------------------------------------------------------------------------------
@SuppressWarnings("unchecked")
public static final EntityType<BlockDecorChair.EntityChair> ET_CHAIR = (EntityType<BlockDecorChair.EntityChair>)(
EntityType.Builder
.create(BlockDecorChair.EntityChair::new, EntityClassification.MISC)
.immuneToFire().size(1e-3f, 1e-3f).disableSerialization()
.setShouldReceiveVelocityUpdates(false).setUpdateInterval(4)
.setCustomClientFactory(BlockDecorChair.EntityChair::customClientFactory)
.build(new ResourceLocation(ModEngineersDecor.MODID, "et_chair").toString())
.setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "et_chair"))
);
private static final EntityType<?> entity_types[] = {
ET_CHAIR
};
//--------------------------------------------------------------------------------------------------------------------
// Container registration
//--------------------------------------------------------------------------------------------------------------------
public static final ContainerType<BlockDecorCraftingTable.BContainer> CT_TREATED_WOOD_CRAFTING_TABLE;
public static final ContainerType<BlockDecorDropper.BContainer> CT_FACTORY_DROPPER;
public static final ContainerType<BlockDecorPlacer.BContainer> CT_FACTORY_PLACER;
public static final ContainerType<BlockDecorHopper.BContainer> CT_FACTORY_HOPPER;
public static final ContainerType<BlockDecorFurnace.BContainer> CT_SMALL_LAB_FURNACE;
public static final ContainerType<BlockDecorFurnaceElectrical.BContainer> CT_SMALL_ELECTRICAL_FURNACE;
public static final ContainerType<BlockDecorWasteIncinerator.BContainer> CT_WASTE_INCINERATOR;
static {
CT_TREATED_WOOD_CRAFTING_TABLE = (new ContainerType<BlockDecorCraftingTable.BContainer>(BlockDecorCraftingTable.BContainer::new));
CT_TREATED_WOOD_CRAFTING_TABLE.setRegistryName(ModEngineersDecor.MODID,"ct_treated_wood_crafting_table");
CT_FACTORY_DROPPER = (new ContainerType<BlockDecorDropper.BContainer>(BlockDecorDropper.BContainer::new));
CT_FACTORY_DROPPER.setRegistryName(ModEngineersDecor.MODID,"ct_factory_dropper");
CT_FACTORY_PLACER = (new ContainerType<BlockDecorPlacer.BContainer>(BlockDecorPlacer.BContainer::new));
CT_FACTORY_PLACER.setRegistryName(ModEngineersDecor.MODID,"ct_factory_placer");
CT_FACTORY_HOPPER = (new ContainerType<BlockDecorHopper.BContainer>(BlockDecorHopper.BContainer::new));
CT_FACTORY_HOPPER.setRegistryName(ModEngineersDecor.MODID,"ct_factory_hopper");
CT_SMALL_LAB_FURNACE = (new ContainerType<BlockDecorFurnace.BContainer>(BlockDecorFurnace.BContainer::new));
CT_SMALL_LAB_FURNACE.setRegistryName(ModEngineersDecor.MODID,"ct_small_lab_furnace");
CT_SMALL_ELECTRICAL_FURNACE = (new ContainerType<BlockDecorFurnaceElectrical.BContainer>(BlockDecorFurnaceElectrical.BContainer::new));
CT_SMALL_ELECTRICAL_FURNACE.setRegistryName(ModEngineersDecor.MODID,"ct_small_electrical_furnace");
CT_WASTE_INCINERATOR = (new ContainerType<BlockDecorWasteIncinerator.BContainer>(BlockDecorWasteIncinerator.BContainer::new));
CT_WASTE_INCINERATOR.setRegistryName(ModEngineersDecor.MODID,"ct_small_waste_incinerator");
}
// DON'T FORGET TO REGISTER THE GUI in registerContainerGuis(), no list/map format found yet for that.
private static final ContainerType<?> container_types[] = {
CT_TREATED_WOOD_CRAFTING_TABLE,
CT_FACTORY_DROPPER,
CT_FACTORY_PLACER,
CT_FACTORY_HOPPER,
CT_SMALL_LAB_FURNACE,
CT_SMALL_ELECTRICAL_FURNACE,
CT_WASTE_INCINERATOR
};
//--------------------------------------------------------------------------------------------------------------------
// Initialisation events
//--------------------------------------------------------------------------------------------------------------------
private static ArrayList<Block> registeredBlocks = new ArrayList<>();
public static ArrayList<Block> allBlocks()
{
ArrayList<Block> blocks = new ArrayList<>();
Collections.addAll(blocks, modBlocks);
Collections.addAll(blocks, devBlocks);
return blocks;
}
public static boolean isExperimentalBlock(Block block)
{ return ArrayUtils.contains(devBlocks, block); }
@Nonnull
public static List<Block> getRegisteredBlocks()
{ return Collections.unmodifiableList(registeredBlocks); }
public static final void registerBlocks(final RegistryEvent.Register<Block> event)
{
if(ModAuxiliaries.isModLoaded("immersiveengineering")) ModAuxiliaries.logInfo("Immersive Engineering also installed ...");
registeredBlocks.addAll(allBlocks());
for(Block e:registeredBlocks) event.getRegistry().register(e);
ModAuxiliaries.logInfo("Registered " + Integer.toString(registeredBlocks.size()) + " blocks.");
}
public static final void registerBlockItems(final RegistryEvent.Register<Item> event)
{
int n = 0;
for(Block e:registeredBlocks) {
ResourceLocation rl = e.getRegistryName();
if(rl == null) continue;
event.getRegistry().register(new BlockItem(e, (new BlockItem.Properties().group(ModEngineersDecor.ITEMGROUP))).setRegistryName(rl));
++n;
}
}
public static final void registerTileEntities(final RegistryEvent.Register<TileEntityType<?>> event)
{
int n_registered = 0;
for(final TileEntityType<?> e:tile_entity_types) {
event.getRegistry().register(e);
++n_registered;
}
ModAuxiliaries.logInfo("Registered " + Integer.toString(n_registered) + " tile entities.");
}
public static final void registerEntities(final RegistryEvent.Register<EntityType<?>> event)
{
int n_registered = 0;
for(final EntityType<?> e:entity_types) {
if((e==ET_CHAIR) && (!registeredBlocks.contains(TREATED_WOOD_STOOL))) continue;
event.getRegistry().register(e);
++n_registered;
}
ModAuxiliaries.logInfo("Registered " + Integer.toString(n_registered) + " entities bound to blocks.");
}
public static final void registerContainers(final RegistryEvent.Register<ContainerType<?>> event)
{
int n_registered = 0;
for(final ContainerType<?> e:container_types) {
event.getRegistry().register(e);
++n_registered;
}
ModAuxiliaries.logInfo("Registered " + Integer.toString(n_registered) + " containers bound to tile entities.");
}
@OnlyIn(Dist.CLIENT)
public static final void registerContainerGuis(final FMLClientSetupEvent event)
{
ScreenManager.registerFactory(CT_TREATED_WOOD_CRAFTING_TABLE, BlockDecorCraftingTable.BGui::new);
ScreenManager.registerFactory(CT_FACTORY_DROPPER, BlockDecorDropper.BGui::new);
ScreenManager.registerFactory(CT_FACTORY_PLACER, BlockDecorPlacer.BGui::new);
ScreenManager.registerFactory(CT_FACTORY_HOPPER, BlockDecorHopper.BGui::new);
ScreenManager.registerFactory(CT_SMALL_LAB_FURNACE, BlockDecorFurnace.BGui::new);
ScreenManager.registerFactory(CT_SMALL_ELECTRICAL_FURNACE, BlockDecorFurnaceElectrical.BGui::new);
ScreenManager.registerFactory(CT_WASTE_INCINERATOR, BlockDecorWasteIncinerator.BGui::new);
}
@OnlyIn(Dist.CLIENT)
public static final void registerTileEntityRenderers(final FMLClientSetupEvent event)
{
// @todo: re-enable
//ClientRegistry.bindTileEntityRenderer(TET_TREATED_WOOD_CRAFTING_TABLE, new wile.engineersdecor.detail.ModRenderers.TesrDecorCraftingTable());
}
public static final void processContentClientSide(final FMLClientSetupEvent event)
{
// Block renderer selection
for(Block block: getRegisteredBlocks()) {
if(block instanceof IDecorBlock) {
switch(((IDecorBlock)block).getRenderTypeHint()) {
case CUTOUT:
RenderTypeLookup.setRenderLayer(block, RenderType.func_228643_e_()/*cutout*/);
break;
case CUTOUT_MIPPED:
RenderTypeLookup.setRenderLayer(block, RenderType.func_228641_d_()/*cutout_mipped*/);
break;
case TRANSLUCENT:
RenderTypeLookup.setRenderLayer(block, RenderType.func_228645_f_()/*transparent*/);
break;
case SOLID:
break;
}
}
}
// Entity renderers
RenderingRegistry.registerEntityRenderingHandler(ET_CHAIR,
manager->(new wile.engineersdecor.detail.ModRenderers.InvisibleEntityRenderer<BlockDecorChair.EntityChair>(manager))
);
}
}

View file

@ -0,0 +1,185 @@
package wile.engineersdecor;
import wile.engineersdecor.detail.ModConfig;
import wile.engineersdecor.detail.Networking;
import wile.engineersdecor.blocks.*;
import wile.engineersdecor.detail.OptionalRecipeCondition.Serializer;
import wile.engineersdecor.datagen.ModLootTables;
import net.minecraft.client.Minecraft;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.inventory.container.ContainerType;
import net.minecraft.item.ItemGroup;
import net.minecraft.tileentity.TileEntityType;
import net.minecraft.world.World;
import net.minecraft.block.Block;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraftforge.common.crafting.CraftingHelper;
import net.minecraftforge.event.entity.living.LivingEvent;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.RegistryEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.DistExecutor;
import net.minecraftforge.fml.ModLoadingContext;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.event.lifecycle.*;
import net.minecraftforge.fml.event.server.FMLServerStartingEvent;
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import javax.annotation.Nullable;
@Mod("engineersdecor")
public class ModEngineersDecor
{
public static final String MODID = "engineersdecor";
public static final int VERSION_DATAFIXER = 0;
private static final Logger LOGGER = LogManager.getLogger();
private static boolean config_loaded = false;
public ModEngineersDecor()
{
FMLJavaModLoadingContext.get().getModEventBus().addListener(this::onSetup);
FMLJavaModLoadingContext.get().getModEventBus().addListener(this::onSendImc);
FMLJavaModLoadingContext.get().getModEventBus().addListener(this::onRecvImc);
FMLJavaModLoadingContext.get().getModEventBus().addListener(this::onClientSetup);
ModLoadingContext.get().registerConfig(net.minecraftforge.fml.config.ModConfig.Type.COMMON, ModConfig.COMMON_CONFIG_SPEC);
ModLoadingContext.get().registerConfig(net.minecraftforge.fml.config.ModConfig.Type.CLIENT, ModConfig.CLIENT_CONFIG_SPEC);
MinecraftForge.EVENT_BUS.register(this);
}
public static final Logger logger() { return LOGGER; }
//
// Events
//
private void onSetup(final FMLCommonSetupEvent event)
{
LOGGER.info("Registering recipe condition processor ...");
CraftingHelper.register(Serializer.INSTANCE);
Networking.init();
if(config_loaded) {
try {
logger().info("Applying loaded config file.");
ModConfig.apply();
} catch(Throwable e) {
logger().error("Failed to apply config: " + e.getMessage());
}
} else {
logger().info("Cannot apply config, load event was not casted yet.");
}
}
private void onClientSetup(final FMLClientSetupEvent event)
{
ModContent.registerContainerGuis(event);
ModContent.registerTileEntityRenderers(event);
ModContent.processContentClientSide(event);
}
private void onSendImc(final InterModEnqueueEvent event)
{}
private void onRecvImc(final InterModProcessEvent event)
{}
@Mod.EventBusSubscriber(bus=Mod.EventBusSubscriber.Bus.MOD)
public static class ForgeEvents
{
@SubscribeEvent
public static void onBlocksRegistry(final RegistryEvent.Register<Block> event)
{ ModContent.registerBlocks(event); }
@SubscribeEvent
public static void onItemRegistry(final RegistryEvent.Register<Item> event)
{ ModContent.registerBlockItems(event); }
@SubscribeEvent
public static void onTileEntityRegistry(final RegistryEvent.Register<TileEntityType<?>> event)
{ ModContent.registerTileEntities(event); }
@SubscribeEvent
public static void onRegisterEntityTypes(final RegistryEvent.Register<EntityType<?>> event)
{ ModContent.registerEntities(event); }
@SubscribeEvent
public static void onRegisterContainerTypes(final RegistryEvent.Register<ContainerType<?>> event)
{ ModContent.registerContainers(event); }
// @SubscribeEvent
public static void onServerStarting(FMLServerStartingEvent event)
{}
@SubscribeEvent
public static void onConfigLoad(net.minecraftforge.fml.config.ModConfig.Loading configEvent)
{ config_loaded = true; }
@SubscribeEvent
public static void onConfigFileChange(net.minecraftforge.fml.config.ModConfig.ConfigReloading configEvent)
{
try {
ModEngineersDecor.logger().info("Config file changed {}", configEvent.getConfig().getFileName());
ModConfig.apply();
} catch(Throwable e) {
ModEngineersDecor.logger().error("Failed to load changed config: " + e.getMessage());
}
}
@SubscribeEvent
public static void onDataGeneration(GatherDataEvent event)
{
event.getGenerator().addProvider(new ModLootTables(event.getGenerator()));
}
}
//
// Sided proxy functionality (skel)
//
public static ISidedProxy proxy = DistExecutor.runForDist(()->ClientProxy::new, ()->ServerProxy::new);
public interface ISidedProxy
{
default @Nullable PlayerEntity getPlayerClientSide() { return null; }
default @Nullable World getWorldClientSide() { return null; }
default @Nullable Minecraft mc() { return null; }
}
public static final class ClientProxy implements ISidedProxy
{
public @Nullable PlayerEntity getPlayerClientSide() { return Minecraft.getInstance().player; }
public @Nullable World getWorldClientSide() { return Minecraft.getInstance().world; }
public @Nullable Minecraft mc() { return Minecraft.getInstance(); }
}
public static final class ServerProxy implements ISidedProxy
{
public @Nullable PlayerEntity getPlayerClientSide() { return null; }
public @Nullable World getWorldClientSide() { return null; }
public @Nullable Minecraft mc() { return null; }
}
//
// Item group / creative tab
//
public static final ItemGroup ITEMGROUP = (new ItemGroup("tab" + MODID) {
@OnlyIn(Dist.CLIENT)
public ItemStack createIcon()
{ return new ItemStack(ModContent.SIGN_MODLOGO); }
});
//
// Player update event
//
@SubscribeEvent
public void onPlayerEvent(final LivingEvent.LivingUpdateEvent event)
{
if(!(event.getEntity() instanceof PlayerEntity)) return;
final PlayerEntity player = (PlayerEntity)event.getEntity();
if(player.world == null) return;
if(player.isOnLadder()) BlockDecorLadder.onPlayerUpdateEvent(player);
}
}

View file

@ -0,0 +1,233 @@
/*
* @file BlockDecorFull.java
* @author Stefan Wilhelm (wile)
* @copyright (C) 2019 Stefan Wilhelm
* @license MIT (see https://opensource.org/licenses/MIT)
*
* Common functionality class for decor blocks.
* Mainly needed for:
* - MC block defaults.
* - Tooltip functionality
* - Model initialisation
*/
package wile.engineersdecor.blocks;
import net.minecraft.block.IWaterLoggable;
import net.minecraft.state.StateContainer;
import net.minecraft.util.math.BlockRayTraceResult;
import net.minecraft.world.server.ServerWorld;
import wile.engineersdecor.detail.ModAuxiliaries;
import net.minecraft.state.BooleanProperty;
import net.minecraft.state.properties.BlockStateProperties;
import net.minecraft.entity.item.ItemEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.fluid.IFluidState;
import net.minecraft.fluid.Fluids;
import net.minecraft.world.IWorld;
import net.minecraft.world.Explosion;
import net.minecraft.world.World;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.shapes.ISelectionContext;
import net.minecraft.util.math.shapes.VoxelShape;
import net.minecraft.util.math.shapes.VoxelShapes;
import net.minecraft.block.Block;
import net.minecraft.block.material.PushReaction;
import net.minecraft.block.BlockState;
import net.minecraft.item.BlockItemUseContext;
import net.minecraft.item.ItemStack;
import net.minecraft.world.IBlockReader;
import net.minecraft.world.storage.loot.LootContext;
import net.minecraft.client.util.ITooltipFlag;
import net.minecraft.util.*;
import net.minecraft.util.text.ITextComponent;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import wile.engineersdecor.detail.ModConfig;
import javax.annotation.Nullable;
import java.util.Collections;
import java.util.List;
import java.util.Random;
public class BlockDecor extends Block implements IDecorBlock
{
public static final long CFG_DEFAULT = 0x0000000000000000L; // no special config
public static final long CFG_CUTOUT = 0x0000000000000001L; // cutout rendering
public static final long CFG_HORIZIONTAL = 0x0000000000000002L; // horizontal block, affects bounding box calculation at construction time and placement
public static final long CFG_LOOK_PLACEMENT = 0x0000000000000004L; // placed in direction the player is looking when placing.
public static final long CFG_FACING_PLACEMENT = 0x0000000000000008L; // placed on the facing the player has clicked.
public static final long CFG_OPPOSITE_PLACEMENT = 0x0000000000000010L; // placed placed in the opposite direction of the face the player clicked.
public static final long CFG_FLIP_PLACEMENT_IF_SAME = 0x0000000000000020L; // placement direction flipped if an instance of the same class was clicked
public static final long CFG_FLIP_PLACEMENT_SHIFTCLICK = 0x0000000000000040L; // placement direction flipped if player is sneaking
public static final long CFG_TRANSLUCENT = 0x0000000000000080L; // indicates a block/pane is glass like (transparent, etc)
public static final long CFG_ELECTRICAL = 0x0000000000010000L; // Denotes if a component is mainly flux driven.
public static final long CFG_REDSTONE_CONTROLLED = 0x0000000000020000L; // Denotes if a component has somehow a redstone control input
public static final long CFG_ANALOG = 0x0000000000040000L; // Denotes if a component has analog behaviour
public static final long CFG_HARD_IE_DEPENDENT = 0x8000000000000000L; // The block is implicitly opt'ed out if IE is not installed
public static final long CFG_WATERLOGGABLE = 0x4000000000000000L; // The derived block extends IWaterLoggable
public static final BooleanProperty WATERLOGGED = BlockStateProperties.WATERLOGGED;
public final long config;
public final VoxelShape vshape;
public BlockDecor(long conf, Block.Properties properties)
{ this(conf, properties, ModAuxiliaries.getPixeledAABB(0, 0, 0, 16, 16,16 )); }
public BlockDecor(long conf, Block.Properties properties, AxisAlignedBB aabb)
{ super(properties); config = conf; vshape = VoxelShapes.create(aabb); }
public BlockDecor(long conf, Block.Properties properties, VoxelShape voxel_shape)
{ super(properties); config = conf; vshape = voxel_shape; }
///////////// --------------------------------------------------------------------------------------------------------
// 1.15 transition
public boolean onBlockActivated(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockRayTraceResult hit)
{ return false; }
@Deprecated
public ActionResultType func_225533_a_(BlockState p_225533_1_, World p_225533_2_, BlockPos p_225533_3_, PlayerEntity p_225533_4_, Hand p_225533_5_, BlockRayTraceResult p_225533_6_)
{
return onBlockActivated(p_225533_1_,p_225533_2_,p_225533_3_,p_225533_4_,p_225533_5_,p_225533_6_) ? ActionResultType.SUCCESS : ActionResultType.PASS;
}
@Deprecated
public void func_225534_a_(BlockState p_225534_1_, ServerWorld p_225534_2_, BlockPos p_225534_3_, Random p_225534_4_)
{ tick(p_225534_1_,p_225534_2_,p_225534_3_,p_225534_4_); }
public void tick(BlockState state, World world, BlockPos pos, Random rnd)
{}
// 1.15 /transition
///////////// --------------------------------------------------------------------------------------------------------
@Override
@OnlyIn(Dist.CLIENT)
public void addInformation(ItemStack stack, @Nullable IBlockReader world, List<ITextComponent> tooltip, ITooltipFlag flag)
{ ModAuxiliaries.Tooltip.addInformation(stack, world, tooltip, flag, true); }
@Override
public RenderTypeHint getRenderTypeHint()
{ return ((config & CFG_CUTOUT)!=0) ? RenderTypeHint.CUTOUT : RenderTypeHint.SOLID; }
@Override
@SuppressWarnings("deprecation")
public VoxelShape getShape(BlockState state, IBlockReader source, BlockPos pos, ISelectionContext selectionContext)
{ return vshape; }
@Override
@SuppressWarnings("deprecation")
public VoxelShape getCollisionShape(BlockState state, IBlockReader world, BlockPos pos, ISelectionContext selectionContext)
{ return vshape; }
@Override
@Nullable
public BlockState getStateForPlacement(BlockItemUseContext context)
{
BlockState state = super.getStateForPlacement(context);
if((config & CFG_WATERLOGGABLE)!=0) {
IFluidState fs = context.getWorld().getFluidState(context.getPos());
state = state.with(WATERLOGGED,fs.getFluid()==Fluids.WATER);
}
return state;
}
@Override
public boolean canSpawnInBlock()
{ return false; }
@Override
@SuppressWarnings("deprecation")
public PushReaction getPushReaction(BlockState state)
{ return PushReaction.NORMAL; }
@Override
@SuppressWarnings("deprecation")
public void onReplaced(BlockState state, World world, BlockPos pos, BlockState newState, boolean isMoving)
{
if(state.hasTileEntity() && (state.getBlock() != newState.getBlock())) {
world.removeTileEntity(pos);
world.updateComparatorOutputLevel(pos, this);
}
}
public static boolean dropBlock(BlockState state, World world, BlockPos pos, @Nullable PlayerEntity player)
{
if(!(state.getBlock() instanceof IDecorBlock)) { world.removeBlock(pos, false); return true; }
if(!world.isRemote()) {
if((ModConfig.with_creative_mode_device_drops) || (player==null) || (!player.isCreative())) {
((IDecorBlock)state.getBlock()).dropList(state, world, pos, player==null).forEach(stack->world.addEntity(new ItemEntity(world, pos.getX()+0.5, pos.getY()+0.5, pos.getZ()+0.5, stack)));
}
}
if(state.getBlock().hasTileEntity(state)) world.removeTileEntity(pos);
world.removeBlock(pos, false);
return true;
}
@Override
public boolean removedByPlayer(BlockState state, World world, BlockPos pos, PlayerEntity player, boolean willHarvest, IFluidState fluid)
{ return hasDynamicDropList() ? dropBlock(state, world, pos, player) : super.removedByPlayer(state, world,pos , player, willHarvest, fluid); }
@Override
public void onExplosionDestroy(World world, BlockPos pos, Explosion explosion)
{ if(hasDynamicDropList()) dropBlock(world.getBlockState(pos), world, pos, null); }
@Override
@SuppressWarnings("deprecation")
public List<ItemStack> getDrops(BlockState state, LootContext.Builder builder)
{ return hasDynamicDropList() ? Collections.singletonList(ItemStack.EMPTY) : super.getDrops(state, builder); }
@Override
@SuppressWarnings("deprecation")
public int getOpacity(BlockState state, IBlockReader world, BlockPos pos)
{ return ((config & (CFG_CUTOUT|CFG_TRANSLUCENT))==0) ? super.getOpacity(state, world, pos) : (state.propagatesSkylightDown(world, pos)?0:1); }
@Override
public boolean propagatesSkylightDown(BlockState state, IBlockReader reader, BlockPos pos)
{
if(((config & CFG_WATERLOGGABLE)!=0) && state.get(WATERLOGGED)) return false;
return super.propagatesSkylightDown(state, reader, pos);
}
@Override
@SuppressWarnings("deprecation")
public IFluidState getFluidState(BlockState state)
{
if((config & CFG_WATERLOGGABLE)!=0) {
return state.get(WATERLOGGED) ? Fluids.WATER.getStillFluidState(false) : super.getFluidState(state);
}
return super.getFluidState(state);
}
@Override
@SuppressWarnings("deprecation")
public BlockState updatePostPlacement(BlockState state, Direction facing, BlockState facingState, IWorld world, BlockPos pos, BlockPos facingPos)
{
if((config & CFG_WATERLOGGABLE)!=0) {
if(state.get(WATERLOGGED)) world.getPendingFluidTicks().scheduleTick(pos, Fluids.WATER, Fluids.WATER.getTickRate(world));
}
return state;
}
/**
* Water loggable version of the basic block.
*/
public static class WaterLoggable extends BlockDecor implements IWaterLoggable
{
public WaterLoggable(long config, Block.Properties properties)
{ super(config|CFG_WATERLOGGABLE, properties); }
public WaterLoggable(long config, Block.Properties properties, AxisAlignedBB aabb)
{ super(config|CFG_WATERLOGGABLE, properties, aabb); }
public WaterLoggable(long config, Block.Properties properties, VoxelShape voxel_shape)
{ super(config|CFG_WATERLOGGABLE, properties, voxel_shape); }
@Override
protected void fillStateContainer(StateContainer.Builder<Block, BlockState> builder)
{ super.fillStateContainer(builder); builder.add(WATERLOGGED); }
}
}

View file

@ -0,0 +1,295 @@
/*
* @file BlockDecorBreaker.java
* @author Stefan Wilhelm (wile)
* @copyright (C) 2019 Stefan Wilhelm
* @license MIT (see https://opensource.org/licenses/MIT)
*
* Small Block Breaker
*/
package wile.engineersdecor.blocks;
import wile.engineersdecor.ModContent;
import wile.engineersdecor.ModEngineersDecor;
import net.minecraft.block.Blocks;
import net.minecraft.block.SoundType;
import net.minecraft.item.BlockItemUseContext;
import net.minecraft.item.ItemStack;
import net.minecraft.world.server.ServerWorld;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.particles.ParticleTypes;
import net.minecraft.state.BooleanProperty;
import net.minecraft.state.StateContainer;
import net.minecraft.tileentity.ITickableTileEntity;
import net.minecraft.tileentity.TileEntityType;
import net.minecraft.world.IBlockReader;
import net.minecraft.world.World;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.*;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.energy.CapabilityEnergy;
import net.minecraftforge.energy.IEnergyStorage;
import javax.annotation.Nullable;
import java.util.HashSet;
import java.util.List;
import java.util.Random;
public class BlockDecorBreaker extends BlockDecorDirectedHorizontal
{
public static final BooleanProperty ACTIVE = BooleanProperty.create("active");
public BlockDecorBreaker(long config, Block.Properties builder, final AxisAlignedBB unrotatedAABB)
{ super(config, builder, unrotatedAABB); }
@Override
protected void fillStateContainer(StateContainer.Builder<Block, BlockState> builder)
{ super.fillStateContainer(builder); builder.add(ACTIVE); }
@Override
@Nullable
public BlockState getStateForPlacement(BlockItemUseContext context)
{ return super.getStateForPlacement(context).with(ACTIVE, false); }
@Override
public boolean hasTileEntity(BlockState state)
{ return true; }
@Override
@Nullable
public TileEntity createTileEntity(BlockState state, IBlockReader world)
{ return new BTileEntity(); }
@OnlyIn(Dist.CLIENT)
public void animateTick(BlockState state, World world, BlockPos pos, Random rnd)
{
if((state.getBlock()!=this) || (!state.get(ACTIVE))) return;
final double rv = rnd.nextDouble();
if(rv > 0.8) return;
final double x=0.5+pos.getX(), y=0.5+pos.getY(), z=0.5+pos.getZ();
final double xc=0.52, xr=rnd.nextDouble()*0.4-0.2, yr=(y-0.3+rnd.nextDouble()*0.2);
switch(state.get(HORIZONTAL_FACING)) {
case WEST: world.addParticle(ParticleTypes.SMOKE, x-xc, yr, z+xr, 0.0, 0.0, 0.0); break;
case EAST: world.addParticle(ParticleTypes.SMOKE, x+xc, yr, z+xr, 0.0, 0.0, 0.0); break;
case NORTH: world.addParticle(ParticleTypes.SMOKE, x+xr, yr, z-xc, 0.0, 0.0, 0.0); break;
default: world.addParticle(ParticleTypes.SMOKE, x+xr, yr, z+xc, 0.0, 0.0, 0.0); break;
}
}
@Override
@SuppressWarnings("deprecation")
public void neighborChanged(BlockState state, World world, BlockPos pos, Block block, BlockPos fromPos, boolean unused)
{
if(!(world instanceof World) || (((World) world).isRemote)) return;
TileEntity te = world.getTileEntity(pos);
if(!(te instanceof BTileEntity)) return;
((BTileEntity)te).block_updated();
}
@Override
@SuppressWarnings("deprecation")
public boolean canProvidePower(BlockState state)
{ return true; }
@Override
@SuppressWarnings("deprecation")
public int getWeakPower(BlockState blockState, IBlockReader blockAccess, BlockPos pos, Direction side)
{ return 0; }
@Override
@SuppressWarnings("deprecation")
public int getStrongPower(BlockState blockState, IBlockReader blockAccess, BlockPos pos, Direction side)
{ return 0; }
//--------------------------------------------------------------------------------------------------------------------
// Tile entity
//--------------------------------------------------------------------------------------------------------------------
public static class BTileEntity extends TileEntity implements ITickableTileEntity, IEnergyStorage
{
public static final int IDLE_TICK_INTERVAL = 40;
public static final int TICK_INTERVAL = 5;
public static final int BOOST_FACTOR = 8;
public static final int DEFAULT_BOOST_ENERGY = 64;
public static final int DEFAULT_BREAKING_RELUCTANCE = 17;
public static final int DEFAULT_MIN_BREAKING_TIME = 15;
public static final int MAX_BREAKING_TIME = 800;
private static int boost_energy_consumption = DEFAULT_BOOST_ENERGY;
private static int breaking_reluctance = DEFAULT_BREAKING_RELUCTANCE;
private static int min_breaking_time = DEFAULT_MIN_BREAKING_TIME;
private static boolean requires_power = false;
private int tick_timer_;
private int active_timer_;
private int proc_time_elapsed_;
private int boost_energy_;
public static void on_config(int boost_energy_per_tick, int breaking_time_per_hardness, int min_breaking_time_ticks, boolean power_required)
{
boost_energy_consumption = TICK_INTERVAL * MathHelper.clamp(boost_energy_per_tick, 16, 512);
breaking_reluctance = MathHelper.clamp(breaking_time_per_hardness, 5, 50);
min_breaking_time = MathHelper.clamp(min_breaking_time_ticks, 10, 100);
requires_power = power_required;
ModEngineersDecor.logger().info("Config block breaker: Boost energy consumption:" + (boost_energy_consumption/TICK_INTERVAL) + "rf/t, reluctance=" + breaking_reluctance + "t/hrdn, break time offset=" + min_breaking_time + "t");
}
public BTileEntity()
{ super(ModContent.TET_SMALL_BLOCK_BREAKER); }
public BTileEntity(TileEntityType<?> te_type)
{ super(te_type); }
public void block_updated()
{ if(tick_timer_ > 2) tick_timer_ = 2; }
// IEnergyStorage ----------------------------------------------------------------------------
protected LazyOptional<IEnergyStorage> energy_handler_ = LazyOptional.of(() -> (IEnergyStorage)this);
@Override
public boolean canExtract()
{ return false; }
@Override
public boolean canReceive()
{ return true; }
@Override
public int getMaxEnergyStored()
{ return boost_energy_consumption; }
@Override
public int getEnergyStored()
{ return boost_energy_; }
@Override
public int extractEnergy(int maxExtract, boolean simulate)
{ return 0; }
@Override
public int receiveEnergy(int maxReceive, boolean simulate)
{ // only speedup support, no buffering, not in nbt -> no markdirty
if((boost_energy_ >= boost_energy_consumption) || (maxReceive < boost_energy_consumption)) return 0;
if(!simulate) boost_energy_ = boost_energy_consumption;
return boost_energy_consumption;
}
// Capability export ----------------------------------------------------------------------------
@Override
public <T> LazyOptional<T> getCapability(net.minecraftforge.common.capabilities.Capability<T> capability, @Nullable Direction facing)
{
if(!this.removed && (facing != null)) {
if(capability== CapabilityEnergy.ENERGY) {
return energy_handler_.cast();
}
}
return super.getCapability(capability, facing);
}
// ITickable ------------------------------------------------------------------------------------
private static HashSet<Block> blacklist = new HashSet<>();
static {
blacklist.add(Blocks.AIR);
blacklist.add(Blocks.BEDROCK);
blacklist.add(Blocks.FIRE);
blacklist.add(Blocks.END_PORTAL);
blacklist.add(Blocks.END_GATEWAY);
blacklist.add(Blocks.END_PORTAL_FRAME);
blacklist.add(Blocks.NETHER_PORTAL);
blacklist.add(Blocks.BARRIER);
}
private static boolean isBreakable(BlockState state, BlockPos pos, World world)
{
final Block block = state.getBlock();
if(blacklist.contains(block)) return false;
if(state.getMaterial().isLiquid()) return false;
if(block.isAir(state, world, pos)) return false;
float bh = state.getBlockHardness(world, pos);
if((bh<0) || (bh>55)) return false;
return true;
}
private boolean breakBlock(BlockState state, BlockPos pos, World world)
{
if(world.isRemote || (!(world instanceof ServerWorld)) || world.restoringBlockSnapshots) return false; // retry next cycle
List<ItemStack> drops = Block.getDrops(state, (ServerWorld)world, pos, world.getTileEntity(pos));
world.removeBlock(pos, false);
for(ItemStack drop:drops) spawnAsEntity(world, pos, drop);
SoundType stype = state.getBlock().getSoundType(state, world, pos, null);
if(stype != null) world.playSound(null, pos, stype.getPlaceSound(), SoundCategory.BLOCKS, stype.getVolume()*0.6f, stype.getPitch());
return true;
}
@Override
@SuppressWarnings("deprecation")
public void tick()
{
if(--tick_timer_ > 0) return;
if(world.isRemote) {
BlockState state = world.getBlockState(pos);
if(!state.get(ACTIVE)) {
tick_timer_ = TICK_INTERVAL;
} else {
tick_timer_ = 1;
// not sure if is so cool to do this each tick ... may be simplified/removed again.
SoundEvent sound = SoundEvents.BLOCK_WOOD_HIT;
BlockState target_state = world.getBlockState(pos.offset(state.get(HORIZONTAL_FACING)));
SoundType stype = target_state.getBlock().getSoundType(target_state);
if((stype == SoundType.CLOTH) || (stype == SoundType.PLANT) || (stype == SoundType.SNOW)) {
sound = SoundEvents.BLOCK_WOOL_HIT;
} else if((stype == SoundType.GROUND) || (stype == SoundType.SAND)) {
sound = SoundEvents.BLOCK_GRAVEL_HIT;
}
world.playSound(pos.getX(), pos.getY(), pos.getZ(), sound, SoundCategory.BLOCKS, 0.1f, 1.2f, false);
}
} else {
tick_timer_ = TICK_INTERVAL;
final BlockState device_state = world.getBlockState(pos);
final BlockPos target_pos = pos.offset(device_state.get(HORIZONTAL_FACING));
final BlockState target_state = world.getBlockState(target_pos);
if((world.isBlockPowered(pos)) || (!isBreakable(target_state, target_pos, world))) {
if(device_state.get(ACTIVE)) world.setBlockState(pos, device_state.with(ACTIVE, false), 1|2);
proc_time_elapsed_ = 0;
tick_timer_ = IDLE_TICK_INTERVAL;
return;
}
int time_needed = (int)(target_state.getBlockHardness(world, pos) * breaking_reluctance) + min_breaking_time;
if(boost_energy_ >= boost_energy_consumption) {
boost_energy_ = 0;
proc_time_elapsed_ += TICK_INTERVAL * (1+BOOST_FACTOR);
time_needed += min_breaking_time * (3*BOOST_FACTOR/5);
active_timer_ = 2;
} else if(!requires_power) {
proc_time_elapsed_ += TICK_INTERVAL;
active_timer_ = 1024;
} else if(active_timer_ > 0) {
--active_timer_;
}
boolean active = (active_timer_ > 0);
if(boost_energy_ >= boost_energy_consumption) {
boost_energy_ = 0;
proc_time_elapsed_ += TICK_INTERVAL * BOOST_FACTOR;
time_needed += min_breaking_time * (3*BOOST_FACTOR/5);
}
time_needed = MathHelper.clamp(time_needed, min_breaking_time, MAX_BREAKING_TIME);
if(proc_time_elapsed_ >= time_needed) {
proc_time_elapsed_ = 0;
breakBlock(target_state, target_pos, world);
active = false;
}
if(device_state.get(ACTIVE) != active) {
world.setBlockState(pos, device_state.with(ACTIVE, active), 1|2);
}
}
}
}
}

View file

@ -0,0 +1,187 @@
/*
* @file BlockDecorFull.java
* @author Stefan Wilhelm (wile)
* @copyright (C) 2019 Stefan Wilhelm
* @license MIT (see https://opensource.org/licenses/MIT)
*
* Full block characteristics class.
*/
package wile.engineersdecor.blocks;
import wile.engineersdecor.ModContent;
import wile.engineersdecor.ModEngineersDecor;
import net.minecraft.entity.*;
import net.minecraft.entity.monster.*;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.network.IPacket;
import net.minecraft.util.math.*;
import net.minecraft.world.IWorldReader;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.util.*;
import net.minecraft.world.World;
import net.minecraftforge.fml.network.FMLPlayMessages;
import net.minecraftforge.fml.network.NetworkHooks;
import java.util.List;
import java.util.Random;
public class BlockDecorChair extends BlockDecorDirected.WaterLoggable
{
private static boolean sitting_enabled = true;
private static double sitting_probability = 0.1;
private static double standup_probability = 0.01;
public static void on_config(boolean without_sitting, boolean without_mob_sitting, double sitting_probability_percent, double standup_probability_percent)
{
sitting_enabled = (!without_sitting);
sitting_probability = (without_sitting||without_mob_sitting) ? 0.0 : MathHelper.clamp(sitting_probability_percent/100, 0, 0.9);
standup_probability = (without_sitting||without_mob_sitting) ? 1.0 : MathHelper.clamp(standup_probability_percent/100, 1e-6, 1e-2);
ModEngineersDecor.logger().info("Config chairs: " + sitting_enabled + ", sit: " + sitting_probability, ", stand up: " + standup_probability);
}
public BlockDecorChair(long config, Block.Properties builder, final AxisAlignedBB unrotatedAABB)
{ super(config, builder.tickRandomly(), unrotatedAABB); }
@Override
@SuppressWarnings("deprecation")
public boolean onBlockActivated(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockRayTraceResult rayTraceResult)
{
if(sitting_enabled && (!world.isRemote)) { EntityChair.sit(world, player, pos); }
return true;
}
@Override
@SuppressWarnings("deprecation")
public void onEntityCollision(BlockState state, World world, BlockPos pos, Entity entity)
{
if(sitting_enabled && (Math.random() < sitting_probability) && (entity instanceof MobEntity)) EntityChair.sit(world, (LivingEntity)entity, pos);
}
@Override
public int tickRate(IWorldReader world)
{ return 10; }
@Override
@SuppressWarnings("deprecation")
public void tick(BlockState state, World world, BlockPos pos, Random rnd)
{
if((!sitting_enabled) || (sitting_probability < 1e-6)) return;
final List<LivingEntity> entities = world.getEntitiesWithinAABB(MobEntity.class, new AxisAlignedBB(pos).grow(2,1,2).expand(0,1,0), e->true);
if(entities.isEmpty()) return;
int index = rnd.nextInt(entities.size());
if((index < 0) || (index >= entities.size())) return;
EntityChair.sit(world, entities.get(index), pos);
}
//--------------------------------------------------------------------------------------------------------------------
// Riding entity for sitting
//--------------------------------------------------------------------------------------------------------------------
public static class EntityChair extends Entity
{
public static final double x_offset = 0.5d;
public static final double y_offset = 0.4d;
public static final double z_offset = 0.5d;
private int t_sit = 0;
public BlockPos chair_pos = new BlockPos(0,0,0);
public EntityChair(EntityType<? extends Entity> entityType, World world)
{
super(entityType, world);
preventEntitySpawning=true;
setMotion(Vec3d.ZERO);
canUpdate(true);
noClip=true;
}
public EntityChair(World world)
{ this(ModContent.ET_CHAIR, world); }
public static EntityChair customClientFactory(FMLPlayMessages.SpawnEntity spkt, World world)
{ return new EntityChair(world); }
public IPacket<?> createSpawnPacket()
{ return NetworkHooks.getEntitySpawningPacket(this); }
public static boolean accepts_mob(LivingEntity entity)
{
if(!(entity instanceof net.minecraft.entity.monster.MonsterEntity)) return false;
if((entity.getType().getSize().height > 2.5) || (entity.getType().getSize().height > 2.0)) return false;
if(entity instanceof ZombieEntity) return true;
if(entity instanceof ZombieVillagerEntity) return true;
if(entity instanceof ZombiePigmanEntity) return true;
if(entity instanceof HuskEntity) return true;
if(entity instanceof StrayEntity) return true;
if(entity instanceof SkeletonEntity) return true;
if(entity instanceof WitherSkeletonEntity) return true;
return false;
}
public static void sit(World world, LivingEntity sitter, BlockPos pos)
{
if(!sitting_enabled) return;
if((world==null) || (world.isRemote) || (sitter==null) || (pos==null)) return;
if((!(sitter instanceof PlayerEntity)) && (!accepts_mob(sitter))) return;
if(!world.getEntitiesWithinAABB(EntityChair.class, new AxisAlignedBB(pos)).isEmpty()) return;
if(sitter.isBeingRidden() || (!sitter.isAlive()) || (sitter.isPassenger()) ) return;
if((!world.isAirBlock(pos.up())) || (!world.isAirBlock(pos.up(2)))) return;
boolean on_top_of_block_position = true;
boolean use_next_negative_y_position = false;
EntityChair chair = new EntityChair(world);
BlockPos chair_pos = chair.getPosition();
chair.chair_pos = pos;
chair.t_sit = 5;
chair.prevPosX = chair_pos.getX();
chair.prevPosY = chair_pos.getY();
chair.prevPosZ = chair_pos.getZ();
chair.setPosition(pos.getX()+x_offset,pos.getY()+y_offset,pos.getZ()+z_offset);
world.addEntity(chair);
sitter.startRiding(chair, true);
}
@Override
protected void registerData() {}
@Override
protected void readAdditional(CompoundNBT compound) {}
@Override
protected void writeAdditional(CompoundNBT compound) {}
@Override
public boolean canBePushed()
{ return false; }
@Override
public double getMountedYOffset()
{ return 0.0; }
@Override
public void tick()
{
if(world.isRemote) return;
super.tick();
if(--t_sit > 0) return;
Entity sitter = getPassengers().isEmpty() ? null : getPassengers().get(0);
if((sitter==null) || (!sitter.isAlive())) {
this.remove();
return;
}
boolean abort = (!sitting_enabled);
final BlockState state = world.getBlockState(chair_pos);
if((state==null) || (!(state.getBlock() instanceof BlockDecorChair))) abort = true;
if(!world.isAirBlock(chair_pos.up())) abort = true;
if((!(sitter instanceof PlayerEntity)) && (Math.random() < standup_probability)) abort = true;
if(abort) {
for(Entity e:getPassengers()) {
if(e.isAlive()) e.stopRiding();
}
this.remove();
}
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,114 @@
/*
* @file BlockDecorDirected.java
* @author Stefan Wilhelm (wile)
* @copyright (C) 2019 Stefan Wilhelm
* @license MIT (see https://opensource.org/licenses/MIT)
*
* Smaller (cutout) block with a defined facing.
*/
package wile.engineersdecor.blocks;
import net.minecraft.block.IWaterLoggable;
import wile.engineersdecor.detail.ModAuxiliaries;
import net.minecraft.entity.EntityType;
import net.minecraft.state.StateContainer;
import net.minecraft.util.math.shapes.ISelectionContext;
import net.minecraft.util.math.shapes.VoxelShapes;
import net.minecraft.item.BlockItemUseContext;
import net.minecraft.state.DirectionProperty;
import net.minecraft.block.Block;
import net.minecraft.block.DirectionalBlock;
import net.minecraft.block.BlockState;
import net.minecraft.world.IBlockReader;
import net.minecraft.util.Direction;
import net.minecraft.util.math.shapes.VoxelShape;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.Arrays;
public class BlockDecorDirected extends BlockDecor
{
public static final DirectionProperty FACING = DirectionalBlock.FACING;
protected final ArrayList<VoxelShape> AABBs;
public BlockDecorDirected(long config, Block.Properties builder, final AxisAlignedBB unrotatedAABB)
{
super(config, builder);
setDefaultState(stateContainer.getBaseState().with(FACING, Direction.UP));
final boolean is_horizontal = ((config & BlockDecor.CFG_HORIZIONTAL)!=0);
AABBs = new ArrayList<VoxelShape>(Arrays.asList(
VoxelShapes.create(ModAuxiliaries.getRotatedAABB(unrotatedAABB, Direction.DOWN, is_horizontal)),
VoxelShapes.create(ModAuxiliaries.getRotatedAABB(unrotatedAABB, Direction.UP, is_horizontal)),
VoxelShapes.create(ModAuxiliaries.getRotatedAABB(unrotatedAABB, Direction.NORTH, is_horizontal)),
VoxelShapes.create(ModAuxiliaries.getRotatedAABB(unrotatedAABB, Direction.SOUTH, is_horizontal)),
VoxelShapes.create(ModAuxiliaries.getRotatedAABB(unrotatedAABB, Direction.WEST, is_horizontal)),
VoxelShapes.create(ModAuxiliaries.getRotatedAABB(unrotatedAABB, Direction.EAST, is_horizontal)),
VoxelShapes.create(unrotatedAABB),
VoxelShapes.create(unrotatedAABB)
));
}
@Override
public RenderTypeHint getRenderTypeHint()
{ return ((config & CFG_CUTOUT)!=0) ? (RenderTypeHint.CUTOUT_MIPPED) : (RenderTypeHint.SOLID); }
@Override
public boolean canSpawnInBlock()
{ return false; }
@Override
@SuppressWarnings("deprecation")
public boolean canEntitySpawn(BlockState state, IBlockReader world, BlockPos pos, EntityType<?> entityType)
{ return false; }
@Override
public VoxelShape getShape(BlockState state, IBlockReader source, BlockPos pos, ISelectionContext selectionContext)
{ return AABBs.get((state.get(FACING)).getIndex() & 0x7); }
@Override
public VoxelShape getCollisionShape(BlockState state, IBlockReader world, BlockPos pos, ISelectionContext selectionContext)
{ return getShape(state, world, pos, selectionContext); }
@Override
protected void fillStateContainer(StateContainer.Builder<Block, BlockState> builder)
{ super.fillStateContainer(builder); builder.add(FACING); }
@Override
@Nullable
public BlockState getStateForPlacement(BlockItemUseContext context)
{
Direction facing = context.getFace();
if((config & (CFG_HORIZIONTAL|CFG_LOOK_PLACEMENT)) == (CFG_HORIZIONTAL|CFG_LOOK_PLACEMENT)) {
// horizontal placement in direction the player is looking
facing = context.getPlacementHorizontalFacing();
} else if((config & (CFG_HORIZIONTAL|CFG_LOOK_PLACEMENT)) == (CFG_HORIZIONTAL)) {
// horizontal placement on a face
if(((facing==Direction.UP)||(facing==Direction.DOWN))) return null;
} else if((config & CFG_LOOK_PLACEMENT)!=0) {
// placement in direction the player is looking, with up and down
facing = context.getNearestLookingDirection();
} else {
// default: placement on the face the player clicking
}
if((config & CFG_OPPOSITE_PLACEMENT)!=0) facing = facing.getOpposite();
if(((config & CFG_FLIP_PLACEMENT_SHIFTCLICK) != 0) && (context.getPlayer().func_225608_bj_()/*isSneaking()*/)) facing = facing.getOpposite();
return super.getStateForPlacement(context).with(FACING, facing);
}
/**
* Water loggable version of directed blocks.
*/
public static class WaterLoggable extends BlockDecorDirected implements IWaterLoggable
{
public WaterLoggable(long config, Block.Properties properties, AxisAlignedBB aabb)
{ super(config|CFG_WATERLOGGABLE, properties, aabb); }
@Override
protected void fillStateContainer(StateContainer.Builder<Block, BlockState> builder)
{ super.fillStateContainer(builder); builder.add(WATERLOGGED); }
}
}

View file

@ -0,0 +1,122 @@
/*
* @file BlockDecorDirectedHorizontal.java
* @author Stefan Wilhelm (wile)
* @copyright (C) 2019 Stefan Wilhelm
* @license MIT (see https://opensource.org/licenses/MIT)
*
* Smaller directed block with direction set narrowed
* to horizontal directions.
*/
package wile.engineersdecor.blocks;
import net.minecraft.block.HorizontalBlock;
import net.minecraft.block.IWaterLoggable;
import net.minecraft.util.Mirror;
import net.minecraft.util.Rotation;
import net.minecraft.entity.EntityType;
import net.minecraft.state.StateContainer;
import net.minecraft.util.math.shapes.ISelectionContext;
import net.minecraft.item.BlockItemUseContext;
import net.minecraft.state.DirectionProperty;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.util.math.shapes.VoxelShapes;
import net.minecraft.world.IBlockReader;
import net.minecraft.util.Direction;
import net.minecraft.util.math.shapes.VoxelShape;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import wile.engineersdecor.detail.ModAuxiliaries;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.Arrays;
public class BlockDecorDirectedHorizontal extends BlockDecor
{
public static final DirectionProperty HORIZONTAL_FACING = HorizontalBlock.HORIZONTAL_FACING;
protected final ArrayList<VoxelShape> AABBs;
public BlockDecorDirectedHorizontal(long config, Block.Properties builder, final AxisAlignedBB unrotatedAABB)
{
super(config|CFG_HORIZIONTAL, builder, unrotatedAABB);
setDefaultState(stateContainer.getBaseState().with(HORIZONTAL_FACING, Direction.NORTH));
AABBs = new ArrayList<VoxelShape>(Arrays.asList(
VoxelShapes.create(ModAuxiliaries.getRotatedAABB(unrotatedAABB, Direction.DOWN, true)),
VoxelShapes.create(ModAuxiliaries.getRotatedAABB(unrotatedAABB, Direction.UP, true)),
VoxelShapes.create(ModAuxiliaries.getRotatedAABB(unrotatedAABB, Direction.NORTH, true)),
VoxelShapes.create(ModAuxiliaries.getRotatedAABB(unrotatedAABB, Direction.SOUTH, true)),
VoxelShapes.create(ModAuxiliaries.getRotatedAABB(unrotatedAABB, Direction.WEST, true)),
VoxelShapes.create(ModAuxiliaries.getRotatedAABB(unrotatedAABB, Direction.EAST, true)),
VoxelShapes.create(unrotatedAABB),
VoxelShapes.create(unrotatedAABB)
));
}
@Override
public RenderTypeHint getRenderTypeHint()
{ return ((config & CFG_CUTOUT)!=0) ? RenderTypeHint.CUTOUT : RenderTypeHint.SOLID; }
@Override
public boolean canSpawnInBlock()
{ return false; }
@Override
@SuppressWarnings("deprecation")
public boolean canEntitySpawn(BlockState state, IBlockReader world, BlockPos pos, EntityType<?> entityType)
{ return false; }
@Override
public VoxelShape getShape(BlockState state, IBlockReader source, BlockPos pos, ISelectionContext selectionContext)
{ return AABBs.get((state.get(HORIZONTAL_FACING)).getIndex() & 0x7); }
@Override
public VoxelShape getCollisionShape(BlockState state, IBlockReader world, BlockPos pos, ISelectionContext selectionContext)
{ return getShape(state, world, pos, selectionContext); }
@Override
protected void fillStateContainer(StateContainer.Builder<Block, BlockState> builder)
{ super.fillStateContainer(builder); builder.add(HORIZONTAL_FACING); }
@Override
@Nullable
public BlockState getStateForPlacement(BlockItemUseContext context)
{
Direction facing = context.getFace();
if((config & CFG_LOOK_PLACEMENT) != 0) {
// horizontal placement in direction the player is looking
facing = context.getPlacementHorizontalFacing();
} else {
// horizontal placement on a face
facing = ((facing==Direction.UP)||(facing==Direction.DOWN)) ? (context.getPlacementHorizontalFacing()) : facing;
}
if((config & CFG_OPPOSITE_PLACEMENT)!=0) facing = facing.getOpposite();
if(((config & CFG_FLIP_PLACEMENT_SHIFTCLICK) != 0) && (context.getPlayer().func_225608_bj_()/*isSneaking()*/)) facing = facing.getOpposite();
return super.getStateForPlacement(context).with(HORIZONTAL_FACING, facing);
}
@Override
@SuppressWarnings("deprecation")
public BlockState rotate(BlockState state, Rotation rot)
{ return state.with(HORIZONTAL_FACING, rot.rotate(state.get(HORIZONTAL_FACING))); }
@Override
@SuppressWarnings("deprecation")
public BlockState mirror(BlockState state, Mirror mirrorIn)
{ return state.rotate(mirrorIn.toRotation(state.get(HORIZONTAL_FACING))); }
/**
* Water loggable version of directed blocks.
*/
public static class WaterLoggable extends BlockDecorDirectedHorizontal implements IWaterLoggable
{
public WaterLoggable(long config, Block.Properties properties, AxisAlignedBB aabb)
{ super(config|CFG_WATERLOGGABLE, properties, aabb); }
@Override
protected void fillStateContainer(StateContainer.Builder<Block, BlockState> builder)
{ super.fillStateContainer(builder); builder.add(WATERLOGGED); }
}
}

View file

@ -0,0 +1,935 @@
/*
* @file BlockDecorDropper.java
* @author Stefan Wilhelm (wile)
* @copyright (C) 2019 Stefan Wilhelm
* @license MIT (see https://opensource.org/licenses/MIT)
*
* Dropper factory automation suitable.
*/
package wile.engineersdecor.blocks;
import wile.engineersdecor.ModContent;
import wile.engineersdecor.ModEngineersDecor;
import wile.engineersdecor.detail.Networking;
import net.minecraft.tileentity.ITickableTileEntity;
import net.minecraft.inventory.container.INamedContainerProvider;
import net.minecraft.block.DoorBlock;
import net.minecraft.entity.player.ServerPlayerEntity;
import net.minecraft.inventory.container.Container;
import net.minecraft.inventory.container.Slot;
import net.minecraft.state.BooleanProperty;
import net.minecraft.state.StateContainer;
import net.minecraft.tileentity.TileEntityType;
import net.minecraft.util.math.*;
import net.minecraft.util.text.StringTextComponent;
import net.minecraft.util.math.shapes.ISelectionContext;
import net.minecraft.util.math.shapes.VoxelShape;
import net.minecraft.util.math.shapes.VoxelShapes;
import net.minecraft.world.IBlockReader;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.world.World;
import net.minecraft.entity.item.ItemEntity;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.item.*;
import net.minecraft.inventory.*;
import net.minecraft.client.gui.screen.inventory.ContainerScreen;
import net.minecraft.util.SoundEvents;
import net.minecraft.util.*;
import net.minecraft.util.text.ITextComponent;
import net.minecraftforge.fml.network.NetworkHooks;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.common.util.FakePlayer;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.items.wrapper.SidedInvWrapper;
import net.minecraftforge.items.CapabilityItemHandler;
import net.minecraftforge.items.IItemHandler;
import com.mojang.blaze3d.systems.RenderSystem;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;
public class BlockDecorDropper extends BlockDecorDirected
{
public static final BooleanProperty OPEN = DoorBlock.OPEN;
public BlockDecorDropper(long config, Block.Properties builder, final AxisAlignedBB unrotatedAABB)
{ super(config, builder, unrotatedAABB); }
@Override
public RenderTypeHint getRenderTypeHint()
{ return RenderTypeHint.SOLID; }
@Override
public VoxelShape getCollisionShape(BlockState state, IBlockReader world, BlockPos pos, ISelectionContext selectionContext)
{ return VoxelShapes.fullCube(); }
@Override
protected void fillStateContainer(StateContainer.Builder<Block, BlockState> builder)
{ super.fillStateContainer(builder); builder.add(OPEN); }
@Override
@Nullable
public BlockState getStateForPlacement(BlockItemUseContext context)
{ return super.getStateForPlacement(context).with(OPEN, false); }
@Override
@SuppressWarnings("deprecation")
public boolean hasComparatorInputOverride(BlockState state)
{ return true; }
@Override
@SuppressWarnings("deprecation")
public int getComparatorInputOverride(BlockState blockState, World world, BlockPos pos)
{ return Container.calcRedstone(world.getTileEntity(pos)); }
@Override
public boolean hasTileEntity(BlockState state)
{ return true; }
@Override
@Nullable
public TileEntity createTileEntity(BlockState state, IBlockReader world)
{ return new BlockDecorDropper.BTileEntity(); }
@Override
public void onBlockPlacedBy(World world, BlockPos pos, BlockState state, LivingEntity placer, ItemStack stack)
{
if(world.isRemote) return;
if((!stack.hasTag()) || (!stack.getTag().contains("tedata"))) return;
CompoundNBT te_nbt = stack.getTag().getCompound("tedata");
if(te_nbt.isEmpty()) return;
final TileEntity te = world.getTileEntity(pos);
if(!(te instanceof BlockDecorDropper.BTileEntity)) return;
((BlockDecorDropper.BTileEntity)te).readnbt(te_nbt, false);
((BlockDecorDropper.BTileEntity)te).reset_rtstate();
((BlockDecorDropper.BTileEntity)te).markDirty();
}
@Override
public boolean hasDynamicDropList()
{ return true; }
@Override
public List<ItemStack> dropList(BlockState state, World world, BlockPos pos, boolean explosion)
{
final List<ItemStack> stacks = new ArrayList<ItemStack>();
if(world.isRemote) return stacks;
final TileEntity te = world.getTileEntity(pos);
if(!(te instanceof BTileEntity)) return stacks;
if(!explosion) {
ItemStack stack = new ItemStack(this, 1);
CompoundNBT te_nbt = ((BTileEntity) te).clear_getnbt();
if(!te_nbt.isEmpty()) {
CompoundNBT nbt = new CompoundNBT();
nbt.put("tedata", te_nbt);
stack.setTag(nbt);
}
stacks.add(stack);
} else {
for(ItemStack stack: ((BTileEntity)te).stacks_) {
if(!stack.isEmpty()) stacks.add(stack);
}
((BTileEntity)te).reset_rtstate();
}
return stacks;
}
@Override
@SuppressWarnings("deprecation")
public boolean onBlockActivated(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockRayTraceResult rayTraceResult)
{
if(world.isRemote) return true;
final TileEntity te = world.getTileEntity(pos);
if(!(te instanceof BlockDecorDropper.BTileEntity)) return true;
if((!(player instanceof ServerPlayerEntity) && (!(player instanceof FakePlayer)))) return true;
NetworkHooks.openGui((ServerPlayerEntity)player,(INamedContainerProvider)te);
return true;
}
@Override
@SuppressWarnings("deprecation")
public void neighborChanged(BlockState state, World world, BlockPos pos, Block block, BlockPos fromPos, boolean unused)
{
if(!(world instanceof World) || (((World) world).isRemote)) return;
TileEntity te = world.getTileEntity(pos);
if(!(te instanceof BTileEntity)) return;
((BTileEntity)te).block_updated();
}
@Override
@SuppressWarnings("deprecation")
public boolean canProvidePower(BlockState state)
{ return true; }
@Override
@SuppressWarnings("deprecation")
public int getWeakPower(BlockState blockState, IBlockReader blockAccess, BlockPos pos, Direction side)
{ return 0; }
@Override
@SuppressWarnings("deprecation")
public int getStrongPower(BlockState blockState, IBlockReader blockAccess, BlockPos pos, Direction side)
{ return 0; }
//--------------------------------------------------------------------------------------------------------------------
// Tile entity
//--------------------------------------------------------------------------------------------------------------------
public static class BTileEntity extends TileEntity implements ITickableTileEntity, INameable, IInventory, INamedContainerProvider, ISidedInventory
{
public static final int NUM_OF_FIELDS = 16;
public static final int TICK_INTERVAL = 32;
public static final int NUM_OF_SLOTS = 15;
public static final int INPUT_SLOTS_FIRST = 0;
public static final int INPUT_SLOTS_SIZE = 12;
public static final int CTRL_SLOTS_FIRST = INPUT_SLOTS_SIZE;
public static final int CTRL_SLOTS_SIZE = 3;
public static final int SHUTTER_CLOSE_DELAY = 40;
public static final int MAX_DROP_COUNT = 32;
public static final int DROP_PERIOD_OFFSET = 10;
///
public static final int DROPLOGIC_FILTER_ANDGATE = 0x01;
public static final int DROPLOGIC_EXTERN_ANDGATE = 0x02;
public static final int DROPLOGIC_SILENT_DROP = 0x04;
public static final int DROPLOGIC_SILENT_OPEN = 0x08;
public static final int DROPLOGIC_CONTINUOUS = 0x10;
///
private int filter_matches_[] = new int[CTRL_SLOTS_SIZE];
private int open_timer_ = 0;
private int drop_timer_ = 0;
private boolean triggered_ = false;
private boolean block_power_signal_ = false;
private boolean block_power_updated_ = false;
private int drop_speed_ = 10;
private int drop_noise_ = 0;
private int drop_xdev_ = 0;
private int drop_ydev_ = 0;
private int drop_count_ = 1;
private int drop_logic_ = DROPLOGIC_EXTERN_ANDGATE;
private int drop_period_ = 0;
private int drop_slot_index_ = 0;
private int tick_timer_ = 0;
protected NonNullList<ItemStack> stacks_;
public static void on_config(int cooldown_ticks)
{
// ModEngineersDecor.logger.info("Config factory dropper:");
}
public BTileEntity()
{ this(ModContent.TET_FACTORY_DROPPER); }
public BTileEntity(TileEntityType<?> te_type)
{
super(te_type);
stacks_ = NonNullList.<ItemStack>withSize(NUM_OF_SLOTS, ItemStack.EMPTY);
reset_rtstate();
}
public CompoundNBT clear_getnbt()
{
CompoundNBT nbt = new CompoundNBT();
writenbt(nbt, false);
for(int i=0; i<stacks_.size(); ++i) stacks_.set(i, ItemStack.EMPTY);
reset_rtstate();
triggered_ = false;
block_power_updated_ = false;
return nbt;
}
public void reset_rtstate()
{
block_power_signal_ = false;
block_power_updated_ = false;
for(int i=0; i<filter_matches_.length; ++i) filter_matches_[i] = 0;
}
public void readnbt(CompoundNBT nbt, boolean update_packet)
{
stacks_ = NonNullList.<ItemStack>withSize(NUM_OF_SLOTS, ItemStack.EMPTY);
ItemStackHelper.loadAllItems(nbt, stacks_);
while(stacks_.size() < NUM_OF_SLOTS) stacks_.add(ItemStack.EMPTY);
block_power_signal_ = nbt.getBoolean("powered");
open_timer_ = nbt.getInt("open_timer");
drop_speed_ = nbt.getInt("drop_speed");
drop_noise_ = nbt.getInt("drop_noise");
drop_xdev_ = nbt.getInt("drop_xdev");
drop_ydev_ = nbt.getInt("drop_ydev");
drop_slot_index_ = nbt.getInt("drop_slot_index");
drop_count_ = MathHelper.clamp(nbt.getInt("drop_count"), 1, MAX_DROP_COUNT);
drop_logic_ = nbt.getInt("drop_logic");
drop_period_ = nbt.getInt("drop_period");
}
protected void writenbt(CompoundNBT nbt, boolean update_packet)
{
ItemStackHelper.saveAllItems(nbt, stacks_);
nbt.putBoolean("powered", block_power_signal_);
nbt.putInt("open_timer", open_timer_);
nbt.putInt("drop_speed", drop_speed_);
nbt.putInt("drop_noise", drop_noise_);
nbt.putInt("drop_xdev", drop_xdev_);
nbt.putInt("drop_ydev", drop_ydev_);
nbt.putInt("drop_slot_index", drop_slot_index_);
nbt.putInt("drop_count", drop_count_);
nbt.putInt("drop_logic", drop_logic_);
nbt.putInt("drop_period", drop_period_);
}
public void block_updated()
{
// RS power check, both edges
boolean powered = world.isBlockPowered(pos);
if(block_power_signal_ != powered) block_power_updated_ = true;
block_power_signal_ = powered;
tick_timer_ = 1;
}
public boolean is_input_slot(int index)
{ return (index >= INPUT_SLOTS_FIRST) && (index < (INPUT_SLOTS_FIRST+INPUT_SLOTS_SIZE)); }
// TileEntity ------------------------------------------------------------------------------
@Override
public void read(CompoundNBT nbt)
{ super.read(nbt); readnbt(nbt, false); }
@Override
public CompoundNBT write(CompoundNBT nbt)
{ super.write(nbt); writenbt(nbt, false); return nbt; }
// INamable ----------------------------------------------------------------------------------------------
@Override
public ITextComponent getName()
{ final Block block=getBlockState().getBlock(); return new StringTextComponent((block!=null) ? block.getTranslationKey() : "Factory dropper"); }
@Override
public boolean hasCustomName()
{ return false; }
@Override
public ITextComponent getCustomName()
{ return getName(); }
// INamedContainerProvider ------------------------------------------------------------------------------
@Override
public ITextComponent getDisplayName()
{ return INameable.super.getDisplayName(); }
@Override
public Container createMenu(int id, PlayerInventory inventory, PlayerEntity player )
{ return new BContainer(id, inventory, this, IWorldPosCallable.of(world, pos), fields); }
// IInventory -------------------------------------------------------------------------------------------
@Override
public int getSizeInventory()
{ return stacks_.size(); }
@Override
public boolean isEmpty()
{ for(ItemStack stack: stacks_) { if(!stack.isEmpty()) return false; } return true; }
@Override
public ItemStack getStackInSlot(int index)
{ return (index < getSizeInventory()) ? stacks_.get(index) : ItemStack.EMPTY; }
@Override
public ItemStack decrStackSize(int index, int count)
{ return ItemStackHelper.getAndSplit(stacks_, index, count); }
@Override
public ItemStack removeStackFromSlot(int index)
{ return ItemStackHelper.getAndRemove(stacks_, index); }
@Override
public void setInventorySlotContents(int index, ItemStack stack)
{
stacks_.set(index, stack);
if(stack.getCount() > getInventoryStackLimit()) stack.setCount(getInventoryStackLimit());
if(tick_timer_ > 8) tick_timer_ = 8;
markDirty();
}
@Override
public int getInventoryStackLimit()
{ return 64; }
@Override
public void markDirty()
{ super.markDirty(); }
@Override
public boolean isUsableByPlayer(PlayerEntity player)
{ return getPos().distanceSq(player.getPosition()) < 36; }
@Override
public void openInventory(PlayerEntity player)
{}
@Override
public void closeInventory(PlayerEntity player)
{ markDirty(); }
@Override
public boolean isItemValidForSlot(int index, ItemStack stack)
{ return true; }
@Override
public void clear()
{ stacks_.clear(); }
// Fields -----------------------------------------------------------------------------------------------
protected final IIntArray fields = new IntArray(BTileEntity.NUM_OF_FIELDS)
{
@Override
public int get(int id)
{
switch(id) {
case 0: return drop_speed_;
case 1: return drop_xdev_;
case 2: return drop_ydev_;
case 3: return drop_noise_;
case 4: return drop_count_;
case 5: return drop_logic_;
case 6: return drop_period_;
case 9: return drop_timer_;
case 10: return open_timer_;
case 11: return block_power_signal_ ? 1 : 0;
case 12: return filter_matches_[0];
case 13: return filter_matches_[1];
case 14: return filter_matches_[2];
case 15: return drop_slot_index_;
default: return 0;
}
}
@Override
public void set(int id, int value)
{
switch(id) {
case 0: drop_speed_ = MathHelper.clamp(value, 0, 100); return;
case 1: drop_xdev_ = MathHelper.clamp(value, -100, 100); return;
case 2: drop_ydev_ = MathHelper.clamp(value, -100, 100); return;
case 3: drop_noise_ = MathHelper.clamp(value, 0, 100); return;
case 4: drop_count_ = MathHelper.clamp(value, 1, MAX_DROP_COUNT); return;
case 5: drop_logic_ = value; return;
case 6: drop_period_ = MathHelper.clamp(value, 0, 100); return;
case 9: drop_timer_ = MathHelper.clamp(value, 0, 400); return;
case 10: open_timer_ = MathHelper.clamp(value, 0, 400); return;
case 11: block_power_signal_ = (value != 0); return;
case 12: filter_matches_[0] = (value & 0x3); return;
case 13: filter_matches_[1] = (value & 0x3); return;
case 14: filter_matches_[2] = (value & 0x3); return;
case 15: drop_slot_index_ = MathHelper.clamp(value, INPUT_SLOTS_FIRST, INPUT_SLOTS_FIRST+INPUT_SLOTS_SIZE-1); return;
default: return;
}
}
};
// ISidedInventory --------------------------------------------------------------------------------------
LazyOptional<? extends IItemHandler>[] item_handlers = SidedInvWrapper.create(this, Direction.UP);
private static final int[] SIDED_INV_SLOTS;
static {
SIDED_INV_SLOTS = new int[INPUT_SLOTS_SIZE];
for(int i=0; i<INPUT_SLOTS_SIZE; ++i) SIDED_INV_SLOTS[i] = i+INPUT_SLOTS_FIRST;
}
@Override
public int[] getSlotsForFace(Direction side)
{ return SIDED_INV_SLOTS; }
@Override
public boolean canInsertItem(int index, ItemStack stack, Direction direction)
{ return is_input_slot(index) && isItemValidForSlot(index, stack); }
@Override
public boolean canExtractItem(int index, ItemStack stack, Direction direction)
{ return false; }
// Capability export ------------------------------------------------------------------------------------
@Override
public <T> LazyOptional<T> getCapability(net.minecraftforge.common.capabilities.Capability<T> capability, @Nullable Direction facing)
{
if(!this.removed && (facing != null)) {
if(capability==CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) return item_handlers[0].cast();
}
return super.getCapability(capability, facing);
}
// ITickable and aux methods ----------------------------------------------------------------------------
private static void drop(World world, BlockPos pos, Direction facing, ItemStack stack, int speed_percent, int xdeviation, int ydeviation, int noise_percent)
{
final double ofs = facing==Direction.DOWN ? 0.8 : 0.7;
Vec3d v0 = new Vec3d(facing.getXOffset(), facing.getYOffset(), facing.getZOffset());
final ItemEntity ei = new ItemEntity(world, (pos.getX()+0.5)+(ofs*v0.x), (pos.getY()+0.5)+(ofs*v0.y), (pos.getZ()+0.5)+(ofs*v0.z), stack);
if((xdeviation != 0) || (ydeviation != 0)) {
double vdx = 1e-2 * MathHelper.clamp(xdeviation, -100, 100);
double vdy = 1e-2 * MathHelper.clamp(ydeviation, -100, 100);
switch(facing) { // switch-case faster than coorsys fwd transform
case DOWN: v0 = v0.add( vdx, 0,-vdy); break;
case NORTH: v0 = v0.add( vdx, vdy, 0); break;
case SOUTH: v0 = v0.add(-vdx, vdy, 0); break;
case EAST: v0 = v0.add(0, vdy, vdx); break;
case WEST: v0 = v0.add(0, vdy, -vdx); break;
case UP: v0 = v0.add( vdx, 0, vdy); break;
}
}
if(noise_percent > 0) {
v0 = v0.add(
((world.rand.nextDouble()-0.5) * 1e-3 * noise_percent),
((world.rand.nextDouble()-0.5) * 1e-3 * noise_percent),
((world.rand.nextDouble()-0.5) * 1e-3 * noise_percent)
);
}
if(speed_percent < 5) speed_percent = 5;
double speed = 1e-2 * speed_percent;
if(noise_percent > 0) speed += (world.rand.nextDouble()-0.5) * 1e-4 * noise_percent;
v0 = v0.normalize().scale(speed);
ei.setMotion(v0.x, v0.y, v0.z);
ei.velocityChanged = true;
world.addEntity(ei);
}
@Nullable
BlockState update_blockstate()
{
BlockState state = world.getBlockState(pos);
if(!(state.getBlock() instanceof BlockDecorDropper)) return null;
boolean open = (open_timer_ > 0);
if(state.get(OPEN) != open) {
state = state.with(OPEN, open);
world.setBlockState(pos, state, 2|16);
if((drop_logic_ & DROPLOGIC_SILENT_OPEN) == 0) {
if(open) {
world.playSound(null, pos, SoundEvents.BLOCK_WOODEN_TRAPDOOR_OPEN, SoundCategory.BLOCKS, 0.08f, 3f);
} else {
world.playSound(null, pos, SoundEvents.BLOCK_WOODEN_TRAPDOOR_CLOSE, SoundCategory.BLOCKS, 0.08f, 3f);
}
}
}
return state;
}
private static int next_slot(int i)
{ return (i<INPUT_SLOTS_SIZE-1) ? (i+1) : INPUT_SLOTS_FIRST; }
@Override
public void tick()
{
if(world.isRemote) return;
if(--open_timer_ < 0) open_timer_ = 0;
if((drop_timer_ > 0) && ((--drop_timer_) == 0)) markDirty();
if(--tick_timer_ > 0) return;
tick_timer_ = TICK_INTERVAL;
final boolean continuous_mode = (drop_logic_ & DROPLOGIC_CONTINUOUS)!=0;
boolean dirty = block_power_updated_;
boolean redstone_trigger = (block_power_signal_ && ((block_power_updated_) || (continuous_mode)));
boolean filter_trigger;
boolean filter_defined;
boolean trigger;
// Trigger logic
{
boolean droppable_slot_found = false;
for(int i=INPUT_SLOTS_FIRST; i<(INPUT_SLOTS_FIRST+INPUT_SLOTS_SIZE); ++i) {
if(stacks_.get(i).getCount() >= drop_count_) { droppable_slot_found = true; break; }
}
// From filters / inventory checks
{
int filter_nset = 0;
int last_filter_matches_[] = filter_matches_.clone();
boolean slot_assigned = false;
for(int ci=0; ci<CTRL_SLOTS_SIZE; ++ci) {
filter_matches_[ci] = 0;
final ItemStack cmp_stack = stacks_.get(CTRL_SLOTS_FIRST+ci);
if(cmp_stack.isEmpty()) continue;
filter_matches_[ci] = 1;
final int cmp_stack_count = cmp_stack.getCount();
int inventory_item_count = 0;
int slot = drop_slot_index_;
for(int i=INPUT_SLOTS_FIRST; i<(INPUT_SLOTS_FIRST+INPUT_SLOTS_SIZE); ++i) {
final ItemStack inp_stack = stacks_.get(slot);
if(!inp_stack.isItemEqual(cmp_stack)) { slot = next_slot(slot); continue; }
inventory_item_count += inp_stack.getCount();
if(inventory_item_count < cmp_stack_count) { slot = next_slot(slot); continue; }
filter_matches_[ci] = 2;
break;
}
}
int nmatched = 0;
for(int i=0; i<filter_matches_.length; ++i) {
if(filter_matches_[i] > 0) ++filter_nset;
if(filter_matches_[i] > 1) ++nmatched;
if(filter_matches_[i] != last_filter_matches_[i]) dirty = true;
}
filter_defined = (filter_nset > 0);
filter_trigger = ((filter_nset > 0) && (nmatched > 0));
if(((drop_logic_ & DROPLOGIC_FILTER_ANDGATE) != 0) && (nmatched != filter_nset)) filter_trigger = false;
}
// gates
{
if(filter_defined) {
trigger = ((drop_logic_ & DROPLOGIC_EXTERN_ANDGATE) != 0) ? (filter_trigger && redstone_trigger) : (filter_trigger || redstone_trigger);
} else {
trigger = redstone_trigger;
}
if(triggered_) { triggered_ = false; trigger = true; }
if(!droppable_slot_found) {
if(open_timer_> 10) open_timer_ = 10; // override if dropping is not possible at all.
} else if(trigger || filter_trigger || redstone_trigger) {
open_timer_ = SHUTTER_CLOSE_DELAY;
}
}
// edge detection for next cycle
{
boolean tr = world.isBlockPowered(pos);
block_power_updated_ = (block_power_signal_ != tr);
block_power_signal_ = tr;
if(block_power_updated_) dirty = true;
}
}
// block state update
final BlockState state = update_blockstate();
if(state == null) { block_power_signal_= false; return; }
// dispense action
if(trigger && (drop_timer_ <= 0)) {
// drop stack for non-filter triggers
ItemStack drop_stacks[] = {ItemStack.EMPTY,ItemStack.EMPTY,ItemStack.EMPTY};
if(!filter_trigger) {
for(int i=0; i<INPUT_SLOTS_SIZE; ++i) {
if(drop_slot_index_ >= INPUT_SLOTS_SIZE) drop_slot_index_ = 0;
int ic = drop_slot_index_;
drop_slot_index_ = next_slot(drop_slot_index_);
ItemStack ds = stacks_.get(ic);
if((!ds.isEmpty()) && (ds.getCount() >= drop_count_)) {
drop_stacks[0] = ds.split(drop_count_);
stacks_.set(ic, ds);
break;
}
}
} else {
for(int fi=0; fi<filter_matches_.length; ++fi) {
if(filter_matches_[fi] > 1) {
drop_stacks[fi] = stacks_.get(CTRL_SLOTS_FIRST+fi).copy();
int ntoremove = drop_stacks[fi].getCount();
for(int i=INPUT_SLOTS_SIZE-1; (i>=0) && (ntoremove>0); --i) {
ItemStack stack = stacks_.get(i);
if(!stack.isItemEqual(drop_stacks[fi])) continue;
if(stack.getCount() <= ntoremove) {
ntoremove -= stack.getCount();
stacks_.set(i, ItemStack.EMPTY);
} else {
stack.shrink(ntoremove);
ntoremove = 0;
stacks_.set(i, stack);
}
}
if(ntoremove > 0) drop_stacks[fi].shrink(ntoremove);
}
}
}
// drop action
boolean dropped = false;
for(int i = 0; i < drop_stacks.length; ++i) {
if(drop_stacks[i].isEmpty()) continue;
dirty = true;
drop(world, pos, state.get(FACING), drop_stacks[i], drop_speed_, drop_xdev_, drop_ydev_, drop_noise_);
dropped = true;
}
// cooldown
if(dropped) drop_timer_ = DROP_PERIOD_OFFSET + drop_period_ * 2; // 0.1s time base -> 100%===10s
// drop sound
if(dropped && ((drop_logic_ & DROPLOGIC_SILENT_DROP) == 0)) {
world.playSound(null, pos, SoundEvents.BLOCK_WOOD_HIT, SoundCategory.BLOCKS, 0.1f, 4f);
}
// advance to next nonempty slot.
for(int i = 0; i < INPUT_SLOTS_SIZE; ++i) {
if(!stacks_.get(drop_slot_index_).isEmpty()) break;
drop_slot_index_ = next_slot(drop_slot_index_);
}
}
if(dirty) markDirty();
if(trigger && (tick_timer_ > 10)) tick_timer_ = 10;
}
}
//--------------------------------------------------------------------------------------------------------------------
// container
//--------------------------------------------------------------------------------------------------------------------
public static class BContainer extends Container implements Networking.INetworkSynchronisableContainer
{
private static final int PLAYER_INV_START_SLOTNO = BTileEntity.NUM_OF_SLOTS;
private final PlayerEntity player_;
private final IInventory inventory_;
private final IWorldPosCallable wpc_;
private final IIntArray fields_;
public final int field(int index) { return fields_.get(index); }
public BContainer(int cid, PlayerInventory player_inventory)
{ this(cid, player_inventory, new Inventory(BTileEntity.NUM_OF_SLOTS), IWorldPosCallable.DUMMY, new IntArray(BTileEntity.NUM_OF_FIELDS)); }
private BContainer(int cid, PlayerInventory player_inventory, IInventory block_inventory, IWorldPosCallable wpc, IIntArray fields)
{
super(ModContent.CT_FACTORY_DROPPER, cid);
fields_ = fields;
wpc_ = wpc;
player_ = player_inventory.player;
inventory_ = block_inventory;
int i=-1;
// input slots (stacks 0 to 11)
for(int y=0; y<2; ++y) {
for(int x=0; x<6; ++x) {
int xpos = 10+x*18, ypos = 6+y*17;
addSlot(new Slot(inventory_, ++i, xpos, ypos));
}
}
// filter slots (stacks 12 to 14)
addSlot(new Slot(inventory_, ++i, 19, 48));
addSlot(new Slot(inventory_, ++i, 55, 48));
addSlot(new Slot(inventory_, ++i, 91, 48));
// player slots
for(int x=0; x<9; ++x) {
addSlot(new Slot(player_inventory, x, 8+x*18, 144)); // player slots: 0..8
}
for(int y=0; y<3; ++y) {
for(int x=0; x<9; ++x) {
addSlot(new Slot(player_inventory, x+y*9+9, 8+x*18, 86+y*18)); // player slots: 9..35
}
}
this.trackIntArray(fields_); // === Add reference holders
}
@Override
public boolean canInteractWith(PlayerEntity player)
{ return inventory_.isUsableByPlayer(player); }
@Override
public ItemStack transferStackInSlot(PlayerEntity player, int index)
{
Slot slot = getSlot(index);
if((slot==null) || (!slot.getHasStack())) return ItemStack.EMPTY;
ItemStack slot_stack = slot.getStack();
ItemStack transferred = slot_stack.copy();
if((index>=0) && (index<PLAYER_INV_START_SLOTNO)) {
// Device slots
if(!mergeItemStack(slot_stack, PLAYER_INV_START_SLOTNO, PLAYER_INV_START_SLOTNO+36, false)) return ItemStack.EMPTY;
} else if((index >= PLAYER_INV_START_SLOTNO) && (index <= PLAYER_INV_START_SLOTNO+36)) {
// Player slot
if(!mergeItemStack(slot_stack, 0, BTileEntity.INPUT_SLOTS_SIZE, false)) return ItemStack.EMPTY;
} else {
// invalid slot
return ItemStack.EMPTY;
}
if(slot_stack.isEmpty()) {
slot.putStack(ItemStack.EMPTY);
} else {
slot.onSlotChanged();
}
if(slot_stack.getCount() == transferred.getCount()) return ItemStack.EMPTY;
slot.onTake(player, slot_stack);
return transferred;
}
// INetworkSynchronisableContainer ---------------------------------------------------------
@OnlyIn(Dist.CLIENT)
public void onGuiAction(CompoundNBT nbt)
{ Networking.PacketContainerSyncClientToServer.sendToServer(windowId, nbt); }
@OnlyIn(Dist.CLIENT)
public void onGuiAction(String key, int value)
{
CompoundNBT nbt = new CompoundNBT();
nbt.putInt(key, value);
Networking.PacketContainerSyncClientToServer.sendToServer(windowId, nbt);
}
@Override
public void onServerPacketReceived(int windowId, CompoundNBT nbt)
{}
@Override
public void onClientPacketReceived(int windowId, PlayerEntity player, CompoundNBT nbt)
{
if(!(inventory_ instanceof BTileEntity)) return;
BTileEntity te = (BTileEntity)inventory_;
if(nbt.contains("drop_speed")) te.drop_speed_ = MathHelper.clamp(nbt.getInt("drop_speed"), 0, 100);
if(nbt.contains("drop_xdev")) te.drop_xdev_ = MathHelper.clamp(nbt.getInt("drop_xdev"), -100, 100);
if(nbt.contains("drop_ydev")) te.drop_ydev_ = MathHelper.clamp(nbt.getInt("drop_ydev"), -100, 100);
if(nbt.contains("drop_count")) te.drop_count_ = MathHelper.clamp(nbt.getInt("drop_count"), 1, BTileEntity.MAX_DROP_COUNT);
if(nbt.contains("drop_period")) te.drop_period_ = MathHelper.clamp(nbt.getInt("drop_period"), 0, 100);
if(nbt.contains("drop_logic")) te.drop_logic_ = nbt.getInt("drop_logic");
if(nbt.contains("manual_rstrigger") && (nbt.getInt("manual_rstrigger")!=0)) { te.block_power_signal_=true; te.block_power_updated_=true; te.tick_timer_=1; }
if(nbt.contains("manual_trigger") && (nbt.getInt("manual_trigger")!=0)) { te.tick_timer_ = 1; te.triggered_ = true; }
te.markDirty();
}
}
//--------------------------------------------------------------------------------------------------------------------
// GUI
//--------------------------------------------------------------------------------------------------------------------
@OnlyIn(Dist.CLIENT)
public static class BGui extends ContainerScreen<BContainer>
{
protected final PlayerEntity player_;
public BGui(BContainer container, PlayerInventory player_inventory, ITextComponent title)
{ super(container, player_inventory, title); this.player_ = player_inventory.player; }
@Override
public void init()
{ super.init(); }
@Override
public void render(int mouseX, int mouseY, float partialTicks)
{
renderBackground();
super.render(mouseX, mouseY, partialTicks);
renderHoveredToolTip(mouseX, mouseY);
}
@Override
public boolean mouseClicked(double mouseX, double mouseY, int mouseButton)
{
BContainer container = (BContainer)getContainer();
int mx = (int)(mouseX - getGuiLeft() + .5), my = (int)(mouseY - getGuiTop() + .5);
if((!isPointInRegion(114, 1, 61, 79, mouseX, mouseY))) {
return super.mouseClicked(mouseX, mouseY, mouseButton);
} else if(isPointInRegion(130, 10, 12, 25, mouseX, mouseY)) {
int force_percent = 100 - MathHelper.clamp(((my-10)*100)/25, 0, 100);
container.onGuiAction("drop_speed", force_percent);
} else if(isPointInRegion(145, 10, 25, 25, mouseX, mouseY)) {
int xdev = MathHelper.clamp( (int)Math.round(((double)((mx-157) * 100)) / 12), -100, 100);
int ydev = MathHelper.clamp(-(int)Math.round(((double)((my- 22) * 100)) / 12), -100, 100);
if(Math.abs(xdev) < 9) xdev = 0;
if(Math.abs(ydev) < 9) ydev = 0;
CompoundNBT nbt = new CompoundNBT();
nbt.putInt("drop_xdev", xdev);
nbt.putInt("drop_ydev", ydev);
container.onGuiAction(nbt);
} else if(isPointInRegion(129, 40, 44, 10, mouseX, mouseY)) {
int ndrop = (mx-135);
if(ndrop < -1) {
ndrop = container.field(4) - 1; // -
} else if(ndrop >= 34) {
ndrop = container.field(4) + 1; // +
} else {
ndrop = MathHelper.clamp(1+ndrop, 1, BTileEntity.MAX_DROP_COUNT); // slider
}
container.onGuiAction("drop_count", ndrop);
} else if(isPointInRegion(129, 50, 44, 10, mouseX, mouseY)) {
int period = (mx-135);
if(period < -1) {
period = container.field(6) - 3; // -
} else if(period >= 34) {
period = container.field(6) + 3; // +
} else {
period = (int)(0.5 + ((100.0 * period)/34));
}
period = MathHelper.clamp(period, 0, 100);
container.onGuiAction("drop_period", period);
} else if(isPointInRegion(114, 51, 9, 9, mouseX, mouseY)) {
container.onGuiAction("manual_rstrigger", 1);
} else if(isPointInRegion(162, 66, 7, 9, mouseX, mouseY)) {
container.onGuiAction("drop_logic", container.field(5) ^ BTileEntity.DROPLOGIC_CONTINUOUS);
} else if(isPointInRegion(132, 66, 9, 9, mouseX, mouseY)) {
container.onGuiAction("drop_logic", container.field(5) ^ BTileEntity.DROPLOGIC_FILTER_ANDGATE);
} else if(isPointInRegion(148, 66, 9, 9, mouseX, mouseY)) {
container.onGuiAction("drop_logic", container.field(5) ^ BTileEntity.DROPLOGIC_EXTERN_ANDGATE);
}
return true;
}
@Override
protected void drawGuiContainerBackgroundLayer(float partialTicks, int mouseX, int mouseY)
{
RenderSystem.enableBlend();
RenderSystem.color4f(1.0F, 1.0F, 1.0F, 1.0F);
this.minecraft.getTextureManager().bindTexture(new ResourceLocation(ModEngineersDecor.MODID, "textures/gui/factory_dropper_gui.png"));
final int x0=getGuiLeft(), y0=getGuiTop(), w=getXSize(), h=getYSize();
blit(x0, y0, 0, 0, w, h);
BContainer container = (BContainer)getContainer();
// active drop slot
{
int drop_slot_index = container.field(15);
if((drop_slot_index < 0) || (drop_slot_index >= 16)) drop_slot_index = 0;
int x = (x0+9+((drop_slot_index % 6) * 18));
int y = (y0+5+((drop_slot_index / 6) * 17));
blit(x, y, 180, 45, 18, 18);
}
// filter LEDs
{
for(int i=0; i<3; ++i) {
int xt = 180 + (6 * container.field(12+i)), yt = 38;
int x = x0 + 31 + (i * 36), y = y0 + 65;
blit(x, y, xt, yt, 6, 6);
}
}
// force adjustment
{
int hy = 2 + (((100-container.field(0)) * 21) / 100);
int x = x0+135, y = y0+12, xt = 181;
int yt = 4 + (23-hy);
blit(x, y, xt, yt, 3, hy);
}
// angle adjustment
{
int x = x0 + 157 - 3 + ((container.field(1) * 12) / 100);
int y = y0 + 22 - 3 - ((container.field(2) * 12) / 100);
blit(x, y, 180, 30, 7, 7);
}
// drop count
{
int x = x0 + 134 - 2 + (container.field(4));
int y = y0 + 45;
blit(x, y, 190, 31, 5, 5);
}
// drop period
{
int px = (int)Math.round(((33.0 * container.field(6)) / 100) + 1);
int x = x0 + 134 - 2 + MathHelper.clamp(px, 0, 33);
int y = y0 + 56;
blit(x, y, 190, 31, 5, 5);
}
// redstone input
{
if(container.field(11) != 0) {
blit(x0+114, y0+51, 189, 18, 9, 9);
}
}
// trigger logic
{
int filter_gate_offset = ((container.field(5) & BTileEntity.DROPLOGIC_FILTER_ANDGATE) != 0) ? 11 : 0;
int extern_gate_offset = ((container.field(5) & BTileEntity.DROPLOGIC_EXTERN_ANDGATE) != 0) ? 11 : 0;
int pulse_mode_offset = ((container.field(5) & BTileEntity.DROPLOGIC_CONTINUOUS ) != 0) ? 10 : 0;
blit(x0+132, y0+66, 179+filter_gate_offset, 66, 9, 9);
blit(x0+148, y0+66, 179+extern_gate_offset, 66, 9, 9);
blit(x0+162, y0+66, 200+pulse_mode_offset, 66, 9, 9);
}
// drop timer running indicator
{
if((container.field(9) > BTileEntity.DROP_PERIOD_OFFSET) && ((System.currentTimeMillis() % 1000) < 500)) {
blit(x0+149, y0+51, 201, 39, 3, 3);
}
}
RenderSystem.disableBlend();
}
}
}

View file

@ -0,0 +1,115 @@
/*
* @file BlockDecorWall.java
* @author Stefan Wilhelm (wile)
* @copyright (C) 2019 Stefan Wilhelm
* @license MIT (see https://opensource.org/licenses/MIT)
*
* Wall blocks.
*/
package wile.engineersdecor.blocks;
import wile.engineersdecor.detail.ModAuxiliaries;
import net.minecraft.world.*;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.fluid.IFluidState;
import net.minecraft.entity.EntityType;
import net.minecraft.util.math.shapes.ISelectionContext;
import net.minecraft.state.StateContainer;
import net.minecraft.block.*;
import net.minecraft.block.material.PushReaction;
import net.minecraft.block.BlockState;
import net.minecraft.client.util.ITooltipFlag;
import net.minecraft.fluid.Fluids;
import net.minecraft.item.BlockItemUseContext;
import net.minecraft.item.ItemStack;
import net.minecraft.util.Direction;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.shapes.VoxelShape;
import net.minecraft.util.text.ITextComponent;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import javax.annotation.Nullable;
import java.util.List;
public class BlockDecorFence extends WallBlock implements IDecorBlock
{
private final VoxelShape[] shape_voxels;
private final VoxelShape[] collision_shape_voxels;
public BlockDecorFence(long config, Block.Properties builder)
{
super(builder);
this.shape_voxels = buildWallShapes(1.5f, 1.5f, 16f, 0f, 16f);
this.collision_shape_voxels = buildWallShapes(1.5f, 1.5f, 24f, 0f, 24f);
}
@Override
@OnlyIn(Dist.CLIENT)
public void addInformation(ItemStack stack, @Nullable IBlockReader world, List<ITextComponent> tooltip, ITooltipFlag flag)
{ ModAuxiliaries.Tooltip.addInformation(stack, world, tooltip, flag, true); }
protected VoxelShape[] buildWallShapes(float pole_width_x, float pole_width_z, float pole_height, float side_min_y, float side_max_y)
{ return super.makeShapes(pole_width_x, pole_width_z, pole_height, side_min_y, side_max_y); }
@Override
public VoxelShape getShape(BlockState state, IBlockReader world, BlockPos pos, ISelectionContext selectionContext)
{ return shape_voxels[this.getIndex(state)]; }
@Override
public VoxelShape getCollisionShape(BlockState state, IBlockReader world, BlockPos pos, ISelectionContext selectionContext)
{ return collision_shape_voxels[this.getIndex(state)]; }
@Override
protected void fillStateContainer(StateContainer.Builder<Block, BlockState> builder)
{ super.fillStateContainer(builder); }
private boolean attachesTo(BlockState facingState, IWorldReader world, BlockPos facingPos, Direction side)
{
final Block block = facingState.getBlock();
if((block instanceof FenceGateBlock) || (block instanceof BlockDecorFence) || (block instanceof BlockDecorWall)) return true;
final BlockState oppositeState = world.getBlockState(facingPos.offset(side, 2));
if(!(oppositeState.getBlock() instanceof BlockDecorFence)) return false;
return facingState.isNormalCube(world, facingPos) && hasSolidSide(facingState, world, facingPos, side);
}
public BlockState getStateForPlacement(BlockItemUseContext context)
{
IWorldReader world = context.getWorld();
BlockPos pos = context.getPos();
IFluidState fs = context.getWorld().getFluidState(context.getPos());
boolean n = attachesTo(world.getBlockState(pos.north()), world, pos.north(), Direction.SOUTH);
boolean e = attachesTo(world.getBlockState(pos.east()), world, pos.east(), Direction.WEST);
boolean s = attachesTo(world.getBlockState(pos.south()), world, pos.south(), Direction.NORTH);
boolean w = attachesTo(world.getBlockState(pos.west()), world, pos.west(), Direction.EAST);
boolean not_straight = (!n || !s || e || w) && (n || s || !e || !w);
return getDefaultState().with(UP, not_straight).with(NORTH, n).with(EAST, e).with(SOUTH, s).with(WEST, w).with(WATERLOGGED, fs.getFluid() == Fluids.WATER);
}
@Override
public BlockState updatePostPlacement(BlockState state, Direction side, BlockState facingState, IWorld world, BlockPos currentPos, BlockPos facingPos)
{
if(state.get(WATERLOGGED)) world.getPendingFluidTicks().scheduleTick(currentPos, Fluids.WATER, Fluids.WATER.getTickRate(world));
if(side == Direction.DOWN) return super.updatePostPlacement(state, side, facingState, world, currentPos, facingPos);
boolean n = (side==Direction.NORTH) ? attachesTo(facingState, world, facingPos, side) : state.get(NORTH);
boolean e = (side==Direction.EAST) ? attachesTo(facingState, world, facingPos, side) : state.get(EAST);
boolean s = (side==Direction.SOUTH) ? attachesTo(facingState, world, facingPos, side) : state.get(SOUTH);
boolean w = (side==Direction.WEST) ? attachesTo(facingState, world, facingPos, side) : state.get(WEST);
boolean not_straight = (!n || !s || e || w) && (n || s || !e || !w);
return state.with(UP, not_straight).with(NORTH, n).with(EAST, e).with(SOUTH, s).with(WEST, w);
}
@Override
@SuppressWarnings("deprecation")
public boolean canEntitySpawn(BlockState state, IBlockReader world, BlockPos pos, EntityType<?> entityType)
{ return false; }
@Override
public boolean canSpawnInBlock()
{ return false; }
@Override
@SuppressWarnings("deprecation")
public PushReaction getPushReaction(BlockState state)
{ return PushReaction.NORMAL; }
}

View file

@ -0,0 +1,74 @@
/*
* @file BlockDecorFloorGrating.java
* @author Stefan Wilhelm (wile)
* @copyright (C) 2019 Stefan Wilhelm
* @license MIT (see https://opensource.org/licenses/MIT)
*
* Floor gratings.
*/
package wile.engineersdecor.blocks;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.entity.Entity;
import net.minecraft.entity.item.ItemEntity;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.shapes.ISelectionContext;
import net.minecraft.util.math.shapes.VoxelShape;
import net.minecraft.util.math.shapes.VoxelShapes;
import net.minecraft.world.IBlockReader;
import net.minecraft.world.World;
public class BlockDecorFloorGrating extends BlockDecor.WaterLoggable
{
public BlockDecorFloorGrating(long config, Block.Properties builder, final AxisAlignedBB unrotatedAABB)
{ super(config|CFG_WATERLOGGABLE, builder, unrotatedAABB); }
@Override
public RenderTypeHint getRenderTypeHint()
{ return RenderTypeHint.CUTOUT; }
@Override
public boolean propagatesSkylightDown(BlockState state, IBlockReader reader, BlockPos pos)
{ return true; }
@Override
public void onLanded(IBlockReader world, Entity entity)
{
if(!(entity instanceof ItemEntity)) {
super.onLanded(world, entity);
} else {
entity.setMotion(0, -0.1,0);
entity.setPositionAndUpdate(entity.getPosition().getX(), entity.getPosition().getY()-0.3, entity.getPosition().getZ());
}
}
@Override
public void onFallenUpon(World world, BlockPos pos, Entity entity, float fallDistance)
{
if(!(entity instanceof ItemEntity)) {
super.onFallenUpon(world, pos, entity, fallDistance);
} else {
entity.setMotion(0, -0.1,0);
entity.setPositionAndUpdate(entity.getPosition().getX(), entity.getPosition().getY()-0.3, entity.getPosition().getZ());
}
}
@Override
@SuppressWarnings("deprecation")
public void onEntityCollision(BlockState state, World world, BlockPos pos, Entity entity)
{
if(!(entity instanceof ItemEntity)) return;
if((entity.getPosition().getY()-pos.getY()) < 0.7) return;
double vy = MathHelper.clamp(entity.getMotion().y, -1.2, -0.2);
entity.setMotion(0, vy, 0);
entity.setPositionAndUpdate(pos.getX()+0.5, entity.getPosition().getY()-0.3, pos.getZ()+0.5);
}
@Override
public VoxelShape getCollisionShape(BlockState state, IBlockReader world, BlockPos pos, ISelectionContext context)
{ return (context.getEntity() instanceof ItemEntity) ? VoxelShapes.empty() : super.getCollisionShape(state, world, pos, context); }
}

View file

@ -0,0 +1,392 @@
/*
* @file BlockDecorFluidFunnel.java
* @author Stefan Wilhelm (wile)
* @copyright (C) 2019 Stefan Wilhelm
* @license MIT (see https://opensource.org/licenses/MIT)
*
* A device that collects and stores fluid blocks above it.
* Tracks flowing fluid to their source blocks. Compatible
* with vanilla infinite water source.
*/
package wile.engineersdecor.blocks;
import wile.engineersdecor.ModContent;
import net.minecraft.block.*;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.BlockItemUseContext;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.state.IntegerProperty;
import net.minecraft.state.StateContainer;
import net.minecraft.fluid.Fluid;
import net.minecraft.fluid.Fluids;
import net.minecraft.fluid.IFluidState;
import net.minecraft.tileentity.ITickableTileEntity;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.tileentity.TileEntityType;
import net.minecraft.util.Direction;
import net.minecraft.util.Hand;
import net.minecraft.util.math.*;
import net.minecraft.world.IBlockReader;
import net.minecraft.world.World;
import net.minecraftforge.common.capabilities.ICapabilityProvider;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.fluids.*;
import net.minecraftforge.fluids.capability.CapabilityFluidHandler;
import net.minecraftforge.fluids.capability.IFluidHandler;
import net.minecraftforge.fluids.capability.IFluidHandler.FluidAction;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.*;
public class BlockDecorFluidFunnel extends BlockDecor
{
public static final int FILL_LEVEL_MAX = 3;
public static final IntegerProperty FILL_LEVEL = IntegerProperty.create("level", 0, FILL_LEVEL_MAX);
public BlockDecorFluidFunnel(long config, Block.Properties builder, final AxisAlignedBB unrotatedAABB)
{ super(config, builder, unrotatedAABB); }
@Override
public RenderTypeHint getRenderTypeHint()
{ return RenderTypeHint.CUTOUT; }
@Override
protected void fillStateContainer(StateContainer.Builder<Block, BlockState> builder)
{ super.fillStateContainer(builder); builder.add(FILL_LEVEL); }
@Override
@Nullable
public BlockState getStateForPlacement(BlockItemUseContext context)
{ return super.getStateForPlacement(context).with(FILL_LEVEL, 0); }
@Override
public boolean hasTileEntity(BlockState state)
{ return true; }
@Override
@Nullable
public TileEntity createTileEntity(BlockState state, IBlockReader world)
{ return new BTileEntity(); }
@Override
@SuppressWarnings("deprecation")
public boolean hasComparatorInputOverride(BlockState state)
{ return true; }
@Override
@SuppressWarnings("deprecation")
public int getComparatorInputOverride(BlockState state, World world, BlockPos pos)
{ return MathHelper.clamp((state.get(FILL_LEVEL)*5), 0, 15); }
@Override
public void onBlockPlacedBy(World world, BlockPos pos, BlockState state, LivingEntity placer, ItemStack stack)
{
if(world.isRemote) return;
if((!stack.hasTag()) || (!stack.getTag().contains("tedata"))) return;
CompoundNBT te_nbt = stack.getTag().getCompound("tedata");
if(te_nbt.isEmpty()) return;
final TileEntity te = world.getTileEntity(pos);
if(!(te instanceof BTileEntity)) return;
((BTileEntity)te).readnbt(te_nbt);
((BTileEntity)te).markDirty();
world.setBlockState(pos, state.with(FILL_LEVEL, 0));
}
@Override
public boolean hasDynamicDropList()
{ return true; }
@Override
public List<ItemStack> dropList(BlockState state, World world, BlockPos pos, boolean explosion)
{
final List<ItemStack> stacks = new ArrayList<ItemStack>();
if(world.isRemote) return stacks;
final TileEntity te = world.getTileEntity(pos);
if(!(te instanceof BTileEntity)) return stacks;
if(!explosion) {
ItemStack stack = new ItemStack(this, 1);
CompoundNBT te_nbt = new CompoundNBT();
((BTileEntity)te).writenbt(te_nbt);
if(!te_nbt.isEmpty()) {
CompoundNBT nbt = new CompoundNBT();
nbt.put("tedata", te_nbt);
stack.setTag(nbt);
}
stacks.add(stack);
} else {
stacks.add(new ItemStack(this, 1));
}
return stacks;
}
@Override
@SuppressWarnings("deprecation")
public boolean onBlockActivated(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockRayTraceResult rayTraceResult)
{
if(world.isRemote) return true;
TileEntity te = world.getTileEntity(pos);
if(!(te instanceof BTileEntity)) return false;
return FluidUtil.interactWithFluidHandler(player, hand, world, pos, rayTraceResult.getFace());
}
@Override
@SuppressWarnings("deprecation")
public void neighborChanged(BlockState state, World world, BlockPos pos, Block block, BlockPos fromPos, boolean unused)
{ TileEntity te = world.getTileEntity(pos); if(te instanceof BTileEntity) ((BTileEntity)te).block_changed(); }
//--------------------------------------------------------------------------------------------------------------------
// Tile entity
//--------------------------------------------------------------------------------------------------------------------
public static class BTileEntity extends TileEntity implements ITickableTileEntity, ICapabilityProvider
{
public static final int TANK_CAPACITY = 3000;
public static final int TICK_INTERVAL = 10; // ca 500ms
public static final int COLLECTION_INTERVAL = 40; // ca 2000ms, simulates suction delay and saves CPU when not drained.
public static final int MAX_TRACK_RADIUS = 16;
public static final int MAX_TRACKING_STEPS_PER_CYCLE = 72;
public static final int MAX_TRACKING_STEPS_PER_CYCLE_INTENSIVE = 1024;
public static final int MAX_TRACK_RADIUS_SQ = MAX_TRACK_RADIUS*MAX_TRACK_RADIUS;
public static final int INTENSIVE_SEARCH_TRIGGER_THRESHOLD = 16;
private FluidStack tank_ = FluidStack.EMPTY;
private int tick_timer_ = 0;
private int collection_timer_ = 0;
private int no_fluid_found_counter_ = 0;
private int intensive_search_counter_ = 0;
private int total_pick_counter_ = 0;
private BlockPos last_pick_pos_ = BlockPos.ZERO;
private ArrayList<Vec3i> search_offsets_ = null;
public void block_changed()
{ tick_timer_ = TICK_INTERVAL; } // collect after flowing fluid has a stable state, otherwise it looks odd.
public BTileEntity()
{ this(ModContent.TET_SMALL_FLUID_FUNNEL); }
public BTileEntity(TileEntityType<?> te_type)
{ super(te_type); }
public void readnbt(CompoundNBT nbt)
{
tank_ = (!nbt.contains("tank")) ? (FluidStack.EMPTY) : (FluidStack.loadFluidStackFromNBT(nbt.getCompound("tank")));
}
public void writenbt(CompoundNBT nbt)
{
if(!tank_.isEmpty()) nbt.put("tank", tank_.writeToNBT(new CompoundNBT()));
}
// TileEntity -----------------------------------------------------------------------------------------
@Override
public void read(CompoundNBT nbt)
{ super.read(nbt); readnbt(nbt); }
@Override
public CompoundNBT write(CompoundNBT nbt)
{ super.write(nbt); writenbt(nbt); return nbt; }
// ICapabilityProvider / Output flow handler ----------------------------------------------------------
private static class OutputFluidHandler implements IFluidHandler
{
private final BTileEntity te;
OutputFluidHandler(BTileEntity parent) { te = parent; }
@Override public int getTanks() { return 1; }
@Override public FluidStack getFluidInTank(int tank) { return te.tank_.copy(); }
@Override public int getTankCapacity(int tank) { return TANK_CAPACITY; }
@Override public boolean isFluidValid(int tank, @Nonnull FluidStack stack) { return true; }
@Override public int fill(FluidStack resource, FluidAction action) { return 0; }
@Override public FluidStack drain(FluidStack resource, FluidAction action)
{
if((resource==null) || (te.tank_.isEmpty())) return FluidStack.EMPTY;
return (!(te.tank_.isFluidEqual(resource))) ? (FluidStack.EMPTY) : drain(resource.getAmount(), action);
}
@Override public FluidStack drain(int maxDrain, FluidAction action)
{
if(te.tank_.isEmpty()) return FluidStack.EMPTY;
FluidStack res = te.tank_.copy();
maxDrain = MathHelper.clamp(maxDrain ,0 , te.tank_.getAmount());
res.setAmount(maxDrain);
if(action != FluidAction.EXECUTE) return res;
te.tank_.setAmount(te.tank_.getAmount()-maxDrain);
if(te.tank_.getAmount() <= 0) te.tank_ = FluidStack.EMPTY;
return res;
}
}
private final LazyOptional<IFluidHandler> fluid_handler_ = LazyOptional.of(() -> new OutputFluidHandler(this));
@Override
public <T> LazyOptional<T> getCapability(net.minecraftforge.common.capabilities.Capability<T> capability, @Nullable Direction facing)
{
if(capability == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY) return fluid_handler_.cast();
return super.getCapability(capability, facing);
}
// ITickableTileEntity --------------------------------------------------------------------------------
private IFluidState get_fluidstate(BlockPos pos)
{
// todo: check if getFluidState() is enough
final Block collection_block = world.getBlockState(pos).getBlock();
if((!(collection_block instanceof IFluidBlock)) && (!(collection_block instanceof FlowingFluidBlock)) && (!(collection_block instanceof IWaterLoggable))) {
return Fluids.EMPTY.getDefaultState();
}
return world.getFluidState(pos);
}
private boolean try_pick(BlockPos pos, IFluidState fluidstate)
{
if(!fluidstate.isSource()) return false;
IFluidHandler hnd = FluidUtil.getFluidHandler(world, pos, null).orElse(null);
FluidStack fs;
if(hnd != null) {
fs = hnd.drain(TANK_CAPACITY, FluidAction.EXECUTE); // IFluidBlock
} else {
fs = new FluidStack(fluidstate.getFluid(), 1000);
BlockState state = world.getBlockState(pos);
if(state instanceof IBucketPickupHandler) {
((IBucketPickupHandler)state).pickupFluid(world, pos, state);
} else {
world.setBlockState(pos, Blocks.AIR.getDefaultState(), 1|2); // ok we can't leave the block, that would be an infinite source of an unknown fluid.
}
}
if((fs==null) || (fs.isEmpty())) return false; // it's marked nonnull but I don't trust every modder - including meself ...
if(tank_.isEmpty()) {
tank_ = fs.copy();
} else if(tank_.isFluidEqual(fs)) {
tank_.setAmount(MathHelper.clamp(tank_.getAmount()+fs.getAmount(), 0, TANK_CAPACITY));
} else {
return false;
}
return true;
}
private boolean can_pick(BlockPos pos, IFluidState fluidstate)
{
if(fluidstate.isSource()) return true;
IFluidHandler hnd = FluidUtil.getFluidHandler(world, pos, null).orElse(null);
if(hnd == null) return false;
FluidStack fs = hnd.drain(TANK_CAPACITY, FluidAction.SIMULATE); // don't trust that everyone returns nonnull
return ((fs!=null) && (!fs.isEmpty())) && (fluidstate.getFluid().isEquivalentTo(fs.getFluid()));
}
private void rebuild_search_offsets(boolean intensive)
{
search_offsets_ = new ArrayList<>(9);
search_offsets_.add(new Vec3i(0, 1, 0)); // up first
{
ArrayList<Vec3i> ofs = new ArrayList<Vec3i>(Arrays.asList(new Vec3i(-1, 0, 0), new Vec3i( 1, 0, 0), new Vec3i( 0, 0,-1), new Vec3i( 0, 0, 1)));
if(intensive || (total_pick_counter_ > 50)) Collections.shuffle(ofs);
search_offsets_.addAll(ofs);
}
if(intensive) {
ArrayList<Vec3i> ofs = new ArrayList<Vec3i>(Arrays.asList(new Vec3i(-1, 1, 0), new Vec3i( 1, 1, 0), new Vec3i( 0, 1,-1), new Vec3i( 0, 1, 1)));
Collections.shuffle(ofs);
search_offsets_.addAll(ofs);
}
}
private boolean try_collect(final BlockPos collection_pos)
{
IFluidState collection_fluidstate = get_fluidstate(collection_pos);
if(collection_fluidstate.isEmpty()) return false;
Fluid fluid_to_collect = collection_fluidstate.getFluid();
if((!tank_.isEmpty()) && (!tank_.getFluid().isEquivalentTo(fluid_to_collect))) return false;
if(try_pick(collection_pos, collection_fluidstate)) { last_pick_pos_ = collection_pos; return true; } // Blocks directly always first. Allows water source blocks to recover/reflow to source blocks.
if((last_pick_pos_==null) || (last_pick_pos_.distanceSq(collection_pos) > MAX_TRACK_RADIUS_SQ)) { last_pick_pos_ = collection_pos; search_offsets_ = null; }
BlockPos pos = last_pick_pos_;
HashSet<BlockPos> checked = new HashSet<>();
Stack<BlockPos> trail = new Stack<BlockPos>();
trail.add(pos);
checked.add(pos);
int steps=0;
boolean intensive = (no_fluid_found_counter_ >= INTENSIVE_SEARCH_TRIGGER_THRESHOLD);
if(intensive) { no_fluid_found_counter_ = 0; ++intensive_search_counter_; }
if(search_offsets_ == null) rebuild_search_offsets(intensive);
int max = intensive ? MAX_TRACKING_STEPS_PER_CYCLE_INTENSIVE : MAX_TRACKING_STEPS_PER_CYCLE;
while(++steps <= max) {
int num_adjacent = 0;
for(int i=0; i<search_offsets_.size(); ++i) {
BlockPos p = pos.add(search_offsets_.get(i));
if(checked.contains(p)) continue;
checked.add(p);
++steps;
IFluidState fluidstate = get_fluidstate(p);
if(fluidstate.getFluid().isEquivalentTo(fluid_to_collect)) {
++num_adjacent;
pos = p;
trail.push(pos);
if(steps < MAX_TRACKING_STEPS_PER_CYCLE_INTENSIVE/2) {
// check for same fluid above (only source blocks)
final int max_surface_search = (MAX_TRACKING_STEPS_PER_CYCLE_INTENSIVE/2)-steps;
for(int k=0; k<max_surface_search; ++k) {
IFluidState fs = get_fluidstate(pos.up());
if(!can_pick(pos.up(), fs)) break;
fluidstate = fs;
pos = pos.up();
trail.push(pos);
}
}
if(try_pick(pos, fluidstate)) {
last_pick_pos_ = pos;
no_fluid_found_counter_ = 0;
search_offsets_ = null;
// probability reset, so it's not turteling too far away, mainly for large nether lava seas, not desert lakes.
if((++total_pick_counter_ > 50) && world.rand.nextInt(10)==0) last_pick_pos_ = collection_pos;
//println("PASS " + steps + " - " + (pos.subtract(collection_pos)));
return true;
}
}
}
if(trail.isEmpty()) break; // reset search
if(num_adjacent==0) pos = trail.pop();
}
//println("FAIL=" + steps + " - " + (pos.subtract(collection_pos)));
//String s = new String(); for(BlockPos p:checked) s += "\n" + p; println(s);
if(intensive_search_counter_ > 2) world.removeBlock(pos, false);
last_pick_pos_ = collection_pos;
search_offsets_ = null; // try other search order
++no_fluid_found_counter_;
return false;
}
public void tick()
{
if((world.isRemote) || (--tick_timer_ > 0)) return;
tick_timer_ = TICK_INTERVAL;
collection_timer_ += TICK_INTERVAL;
boolean dirty = false;
// Collection
if((collection_timer_ >= COLLECTION_INTERVAL) && ((tank_==null) || (tank_.getAmount() <= (TANK_CAPACITY-1000)))) {
collection_timer_ = 0;
if(!world.isBlockPowered(pos)) { // redstone disable feature
if(last_pick_pos_==null) last_pick_pos_ = pos.up();
if(try_collect(pos.up())) dirty = true;
}
}
// Gravity fluid transfer
if((tank_.getAmount() >= 1000)) {
IFluidHandler fh = FluidUtil.getFluidHandler(world, pos.down(), Direction.UP).orElse(null);
if(fh != null) {
FluidStack fs = new FluidStack(tank_.getFluid(), 1000);
int nfilled = MathHelper.clamp(fh.fill(fs, FluidAction.EXECUTE), 0, 1000);
tank_.shrink(nfilled);
dirty = true;
}
}
// Block state
int fill_level = (tank_==null) ? 0 : (MathHelper.clamp(tank_.getAmount()/1000,0,FILL_LEVEL_MAX));
final BlockState funnel_state = world.getBlockState(pos);
if(funnel_state.get(FILL_LEVEL) != fill_level) world.setBlockState(pos, funnel_state.with(FILL_LEVEL, fill_level), 2|16);
if(dirty) markDirty();
}
}
}

View file

@ -0,0 +1,997 @@
/*
* @file BlockFurnace.java
* @author Stefan Wilhelm (wile)
* @copyright (C) 2019 Stefan Wilhelm
* @license MIT (see https://opensource.org/licenses/MIT)
*
* ED Lab furnace.
*/
package wile.engineersdecor.blocks;
import wile.engineersdecor.ModContent;
import wile.engineersdecor.ModEngineersDecor;
import wile.engineersdecor.detail.ExtItems;
import wile.engineersdecor.detail.Networking;
import net.minecraft.tileentity.*;
import net.minecraft.inventory.container.*;
import net.minecraft.item.crafting.AbstractCookingRecipe;
import net.minecraft.item.crafting.IRecipeType;
import net.minecraft.block.RedstoneTorchBlock;
import net.minecraft.client.gui.screen.inventory.ContainerScreen;
import net.minecraft.entity.item.ExperienceOrbEntity;
import net.minecraft.item.crafting.FurnaceRecipe;
import net.minecraft.item.crafting.IRecipe;
import net.minecraft.particles.ParticleTypes;
import net.minecraft.stats.Stats;
import net.minecraft.util.math.BlockRayTraceResult;
import net.minecraft.world.IBlockReader;
import net.minecraft.entity.player.ServerPlayerEntity;
import net.minecraft.util.SoundEvents;
import net.minecraft.state.BooleanProperty;
import net.minecraft.state.StateContainer;
import net.minecraft.util.text.StringTextComponent;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.world.World;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.item.Items;
import net.minecraft.item.*;
import net.minecraft.inventory.*;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.*;
import net.minecraftforge.common.ForgeHooks;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.energy.CapabilityEnergy;
import net.minecraftforge.fml.hooks.BasicEventHooks;
import net.minecraftforge.fml.network.NetworkHooks;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.common.util.FakePlayer;
import net.minecraftforge.energy.IEnergyStorage;
import net.minecraftforge.items.CapabilityItemHandler;
import net.minecraftforge.items.IItemHandler;
import net.minecraftforge.items.wrapper.SidedInvWrapper;
import com.mojang.blaze3d.systems.RenderSystem;
import javax.annotation.Nullable;
import java.util.*;
public class BlockDecorFurnace extends BlockDecorDirected
{
public static final BooleanProperty LIT = RedstoneTorchBlock.LIT;
public BlockDecorFurnace(long config, Block.Properties builder, final AxisAlignedBB unrotatedAABB)
{
super(config, builder, unrotatedAABB);
setDefaultState(stateContainer.getBaseState().with(FACING, Direction.NORTH).with(LIT, false));
}
@Override
protected void fillStateContainer(StateContainer.Builder<Block, BlockState> builder)
{ super.fillStateContainer(builder); builder.add(LIT); }
@Override
@SuppressWarnings("deprecation")
public int getLightValue(BlockState state)
{ return state.get(LIT) ? super.getLightValue(state) : 0; }
@Override
@Nullable
public BlockState getStateForPlacement(BlockItemUseContext context)
{ return super.getStateForPlacement(context).with(FACING, context.getPlacementHorizontalFacing().getOpposite()).with(LIT, false); }
@Override
@SuppressWarnings("deprecation")
public boolean hasComparatorInputOverride(BlockState state)
{ return true; }
@Override
@SuppressWarnings("deprecation")
public int getComparatorInputOverride(BlockState blockState, World world, BlockPos pos)
{ return Container.calcRedstone(world.getTileEntity(pos)); }
@Override
public boolean hasTileEntity(BlockState state)
{ return true; }
@Override
@Nullable
public TileEntity createTileEntity(BlockState state, IBlockReader world)
{ return new BlockDecorFurnace.BTileEntity(); }
@Override
public void onBlockPlacedBy(World world, BlockPos pos, BlockState state, LivingEntity placer, ItemStack stack)
{
world.setBlockState(pos, state.with(LIT, false));
if(world.isRemote) return;
if((!stack.hasTag()) || (!stack.getTag().contains("inventory"))) return;
CompoundNBT inventory_nbt = stack.getTag().getCompound("inventory");
if(inventory_nbt.isEmpty()) return;
final TileEntity te = world.getTileEntity(pos);
if(!(te instanceof BlockDecorFurnace.BTileEntity)) return;
final BlockDecorFurnace.BTileEntity bte = ((BlockDecorFurnace.BTileEntity)te);
bte.readnbt(inventory_nbt);
bte.markDirty();
world.setBlockState(pos, state.with(LIT, bte.burning()));
}
@Override
public boolean hasDynamicDropList()
{ return true; }
@Override
public List<ItemStack> dropList(BlockState state, World world, BlockPos pos, boolean explosion) {
final List<ItemStack> stacks = new ArrayList<ItemStack>();
if(world.isRemote) return stacks;
final TileEntity te = world.getTileEntity(pos);
if(!(te instanceof BTileEntity)) return stacks;
if(!explosion) {
ItemStack stack = new ItemStack(this, 1);
CompoundNBT inventory_nbt = ((BTileEntity)te).reset_getnbt();
if(!inventory_nbt.isEmpty()) {
CompoundNBT nbt = new CompoundNBT();
nbt.put("inventory", inventory_nbt);
stack.setTag(nbt);
}
stacks.add(stack);
} else {
for(ItemStack stack: ((BTileEntity)te).stacks_) stacks.add(stack);
((BTileEntity)te).reset();
}
return stacks;
}
@Override
@SuppressWarnings("deprecation")
public boolean onBlockActivated(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockRayTraceResult rayTraceResult)
{
if(world.isRemote) return true;
final TileEntity te = world.getTileEntity(pos);
if(!(te instanceof BlockDecorFurnace.BTileEntity)) return true;
if((!(player instanceof ServerPlayerEntity) && (!(player instanceof FakePlayer)))) return true;
NetworkHooks.openGui((ServerPlayerEntity)player,(INamedContainerProvider)te);
player.addStat(Stats.INTERACT_WITH_FURNACE);
return true;
}
@Override
@OnlyIn(Dist.CLIENT)
public void animateTick(BlockState state, World world, BlockPos pos, Random rnd)
{
if((state.getBlock()!=this) || (!state.get(LIT))) return;
final double rv = rnd.nextDouble();
if(rv > 0.5) return;
final double x=0.5+pos.getX(), y=0.5+pos.getY(), z=0.5+pos.getZ();
final double xc=0.52, xr=rnd.nextDouble()*0.4-0.2, yr=(y-0.3+rnd.nextDouble()*0.2);
if(rv < 0.1d) world.playSound(x, y, z, SoundEvents.BLOCK_FURNACE_FIRE_CRACKLE, SoundCategory.BLOCKS, 0.4f, 0.5f, false);
switch(state.get(FACING)) {
case WEST: world.addParticle(ParticleTypes.SMOKE, x-xc, yr, z+xr, 0.0, 0.0, 0.0); break;
case EAST: world.addParticle(ParticleTypes.SMOKE, x+xc, yr, z+xr, 0.0, 0.0, 0.0); break;
case NORTH: world.addParticle(ParticleTypes.SMOKE, x+xr, yr, z-xc, 0.0, 0.0, 0.0); break;
default: world.addParticle(ParticleTypes.SMOKE, x+xr, yr, z+xc, 0.0, 0.0, 0.0); break;
}
}
//--------------------------------------------------------------------------------------------------------------------
// Tile entity
//--------------------------------------------------------------------------------------------------------------------
public static class BTileEntity extends TileEntity implements ITickableTileEntity, INameable, IInventory, INamedContainerProvider, ISidedInventory, IEnergyStorage
{
public static final IRecipeType<FurnaceRecipe> RECIPE_TYPE = IRecipeType.SMELTING;
public static final int NUM_OF_FIELDS = 5;
public static final int TICK_INTERVAL = 4;
public static final int FIFO_INTERVAL = 20;
public static final int STD_SMELTING_TIME = 200;
public static final int MAX_BURNTIME = 0x7fff;
public static final int DEFAULT_BOOST_ENERGY = 32;
public static final int NUM_OF_SLOTS = 11;
public static final int SMELTING_INPUT_SLOT_NO = 0;
public static final int SMELTING_FUEL_SLOT_NO = 1;
public static final int SMELTING_OUTPUT_SLOT_NO = 2;
public static final int FIFO_INPUT_0_SLOT_NO = 3;
public static final int FIFO_INPUT_1_SLOT_NO = 4;
public static final int FIFO_FUEL_0_SLOT_NO = 5;
public static final int FIFO_FUEL_1_SLOT_NO = 6;
public static final int FIFO_OUTPUT_0_SLOT_NO = 7;
public static final int FIFO_OUTPUT_1_SLOT_NO = 8;
public static final int AUX_0_SLOT_NO = 9;
public static final int AUX_1_SLOT_NO =10;
// Config ----------------------------------------------------------------------------------
private static double proc_fuel_efficiency_ = 1.0;
private static double proc_speed_ = 1.2;
private static int boost_energy_consumption = DEFAULT_BOOST_ENERGY * TICK_INTERVAL;
public static void on_config(int speed_percent, int fuel_efficiency_percent, int boost_energy_per_tick)
{
proc_speed_ = ((double)MathHelper.clamp(speed_percent, 10, 500)) / 100;
proc_fuel_efficiency_ = ((double) MathHelper.clamp(fuel_efficiency_percent, 10, 500)) / 100;
boost_energy_consumption = TICK_INTERVAL * MathHelper.clamp(boost_energy_per_tick, 16, 512);
ModEngineersDecor.logger().info("Config lab furnace speed:" + (proc_speed_*100) + "%, efficiency:" + (proc_fuel_efficiency_*100) + "%");
}
// BTileEntity -----------------------------------------------------------------------------
private int tick_timer_;
private int fifo_timer_;
private int burntime_left_;
private int fuel_burntime_;
private double proc_time_elapsed_;
private int proc_time_needed_;
private int field_is_burning_;
private int field_proc_time_elapsed_;
private int boost_energy_; // small, not saved in nbt.
private boolean heater_inserted_ = false;
protected NonNullList<ItemStack> stacks_;
protected @Nullable IRecipe current_recipe_ = null;
private final List<String> recent_recipes_ = new ArrayList<>();
public BTileEntity()
{ this(ModContent.TET_SMALL_LAB_FURNACE); }
public BTileEntity(TileEntityType<?> te_type)
{ super(te_type); reset(); }
public CompoundNBT reset_getnbt()
{
CompoundNBT nbt = new CompoundNBT();
writenbt(nbt);
reset();
return nbt;
}
public void reset()
{
stacks_ = NonNullList.<ItemStack>withSize(NUM_OF_SLOTS, ItemStack.EMPTY);
proc_time_elapsed_ = 0;
proc_time_needed_ = 0;
burntime_left_ = 0;
fuel_burntime_ = 0;
fifo_timer_ = 0;
tick_timer_ = 0;
current_recipe_ = null;
}
public void readnbt(CompoundNBT nbt)
{
ItemStackHelper.loadAllItems(nbt, stacks_);
while(stacks_.size() < NUM_OF_SLOTS) stacks_.add(ItemStack.EMPTY);
burntime_left_ = nbt.getInt("BurnTime");
proc_time_elapsed_ = nbt.getInt("CookTime");
proc_time_needed_ = nbt.getInt("CookTimeTotal");
fuel_burntime_ = nbt.getInt("FuelBurnTime");
CompoundNBT rr = nbt.getCompound("Recipes");
for(int i=0; i<rr.size(); ++i) {
String recipe_id = rr.getString(Integer.toString(i));
if(recipe_id.isEmpty()) break; // no further processing, nbt data set broken.
recent_recipes_.add(recipe_id);
}
}
private void writenbt(CompoundNBT nbt)
{
nbt.putInt("BurnTime", MathHelper.clamp(burntime_left_,0 , MAX_BURNTIME));
nbt.putInt("CookTime", MathHelper.clamp((int)proc_time_elapsed_, 0, MAX_BURNTIME));
nbt.putInt("CookTimeTotal", MathHelper.clamp(proc_time_needed_, 0, MAX_BURNTIME));
nbt.putInt("FuelBurnTime", MathHelper.clamp(fuel_burntime_, 0, MAX_BURNTIME));
ItemStackHelper.saveAllItems(nbt, stacks_);
CompoundNBT rr = new CompoundNBT();
for(int i=0; i<recent_recipes_.size(); ++i) rr.putString(Integer.toString(i), recent_recipes_.get(i));
nbt.put("Recipes", rr);
}
// TileEntity ------------------------------------------------------------------------------
@Override
public void read(CompoundNBT nbt)
{ super.read(nbt); readnbt(nbt); }
@Override
public CompoundNBT write(CompoundNBT nbt)
{ super.write(nbt); writenbt(nbt); return nbt; }
// INamedContainerProvider / INameable ------------------------------------------------------
@Override
public ITextComponent getName()
{ final Block block=getBlockState().getBlock(); return new StringTextComponent((block!=null) ? block.getTranslationKey() : "Lab furnace"); }
@Override
public boolean hasCustomName()
{ return false; }
@Override
public ITextComponent getCustomName()
{ return getName(); }
// IContainerProvider ----------------------------------------------------------------------
@Override
public ITextComponent getDisplayName()
{ return INameable.super.getDisplayName(); }
@Override
public Container createMenu(int id, PlayerInventory inventory, PlayerEntity player )
{ return new BlockDecorFurnace.BContainer(id, inventory, this, IWorldPosCallable.of(world, pos), fields); }
// IInventory ------------------------------------------------------------------------------
@Override
public int getSizeInventory()
{ return stacks_.size(); }
@Override
public boolean isEmpty()
{ for(ItemStack stack: stacks_) { if(!stack.isEmpty()) return false; } return true; }
@Override
public ItemStack getStackInSlot(int index)
{ return (index < getSizeInventory()) ? stacks_.get(index) : ItemStack.EMPTY; }
@Override
public ItemStack decrStackSize(int index, int count)
{ return ItemStackHelper.getAndSplit(stacks_, index, count); }
@Override
public ItemStack removeStackFromSlot(int index)
{ return ItemStackHelper.getAndRemove(stacks_, index); }
@Override
public void setInventorySlotContents(int index, ItemStack stack)
{
ItemStack slot_stack = stacks_.get(index);
boolean already_in_slot = (!stack.isEmpty()) && (stack.isItemEqual(slot_stack)) && (ItemStack.areItemStackTagsEqual(stack, slot_stack));
stacks_.set(index, stack);
if(stack.getCount() > getInventoryStackLimit()) stack.setCount(getInventoryStackLimit());
if((index == SMELTING_INPUT_SLOT_NO) && (!already_in_slot)) {
proc_time_needed_ = getSmeltingTimeNeeded(world, stack);
proc_time_elapsed_ = 0;
markDirty();
}
}
@Override
public int getInventoryStackLimit()
{ return 64; }
@Override
public void markDirty()
{ super.markDirty(); }
@Override
public boolean isUsableByPlayer(PlayerEntity player)
{ return getPos().distanceSq(player.getPosition()) < 36; }
@Override
public void openInventory(PlayerEntity player)
{}
@Override
public void closeInventory(PlayerEntity player)
{ markDirty(); }
@Override
public boolean isItemValidForSlot(int index, ItemStack stack)
{
switch(index) {
case SMELTING_OUTPUT_SLOT_NO:
case FIFO_OUTPUT_0_SLOT_NO:
case FIFO_OUTPUT_1_SLOT_NO:
return false;
case SMELTING_INPUT_SLOT_NO:
case FIFO_INPUT_0_SLOT_NO:
case FIFO_INPUT_1_SLOT_NO:
return true;
case AUX_0_SLOT_NO:
case AUX_1_SLOT_NO:
return true;
default: {
ItemStack slot_stack = stacks_.get(FIFO_FUEL_1_SLOT_NO);
return isFuel(world, stack) || FurnaceFuelSlot.isBucket(stack) && (slot_stack.getItem() != Items.BUCKET);
}
}
}
@Override
public void clear()
{ stacks_.clear(); }
// Fields -----------------------------------------------------------------------------------------------
protected final IIntArray fields = new IntArray(BTileEntity.NUM_OF_FIELDS)
{
@Override
public int get(int id)
{
switch(id) {
case 0: return BTileEntity.this.burntime_left_;
case 1: return BTileEntity.this.fuel_burntime_;
case 2: return (int)BTileEntity.this.field_proc_time_elapsed_;
case 3: return BTileEntity.this.proc_time_needed_;
case 4: return BTileEntity.this.field_is_burning_;
default: return 0;
}
}
@Override
public void set(int id, int value)
{
switch(id) {
case 0: BTileEntity.this.burntime_left_ = value; break;
case 1: BTileEntity.this.fuel_burntime_ = value; break;
case 2: BTileEntity.this.field_proc_time_elapsed_ = value; break;
case 3: BTileEntity.this.proc_time_needed_ = value; break;
case 4: BTileEntity.this.field_is_burning_ = value;
}
}
};
// ISidedInventory ----------------------------------------------------------------------------
private static final int[] SLOTS_TOP = new int[] {FIFO_INPUT_1_SLOT_NO};
private static final int[] SLOTS_BOTTOM = new int[] {FIFO_OUTPUT_1_SLOT_NO};
private static final int[] SLOTS_SIDES = new int[] {FIFO_FUEL_1_SLOT_NO};
@Override
public int[] getSlotsForFace(Direction side)
{
if(side == Direction.DOWN) return SLOTS_BOTTOM;
if(side == Direction.UP) return SLOTS_TOP;
return SLOTS_SIDES;
}
@Override
public boolean canInsertItem(int index, ItemStack itemStackIn, Direction direction)
{ return isItemValidForSlot(index, itemStackIn); }
@Override
public boolean canExtractItem(int index, ItemStack stack, Direction direction)
{
if((direction!=Direction.DOWN) || ((index!=SMELTING_FUEL_SLOT_NO) && (index!=FIFO_FUEL_0_SLOT_NO) && (index!=FIFO_FUEL_1_SLOT_NO) )) return true;
return (stack.getItem()==Items.BUCKET);
}
// IEnergyStorage ----------------------------------------------------------------------------
@Override
public boolean canExtract()
{ return false; }
@Override
public boolean canReceive()
{ return true; }
@Override
public int getMaxEnergyStored()
{ return boost_energy_consumption; }
@Override
public int getEnergyStored()
{ return boost_energy_; }
@Override
public int extractEnergy(int maxExtract, boolean simulate)
{ return 0; }
@Override
public int receiveEnergy(int maxReceive, boolean simulate)
{ // only speedup support, no buffering, not in nbt -> no markdirty
if((boost_energy_ >= boost_energy_consumption) || (maxReceive < boost_energy_consumption)) return 0;
if(!simulate) boost_energy_ = boost_energy_consumption;
return boost_energy_consumption;
}
// Capability export ----------------------------------------------------------------------------
LazyOptional<? extends IItemHandler>[] item_handlers = SidedInvWrapper.create(this, Direction.UP, Direction.DOWN, Direction.NORTH);
protected LazyOptional<IEnergyStorage> energy_handler_ = LazyOptional.of(() -> (IEnergyStorage)this);
@Override
public <T> LazyOptional<T> getCapability(net.minecraftforge.common.capabilities.Capability<T> capability, @Nullable Direction facing)
{
if(!this.removed && (facing != null)) {
if(capability==CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) {
if(facing == Direction.UP) return item_handlers[0].cast();
if(facing == Direction.DOWN) return item_handlers[1].cast();
return item_handlers[2].cast();
} else if(capability== CapabilityEnergy.ENERGY) {
return energy_handler_.cast();
}
}
return super.getCapability(capability, facing);
}
// ITickableTileEntity -------------------------------------------------------------------------
@Override
public void tick()
{
if(--tick_timer_ > 0) return;
tick_timer_ = TICK_INTERVAL;
final boolean was_burning = burning();
if(was_burning) burntime_left_ -= TICK_INTERVAL;
if(burntime_left_ < 0) burntime_left_ = 0;
if(world.isRemote) return;
boolean dirty = false;
if(--fifo_timer_ <= 0) {
fifo_timer_ = FIFO_INTERVAL/TICK_INTERVAL;
// note, intentionally not using bitwise OR piping.
if(transferItems(FIFO_OUTPUT_0_SLOT_NO, FIFO_OUTPUT_1_SLOT_NO, 1)) dirty = true;
if(transferItems(SMELTING_OUTPUT_SLOT_NO, FIFO_OUTPUT_0_SLOT_NO, 1)) dirty = true;
if(transferItems(FIFO_FUEL_0_SLOT_NO, SMELTING_FUEL_SLOT_NO, 1)) dirty = true;
if(transferItems(FIFO_FUEL_1_SLOT_NO, FIFO_FUEL_0_SLOT_NO, 1)) dirty = true;
if(transferItems(FIFO_INPUT_0_SLOT_NO, SMELTING_INPUT_SLOT_NO, 1)) dirty = true;
if(transferItems(FIFO_INPUT_1_SLOT_NO, FIFO_INPUT_0_SLOT_NO, 1)) dirty = true;
heater_inserted_ = (ExtItems.IE_EXTERNAL_HEATER==null) // without IE always allow electrical boost
|| (stacks_.get(AUX_0_SLOT_NO).getItem()==ExtItems.IE_EXTERNAL_HEATER)
|| (stacks_.get(AUX_1_SLOT_NO).getItem()==ExtItems.IE_EXTERNAL_HEATER);
if(!burning()) cleanupRecentRecipes();
}
ItemStack fuel = stacks_.get(SMELTING_FUEL_SLOT_NO);
if(burning() || (!fuel.isEmpty()) && (!(stacks_.get(SMELTING_INPUT_SLOT_NO)).isEmpty())) {
IRecipe last_recipe = currentRecipe();
updateCurrentRecipe();
if(currentRecipe() != last_recipe) {
proc_time_elapsed_ = 0;
proc_time_needed_ = getSmeltingTimeNeeded(world, stacks_.get(SMELTING_INPUT_SLOT_NO));
}
if(!burning() && canSmeltCurrentItem()) {
burntime_left_ = (int)MathHelper.clamp((proc_fuel_efficiency_ * getFuelBurntime(world, fuel)), 0, MAX_BURNTIME);
fuel_burntime_ = (int)MathHelper.clamp(((double)burntime_left_)/((proc_speed_ > 0) ? proc_speed_ : 1), 1, MAX_BURNTIME);
if(burning()) {
dirty = true;
if(!fuel.isEmpty()) {
Item fuel_item = fuel.getItem();
fuel.shrink(1);
if(fuel.isEmpty()) stacks_.set(SMELTING_FUEL_SLOT_NO, fuel_item.getContainerItem(fuel));
}
}
}
if(burning() && canSmeltCurrentItem()) {
proc_time_elapsed_ += TICK_INTERVAL * proc_speed_;
if(heater_inserted_ && (boost_energy_ >= boost_energy_consumption)) { boost_energy_ = 0; proc_time_elapsed_ += TICK_INTERVAL; }
if(proc_time_elapsed_ >= proc_time_needed_) {
proc_time_elapsed_ = 0;
proc_time_needed_ = getSmeltingTimeNeeded(world, stacks_.get(SMELTING_INPUT_SLOT_NO));
smeltCurrentItem();
dirty = true;
}
} else {
proc_time_elapsed_ = 0;
}
} else if((!burning()) && (proc_time_elapsed_ > 0)) {
proc_time_elapsed_ = MathHelper.clamp(proc_time_elapsed_-2, 0, proc_time_needed_);
}
if(was_burning != burning()) {
dirty = true;
final BlockState state = world.getBlockState(pos);
if(state.getBlock() instanceof BlockDecorFurnace) {
world.setBlockState(pos, state.with(LIT, burning()));
}
}
if(dirty) {
markDirty();
}
field_is_burning_ = this.burning() ? 1 : 0;
field_proc_time_elapsed_ = (int)proc_time_elapsed_;
}
// Furnace -------------------------------------------------------------------------------------
@Nullable
public static final <T extends AbstractCookingRecipe> T getSmeltingResult(IRecipeType<T> recipe_type, World world, ItemStack stack)
{
if(stack.isEmpty()) return null;
Inventory inventory = new Inventory(3);
inventory.setInventorySlotContents(0, stack);
return world.getRecipeManager().getRecipe(recipe_type, inventory, world).orElse(null);
}
@Nullable
protected IRecipe currentRecipe()
{ return current_recipe_; }
public boolean burning()
{ return burntime_left_ > 0; }
public int getSmeltingTimeNeeded(World world, ItemStack stack)
{
if(stack.isEmpty()) return 0;
AbstractCookingRecipe recipe = getSmeltingResult(RECIPE_TYPE, world, stack);
if(recipe == null) return 0;
int t = recipe.getCookTime();
return (t<=0) ? STD_SMELTING_TIME : t;
}
private boolean transferItems(final int index_from, final int index_to, int count)
{
ItemStack from = stacks_.get(index_from);
if(from.isEmpty()) return false;
ItemStack to = stacks_.get(index_to);
if(from.getCount() < count) count = from.getCount();
if(count <= 0) return false;
boolean changed = true;
if(to.isEmpty()) {
stacks_.set(index_to, from.split(count));
} else if(to.getCount() >= to.getMaxStackSize()) {
changed = false;
} else if((!from.isItemEqual(to)) || (!ItemStack.areItemStackTagsEqual(from, to))) {
changed = false;
} else {
if((to.getCount()+count) >= to.getMaxStackSize()) {
from.shrink(to.getMaxStackSize()-to.getCount());
to.setCount(to.getMaxStackSize());
} else {
from.shrink(count);
to.grow(count);
}
}
if(from.isEmpty() && from!=ItemStack.EMPTY) {
stacks_.set(index_from, ItemStack.EMPTY);
changed = true;
}
return changed;
}
protected boolean canSmeltCurrentItem()
{
if((currentRecipe()==null) || (stacks_.get(SMELTING_INPUT_SLOT_NO).isEmpty())) return false;
final ItemStack recipe_result_items = getSmeltingResult(stacks_.get(SMELTING_INPUT_SLOT_NO));
if(recipe_result_items.isEmpty()) return false;
final ItemStack result_stack = stacks_.get(SMELTING_OUTPUT_SLOT_NO);
if(result_stack.isEmpty()) return true;
if(!result_stack.isItemEqual(recipe_result_items)) return false;
if(result_stack.getCount() + recipe_result_items.getCount() <= getInventoryStackLimit() && result_stack.getCount() + recipe_result_items.getCount() <= result_stack.getMaxStackSize()) return true;
return result_stack.getCount() + recipe_result_items.getCount() <= recipe_result_items.getMaxStackSize();
}
protected void smeltCurrentItem()
{
if(!canSmeltCurrentItem()) return;
final ItemStack smelting_input_stack = stacks_.get(SMELTING_INPUT_SLOT_NO);
final ItemStack recipe_result_items = getSmeltingResult(smelting_input_stack);
final ItemStack smelting_output_stack = stacks_.get(SMELTING_OUTPUT_SLOT_NO);
final ItemStack fuel_stack = stacks_.get(SMELTING_FUEL_SLOT_NO);
if(smelting_output_stack.isEmpty()) {
stacks_.set(SMELTING_OUTPUT_SLOT_NO, recipe_result_items.copy());
} else if(smelting_output_stack.getItem() == recipe_result_items.getItem()) {
smelting_output_stack.grow(recipe_result_items.getCount());
}
smelting_input_stack.shrink(1);
}
public static int getFuelBurntime(World world, ItemStack stack)
{
if(stack.isEmpty()) return 0;
int t = ForgeHooks.getBurnTime(stack);
return (t<0) ? 0 : t;
}
public static boolean isFuel(World world, ItemStack stack)
{ return getFuelBurntime(world, stack) > 0; }
public float getSmeltingExperience(ItemStack stack)
{
// This method is not often needed, so the time managing dealing with the recent
// recipes is mainly invested here.
float xp = stack.getItem().getSmeltingExperience(stack);
if(xp >= 0) return xp;
for(int i=0; i<recent_recipes_.size(); ++i) {
IRecipe r = world.getRecipeManager().getRecipe(new ResourceLocation(recent_recipes_.get(i))).orElse(null);
if((!(r instanceof AbstractCookingRecipe))) continue; // recipe not available (e.g. at the moment).
if(!(stack.isItemEqual(r.getRecipeOutput()))) continue;
xp = ((AbstractCookingRecipe)r).getExperience();
}
return (xp <= 0) ? 0 : xp;
}
public ItemStack getSmeltingResult(final ItemStack stack)
{ return (currentRecipe()==null) ? (ItemStack.EMPTY) : (currentRecipe().getRecipeOutput()); }
public static boolean canSmelt(World world, final ItemStack stack)
{ return getSmeltingResult(RECIPE_TYPE, world, stack) != null; }
protected void updateCurrentRecipe()
{ setCurrentRecipe(getSmeltingResult(RECIPE_TYPE, world, stacks_.get(SMELTING_INPUT_SLOT_NO))); }
protected void setCurrentRecipe(IRecipe<?> recipe)
{
if(recipe == null) { current_recipe_ = null; return; }
current_recipe_ = recipe;
String recipe_id = recipe.getId().toString();
if(!recent_recipes_.contains(recipe_id)) recent_recipes_.add(recipe_id);
}
private void cleanupRecentRecipes()
{
if(recent_recipes_.isEmpty()) return;
if(!stacks_.get(SMELTING_INPUT_SLOT_NO).isEmpty()) return;
if(!stacks_.get(SMELTING_OUTPUT_SLOT_NO).isEmpty()) return;
if(!stacks_.get(FIFO_OUTPUT_0_SLOT_NO).isEmpty()) return;
if(!stacks_.get(FIFO_OUTPUT_1_SLOT_NO).isEmpty()) return;
recent_recipes_.clear();
}
}
//--------------------------------------------------------------------------------------------------------------------
// container slots
//--------------------------------------------------------------------------------------------------------------------
public static class BContainer extends Container implements Networking.INetworkSynchronisableContainer
{
// Slots --------------------------------------------------------------------------------------------
public static class BSlotInpFifo extends Slot
{
public BSlotInpFifo(IInventory inv, int index, int xpos, int ypos)
{ super(inv, index, xpos, ypos); }
}
public static class BSlotFuelFifo extends Slot
{
public BSlotFuelFifo(IInventory inv, int index, int xpos, int ypos)
{ super(inv, index, xpos, ypos); }
}
public static class BSlotOutFifo extends BSlotResult
{
public BSlotOutFifo(PlayerEntity player, IInventory inventory, int index, int xpos, int ypos)
{ super(player, inventory, index, xpos, ypos); }
}
public static class BSlotResult extends Slot
{
private final IInventory inventory_;
private final PlayerEntity player_;
private int removeCount = 0;
public BSlotResult(PlayerEntity player, IInventory inventory, int index, int xpos, int ypos)
{ super(inventory, index, xpos, ypos); inventory_ = inventory; player_ = player; }
@Override
public boolean isItemValid(ItemStack stack)
{ return false; }
@Override
public ItemStack decrStackSize(int amount)
{ removeCount += getHasStack() ? Math.min(amount, getStack().getCount()) : 0; return super.decrStackSize(amount); }
@Override
public ItemStack onTake(PlayerEntity thePlayer, ItemStack stack)
{ onCrafting(stack); super.onTake(thePlayer, stack); return stack; }
@Override
protected void onCrafting(ItemStack stack, int amount)
{ removeCount += amount; onCrafting(stack); }
@Override
protected void onCrafting(ItemStack stack)
{
stack.onCrafting(player_.world, player_, removeCount);
if((!player_.world.isRemote) && (inventory_ instanceof BTileEntity)) {
BTileEntity te = (BTileEntity)inventory_;
int xp = removeCount;
float sxp = te.getSmeltingExperience(stack);
if(sxp == 0) {
xp = 0;
} else if(sxp < 1.0) {
xp = (int)((sxp*xp) + Math.round(Math.random()+0.75));
}
while(xp > 0) {
int k = ExperienceOrbEntity.getXPSplit(xp);
xp -= k;
player_.world.addEntity((new ExperienceOrbEntity(player_.world, player_.getPosition().getX(), player_.getPosition().getY()+0.5, player_.getPosition().getZ()+0.5, k)));
}
}
removeCount = 0;
BasicEventHooks.firePlayerSmeltedEvent(player_, stack);
}
}
public static class BFuelSlot extends Slot
{
private final BContainer container_;
public BFuelSlot(IInventory inventory, int index, int xpos, int ypos, BContainer container)
{ super(inventory, index, xpos, ypos); container_=container; }
@Override
public boolean isItemValid(ItemStack stack)
{ return isBucket(stack) || (BTileEntity.isFuel(container_.world(), stack)); }
@Override
public int getItemStackLimit(ItemStack stack)
{ return isBucket(stack) ? 1 : super.getItemStackLimit(stack); }
protected static boolean isBucket(ItemStack stack)
{ return (stack.getItem()==Items.BUCKET); }
}
// Container ----------------------------------------------------------------------------------------
private static final int PLAYER_INV_START_SLOTNO = 11;
protected final PlayerEntity player_;
protected final IInventory inventory_;
protected final IWorldPosCallable wpc_;
private final IIntArray fields_;
private final IRecipeType<? extends AbstractCookingRecipe> recipe_type_;
public int field(int index) { return fields_.get(index); }
public PlayerEntity player() { return player_ ; }
public IInventory inventory() { return inventory_ ; }
public World world() { return player_.world; }
public BContainer(int cid, PlayerInventory player_inventory)
{ this(cid, player_inventory, new Inventory(BTileEntity.NUM_OF_SLOTS), IWorldPosCallable.DUMMY, new IntArray(BTileEntity.NUM_OF_FIELDS)); }
private BContainer(int cid, PlayerInventory player_inventory, IInventory block_inventory, IWorldPosCallable wpc, IIntArray fields)
{
super(ModContent.CT_SMALL_LAB_FURNACE, cid);
player_ = player_inventory.player;
inventory_ = block_inventory;
wpc_ = wpc;
fields_ = fields;
recipe_type_ = BTileEntity.RECIPE_TYPE;
addSlot(new Slot(inventory_, 0, 59, 17)); // smelting input
addSlot(new BFuelSlot(inventory_, 1, 59, 53, this)); // fuel
addSlot(new BSlotResult(player_, inventory_, 2, 101, 35)); // smelting result
addSlot(new BSlotInpFifo(inventory_, 3, 34, 17)); // input fifo 0
addSlot(new BSlotInpFifo(inventory_, 4, 16, 17)); // input fifo 1
addSlot(new BSlotFuelFifo(inventory_, 5, 34, 53)); // fuel fifo 0
addSlot(new BSlotFuelFifo(inventory_, 6, 16, 53)); // fuel fifo 1
addSlot(new BSlotOutFifo(player_inventory.player, inventory_, 7, 126, 35)); // out fifo 0
addSlot(new BSlotOutFifo(player_inventory.player, inventory_, 8, 144, 35)); // out fifo 1
addSlot(new Slot(inventory_, 9, 126, 61)); // aux slot 1
addSlot(new Slot(inventory_, 10, 144, 61)); // aux slot 2
for(int x=0; x<9; ++x) {
addSlot(new Slot(player_inventory, x, 8+x*18, 144)); // player slots: 0..8
}
for(int y=0; y<3; ++y) {
for(int x=0; x<9; ++x) {
addSlot(new Slot(player_inventory, x+y*9+9, 8+x*18, 86+y*18)); // player slots: 9..35
}
}
this.trackIntArray(fields_); // === Add reference holders
}
@Override
public boolean canInteractWith(PlayerEntity player)
{ return inventory_.isUsableByPlayer(player); }
@Override
public ItemStack transferStackInSlot(PlayerEntity player, int index)
{
Slot slot = getSlot(index);
if((slot==null) || (!slot.getHasStack())) return ItemStack.EMPTY;
ItemStack slot_stack = slot.getStack();
ItemStack transferred = slot_stack.copy();
if((index==2) || (index==7) || (index==8)) {
// Output slots
if(!mergeItemStack(slot_stack, PLAYER_INV_START_SLOTNO, PLAYER_INV_START_SLOTNO+36, true)) return ItemStack.EMPTY;
slot.onSlotChange(slot_stack, transferred);
} else if((index==0) || (index==3) || (index==4)) {
// Input slots
if(!mergeItemStack(slot_stack, PLAYER_INV_START_SLOTNO, PLAYER_INV_START_SLOTNO+36, false)) return ItemStack.EMPTY;
} else if((index==1) || (index==5) || (index==6)) {
// Fuel slots
if(!mergeItemStack(slot_stack, PLAYER_INV_START_SLOTNO, PLAYER_INV_START_SLOTNO+36, false)) return ItemStack.EMPTY;
} else if((index==9) || (index==10)) {
if(!mergeItemStack(slot_stack, PLAYER_INV_START_SLOTNO, PLAYER_INV_START_SLOTNO+36, false)) return ItemStack.EMPTY;
} else if((index >= PLAYER_INV_START_SLOTNO) && (index <= PLAYER_INV_START_SLOTNO+36)) {
// Player inventory
if(BTileEntity.canSmelt(world(), slot_stack)) {
if(
(!mergeItemStack(slot_stack, 0, 1, false)) && // smelting input
(!mergeItemStack(slot_stack, 3, 4, false)) && // fifo0
(!mergeItemStack(slot_stack, 4, 5, false)) // fifo1
) return ItemStack.EMPTY;
} else if(BTileEntity.isFuel(player_.world, slot_stack)) {
if(
(!mergeItemStack(slot_stack, 1, 2, false)) && // fuel input
(!mergeItemStack(slot_stack, 5, 6, false)) && // fuel fifo0
(!mergeItemStack(slot_stack, 6, 7, false)) // fuel fifo1
) return ItemStack.EMPTY;
} else if((index >= PLAYER_INV_START_SLOTNO) && (index < PLAYER_INV_START_SLOTNO+27)) {
// player inventory --> player hotbar
if(!mergeItemStack(slot_stack, PLAYER_INV_START_SLOTNO+27, PLAYER_INV_START_SLOTNO+36, false)) return ItemStack.EMPTY;
} else if((index >= PLAYER_INV_START_SLOTNO+27) && (index < PLAYER_INV_START_SLOTNO+36) && (!mergeItemStack(slot_stack, PLAYER_INV_START_SLOTNO, PLAYER_INV_START_SLOTNO+27, false))) {
// player hotbar --> player inventory
return ItemStack.EMPTY;
}
} else {
// invalid slot
return ItemStack.EMPTY;
}
if(slot_stack.isEmpty()) {
slot.putStack(ItemStack.EMPTY);
} else {
slot.onSlotChanged();
}
if(slot_stack.getCount() == transferred.getCount()) return ItemStack.EMPTY;
slot.onTake(player, slot_stack);
//if(!player.world.isRemote) detectAndSendChanges();
return transferred;
}
// INetworkSynchronisableContainer ---------------------------------------------------------
@OnlyIn(Dist.CLIENT)
public void onGuiAction(CompoundNBT nbt)
{ Networking.PacketContainerSyncClientToServer.sendToServer(windowId, nbt); }
@OnlyIn(Dist.CLIENT)
public void onGuiAction(String key, int value)
{
CompoundNBT nbt = new CompoundNBT();
nbt.putInt(key, value);
Networking.PacketContainerSyncClientToServer.sendToServer(windowId, nbt);
}
@Override
public void onServerPacketReceived(int windowId, CompoundNBT nbt)
{}
@Override
public void onClientPacketReceived(int windowId, PlayerEntity player, CompoundNBT nbt)
{}
}
//--------------------------------------------------------------------------------------------------------------------
// GUI
//--------------------------------------------------------------------------------------------------------------------
@OnlyIn(Dist.CLIENT)
public static class BGui extends ContainerScreen<BContainer>
{
protected final PlayerEntity player_;
public BGui(BContainer container, PlayerInventory player_inventory, ITextComponent title)
{ super(container, player_inventory, title); this.player_ = player_inventory.player; }
@Override
public void init()
{ super.init(); }
@Override
public void render(int mouseX, int mouseY, float partialTicks)
{
renderBackground();
super.render(mouseX, mouseY, partialTicks);
renderHoveredToolTip(mouseX, mouseY);
}
@Override
protected void drawGuiContainerBackgroundLayer(float partialTicks, int mouseX, int mouseY)
{
RenderSystem.enableBlend();
RenderSystem.color4f(1.0F, 1.0F, 1.0F, 1.0F);
this.minecraft.getTextureManager().bindTexture(new ResourceLocation(ModEngineersDecor.MODID, "textures/gui/small_lab_furnace_gui.png"));
final int x0=guiLeft, y0=this.guiTop, w=xSize, h=ySize;
blit(x0, y0, 0, 0, w, h);
if(getContainer().field(4) != 0) {
final int k = flame_px(13);
blit(x0+59, y0+36+12-k, 176, 12-k, 14, k+1);
}
blit(x0+79, y0+36, 176, 15, 1+progress_px(17), 15);
RenderSystem.disableBlend();
}
private int progress_px(int pixels)
{ final int tc=getContainer().field(2), T=getContainer().field(3); return ((T>0) && (tc>0)) ? (tc * pixels / T) : (0); }
private int flame_px(int pixels)
{ int ibt = getContainer().field(1); return ((getContainer().field(0) * pixels) / ((ibt>0) ? (ibt) : (BTileEntity.STD_SMELTING_TIME))); }
}
}

View file

@ -0,0 +1,779 @@
/*
* @file BlockDecorFurnaceElectrical.java
* @author Stefan Wilhelm (wile)
* @copyright (C) 2019 Stefan Wilhelm
* @license MIT (see https://opensource.org/licenses/MIT)
*
* ED small electrical pass-through furnace.
*/
package wile.engineersdecor.blocks;
import wile.engineersdecor.ModContent;
import wile.engineersdecor.ModEngineersDecor;
import wile.engineersdecor.detail.Networking;
import net.minecraft.inventory.container.*;
import net.minecraft.item.crafting.AbstractCookingRecipe;
import net.minecraft.item.crafting.FurnaceRecipe;
import net.minecraft.item.crafting.IRecipe;
import net.minecraft.item.crafting.IRecipeType;
import net.minecraft.tileentity.ITickableTileEntity;
import net.minecraft.tileentity.TileEntityType;
import net.minecraft.util.math.BlockRayTraceResult;
import net.minecraft.block.Block;
import net.minecraft.entity.player.ServerPlayerEntity;
import net.minecraft.util.text.StringTextComponent;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.world.IBlockReader;
import net.minecraft.block.BlockState;
import net.minecraft.world.World;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.entity.LivingEntity;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.item.Items;
import net.minecraft.item.*;
import net.minecraft.inventory.*;
import net.minecraft.client.gui.screen.inventory.ContainerScreen;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.*;
import net.minecraft.stats.Stats;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.common.util.FakePlayer;
import net.minecraftforge.fml.network.NetworkHooks;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.energy.CapabilityEnergy;
import net.minecraftforge.energy.IEnergyStorage;
import net.minecraftforge.items.CapabilityItemHandler;
import net.minecraftforge.items.IItemHandler;
import net.minecraftforge.items.ItemHandlerHelper;
import com.mojang.blaze3d.systems.RenderSystem;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.Random;
public class BlockDecorFurnaceElectrical extends BlockDecorFurnace
{
public BlockDecorFurnaceElectrical(long config, Block.Properties builder, final AxisAlignedBB unrotatedAABB)
{ super(config, builder, unrotatedAABB); }
@Override
@Nullable
public TileEntity createTileEntity(BlockState state, IBlockReader world)
{ return new BlockDecorFurnaceElectrical.BTileEntity(); }
@Override
public boolean onBlockActivated(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockRayTraceResult rayTraceResult)
{
if(world.isRemote) return true;
final TileEntity te = world.getTileEntity(pos);
if(!(te instanceof BlockDecorFurnaceElectrical.BTileEntity)) return true;
if((!(player instanceof ServerPlayerEntity) && (!(player instanceof FakePlayer)))) return true;
NetworkHooks.openGui((ServerPlayerEntity)player,(INamedContainerProvider)te);
player.addStat(Stats.INTERACT_WITH_FURNACE);
return true;
}
@Override
public void onBlockPlacedBy(World world, BlockPos pos, BlockState state, LivingEntity placer, ItemStack stack)
{
world.setBlockState(pos, state.with(LIT, false));
if(world.isRemote) return;
if((!stack.hasTag()) || (!stack.getTag().contains("inventory"))) return;
CompoundNBT inventory_nbt = stack.getTag().getCompound("inventory");
if(inventory_nbt.isEmpty()) return;
final TileEntity te = world.getTileEntity(pos);
if(!(te instanceof BlockDecorFurnaceElectrical.BTileEntity)) return;
BTileEntity bte = (BlockDecorFurnaceElectrical.BTileEntity)te;
bte.readnbt(inventory_nbt);
bte.markDirty();
world.setBlockState(pos, state.with(LIT, bte.burning()));
}
@Override
@OnlyIn(Dist.CLIENT)
public void animateTick(BlockState state, World world, BlockPos pos, Random rnd)
{}
//--------------------------------------------------------------------------------------------------------------------
// Tile entity
//--------------------------------------------------------------------------------------------------------------------
public static class BTileEntity extends BlockDecorFurnace.BTileEntity implements ITickableTileEntity, INameable, IInventory, INamedContainerProvider, ISidedInventory, IEnergyStorage
{
public static final IRecipeType<FurnaceRecipe> RECIPE_TYPE = IRecipeType.SMELTING;
public static final int NUM_OF_FIELDS = 7;
public static final int TICK_INTERVAL = 4;
public static final int FIFO_INTERVAL = 20;
public static final int HEAT_CAPACITY = 200;
public static final int HEAT_INCREMENT = 20;
public static final int MAX_ENERGY_TRANSFER = 256;
public static final int MAX_ENERGY_BUFFER = 32000;
public static final int MAX_SPEED_SETTING = 2;
public static final int NUM_OF_SLOTS = 7;
public static final int SMELTING_INPUT_SLOT_NO = 0;
public static final int SMELTING_AUX_SLOT_NO = 1;
public static final int SMELTING_OUTPUT_SLOT_NO = 2;
public static final int FIFO_INPUT_0_SLOT_NO = 3;
public static final int FIFO_INPUT_1_SLOT_NO = 4;
public static final int FIFO_OUTPUT_0_SLOT_NO = 5;
public static final int FIFO_OUTPUT_1_SLOT_NO = 6;
public static final int DEFAULT_SPEED_PERCENT = 200;
public static final int DEFAULT_ENERGY_CONSUMPTION = 16;
public static final int DEFAULT_SCALED_ENERGY_CONSUMPTION = DEFAULT_ENERGY_CONSUMPTION * HEAT_INCREMENT * DEFAULT_SPEED_PERCENT / 100;
// Config ----------------------------------------------------------------------------------
private static boolean with_automatic_inventory_pulling_ = false;
private static int energy_consumption_ = DEFAULT_SCALED_ENERGY_CONSUMPTION;
private static int transfer_energy_consumption_ = DEFAULT_SCALED_ENERGY_CONSUMPTION / 8;
private static int proc_speed_percent_ = DEFAULT_SPEED_PERCENT;
public static void on_config(int speed_percent, int standard_energy_per_tick, boolean with_automatic_inventory_pulling)
{
proc_speed_percent_ = MathHelper.clamp(speed_percent, 10, 500);
energy_consumption_ = MathHelper.clamp(standard_energy_per_tick, 10, 256) * HEAT_INCREMENT * proc_speed_percent_ / 100;
transfer_energy_consumption_ = MathHelper.clamp(energy_consumption_ / 8, 8, HEAT_INCREMENT);
with_automatic_inventory_pulling_ = with_automatic_inventory_pulling;
ModEngineersDecor.logger().info("Config electrical furnace speed:" + proc_speed_percent_ + ", power consumption:" + energy_consumption_);
}
// BTileEntity -----------------------------------------------------------------------------
private int burntime_left_;
private int proc_time_elapsed_;
private int proc_time_needed_;
private int energy_stored_;
private int field_max_energy_stored_;
private int field_isburning_;
private int speed_;
private int tick_timer_;
private int fifo_timer_;
public BTileEntity()
{ this(ModContent.TET_SMALL_ELECTRICAL_FURNACE); }
public BTileEntity(TileEntityType<?> te_type)
{ super(te_type); }
public void reset()
{
super.reset();
stacks_ = NonNullList.<ItemStack>withSize(NUM_OF_SLOTS, ItemStack.EMPTY);
burntime_left_ = 0;
proc_time_elapsed_ = 0;
proc_time_needed_ = 0;
fifo_timer_ = 0;
tick_timer_ = 0;
energy_stored_ = 0;
speed_ = 0;
field_max_energy_stored_ = getMaxEnergyStored();
field_isburning_ = 0;
}
public void readnbt(CompoundNBT nbt)
{
ItemStackHelper.loadAllItems(nbt, this.stacks_);
while(this.stacks_.size() < NUM_OF_SLOTS) this.stacks_.add(ItemStack.EMPTY);
burntime_left_ = nbt.getInt("BurnTime");
proc_time_elapsed_ = nbt.getInt("CookTime");
proc_time_needed_ = nbt.getInt("CookTimeTotal");
energy_stored_ = nbt.getInt("Energy");
speed_ = nbt.getInt("SpeedSetting");
}
protected void writenbt(CompoundNBT nbt)
{
nbt.putInt("BurnTime", MathHelper.clamp(burntime_left_, 0, HEAT_CAPACITY));
nbt.putInt("CookTime", MathHelper.clamp(proc_time_elapsed_, 0, MAX_BURNTIME));
nbt.putInt("CookTimeTotal", MathHelper.clamp(proc_time_needed_, 0, MAX_BURNTIME));
nbt.putInt("Energy", MathHelper.clamp(energy_stored_, 0, MAX_ENERGY_BUFFER));
nbt.putInt("SpeedSetting", MathHelper.clamp(speed_, -1, MAX_SPEED_SETTING));
ItemStackHelper.saveAllItems(nbt, stacks_);
}
// INameable -------------------------------------------------------------------------------
@Override
public ITextComponent getName()
{ final Block block=getBlockState().getBlock(); return new StringTextComponent((block!=null) ? block.getTranslationKey() : "Small electrical furnace"); }
// IContainerProvider ----------------------------------------------------------------------
@Override
public Container createMenu(int id, PlayerInventory inventory, PlayerEntity player )
{ return new BlockDecorFurnaceElectrical.BContainer(id, inventory, this, IWorldPosCallable.of(world, pos), fields); }
// IInventory ------------------------------------------------------------------------------
@Override
public boolean isItemValidForSlot(int index, ItemStack stack)
{
switch(index) {
case SMELTING_INPUT_SLOT_NO:
case FIFO_INPUT_0_SLOT_NO:
case FIFO_INPUT_1_SLOT_NO:
return true;
default:
return false;
}
}
@Override
public ItemStack getStackInSlot(int index)
{ return ((index < 0) || (index >= SIDED_INV_SLOTS.length)) ? ItemStack.EMPTY : stacks_.get(SIDED_INV_SLOTS[index]); }
// Fields -----------------------------------------------------------------------------------------------
protected final IIntArray fields = new IntArray(BTileEntity.NUM_OF_FIELDS)
{
@Override
public int get(int id)
{
switch(id) {
case 0: return BTileEntity.this.burntime_left_;
case 1: return BTileEntity.this.energy_stored_;
case 2: return BTileEntity.this.proc_time_elapsed_;
case 3: return BTileEntity.this.proc_time_needed_;
case 4: return BTileEntity.this.speed_;
case 5: return BTileEntity.this.field_max_energy_stored_;
case 6: return BTileEntity.this.field_isburning_;
default: return 0;
}
}
@Override
public void set(int id, int value)
{
switch(id) {
case 0: BTileEntity.this.burntime_left_ = value; break;
case 1: BTileEntity.this.energy_stored_ = value; break;
case 2: BTileEntity.this.proc_time_elapsed_ = value; break;
case 3: BTileEntity.this.proc_time_needed_ = value; break;
case 4: BTileEntity.this.speed_ = value; break;
case 5: BTileEntity.this.field_max_energy_stored_ = value; break;
case 6: BTileEntity.this.field_isburning_ = value; break;
}
}
};
// ISidedInventory ----------------------------------------------------------------------------
private static final int[] SIDED_INV_SLOTS = new int[] {
SMELTING_INPUT_SLOT_NO, SMELTING_AUX_SLOT_NO, SMELTING_OUTPUT_SLOT_NO,
FIFO_INPUT_0_SLOT_NO, FIFO_INPUT_1_SLOT_NO, FIFO_OUTPUT_0_SLOT_NO, FIFO_OUTPUT_1_SLOT_NO
};
@Override
public int[] getSlotsForFace(Direction side)
{ return SIDED_INV_SLOTS; }
@Override
public boolean canInsertItem(int index, ItemStack itemStackIn, Direction direction)
{ return isItemValidForSlot(index, itemStackIn); }
@Override
public boolean canExtractItem(int index, ItemStack stack, Direction direction)
{ return ((index!=SMELTING_INPUT_SLOT_NO) && (index!=FIFO_INPUT_0_SLOT_NO) && (index!=FIFO_INPUT_1_SLOT_NO)) || (stack.getItem()==Items.BUCKET); }
// IEnergyStorage ----------------------------------------------------------------------------
@Override
public boolean canExtract()
{ return false; }
@Override
public boolean canReceive()
{ return true; }
@Override
public int getMaxEnergyStored()
{ return MAX_ENERGY_BUFFER; }
@Override
public int getEnergyStored()
{ return energy_stored_; }
@Override
public int extractEnergy(int maxExtract, boolean simulate)
{ return 0; }
@Override
public int receiveEnergy(int maxReceive, boolean simulate)
{
if(energy_stored_ >= MAX_ENERGY_BUFFER) return 0;
int n = Math.min(maxReceive, (MAX_ENERGY_BUFFER - energy_stored_));
if(n > MAX_ENERGY_TRANSFER) n = MAX_ENERGY_TRANSFER;
if(!simulate) {energy_stored_ += n; markDirty(); }
return n;
}
// IItemHandler --------------------------------------------------------------------------------
protected static class BItemHandler implements IItemHandler
{
private BTileEntity te;
BItemHandler(BTileEntity te)
{ this.te = te; }
@Override
public int getSlots()
{ return SIDED_INV_SLOTS.length; }
@Override
@Nonnull
public ItemStack getStackInSlot(int index)
{ return te.getStackInSlot(index); }
@Override
public int getSlotLimit(int index)
{ return te.getInventoryStackLimit(); }
@Override
public boolean isItemValid(int slot, @Nonnull ItemStack stack)
{ return true; }
@Override
@Nonnull
public ItemStack insertItem(int index, @Nonnull ItemStack stack, boolean simulate)
{
if(stack.isEmpty()) return ItemStack.EMPTY;
if((index < 0) || (index >= SIDED_INV_SLOTS.length)) return ItemStack.EMPTY;
int slotno = SIDED_INV_SLOTS[index];
ItemStack slotstack = getStackInSlot(slotno);
if(!slotstack.isEmpty()) {
if(slotstack.getCount() >= Math.min(slotstack.getMaxStackSize(), getSlotLimit(index))) return stack;
if(!ItemHandlerHelper.canItemStacksStack(stack, slotstack)) return stack;
if(!te.canInsertItem(slotno, stack, Direction.UP) || (!te.isItemValidForSlot(slotno, stack))) return stack;
int n = Math.min(stack.getMaxStackSize(), getSlotLimit(index)) - slotstack.getCount();
if(stack.getCount() <= n) {
if(!simulate) {
ItemStack copy = stack.copy();
copy.grow(slotstack.getCount());
te.setInventorySlotContents(slotno, copy);
}
return ItemStack.EMPTY;
} else {
stack = stack.copy();
if(!simulate) {
ItemStack copy = stack.split(n);
copy.grow(slotstack.getCount());
te.setInventorySlotContents(slotno, copy);
return stack;
} else {
stack.shrink(n);
return stack;
}
}
} else {
if(!te.canInsertItem(slotno, stack, Direction.UP) || (!te.isItemValidForSlot(slotno, stack))) return stack;
int n = Math.min(stack.getMaxStackSize(), getSlotLimit(index));
if(n < stack.getCount()) {
stack = stack.copy();
if(!simulate) {
te.setInventorySlotContents(slotno, stack.split(n));
return stack;
} else {
stack.shrink(n);
return stack;
}
} else {
if(!simulate) te.setInventorySlotContents(slotno, stack);
return ItemStack.EMPTY;
}
}
}
@Override
@Nonnull
public ItemStack extractItem(int index, int amount, boolean simulate)
{
if(amount == 0) return ItemStack.EMPTY;
if((index < 0) || (index >= SIDED_INV_SLOTS.length)) return ItemStack.EMPTY;
int slotno = SIDED_INV_SLOTS[index];
ItemStack stackInSlot = getStackInSlot(slotno);
if(stackInSlot.isEmpty()) return ItemStack.EMPTY;
if(!te.canExtractItem(slotno, stackInSlot, Direction.DOWN)) return ItemStack.EMPTY;
if(simulate) {
if(stackInSlot.getCount() < amount) return stackInSlot.copy();
ItemStack ostack = stackInSlot.copy();
ostack.setCount(amount);
return ostack;
} else {
ItemStack ostack = te.decrStackSize(slotno, Math.min(stackInSlot.getCount(), amount));
te.markDirty();
return ostack;
}
}
}
// Capability export ----------------------------------------------------------------------------
protected LazyOptional<IItemHandler> item_handler_ = LazyOptional.of(() -> new BItemHandler(this));
protected LazyOptional<IEnergyStorage> energy_handler_ = LazyOptional.of(() -> (IEnergyStorage)this);
@Override
public <T> LazyOptional<T> getCapability(net.minecraftforge.common.capabilities.Capability<T> capability, @Nullable Direction facing)
{
if(!this.removed && (facing != null)) {
if(capability==CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) return item_handler_.cast();
if(capability== CapabilityEnergy.ENERGY) return energy_handler_.cast();
}
return super.getCapability(capability, facing);
}
// ITickableTileEntity -------------------------------------------------------------------------
@Override
public void tick()
{
if(--tick_timer_ > 0) return;
tick_timer_ = TICK_INTERVAL;
final boolean was_burning = burning();
if(was_burning) burntime_left_ -= TICK_INTERVAL;
if(burntime_left_ < 0) burntime_left_ = 0;
if(world.isRemote) return;
boolean update_blockstate = (was_burning != burning());
boolean dirty = update_blockstate;
boolean shift_in = false;
boolean shift_out = false;
if(--fifo_timer_ <= 0) {
fifo_timer_ = FIFO_INTERVAL/TICK_INTERVAL;
if(transferItems(FIFO_OUTPUT_0_SLOT_NO, FIFO_OUTPUT_1_SLOT_NO, 64)) { dirty = true; } else { shift_out = true; }
if(transferItems(SMELTING_OUTPUT_SLOT_NO, FIFO_OUTPUT_0_SLOT_NO, 64)) dirty = true;
if(transferItems(FIFO_INPUT_0_SLOT_NO, SMELTING_INPUT_SLOT_NO, 64)) dirty = true;
if(transferItems(FIFO_INPUT_1_SLOT_NO, FIFO_INPUT_0_SLOT_NO, 64)) { dirty = true; } else { shift_in = true; }
}
if((!(stacks_.get(SMELTING_INPUT_SLOT_NO)).isEmpty()) && (energy_stored_ >= energy_consumption_)) {
IRecipe last_recipe = currentRecipe();
updateCurrentRecipe();
if(currentRecipe() != last_recipe) {
proc_time_elapsed_ = 0;
proc_time_needed_ = getSmeltingTimeNeeded(world, stacks_.get(SMELTING_INPUT_SLOT_NO));
}
final boolean can_smelt = canSmeltCurrentItem();
if((!can_smelt) && (getSmeltingResult(stacks_.get(SMELTING_INPUT_SLOT_NO)).isEmpty())) {
// bypass
if(transferItems(SMELTING_INPUT_SLOT_NO, SMELTING_OUTPUT_SLOT_NO, 1)) dirty = true;
} else {
// smelt
if(!burning() && can_smelt) {
if(heat_up()) { dirty = true; update_blockstate = true; }
}
if(burning() && can_smelt) {
if(heat_up()) dirty = true;
proc_time_elapsed_ += (TICK_INTERVAL * proc_speed_percent_/100);
if(proc_time_elapsed_ >= proc_time_needed_) {
proc_time_elapsed_ = 0;
proc_time_needed_ = getSmeltingTimeNeeded(world, stacks_.get(SMELTING_INPUT_SLOT_NO));
smeltCurrentItem();
dirty = true;
shift_out = true;
}
} else {
proc_time_elapsed_ = 0;
}
}
} else if(proc_time_elapsed_ > 0) {
proc_time_elapsed_ -= ((stacks_.get(SMELTING_INPUT_SLOT_NO)).isEmpty() ? 20 : 1);
if(proc_time_elapsed_ < 0) { proc_time_elapsed_ = 0; shift_out = true; update_blockstate = true; }
}
if(update_blockstate) {
dirty = true;
sync_blockstate();
}
if(adjacent_inventory_shift(shift_in, shift_out)) dirty = true;
if(dirty) markDirty();
field_max_energy_stored_ = getMaxEnergyStored();
field_isburning_ = burning() ? 1 : 0;
//if(this.energy_stored_ < this.getMaxEnergyStored() / 5) this.energy_stored_ = this.getMaxEnergyStored();
}
// Furnace --------------------------------------------------------------------------------------
protected void updateCurrentRecipe() //// Change this for other recipe registry (e.g. craft tweaker modified).
{ setCurrentRecipe(getSmeltingResult(RECIPE_TYPE, world, stacks_.get(SMELTING_INPUT_SLOT_NO))); }
public boolean burning()
{ return burntime_left_ > 0; }
private boolean transferItems(final int index_from, final int index_to, int count)
{
ItemStack from = stacks_.get(index_from);
if(from.isEmpty()) return false;
ItemStack to = stacks_.get(index_to);
if(from.getCount() < count) count = from.getCount();
if(count <= 0) return false;
boolean changed = true;
if(to.isEmpty()) {
stacks_.set(index_to, from.split(count));
} else if(to.getCount() >= to.getMaxStackSize()) {
changed = false;
} else if((!from.isItemEqual(to)) || (!ItemStack.areItemStackTagsEqual(from, to))) {
changed = false;
} else {
if((to.getCount()+count) >= to.getMaxStackSize()) {
from.shrink(to.getMaxStackSize()-to.getCount());
to.setCount(to.getMaxStackSize());
} else {
from.shrink(count);
to.grow(count);
}
}
if(from.isEmpty() && from!=ItemStack.EMPTY) {
stacks_.set(index_from, ItemStack.EMPTY);
changed = true;
}
return changed;
}
private boolean adjacent_inventory_shift(boolean inp, boolean out)
{
boolean dirty = false;
if(energy_stored_ < transfer_energy_consumption_) return false;
final BlockState state = world.getBlockState(pos);
if(!(state.getBlock() instanceof BlockDecorFurnaceElectrical)) return false;
final Direction out_facing = state.get(FACING);
if(out && (!stacks_.get(FIFO_OUTPUT_1_SLOT_NO).isEmpty())) {
TileEntity te = world.getTileEntity(pos.offset(out_facing));
if(te!=null) {
IItemHandler hnd = te.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, out_facing).orElse(null);
if(hnd != null) {
ItemStack remaining = ItemHandlerHelper.insertItemStacked(hnd, stacks_.get(FIFO_OUTPUT_1_SLOT_NO).copy(), false);
stacks_.set(FIFO_OUTPUT_1_SLOT_NO, remaining);
energy_stored_ -= transfer_energy_consumption_;
dirty = true;
}
}
}
if(with_automatic_inventory_pulling_) {
final Direction inp_facing = state.get(FACING).getOpposite();
if(inp && (stacks_.get(FIFO_INPUT_1_SLOT_NO).isEmpty())) {
TileEntity te = world.getTileEntity(pos.offset(inp_facing));
if(te!=null) {
IItemHandler hnd = te.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, inp_facing).orElse(null);
if(hnd != null) {
for(int i=0; i< hnd.getSlots(); ++i) {
ItemStack adj_stack = hnd.getStackInSlot(i);
if(!adj_stack.isEmpty()) {
ItemStack my_stack = adj_stack.copy();
if(my_stack.getCount() > getInventoryStackLimit()) my_stack.setCount(getInventoryStackLimit());
adj_stack.shrink(my_stack.getCount());
stacks_.set(FIFO_INPUT_1_SLOT_NO, my_stack);
energy_stored_ -= transfer_energy_consumption_;
dirty = true;
break;
}
}
}
}
}
}
return dirty;
}
// returns TE dirty
private boolean heat_up()
{
if(energy_stored_ < (energy_consumption_)) return false;
if(burntime_left_ >= (HEAT_CAPACITY-HEAT_INCREMENT)) return false;
energy_stored_ -= energy_consumption_;
burntime_left_ += HEAT_INCREMENT;
this.markDirty();
return true;
}
private void sync_blockstate()
{
final BlockState state = world.getBlockState(pos);
if((state.getBlock() instanceof BlockDecorFurnaceElectrical) && (state.get(LIT) != burning())) {
world.setBlockState(pos, state.with(LIT, burning()), 2);
}
}
}
//--------------------------------------------------------------------------------------------------------------------
// container
//--------------------------------------------------------------------------------------------------------------------
public static class BContainer extends Container implements Networking.INetworkSynchronisableContainer
{
private static final int PLAYER_INV_START_SLOTNO = 7;
protected final PlayerEntity player_;
protected final IInventory inventory_;
protected final IWorldPosCallable wpc_;
private final IIntArray fields_;
private final IRecipeType<? extends AbstractCookingRecipe> recipe_type_;
public int field(int index) { return fields_.get(index); }
public PlayerEntity player() { return player_ ; }
public IInventory inventory() { return inventory_ ; }
public World world() { return player_.world; }
public BContainer(int cid, PlayerInventory player_inventory)
{ this(cid, player_inventory, new Inventory(BTileEntity.NUM_OF_SLOTS), IWorldPosCallable.DUMMY, new IntArray(BTileEntity.NUM_OF_FIELDS)); }
private BContainer(int cid, PlayerInventory player_inventory, IInventory block_inventory, IWorldPosCallable wpc, IIntArray fields)
{
super(ModContent.CT_SMALL_ELECTRICAL_FURNACE, cid);
player_ = player_inventory.player;
inventory_ = block_inventory;
wpc_ = wpc;
fields_ = fields;
recipe_type_ = BTileEntity.RECIPE_TYPE;
addSlot(new Slot(inventory_, 0, 59, 28)); // smelting input
addSlot(new Slot(inventory_, 1, 16, 52)); // aux
addSlot(new BlockDecorFurnace.BContainer.BSlotResult(player_, inventory_, 2, 101, 28)); // smelting result
addSlot(new BlockDecorFurnace.BContainer.BSlotInpFifo(inventory_, 3, 34, 28)); // input fifo 0
addSlot(new BlockDecorFurnace.BContainer.BSlotInpFifo(inventory_, 4, 16, 28)); // input fifo 1
addSlot(new BlockDecorFurnace.BContainer.BSlotOutFifo(player_, inventory_, 5, 126, 28)); // out fifo 0
addSlot(new BlockDecorFurnace.BContainer.BSlotOutFifo(player_, inventory_, 6, 144, 28)); // out fifo 1
for(int x=0; x<9; ++x) {
addSlot(new Slot(player_inventory, x, 8+x*18, 144)); // player slots: 0..8
}
for(int y=0; y<3; ++y) {
for(int x=0; x<9; ++x) {
addSlot(new Slot(player_inventory, x+y*9+9, 8+x*18, 86+y*18)); // player slots: 9..35
}
}
this.trackIntArray(fields_); // === Add reference holders
}
@Override
public boolean canInteractWith(PlayerEntity player)
{ return inventory_.isUsableByPlayer(player); }
@Override
public ItemStack transferStackInSlot(PlayerEntity player, int index)
{
Slot slot = getSlot(index);
if((slot==null) || (!slot.getHasStack())) return ItemStack.EMPTY;
ItemStack slot_stack = slot.getStack();
ItemStack transferred = slot_stack.copy();
if((index==2) || (index==5) || (index==6)) {
// Output slots
if(!mergeItemStack(slot_stack, PLAYER_INV_START_SLOTNO, PLAYER_INV_START_SLOTNO+36, true)) return ItemStack.EMPTY;
slot.onSlotChange(slot_stack, transferred);
} else if((index==0) || (index==3) || (index==4)) {
// Input slots
if(!mergeItemStack(slot_stack, PLAYER_INV_START_SLOTNO, PLAYER_INV_START_SLOTNO+36, false)) return ItemStack.EMPTY;
} else if(index==1) {
// Bypass slot
if(!mergeItemStack(slot_stack, PLAYER_INV_START_SLOTNO, PLAYER_INV_START_SLOTNO+36, false)) return ItemStack.EMPTY;
} else if((index >= PLAYER_INV_START_SLOTNO) && (index <= PLAYER_INV_START_SLOTNO+36)) {
// Player inventory
if(BTileEntity.canSmelt(world(), slot_stack)) {
if(
(!mergeItemStack(slot_stack, 0, 1, false)) && // smelting input
(!mergeItemStack(slot_stack, 3, 4, false)) && // fifo0
(!mergeItemStack(slot_stack, 4, 5, false)) // fifo1
) return ItemStack.EMPTY;
} else if((index >= PLAYER_INV_START_SLOTNO) && (index < PLAYER_INV_START_SLOTNO+27)) {
// player inventory --> player hotbar
if(!mergeItemStack(slot_stack, PLAYER_INV_START_SLOTNO+27, PLAYER_INV_START_SLOTNO+36, false)) return ItemStack.EMPTY;
} else if((index >= PLAYER_INV_START_SLOTNO+27) && (index < PLAYER_INV_START_SLOTNO+36) && (!mergeItemStack(slot_stack, PLAYER_INV_START_SLOTNO, PLAYER_INV_START_SLOTNO+27, false))) {
// player hotbar --> player inventory
return ItemStack.EMPTY;
}
} else {
// invalid slot
return ItemStack.EMPTY;
}
if(slot_stack.isEmpty()) {
slot.putStack(ItemStack.EMPTY);
} else {
slot.onSlotChanged();
}
if(slot_stack.getCount() == transferred.getCount()) return ItemStack.EMPTY;
slot.onTake(player, slot_stack);
return transferred;
}
// INetworkSynchronisableContainer ---------------------------------------------------------
@OnlyIn(Dist.CLIENT)
public void onGuiAction(CompoundNBT nbt)
{ Networking.PacketContainerSyncClientToServer.sendToServer(windowId, nbt); }
@OnlyIn(Dist.CLIENT)
public void onGuiAction(String key, int value)
{ CompoundNBT nbt=new CompoundNBT(); nbt.putInt(key, value); Networking.PacketContainerSyncClientToServer.sendToServer(windowId, nbt); }
@Override
public void onServerPacketReceived(int windowId, CompoundNBT nbt)
{}
@Override
public void onClientPacketReceived(int windowId, PlayerEntity player, CompoundNBT nbt)
{}
}
//--------------------------------------------------------------------------------------------------------------------
// GUI
//--------------------------------------------------------------------------------------------------------------------
@OnlyIn(Dist.CLIENT)
public static class BGui extends ContainerScreen<BContainer>
{
protected final PlayerEntity player_;
public BGui(BContainer container, PlayerInventory player_inventory, ITextComponent title)
{ super(container, player_inventory, title); this.player_ = player_inventory.player; }
@Override
public void init()
{ super.init(); }
@Override
public void render(int mouseX, int mouseY, float partialTicks)
{
renderBackground();
super.render(mouseX, mouseY, partialTicks);
renderHoveredToolTip(mouseX, mouseY);
}
@Override
protected void drawGuiContainerBackgroundLayer(float partialTicks, int mouseX, int mouseY)
{
RenderSystem.enableBlend();
RenderSystem.color4f(1.0F, 1.0F, 1.0F, 1.0F);
minecraft.getTextureManager().bindTexture(new ResourceLocation(ModEngineersDecor.MODID, "textures/gui/small_electrical_furnace_gui.png"));
final int x0=(width-xSize)/2, y0=(height-ySize)/2, w=xSize, h=ySize;
blit(x0, y0, 0, 0, w, h);
if(getContainer().field(6)!=0) {
final int hi = 13;
final int k = heat_px(hi);
blit(x0+61, y0+53+hi-k, 177, hi-k, 13, k);
}
blit(x0+79, y0+30, 176, 15, 1+progress_px(17), 15);
int we = energy_px(32, 8);
if(we>0) blit(x0+88, y0+53, 185, 30, we, 13);
RenderSystem.disableBlend();
}
private int progress_px(int pixels)
{ final int tc=getContainer().field(2), T=getContainer().field(3); return ((T>0) && (tc>0)) ? (tc * pixels / T) : (0); }
private int heat_px(int pixels)
{
int k = ((getContainer().field(0) * (pixels+1)) / (BlockDecorFurnaceElectrical.BTileEntity.HEAT_CAPACITY));
return (k < pixels) ? k : pixels;
}
private int energy_px(int maxwidth, int quantization)
{
int emax = getContainer().field(5);
int k = ((maxwidth * getContainer().field(1) * 9) / 8) /((emax>0?emax:1)+1);
k = (k >= maxwidth-2) ? maxwidth : k;
if(quantization > 0) k = ((k+(quantization/2))/quantization) * quantization;
return k;
}
}
}

View file

@ -0,0 +1,52 @@
/*
* @file BlockDecorFull.java
* @author Stefan Wilhelm (wile)
* @copyright (C) 2019 Stefan Wilhelm
* @license MIT (see https://opensource.org/licenses/MIT)
*
* Full block characteristics class. Explicitly overrides some
* `Block` methods to return faster due to exclusive block properties.
*/
package wile.engineersdecor.blocks;
import wile.engineersdecor.detail.ModAuxiliaries;
import net.minecraft.world.IBlockReader;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.StainedGlassBlock;
import net.minecraft.item.DyeColor;
import net.minecraft.item.ItemStack;
import net.minecraft.util.Direction;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.client.util.ITooltipFlag;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import javax.annotation.Nullable;
import java.util.List;
public class BlockDecorGlassBlock extends StainedGlassBlock implements IDecorBlock
{
public BlockDecorGlassBlock(long config, Block.Properties properties)
{ super(DyeColor.BLACK, properties); }
@Override
@OnlyIn(Dist.CLIENT)
public void addInformation(ItemStack stack, @Nullable IBlockReader world, List<ITextComponent> tooltip, ITooltipFlag flag)
{ ModAuxiliaries.Tooltip.addInformation(stack, world, tooltip, flag, true); }
@Override
public RenderTypeHint getRenderTypeHint()
{ return RenderTypeHint.TRANSLUCENT; }
@Override
@OnlyIn(Dist.CLIENT)
@SuppressWarnings("deprecation")
public boolean isSideInvisible(BlockState state, BlockState adjacentBlockState, Direction side)
{ return (adjacentBlockState.getBlock()==this) ? true : super.isSideInvisible(state, adjacentBlockState, side); }
@Override
public boolean canSpawnInBlock()
{ return false; }
}

View file

@ -0,0 +1,195 @@
/*
* @file BlockDecorHalfSlab.java
* @author Stefan Wilhelm (wile)
* @copyright (C) 2019 Stefan Wilhelm
* @license MIT (see https://opensource.org/licenses/MIT)
*
* Half slab ("slab slices") characteristics class. Actually
* it's now a quater slab, but who cares.
*/
package wile.engineersdecor.blocks;
import wile.engineersdecor.detail.ModAuxiliaries;
import net.minecraft.block.*;
import net.minecraft.client.util.ITooltipFlag;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.state.IntegerProperty;
import net.minecraft.util.*;
import net.minecraft.util.math.BlockRayTraceResult;
import net.minecraft.util.math.Vec3d;
import net.minecraft.util.math.shapes.VoxelShapes;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.world.World;
import net.minecraft.entity.EntityType;
import net.minecraft.state.StateContainer;
import net.minecraft.util.math.shapes.ISelectionContext;
import net.minecraft.item.BlockItemUseContext;
import net.minecraft.block.BlockState;
import net.minecraft.world.IBlockReader;
import net.minecraft.util.math.shapes.VoxelShape;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import wile.engineersdecor.detail.ModConfig;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class BlockDecorHalfSlab extends BlockDecor implements IWaterLoggable
{
public static final IntegerProperty PARTS = IntegerProperty.create("parts", 0, 14);
protected static final VoxelShape AABBs[] = {
VoxelShapes.create(new AxisAlignedBB(0, 0./16, 0, 1, 2./16, 1)),
VoxelShapes.create(new AxisAlignedBB(0, 0./16, 0, 1, 4./16, 1)),
VoxelShapes.create(new AxisAlignedBB(0, 0./16, 0, 1, 6./16, 1)),
VoxelShapes.create(new AxisAlignedBB(0, 0./16, 0, 1, 8./16, 1)),
VoxelShapes.create(new AxisAlignedBB(0, 0./16, 0, 1, 10./16, 1)),
VoxelShapes.create(new AxisAlignedBB(0, 0./16, 0, 1, 12./16, 1)),
VoxelShapes.create(new AxisAlignedBB(0, 0./16, 0, 1, 14./16, 1)),
VoxelShapes.create(new AxisAlignedBB(0, 0./16, 0, 1, 16./16, 1)),
VoxelShapes.create(new AxisAlignedBB(0, 2./16, 0, 1, 16./16, 1)),
VoxelShapes.create(new AxisAlignedBB(0, 4./16, 0, 1, 16./16, 1)),
VoxelShapes.create(new AxisAlignedBB(0, 6./16, 0, 1, 16./16, 1)),
VoxelShapes.create(new AxisAlignedBB(0, 8./16, 0, 1, 16./16, 1)),
VoxelShapes.create(new AxisAlignedBB(0, 10./16, 0, 1, 16./16, 1)),
VoxelShapes.create(new AxisAlignedBB(0, 12./16, 0, 1, 16./16, 1)),
VoxelShapes.create(new AxisAlignedBB(0, 14./16, 0, 1, 16./16, 1)),
VoxelShapes.create(new AxisAlignedBB(0,0,0,1,1,1)) // <- with 4bit fill
};
protected static final int num_slabs_contained_in_parts_[] = { 1,2,3,4,5,6,7,8,7,6,5,4,3,2,1 ,0x1 }; // <- with 4bit fill
public BlockDecorHalfSlab(long config, Block.Properties builder)
{ super(config|CFG_WATERLOGGABLE, builder); }
protected boolean is_cube(BlockState state)
{ return state.get(PARTS) == 0x07; }
@Override
@OnlyIn(Dist.CLIENT)
public void addInformation(ItemStack stack, @Nullable IBlockReader world, List<ITextComponent> tooltip, ITooltipFlag flag)
{
if(!ModAuxiliaries.Tooltip.addInformation(stack, world, tooltip, flag, true)) return;
if(!ModConfig.without_direct_slab_pickup) ModAuxiliaries.Tooltip.addInformation("engineersdecor.tooltip.slabpickup", "engineersdecor.tooltip.slabpickup", tooltip, flag, true);
}
@Override
public RenderTypeHint getRenderTypeHint()
{ return (((config & CFG_TRANSLUCENT)!=0) ? (RenderTypeHint.TRANSLUCENT) : (RenderTypeHint.CUTOUT)); }
@Override
public boolean canSpawnInBlock()
{ return false; }
@Override
@SuppressWarnings("deprecation")
public boolean canEntitySpawn(BlockState state, IBlockReader world, BlockPos pos, EntityType<?> entityType)
{ return false; }
@Override
public VoxelShape getShape(BlockState state, IBlockReader source, BlockPos pos, ISelectionContext selectionContext)
{ return AABBs[state.get(PARTS) & 0xf]; }
@Override
public VoxelShape getCollisionShape(BlockState state, IBlockReader world, BlockPos pos, ISelectionContext selectionContext)
{ return getShape(state, world, pos, selectionContext); }
@Override
protected void fillStateContainer(StateContainer.Builder<Block, BlockState> builder)
{ super.fillStateContainer(builder); builder.add(PARTS, WATERLOGGED); }
@Override
@Nullable
public BlockState getStateForPlacement(BlockItemUseContext context)
{
final Direction facing = context.getFace();
double y = context.getHitVec().getY();
return super.getStateForPlacement(context).with(PARTS, ((facing==Direction.UP) || ((facing!=Direction.DOWN) && (y < 0.6))) ? 0 : 14);
}
@Override
@SuppressWarnings("deprecation")
public BlockState rotate(BlockState state, Rotation rot)
{ return state; }
@Override
@SuppressWarnings("deprecation")
public BlockState mirror(BlockState state, Mirror mirrorIn)
{ return state; }
@Override
public boolean hasDynamicDropList()
{ return true; }
@Override
public List<ItemStack> dropList(BlockState state, World world, BlockPos pos, boolean explosion)
{ return new ArrayList<ItemStack>(Collections.singletonList(new ItemStack(this.asItem(), num_slabs_contained_in_parts_[state.get(PARTS) & 0xf]))); }
@Override
@SuppressWarnings("deprecation")
public boolean onBlockActivated(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockRayTraceResult rayTraceResult)
{
Direction face = rayTraceResult.getFace();
final ItemStack stack = player.getHeldItem(hand);
if(stack.isEmpty() || (Block.getBlockFromItem(stack.getItem()) != this)) return false;
if((face != Direction.UP) && (face != Direction.DOWN)) return false;
int parts = state.get(PARTS);
if((face != Direction.UP) && (parts > 7)) {
world.setBlockState(pos, state.with(PARTS, parts-1), 3);
} else if((face != Direction.DOWN) && (parts < 7)) {
world.setBlockState(pos, state.with(PARTS, parts+1), 3);
} else {
return (parts != 7);
}
if(world.isRemote) return true;
if(!player.isCreative()) {
stack.shrink(1);
if(player.inventory != null) player.inventory.markDirty();
}
SoundType st = this.getSoundType(state, world, pos, null);
world.playSound(null, pos, st.getPlaceSound(), SoundCategory.BLOCKS, (st.getVolume()+1f)/2.5f, 0.9f*st.getPitch());
return true;
}
@Override
@SuppressWarnings("deprecation")
public void onBlockClicked(BlockState state, World world, BlockPos pos, PlayerEntity player)
{
if((world.isRemote) || (ModConfig.without_direct_slab_pickup)) return;
final ItemStack stack = player.getHeldItemMainhand();
if(stack.isEmpty() || (Block.getBlockFromItem(stack.getItem()) != this)) return;
if(stack.getCount() >= stack.getMaxStackSize()) return;
Vec3d lv = player.getLookVec();
Direction facing = Direction.getFacingFromVector((float)lv.x, (float)lv.y, (float)lv.z);
if((facing != Direction.UP) && (facing != Direction.DOWN)) return;
if(state.getBlock() != this) return;
int parts = state.get(PARTS);
if((facing == Direction.DOWN) && (parts <= 7)) {
if(parts > 0) {
world.setBlockState(pos, state.with(PARTS, parts-1), 3);
} else {
world.removeBlock(pos, false);
}
} else if((facing == Direction.UP) && (parts >= 7)) {
if(parts < 14) {
world.setBlockState(pos, state.with(PARTS, parts + 1), 3);
} else {
world.removeBlock(pos, false);
}
} else {
return;
}
if(!player.isCreative()) {
stack.grow(1);
if(player.inventory != null) player.inventory.markDirty(); // @todo: check if inventory can actually be null
}
SoundType st = this.getSoundType(state, world, pos, null);
world.playSound(player, pos, st.getPlaceSound(), SoundCategory.BLOCKS, (st.getVolume()+1f)/2.5f, 0.9f*st.getPitch());
}
}

View file

@ -0,0 +1,877 @@
/*
* @file BlockDecorHopper.java
* @author Stefan Wilhelm (wile)
* @copyright (C) 2019 Stefan Wilhelm
* @license MIT (see https://opensource.org/licenses/MIT)
*
* Hopper, factory automation suitable.
*/
package wile.engineersdecor.blocks;
import wile.engineersdecor.ModContent;
import wile.engineersdecor.ModEngineersDecor;
import wile.engineersdecor.detail.Networking;
import net.minecraft.world.IBlockReader;
import net.minecraft.world.World;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.HopperBlock;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.tileentity.TileEntityType;
import net.minecraft.tileentity.HopperTileEntity;
import net.minecraft.tileentity.ITickableTileEntity;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.ServerPlayerEntity;
import net.minecraft.entity.item.ItemEntity;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.item.*;
import net.minecraft.inventory.*;
import net.minecraft.inventory.container.INamedContainerProvider;
import net.minecraft.inventory.container.Container;
import net.minecraft.inventory.container.Slot;
import net.minecraft.util.*;
import net.minecraft.util.math.*;
import net.minecraft.util.text.*;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.client.gui.screen.inventory.ContainerScreen;
import net.minecraftforge.fml.network.NetworkHooks;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.common.util.FakePlayer;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.items.wrapper.SidedInvWrapper;
import net.minecraftforge.items.CapabilityItemHandler;
import net.minecraftforge.items.IItemHandler;
import com.mojang.blaze3d.systems.RenderSystem;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;
public class BlockDecorHopper extends BlockDecorDirected
{
public BlockDecorHopper(long config, Block.Properties builder, final AxisAlignedBB unrotatedAABB)
{ super(config, builder, unrotatedAABB); }
@Override
@SuppressWarnings("deprecation")
public boolean hasComparatorInputOverride(BlockState state)
{ return true; }
@Override
@SuppressWarnings("deprecation")
public int getComparatorInputOverride(BlockState blockState, World world, BlockPos pos)
{ return Container.calcRedstone(world.getTileEntity(pos)); }
@Override
public boolean hasTileEntity(BlockState state)
{ return true; }
@Override
@Nullable
public TileEntity createTileEntity(BlockState state, IBlockReader world)
{ return new BlockDecorHopper.BTileEntity(); }
@Override
public void onBlockPlacedBy(World world, BlockPos pos, BlockState state, LivingEntity placer, ItemStack stack)
{
if(world.isRemote) return;
if((!stack.hasTag()) || (!stack.getTag().contains("tedata"))) return;
CompoundNBT te_nbt = stack.getTag().getCompound("tedata");
if(te_nbt.isEmpty()) return;
final TileEntity te = world.getTileEntity(pos);
if(!(te instanceof BTileEntity)) return;
((BTileEntity)te).readnbt(te_nbt, false);
((BTileEntity)te).reset_rtstate();
((BTileEntity)te).markDirty();
}
@Override
public boolean hasDynamicDropList()
{ return true; }
@Override
public List<ItemStack> dropList(BlockState state, World world, BlockPos pos, boolean explosion)
{
final List<ItemStack> stacks = new ArrayList<ItemStack>();
if(world.isRemote) return stacks;
final TileEntity te = world.getTileEntity(pos);
if(!(te instanceof BTileEntity)) return stacks;
if(!explosion) {
ItemStack stack = new ItemStack(this, 1);
CompoundNBT te_nbt = ((BTileEntity)te).clear_getnbt();
if(!te_nbt.isEmpty()) {
CompoundNBT nbt = new CompoundNBT();
nbt.put("tedata", te_nbt);
stack.setTag(nbt);
}
stacks.add(stack);
} else {
for(ItemStack stack: ((BTileEntity)te).stacks_) {
if(!stack.isEmpty()) stacks.add(stack);
}
((BTileEntity)te).reset_rtstate();
}
return stacks;
}
@Override
@SuppressWarnings("deprecation")
public boolean onBlockActivated(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockRayTraceResult rayTraceResult)
{
if(world.isRemote) return true;
final TileEntity te = world.getTileEntity(pos);
if(!(te instanceof BTileEntity)) return true;
if((!(player instanceof ServerPlayerEntity) && (!(player instanceof FakePlayer)))) return true;
NetworkHooks.openGui((ServerPlayerEntity)player,(INamedContainerProvider)te);
return true;
}
@Override
@SuppressWarnings("deprecation")
public void neighborChanged(BlockState state, World world, BlockPos pos, Block block, BlockPos fromPos, boolean unused)
{
if(!(world instanceof World) || (((World) world).isRemote)) return;
TileEntity te = world.getTileEntity(pos);
if(!(te instanceof BTileEntity)) return;
((BTileEntity)te).block_updated();
}
@Override
public void onFallenUpon(World world, BlockPos pos, Entity entity, float fallDistance)
{
super.onFallenUpon(world, pos, entity, fallDistance);
if(!(entity instanceof ItemEntity)) return;
TileEntity te = world.getTileEntity(pos);
if(!(te instanceof BTileEntity)) return;
((BTileEntity)te).collection_timer_ = 0;
}
@Override
@SuppressWarnings("deprecation")
public boolean canProvidePower(BlockState state)
{ return true; }
@Override
@SuppressWarnings("deprecation")
public int getWeakPower(BlockState blockState, IBlockReader blockAccess, BlockPos pos, Direction side)
{ return 0; }
@Override
@SuppressWarnings("deprecation")
public int getStrongPower(BlockState blockState, IBlockReader blockAccess, BlockPos pos, Direction side)
{ return 0; }
//--------------------------------------------------------------------------------------------------------------------
// Tile entity
//--------------------------------------------------------------------------------------------------------------------
public static class BTileEntity extends TileEntity implements ITickableTileEntity, INameable, IInventory, INamedContainerProvider, ISidedInventory
{
public static final int NUM_OF_FIELDS = 7;
public static final int TICK_INTERVAL = 10;
public static final int COLLECTION_INTERVAL = 50;
public static final int NUM_OF_SLOTS = 18;
public static final int MAX_TRANSFER_COUNT = 32;
public static final int MAX_COLLECTION_RANGE = 4;
public static final int PERIOD_OFFSET = 10;
///
public static final int LOGIC_INVERTED = 0x01;
public static final int LOGIC_CONTINUOUS = 0x02;
///
private boolean block_power_signal_ = false;
private boolean block_power_updated_ = false;
private int collection_timer_ = 0;
private int delay_timer_ = 0;
private int transfer_count_ = 1;
private int logic_ = LOGIC_INVERTED|LOGIC_CONTINUOUS;
private int transfer_period_ = 0;
private int collection_range_ = 0;
private int current_slot_index_ = 0;
private int tick_timer_ = 0;
protected NonNullList<ItemStack> stacks_;
public static void on_config(int cooldown_ticks)
{
// ModEngineersDecor.logger.info("Config factory hopper:");
}
public BTileEntity()
{
this(ModContent.TET_FACTORY_HOPPER);
stacks_ = NonNullList.<ItemStack>withSize(NUM_OF_SLOTS, ItemStack.EMPTY);
reset_rtstate();
}
public BTileEntity(TileEntityType<?> te_type)
{
super(te_type);
stacks_ = NonNullList.<ItemStack>withSize(NUM_OF_SLOTS, ItemStack.EMPTY);
reset_rtstate();
}
public void reset_rtstate()
{
block_power_signal_ = false;
block_power_updated_ = false;
}
public CompoundNBT clear_getnbt()
{
CompoundNBT nbt = new CompoundNBT();
block_power_signal_ = false;
writenbt(nbt, false);
for(int i=0; i<stacks_.size(); ++i) stacks_.set(i, ItemStack.EMPTY);
reset_rtstate();
block_power_updated_ = false;
return nbt;
}
public void readnbt(CompoundNBT nbt, boolean update_packet)
{
stacks_ = NonNullList.<ItemStack>withSize(NUM_OF_SLOTS, ItemStack.EMPTY);
ItemStackHelper.loadAllItems(nbt, stacks_);
while(stacks_.size() < NUM_OF_SLOTS) stacks_.add(ItemStack.EMPTY);
block_power_signal_ = nbt.getBoolean("powered");
current_slot_index_ = nbt.getInt("act_slot_index");
transfer_count_ = MathHelper.clamp(nbt.getInt("xsize"), 1, MAX_TRANSFER_COUNT);
logic_ = nbt.getInt("logic");
transfer_period_ = nbt.getInt("period");
collection_range_ = nbt.getInt("range");
}
protected void writenbt(CompoundNBT nbt, boolean update_packet)
{
ItemStackHelper.saveAllItems(nbt, stacks_);
nbt.putBoolean("powered", block_power_signal_);
nbt.putInt("act_slot_index", current_slot_index_);
nbt.putInt("xsize", transfer_count_);
nbt.putInt("logic", logic_);
nbt.putInt("period", transfer_period_);
nbt.putInt("range", collection_range_);
}
public void block_updated()
{
// RS power check, both edges
boolean powered = world.isBlockPowered(pos);
if(block_power_signal_ != powered) block_power_updated_ = true;
block_power_signal_ = powered;
tick_timer_ = 1;
}
public boolean is_input_slot(int index)
{ return (index >= 0) && (index < NUM_OF_SLOTS); }
// TileEntity --------------------------------------------------------------------------------------------
@Override
public void read(CompoundNBT nbt)
{ super.read(nbt); readnbt(nbt, false); }
@Override
public CompoundNBT write(CompoundNBT nbt)
{ super.write(nbt); writenbt(nbt, false); return nbt; }
// INamable ----------------------------------------------------------------------------------------------
@Override
public ITextComponent getName()
{ final Block block=getBlockState().getBlock(); return new StringTextComponent((block!=null) ? block.getTranslationKey() : "Factory Hopper"); }
@Override
public boolean hasCustomName()
{ return false; }
@Override
public ITextComponent getCustomName()
{ return getName(); }
// INamedContainerProvider ------------------------------------------------------------------------------
@Override
public ITextComponent getDisplayName()
{ return INameable.super.getDisplayName(); }
@Override
public Container createMenu(int id, PlayerInventory inventory, PlayerEntity player )
{ return new BContainer(id, inventory, this, IWorldPosCallable.of(world, pos), fields); }
// IInventory --------------------------------------------------------------------------------------------
@Override
public int getSizeInventory()
{ return stacks_.size(); }
@Override
public boolean isEmpty()
{ for(ItemStack stack: stacks_) { if(!stack.isEmpty()) return false; } return true; }
@Override
public ItemStack getStackInSlot(int index)
{ return (index < stacks_.size()) ? stacks_.get(index) : ItemStack.EMPTY; }
@Override
public ItemStack decrStackSize(int index, int count)
{ return ItemStackHelper.getAndSplit(stacks_, index, count); }
@Override
public ItemStack removeStackFromSlot(int index)
{ return ItemStackHelper.getAndRemove(stacks_, index); }
@Override
public void setInventorySlotContents(int index, ItemStack stack)
{
stacks_.set(index, stack);
if(stack.getCount() > getInventoryStackLimit()) stack.setCount(getInventoryStackLimit());
if(tick_timer_ > 8) tick_timer_ = 8;
markDirty();
}
@Override
public int getInventoryStackLimit()
{ return 64; }
@Override
public void markDirty()
{ super.markDirty(); }
@Override
public boolean isUsableByPlayer(PlayerEntity player)
{ return getPos().distanceSq(player.getPosition()) < 36; }
@Override
public void openInventory(PlayerEntity player)
{}
@Override
public void closeInventory(PlayerEntity player)
{ markDirty(); }
@Override
public boolean isItemValidForSlot(int index, ItemStack stack)
{ return true; }
@Override
public void clear()
{ stacks_.clear(); }
// Fields -----------------------------------------------------------------------------------------------
protected final IIntArray fields = new IntArray(BTileEntity.NUM_OF_FIELDS)
{
@Override
public int get(int id)
{
switch(id) {
case 0: return collection_range_;
case 1: return transfer_count_;
case 2: return logic_;
case 3: return transfer_period_;
case 4: return delay_timer_;
case 5: return block_power_signal_ ? 1 : 0;
case 6: return current_slot_index_;
default: return 0;
}
}
@Override
public void set(int id, int value)
{
switch(id) {
case 0: collection_range_ = MathHelper.clamp(value,0, MAX_COLLECTION_RANGE); return;
case 1: transfer_count_ = MathHelper.clamp(value,1, MAX_TRANSFER_COUNT); return;
case 2: logic_ = value; return;
case 3: transfer_period_ = MathHelper.clamp(value,0, 100); return;
case 4: delay_timer_ = MathHelper.clamp(value,0, 400); return;
case 5: block_power_signal_ = (value != 0); return;
case 6: current_slot_index_ = MathHelper.clamp(value, 0, NUM_OF_SLOTS-1); return;
default: return;
}
}
};
// ISidedInventory --------------------------------------------------------------------------------------
LazyOptional<? extends IItemHandler>[] item_handlers = SidedInvWrapper.create(this, Direction.UP);
private static final int[] SIDED_INV_SLOTS;
static {
SIDED_INV_SLOTS = new int[NUM_OF_SLOTS];
for(int i=0; i<NUM_OF_SLOTS; ++i) SIDED_INV_SLOTS[i] = i;
}
@Override
public int[] getSlotsForFace(Direction side)
{ return SIDED_INV_SLOTS; }
@Override
public boolean canInsertItem(int index, ItemStack stack, Direction direction)
{ return is_input_slot(index) && isItemValidForSlot(index, stack); }
@Override
public boolean canExtractItem(int index, ItemStack stack, Direction direction)
{ return (direction != Direction.UP); }
// Capability export ------------------------------------------------------------------------------------
@Override
public <T> LazyOptional<T> getCapability(net.minecraftforge.common.capabilities.Capability<T> capability, @Nullable Direction facing)
{
if(!this.removed && (facing != null)) {
if(capability==CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) return item_handlers[0].cast();
}
return super.getCapability(capability, facing);
}
// ITickable and aux methods ---------------------------------------------------------------------
private static int next_slot(int i)
{ return (i<NUM_OF_SLOTS-1) ? (i+1) : 0; }
private int try_insert_into_hopper(final ItemStack stack)
{
final int max_to_insert = stack.getCount();
int n_to_insert = max_to_insert;
int first_empty_slot = -1;
for(int i=0; i<stacks_.size(); ++i) {
final ItemStack slotstack = stacks_.get(i);
if((first_empty_slot < 0) && slotstack.isEmpty()) { first_empty_slot=i; continue; }
if(!stack.isItemEqual(slotstack)) continue;
int nspace = slotstack.getMaxStackSize() - slotstack.getCount();
if(nspace <= 0) {
continue;
} else if(nspace >= n_to_insert) {
slotstack.grow(n_to_insert);
n_to_insert = 0;
break;
} else {
slotstack.grow(nspace);
n_to_insert -= nspace;
}
}
if((n_to_insert > 0) && (first_empty_slot >= 0)) {
ItemStack new_stack = stack.copy();
new_stack.setCount(n_to_insert);
stacks_.set(first_empty_slot, new_stack);
n_to_insert = 0;
}
return max_to_insert - n_to_insert;
}
private boolean try_insert(Direction facing)
{
ItemStack current_stack = ItemStack.EMPTY;
for(int i=0; i<NUM_OF_SLOTS; ++i) {
if(current_slot_index_ >= NUM_OF_SLOTS) current_slot_index_ = 0;
current_stack = stacks_.get(current_slot_index_);
if(!current_stack.isEmpty()) break;
current_slot_index_ = next_slot(current_slot_index_);
}
if(current_stack.isEmpty()) {
current_slot_index_ = 0;
return false;
}
final TileEntity te = world.getTileEntity(pos.offset(facing));
if(te == null) { delay_timer_ = TICK_INTERVAL+2; return false; } // no reason to recalculate this all the time if there is nothere to insert.
final IItemHandler ih = te.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, facing.getOpposite()).orElse(null);
if(ih == null) { delay_timer_ = TICK_INTERVAL+2; return false; }
if(te instanceof HopperTileEntity) {
Direction f = world.getBlockState(pos.offset(facing)).get(HopperBlock.FACING);
if(f==facing.getOpposite()) return false; // no back transfer
} else if(te instanceof BTileEntity) {
Direction f = world.getBlockState(pos.offset(facing)).get(FACING);
if(f==facing.getOpposite()) return false;
}
ItemStack insert_stack = current_stack.copy();
if(insert_stack.getCount() > transfer_count_) insert_stack.setCount(transfer_count_);
final int initial_insert_stack_size = insert_stack.getCount();
int first_empty_slot_index = -1;
if((ih == null) || ih.getSlots() <= 0) return false;
for(int i=0; i<ih.getSlots(); ++i) {
if(!ih.isItemValid(i, insert_stack)) continue;
final ItemStack target_stack = ih.getStackInSlot(i);
if((first_empty_slot_index < 0) && target_stack.isEmpty()) first_empty_slot_index = i;
if(!target_stack.isItemEqual(insert_stack)) continue;
insert_stack = ih.insertItem(i, insert_stack.copy(), false);
if(insert_stack.isEmpty()) break;
}
if((first_empty_slot_index >= 0) && (!insert_stack.isEmpty())) {
insert_stack = ih.insertItem(first_empty_slot_index, insert_stack.copy(), false);
}
final int num_inserted = initial_insert_stack_size-insert_stack.getCount();
if(num_inserted > 0) {
current_stack.shrink(num_inserted);
stacks_.set(current_slot_index_, current_stack);
}
if(!insert_stack.isEmpty()) current_slot_index_ = next_slot(current_slot_index_);
return (num_inserted > 0);
}
private boolean try_item_handler_extract(final IItemHandler ih)
{
final int end = ih.getSlots();
int n_to_extract = transfer_count_;
for(int i=0; i<end; ++i) {
if(ih.getStackInSlot(i).isEmpty()) continue;
ItemStack stack = ih.extractItem(i, n_to_extract, true);
if(stack.isEmpty()) continue;
int n_accepted = try_insert_into_hopper(stack);
if(n_accepted > 0) {
ItemStack test = ih.extractItem(i, n_accepted, false);
n_to_extract -= n_accepted;
if(n_to_extract <= 0) break;
}
}
return (n_to_extract < transfer_count_);
}
private boolean try_inventory_extract(final IInventory inv)
{
final int end = inv.getSizeInventory();
int n_to_extract = transfer_count_;
for(int i=0; i<end; ++i) {
ItemStack stack = inv.getStackInSlot(i).copy();
if(stack.isEmpty()) continue;
int n_accepted = try_insert_into_hopper(stack);
if(n_accepted > 0) {
stack.shrink(n_accepted);
n_to_extract -= n_accepted;
if(stack.isEmpty()) stack = ItemStack.EMPTY;
inv.setInventorySlotContents(i, stack);
if(n_to_extract <= 0) break;
}
}
if(n_to_extract < transfer_count_) {
inv.markDirty();
return true;
} else {
return false;
}
}
private boolean try_collect(Direction facing)
{
AxisAlignedBB collection_volume;
Vec3d rpos;
if(facing==Direction.UP) {
rpos = new Vec3d(0.5+pos.getX(),1.5+pos.getY(),0.5+pos.getZ());
collection_volume = (new AxisAlignedBB(pos.up())).grow(0.1+collection_range_, 0.6, 0.1+collection_range_);
} else {
rpos = new Vec3d(0.5+pos.getX(),-1.5+pos.getY(),0.5+pos.getZ());
collection_volume = (new AxisAlignedBB(pos.down(2))).grow(0.1+collection_range_, 1, 0.1+collection_range_);
}
final List<ItemEntity> items = world.getEntitiesWithinAABB(ItemEntity.class, collection_volume);
if(items.size() <= 0) return false;
final int max_to_collect = 3;
int n_collected = 0;
for(ItemEntity ie:items) {
boolean is_direct_collection_tange = ie.getDistanceSq(rpos)<0.7;
if(!is_direct_collection_tange && (ie.cannotPickup() || (!ie.onGround))) continue;
ItemStack stack = ie.getItem();
int n_accepted = try_insert_into_hopper(stack);
if(n_accepted <= 0) continue;
if(n_accepted == stack.getCount()) {
ie.remove();
} else {
stack.shrink(n_accepted);
}
if((!is_direct_collection_tange) && (++n_collected >= max_to_collect)) break;
}
return (n_collected > 0);
}
@Override
public void tick()
{
// Tick cycle pre-conditions
if(world.isRemote) return;
if((delay_timer_ > 0) && ((--delay_timer_) == 0)) markDirty();
if(--tick_timer_ > 0) return;
tick_timer_ = TICK_INTERVAL;
// Cycle init
boolean dirty = block_power_updated_;
final boolean rssignal = ((logic_ & LOGIC_INVERTED)!=0)==(!block_power_signal_);
final boolean pulse_mode = ((logic_ & LOGIC_CONTINUOUS)==0);
boolean trigger = (rssignal && ((block_power_updated_) || (!pulse_mode)));
final BlockState state = world.getBlockState(pos);
if(state == null) { block_power_signal_= false; return; }
final Direction hopper_facing = state.get(FACING);
// Trigger edge detection for next cycle
{
boolean tr = world.isBlockPowered(pos);
block_power_updated_ = (block_power_signal_ != tr);
block_power_signal_ = tr;
if(block_power_updated_) dirty = true;
}
// Collection
if(rssignal || pulse_mode) {
Direction hopper_input_facing = (hopper_facing==Direction.UP) ? Direction.DOWN : Direction.UP;
TileEntity te = world.getTileEntity(pos.offset(hopper_input_facing));
final IItemHandler ih = (te==null) ? (null) : (te.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, hopper_input_facing.getOpposite()).orElse(null));
if((ih != null) || (te instanceof ISidedInventory)) {
// IItemHandler pulling
if((ih != null)) {
if(try_item_handler_extract(ih)) dirty = true;
} else {
if(try_inventory_extract((IInventory)te)) dirty = true;
}
} else if((collection_timer_ -= TICK_INTERVAL) <= 0) {
// Ranged collection
collection_timer_ = COLLECTION_INTERVAL;
if(try_collect(hopper_input_facing)) dirty = true;
}
}
// Insertion
if(trigger && (delay_timer_ <= 0)) {
delay_timer_ = PERIOD_OFFSET + transfer_period_ * 2;
if(try_insert(hopper_facing)) dirty = true;
}
if(dirty) markDirty();
if(trigger && (tick_timer_ > TICK_INTERVAL)) tick_timer_ = TICK_INTERVAL;
}
}
//--------------------------------------------------------------------------------------------------------------------
// container
//--------------------------------------------------------------------------------------------------------------------
public static class BContainer extends Container implements Networking.INetworkSynchronisableContainer
{
private static final int PLAYER_INV_START_SLOTNO = BTileEntity.NUM_OF_SLOTS;
private final PlayerEntity player_;
private final IInventory inventory_;
private final IWorldPosCallable wpc_;
private final IIntArray fields_;
public final int field(int index) { return fields_.get(index); }
public BContainer(int cid, PlayerInventory player_inventory)
{ this(cid, player_inventory, new Inventory(BTileEntity.NUM_OF_SLOTS), IWorldPosCallable.DUMMY, new IntArray(BTileEntity.NUM_OF_FIELDS)); }
private BContainer(int cid, PlayerInventory player_inventory, IInventory block_inventory, IWorldPosCallable wpc, IIntArray fields)
{
super(ModContent.CT_FACTORY_HOPPER, cid);
fields_ = fields;
wpc_ = wpc;
player_ = player_inventory.player;
inventory_ = block_inventory;
int i=-1;
// input slots (stacks 0 to 17)
for(int y=0; y<3; ++y) {
for(int x=0; x<6; ++x) {
int xpos = 11+x*18, ypos = 9+y*17;
addSlot(new Slot(inventory_, ++i, xpos, ypos));
}
}
// player slots
for(int x=0; x<9; ++x) {
addSlot(new Slot(player_inventory, x, 8+x*18, 129)); // player slots: 0..8
}
for(int y=0; y<3; ++y) {
for(int x=0; x<9; ++x) {
addSlot(new Slot(player_inventory, x+y*9+9, 8+x*18, 71+y*18)); // player slots: 9..35
}
}
this.trackIntArray(fields_); // === Add reference holders
}
@Override
public boolean canInteractWith(PlayerEntity player)
{ return inventory_.isUsableByPlayer(player); }
@Override
public ItemStack transferStackInSlot(PlayerEntity player, int index)
{
Slot slot = getSlot(index);
if((slot==null) || (!slot.getHasStack())) return ItemStack.EMPTY;
ItemStack slot_stack = slot.getStack();
ItemStack transferred = slot_stack.copy();
if((index>=0) && (index<PLAYER_INV_START_SLOTNO)) {
// Device slots
if(!mergeItemStack(slot_stack, PLAYER_INV_START_SLOTNO, PLAYER_INV_START_SLOTNO+36, false)) return ItemStack.EMPTY;
} else if((index >= PLAYER_INV_START_SLOTNO) && (index <= PLAYER_INV_START_SLOTNO+36)) {
// Player slot
if(!mergeItemStack(slot_stack, 0, BTileEntity.NUM_OF_SLOTS, false)) return ItemStack.EMPTY;
} else {
// invalid slot
return ItemStack.EMPTY;
}
if(slot_stack.isEmpty()) {
slot.putStack(ItemStack.EMPTY);
} else {
slot.onSlotChanged();
}
if(slot_stack.getCount() == transferred.getCount()) return ItemStack.EMPTY;
slot.onTake(player, slot_stack);
return transferred;
}
// INetworkSynchronisableContainer ---------------------------------------------------------
@OnlyIn(Dist.CLIENT)
public void onGuiAction(CompoundNBT nbt)
{ Networking.PacketContainerSyncClientToServer.sendToServer(windowId, nbt); }
@OnlyIn(Dist.CLIENT)
public void onGuiAction(String key, int value)
{
CompoundNBT nbt = new CompoundNBT();
nbt.putInt(key, value);
Networking.PacketContainerSyncClientToServer.sendToServer(windowId, nbt);
}
@Override
public void onServerPacketReceived(int windowId, CompoundNBT nbt)
{}
@Override
public void onClientPacketReceived(int windowId, PlayerEntity player, CompoundNBT nbt)
{
if(!(inventory_ instanceof BTileEntity)) return;
BTileEntity te = (BTileEntity)inventory_;
if(nbt.contains("xsize")) te.transfer_count_ = MathHelper.clamp(nbt.getInt("xsize"), 1, BTileEntity.MAX_TRANSFER_COUNT);
if(nbt.contains("period")) te.transfer_period_ = MathHelper.clamp(nbt.getInt("period"), 0, 100);
if(nbt.contains("range")) te.collection_range_ = MathHelper.clamp(nbt.getInt("range"), 0, BTileEntity.MAX_COLLECTION_RANGE);
if(nbt.contains("logic")) te.logic_ = nbt.getInt("logic");
if(nbt.contains("manual_trigger") && (nbt.getInt("manual_trigger")!=0)) { te.block_power_signal_=true; te.block_power_updated_=true; te.tick_timer_=1; }
te.markDirty();
}
}
//--------------------------------------------------------------------------------------------------------------------
// GUI
//--------------------------------------------------------------------------------------------------------------------
@OnlyIn(Dist.CLIENT)
public static class BGui extends ContainerScreen<BContainer>
{
protected final PlayerEntity player_;
public BGui(BContainer container, PlayerInventory player_inventory, ITextComponent title)
{ super(container, player_inventory, title); this.player_ = player_inventory.player; }
@Override
public void init()
{ super.init(); }
@Override
public void render(int mouseX, int mouseY, float partialTicks)
{
renderBackground();
super.render(mouseX, mouseY, partialTicks);
renderHoveredToolTip(mouseX, mouseY);
}
@Override
public boolean mouseClicked(double mouseX, double mouseY, int mouseButton)
{
BContainer container = (BContainer)getContainer();
int mx = (int)(mouseX - getGuiLeft() + .5), my = (int)(mouseY - getGuiTop() + .5);
if((!isPointInRegion(126, 1, 49, 60, mouseX, mouseY))) {
return super.mouseClicked(mouseX, mouseY, mouseButton);
} else if(isPointInRegion(128, 9, 44, 10, mouseX, mouseY)) {
int range = (mx-133);
if(range < -1) {
range = container.field(0) - 1; // -
} else if(range >= 34) {
range = container.field(0) + 1; // +
} else {
range = (int)(0.5 + ((((double)BTileEntity.MAX_COLLECTION_RANGE) * range)/34)); // slider
range = MathHelper.clamp(range, 0, BTileEntity.MAX_COLLECTION_RANGE);
}
container.onGuiAction("range", range);
} else if(isPointInRegion(128, 21, 44, 10, mouseX, mouseY)) {
int period = (mx-133);
if(period < -1) {
period = container.field(3) - 3; // -
} else if(period >= 35) {
period = container.field(3) + 3; // +
} else {
period = (int)(0.5 + ((100.0 * period)/34));
}
period = MathHelper.clamp(period, 0, 100);
container.onGuiAction("period", period);
} else if(isPointInRegion(128, 34, 44, 10, mouseX, mouseY)) {
int ndrop = (mx-134);
if(ndrop < -1) {
ndrop = container.field(1) - 1; // -
} else if(ndrop >= 34) {
ndrop = container.field(1) + 1; // +
} else {
ndrop = MathHelper.clamp(1+ndrop, 1, BTileEntity.MAX_TRANSFER_COUNT); // slider
}
container.onGuiAction("xsize", ndrop);
} else if(isPointInRegion(133, 49, 9, 9, mouseX, mouseY)) {
container.onGuiAction("manual_trigger", 1);
} else if(isPointInRegion(145, 49, 9, 9, mouseX, mouseY)) {
container.onGuiAction("logic", container.field(2) ^ BTileEntity.LOGIC_INVERTED);
} else if(isPointInRegion(159, 49, 7, 9, mouseX, mouseY)) {
container.onGuiAction("logic", container.field(2) ^ BTileEntity.LOGIC_CONTINUOUS);
}
return true;
}
@Override
protected void drawGuiContainerBackgroundLayer(float partialTicks, int mouseX, int mouseY)
{
RenderSystem.enableBlend();
RenderSystem.color4f(1.0F, 1.0F, 1.0F, 1.0F);
this.minecraft.getTextureManager().bindTexture(new ResourceLocation(ModEngineersDecor.MODID, "textures/gui/factory_hopper_gui.png"));
final int x0=getGuiLeft(), y0=getGuiTop(), w=getXSize(), h=getYSize();
blit(x0, y0, 0, 0, w, h);
BContainer container = (BContainer)getContainer();
// active slot
{
int slot_index = container.field(6);
if((slot_index < 0) || (slot_index >= BTileEntity.NUM_OF_SLOTS)) slot_index = 0;
int x = (x0+10+((slot_index % 6) * 18));
int y = (y0+8+((slot_index / 6) * 17));
blit(x, y, 200, 8, 18, 18);
}
// collection range
{
int lut[] = { 133, 141, 149, 157, 166 };
int px = lut[MathHelper.clamp(container.field(0), 0, BTileEntity.MAX_COLLECTION_RANGE)];
int x = x0 + px - 2;
int y = y0 + 14;
blit(x, y, 179, 40, 5, 5);
}
// transfer period
{
int px = (int)Math.round(((33.5 * container.field(3)) / 100) + 1);
int x = x0 + 132 - 2 + MathHelper.clamp(px, 0, 34);
int y = y0 + 27;
blit(x, y, 179, 40, 5, 5);
}
// transfer count
{
int x = x0 + 133 - 2 + (container.field(1));
int y = y0 + 40;
blit(x, y, 179, 40, 5, 5);
}
// redstone input
{
if(container.field(5) != 0) {
blit(x0+133, y0+49, 217, 49, 9, 9);
}
}
// trigger logic
{
int inverter_offset = ((container.field(2) & BTileEntity.LOGIC_INVERTED) != 0) ? 11 : 0;
blit(x0+145, y0+49, 177+inverter_offset, 49, 9, 9);
int pulse_mode_offset = ((container.field(2) & BTileEntity.LOGIC_CONTINUOUS ) != 0) ? 9 : 0;
blit(x0+159, y0+49, 199+pulse_mode_offset, 49, 9, 9);
}
// delay timer running indicator
{
if((container.field(4) > BTileEntity.PERIOD_OFFSET) && ((System.currentTimeMillis() % 1000) < 500)) {
blit(x0+148, y0+22, 187, 22, 3, 3);
}
}
RenderSystem.disableBlend();
}
}
}

View file

@ -0,0 +1,133 @@
/*
* @file BlockDecorHorizontalSupport.java
* @author Stefan Wilhelm (wile)
* @copyright (C) 2019 Stefan Wilhelm
* @license MIT (see https://opensource.org/licenses/MIT)
*
* Horizontal ceiling support. Symmetric x axis, fixed in
* xz plane, therefore boolean placement state.
*/
package wile.engineersdecor.blocks;
import net.minecraft.block.IWaterLoggable;
import wile.engineersdecor.ModContent;
import wile.engineersdecor.detail.ModAuxiliaries;
import net.minecraft.entity.EntityType;
import net.minecraft.util.math.shapes.ISelectionContext;
import net.minecraft.block.Block;
import net.minecraft.item.BlockItemUseContext;
import net.minecraft.state.BooleanProperty;
import net.minecraft.state.IntegerProperty;
import net.minecraft.state.StateContainer;
import net.minecraft.util.*;
import net.minecraft.util.math.shapes.VoxelShape;
import net.minecraft.util.math.shapes.VoxelShapes;
import net.minecraft.world.IBlockReader;
import net.minecraft.world.IWorld;
import net.minecraft.world.World;
import net.minecraft.block.BlockState;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.Arrays;
public class BlockDecorHorizontalSupport extends BlockDecor implements IWaterLoggable
{
public static final BooleanProperty EASTWEST = BooleanProperty.create("eastwest");
public static final BooleanProperty LEFTBEAM = BooleanProperty.create("leftbeam");
public static final BooleanProperty RIGHTBEAM = BooleanProperty.create("rightbeam");
public static final IntegerProperty DOWNCONNECT = IntegerProperty.create("downconnect", 0, 2);
protected final ArrayList<VoxelShape> AABBs;
public BlockDecorHorizontalSupport(long config, Block.Properties builder, final AxisAlignedBB unrotatedAABB)
{
super(config|CFG_HORIZIONTAL|CFG_WATERLOGGABLE, builder);
AABBs = new ArrayList<VoxelShape>(Arrays.asList(
// Effective bounding box
VoxelShapes.create(ModAuxiliaries.getRotatedAABB(unrotatedAABB.grow(2.0/16, 0, 0), Direction.NORTH, true)),
VoxelShapes.create(ModAuxiliaries.getRotatedAABB(unrotatedAABB.grow(2.0/16, 0, 0), Direction.WEST, true)),
// Displayed bounding box
VoxelShapes.create(ModAuxiliaries.getRotatedAABB(unrotatedAABB, Direction.NORTH, true)),
VoxelShapes.create(ModAuxiliaries.getRotatedAABB(unrotatedAABB, Direction.WEST, true))
));
}
@Override
public RenderTypeHint getRenderTypeHint()
{ return RenderTypeHint.CUTOUT; }
@Override
public boolean canSpawnInBlock()
{ return false; }
@Override
@SuppressWarnings("deprecation")
public boolean canEntitySpawn(BlockState state, IBlockReader world, BlockPos pos, EntityType<?> entityType)
{ return false; }
@Override
public VoxelShape getShape(BlockState state, IBlockReader source, BlockPos pos, ISelectionContext selectionContext)
{ return AABBs.get(state.get(EASTWEST) ? 0x1 : 0x0); }
@Override
public VoxelShape getCollisionShape(BlockState state, IBlockReader world, BlockPos pos, ISelectionContext selectionContext)
{ return getShape(state, world, pos, selectionContext); }
@Override
protected void fillStateContainer(StateContainer.Builder<Block, BlockState> builder)
{ super.fillStateContainer(builder); builder.add(EASTWEST, RIGHTBEAM, LEFTBEAM, DOWNCONNECT, WATERLOGGED); }
@Override
@Nullable
public BlockState getStateForPlacement(BlockItemUseContext context)
{ return temp_block_update_until_better(super.getStateForPlacement(context).with(EASTWEST, context.getPlacementHorizontalFacing().getAxis()==Direction.Axis.X), context.getWorld(), context.getPos()); }
private BlockState temp_block_update_until_better(BlockState state, IWorld world, BlockPos pos)
{
boolean ew = state.get(EASTWEST);
final BlockState rstate = world.getBlockState((!ew) ? (pos.east()) : (pos.south()) );
final BlockState lstate = world.getBlockState((!ew) ? (pos.west()) : (pos.north()) );
final BlockState dstate = world.getBlockState(pos.down());
int down_connector = 0;
if((dstate.getBlock() instanceof BlockDecorStraightPole)) {
final Direction dfacing = dstate.get(BlockDecorStraightPole.FACING);
final BlockDecorStraightPole pole = (BlockDecorStraightPole)dstate.getBlock();
if((dfacing.getAxis() == Direction.Axis.Y)) {
if((pole== ModContent.THICK_STEEL_POLE) || ((pole==ModContent.THICK_STEEL_POLE_HEAD) && (dfacing==Direction.UP))) {
down_connector = 2;
} else if((pole==ModContent.THIN_STEEL_POLE) || ((pole==ModContent.THIN_STEEL_POLE_HEAD) && (dfacing==Direction.UP))) {
down_connector = 1;
}
}
}
return state.with(RIGHTBEAM, (rstate.getBlock()==this) && (rstate.get(EASTWEST) != ew))
.with(LEFTBEAM , (lstate.getBlock()==this) && (lstate.get(EASTWEST) != ew))
.with(DOWNCONNECT , down_connector);
}
@Override
@SuppressWarnings("deprecation")
public BlockState updatePostPlacement(BlockState state, Direction facing, BlockState facingState, IWorld world, BlockPos pos, BlockPos facingPos)
{ return temp_block_update_until_better(state, world, pos); }
@Deprecated
@SuppressWarnings("deprecation")
public void neighborChanged(BlockState state, World world, BlockPos pos, Block block, BlockPos fromPos)
{ world.setBlockState(pos, temp_block_update_until_better(state, world, pos)); }
@Override
@SuppressWarnings("deprecation")
public BlockState rotate(BlockState state, Rotation rot)
{ return (rot==Rotation.CLOCKWISE_180) ? state : state.with(EASTWEST, !state.get(EASTWEST)); }
@Override
@SuppressWarnings("deprecation")
public BlockState mirror(BlockState state, Mirror mirrorIn)
{ return state; }
}

View file

@ -0,0 +1,102 @@
/*
* @file BlockDecorLadder.java
* @author Stefan Wilhelm (wile)
* @copyright (C) 2019 Stefan Wilhelm
* @license MIT (see https://opensource.org/licenses/MIT)
*
* Ladder block. The implementation is based on the vanilla
* net.minecraft.block.BlockLadder. Minor changes to enable
* later configuration (for block list based construction
* time configuration), does not drop when the block behind
* is broken, etc.
*/
package wile.engineersdecor.blocks;
import wile.engineersdecor.detail.ModAuxiliaries;
import net.minecraft.fluid.IFluidState;
import net.minecraft.world.Explosion;
import net.minecraft.world.World;
import net.minecraft.entity.EntityType;
import net.minecraft.util.math.Vec3d;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.block.BlockState;
import net.minecraft.block.*;
import net.minecraft.block.material.PushReaction;
import net.minecraft.client.util.ITooltipFlag;
import net.minecraft.item.ItemStack;
import net.minecraft.util.math.shapes.VoxelShape;
import net.minecraft.util.math.shapes.VoxelShapes;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.world.IBlockReader;
import net.minecraft.util.*;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import javax.annotation.Nullable;
import java.util.List;
public class BlockDecorLadder extends LadderBlock implements IDecorBlock
{
protected static final AxisAlignedBB EDLADDER_UNROTATED_AABB = ModAuxiliaries.getPixeledAABB(3, 0, 0, 13, 16, 3);
protected static final VoxelShape EDLADDER_SOUTH_AABB = VoxelShapes.create(ModAuxiliaries.getRotatedAABB(EDLADDER_UNROTATED_AABB, Direction.SOUTH, false));
protected static final VoxelShape EDLADDER_EAST_AABB = VoxelShapes.create(ModAuxiliaries.getRotatedAABB(EDLADDER_UNROTATED_AABB, Direction.EAST, false));
protected static final VoxelShape EDLADDER_WEST_AABB = VoxelShapes.create(ModAuxiliaries.getRotatedAABB(EDLADDER_UNROTATED_AABB, Direction.WEST, false));
protected static final VoxelShape EDLADDER_NORTH_AABB = VoxelShapes.create(ModAuxiliaries.getRotatedAABB(EDLADDER_UNROTATED_AABB, Direction.NORTH, false));
private static boolean without_speed_boost_ = false;
public static void on_config(boolean without_speed_boost)
{ without_speed_boost_ = without_speed_boost; }
public BlockDecorLadder(long config, Block.Properties builder)
{ super(builder); }
@Override
public RenderTypeHint getRenderTypeHint()
{ return RenderTypeHint.CUTOUT; }
@Override
@OnlyIn(Dist.CLIENT)
public void addInformation(ItemStack stack, @Nullable IBlockReader world, List<ITextComponent> tooltip, ITooltipFlag flag)
{ ModAuxiliaries.Tooltip.addInformation(stack, world, tooltip, flag, true); }
public VoxelShape getShape(BlockState state, IBlockReader worldIn, BlockPos pos)
{
switch ((Direction)state.get(FACING)) {
case NORTH: return EDLADDER_NORTH_AABB;
case SOUTH: return EDLADDER_SOUTH_AABB;
case WEST: return EDLADDER_WEST_AABB;
default: return EDLADDER_EAST_AABB;
}
}
@Override
public boolean canSpawnInBlock()
{ return false; }
@Override
@SuppressWarnings("deprecation")
public boolean canEntitySpawn(BlockState state, IBlockReader world, BlockPos pos, EntityType<?> entityType)
{ return false; }
@Override
@SuppressWarnings("deprecation")
public PushReaction getPushReaction(BlockState state)
{ return PushReaction.NORMAL; }
// Player update event, forwarded from the main mod instance.
public static void onPlayerUpdateEvent(final PlayerEntity player)
{
if((without_speed_boost_) || (player.onGround) || (!player.isOnLadder()) || (player.func_225608_bj_()/*isSneaking()*/) || (player.isSpectator())) return;
double lvy = player.getLookVec().y;
if(Math.abs(lvy) < 0.94) return;
final BlockPos pos = player.getPosition();
final BlockState state = player.world.getBlockState(pos);
if(!(state.getBlock() instanceof BlockDecorLadder)) return;
player.fallDistance = 0;
player.setMotionMultiplier(state, new Vec3d(0.2, (lvy>0)?(3):(6), 0.2));
}
}

View file

@ -0,0 +1,627 @@
/*
* @file BlockDecorMilker.java
* @author Stefan Wilhelm (wile)
* @copyright (C) 2019 Stefan Wilhelm
* @license MIT (see https://opensource.org/licenses/MIT)
*
* Frequently attracts and milks nearby cows
*/
package wile.engineersdecor.blocks;
import wile.engineersdecor.ModEngineersDecor;
import wile.engineersdecor.ModContent;
import wile.engineersdecor.detail.ExtItems;
import wile.engineersdecor.detail.ItemHandling;
import net.minecraft.world.World;
import net.minecraft.world.IWorldReader;
import net.minecraft.world.IBlockReader;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.state.BooleanProperty;
import net.minecraft.state.StateContainer;
import net.minecraft.tileentity.ITickableTileEntity;
import net.minecraft.tileentity.TileEntityType;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.entity.CreatureEntity;
import net.minecraft.entity.item.ItemEntity;
import net.minecraft.entity.passive.CowEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.LivingEntity;
import net.minecraft.item.*;
import net.minecraft.fluid.Fluid;
import net.minecraft.fluid.Fluids;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.util.*;
import net.minecraft.util.math.*;
import net.minecraftforge.common.capabilities.ICapabilityProvider;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.energy.CapabilityEnergy;
import net.minecraftforge.energy.IEnergyStorage;
import net.minecraftforge.items.IItemHandler;
import net.minecraftforge.items.ItemHandlerHelper;
import net.minecraftforge.items.wrapper.PlayerMainInvWrapper;
import net.minecraftforge.fluids.FluidUtil;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.capability.CapabilityFluidHandler;
import net.minecraftforge.fluids.capability.IFluidHandler;
import net.minecraftforge.fluids.capability.IFluidHandler.FluidAction;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.*;
import java.util.Map.Entry;
public class BlockDecorMilker extends BlockDecorDirectedHorizontal
{
public static final BooleanProperty FILLED = BooleanProperty.create("filled");
public static final BooleanProperty ACTIVE = BooleanProperty.create("active");
public BlockDecorMilker(long config, Block.Properties builder, final AxisAlignedBB unrotatedAABB)
{ super(config, builder, unrotatedAABB); }
@Override
protected void fillStateContainer(StateContainer.Builder<Block, BlockState> builder)
{ super.fillStateContainer(builder); builder.add(ACTIVE); builder.add(FILLED); }
@Override
@Nullable
public BlockState getStateForPlacement(BlockItemUseContext context)
{ return super.getStateForPlacement(context).with(FILLED, false).with(ACTIVE, false); }
@Override
@SuppressWarnings("deprecation")
public boolean hasComparatorInputOverride(BlockState state)
{ return true; }
@Override
@SuppressWarnings("deprecation")
public int getComparatorInputOverride(BlockState state, World world, BlockPos pos)
{
BTileEntity te = getTe(world, pos);
return (te==null) ? 0 : MathHelper.clamp((16 * te.fluid_level())/BTileEntity.TANK_CAPACITY, 0, 15);
}
@Override
public boolean hasTileEntity(BlockState state)
{ return true; }
@Override
@Nullable
public TileEntity createTileEntity(BlockState state, IBlockReader world)
{ return new BTileEntity(); }
@Override
@SuppressWarnings("deprecation")
public boolean onBlockActivated(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockRayTraceResult hit)
{
if(world.isRemote) return true;
BTileEntity te = getTe(world, pos);
if(te==null) return true;
final ItemStack in_stack = player.getHeldItem(hand);
final ItemStack out_stack = BTileEntity.milk_filled_container_item(in_stack);
if(out_stack.isEmpty() && (te.fluid_handler()!=null)) return FluidUtil.interactWithFluidHandler(player, hand, te.fluid_handler());
boolean drained = false;
IItemHandler player_inventory = new PlayerMainInvWrapper(player.inventory);
if(te.fluid_level() >= BTileEntity.BUCKET_SIZE) {
final ItemStack insert_stack = out_stack.copy();
ItemStack remainder = ItemHandlerHelper.insertItemStacked(player_inventory, insert_stack, false);
if(remainder.getCount() < insert_stack.getCount()) {
te.drain(BTileEntity.BUCKET_SIZE);
in_stack.shrink(1);
drained = true;
if(remainder.getCount() > 0) {
final ItemEntity ei = new ItemEntity(world, player.getPosition().getX(), player.getPosition().getY()+0.5, player.getPosition().getZ(), remainder);
ei.setPickupDelay(40);
ei.setMotion(0,0,0);
world.addEntity(ei);
}
}
}
if(drained) {
world.playSound(null, pos, SoundEvents.ITEM_BUCKET_FILL, SoundCategory.BLOCKS, 0.8f, 1f);
}
return true;
}
@Nullable
private BTileEntity getTe(World world, BlockPos pos)
{ final TileEntity te=world.getTileEntity(pos); return (!(te instanceof BTileEntity)) ? (null) : ((BTileEntity)te); }
//--------------------------------------------------------------------------------------------------------------------
// Tile entity
//--------------------------------------------------------------------------------------------------------------------
public static class BTileEntity extends TileEntity implements ITickableTileEntity, IEnergyStorage, ICapabilityProvider
{
public static final int BUCKET_SIZE = 1000;
public static final int TICK_INTERVAL = 80;
public static final int PROCESSING_TICK_INTERVAL = 20;
public static final int TANK_CAPACITY = BUCKET_SIZE * 12;
public static final int MAX_MILKING_TANK_LEVEL = TANK_CAPACITY-500;
public static final int FILLED_INDICATION_THRESHOLD = BUCKET_SIZE;
public static final int MAX_ENERGY_BUFFER = 16000;
public static final int MAX_ENERGY_TRANSFER = 512;
public static final int DEFAULT_ENERGY_CONSUMPTION = 0;
private static final Direction FLUID_TRANSFER_DIRECTRIONS[] = {Direction.DOWN,Direction.EAST,Direction.SOUTH,Direction.WEST,Direction.NORTH};
private enum MilkingState { IDLE, PICKED, COMING, POSITIONING, MILKING, LEAVING, WAITING }
private static FluidStack milk_fluid_ = new FluidStack(Fluids.WATER, 0);
private static HashMap<ItemStack, ItemStack> milk_containers_ = new HashMap<>();
private static int energy_consumption = DEFAULT_ENERGY_CONSUMPTION;
private int tick_timer_;
private int energy_stored_;
private int tank_level_ = 0;
private UUID tracked_cow_ = null;
private MilkingState state_ = MilkingState.IDLE;
private int state_timeout_ = 0;
private int state_timer_ = 0;
private BlockPos tracked_cow_original_position_ = null;
public static void on_config(int energy_consumption_per_tick)
{
energy_consumption = MathHelper.clamp(energy_consumption_per_tick, 0, 128);
{
Fluid milk = null; // FluidRe.getFluid("milk");
if(milk != null) milk_fluid_ = new FluidStack(milk, BUCKET_SIZE);
}
{
milk_containers_.put(new ItemStack(Items.BUCKET), new ItemStack(Items.MILK_BUCKET));
if(ExtItems.BOTTLED_MILK_BOTTLE_DRINKLABLE!=null) milk_containers_.put(new ItemStack(Items.GLASS_BOTTLE), new ItemStack(ExtItems.BOTTLED_MILK_BOTTLE_DRINKLABLE));
}
ModEngineersDecor.logger().info(
"Config milker energy consumption:" + energy_consumption + "rf/t"
+ ((milk_fluid_==null)?"":" [milk fluid available]")
+ ((ExtItems.BOTTLED_MILK_BOTTLE_DRINKLABLE==null)?"":" [bottledmilk mod available]")
);
}
public BTileEntity()
{ this(ModContent.TET_SMALL_MILKING_MACHINE); }
public BTileEntity(TileEntityType<?> te_type)
{ super(te_type); reset(); }
public void reset()
{
tank_level_ = 0;
energy_stored_ = 0;
tick_timer_ = 0;
tracked_cow_ = null;
state_ = MilkingState.IDLE;
state_timeout_ = 0;
}
public CompoundNBT destroy_getnbt()
{
final UUID cowuid = tracked_cow_;
CompoundNBT nbt = new CompoundNBT();
writenbt(nbt, false); reset();
if(cowuid == null) return nbt;
world.getEntitiesWithinAABB(CowEntity.class, new AxisAlignedBB(pos).grow(16, 16, 16), e->e.getUniqueID().equals(cowuid)).forEach(e->e.setNoAI(false));
return nbt;
}
public void readnbt(CompoundNBT nbt, boolean update_packet)
{
tank_level_ = nbt.getInt("tank");
energy_stored_ = nbt.getInt("energy");
}
protected void writenbt(CompoundNBT nbt, boolean update_packet)
{
if(tank_level_ > 0) nbt.putInt("tank", tank_level_);
if(energy_stored_ > 0) nbt.putInt("energy", energy_stored_ );
}
private IFluidHandler fluid_handler()
{ return fluid_handler_.orElse(null); }
private int fluid_level()
{ return MathHelper.clamp(tank_level_, 0, TANK_CAPACITY); }
private void drain(int amount)
{ tank_level_ = MathHelper.clamp(tank_level_-BUCKET_SIZE, 0, TANK_CAPACITY); markDirty(); }
// TileEntity ------------------------------------------------------------------------------
@Override
public void read(CompoundNBT nbt)
{ super.read(nbt); readnbt(nbt, false); }
@Override
public CompoundNBT write(CompoundNBT nbt)
{ super.write(nbt); writenbt(nbt, false); return nbt; }
// IEnergyStorage ----------------------------------------------------------------------------
protected LazyOptional<IEnergyStorage> energy_handler_ = LazyOptional.of(() -> (IEnergyStorage)this);
@Override public boolean canExtract() { return false; }
@Override public boolean canReceive() { return true; }
@Override public int getMaxEnergyStored() { return MAX_ENERGY_BUFFER; }
@Override public int getEnergyStored() { return energy_stored_; }
@Override public int extractEnergy(int maxExtract, boolean simulate) { return 0; }
@Override
public int receiveEnergy(int maxReceive, boolean simulate)
{
if(energy_stored_ >= MAX_ENERGY_BUFFER) return 0;
int n = Math.min(maxReceive, (MAX_ENERGY_BUFFER - energy_stored_));
if(n > MAX_ENERGY_TRANSFER) n = MAX_ENERGY_TRANSFER;
if(!simulate) {energy_stored_ += n; markDirty(); }
return n;
}
// IFluidHandler / IFluidTankProperties ---------------------------------------------------------------------
private LazyOptional<IFluidHandler> fluid_handler_ = LazyOptional.of(() -> (IFluidHandler)new BFluidHandler(this));
private static class BFluidHandler implements IFluidHandler
{
private final BTileEntity te;
BFluidHandler(BTileEntity te) { this.te = te; }
@Override public int getTanks() { return 1; }
@Override public FluidStack getFluidInTank(int tank) { return new FluidStack(milk_fluid_, te.fluid_level()); }
@Override public int getTankCapacity(int tank) { return TANK_CAPACITY; }
@Override public boolean isFluidValid(int tank, @Nonnull FluidStack stack) { return false; }
@Override public int fill(FluidStack resource, FluidAction action) { return 0; }
@Override
public FluidStack drain(FluidStack resource, FluidAction action)
{ return (!resource.isFluidEqual(milk_fluid_)) ? (FluidStack.EMPTY) : drain(resource.getAmount(), action); }
@Override
public FluidStack drain(int maxDrain, FluidAction action)
{
if(te.fluid_level() <= 0) return FluidStack.EMPTY;
FluidStack fs = milk_fluid_.copy();
fs.setAmount(Math.min(fs.getAmount(), te.fluid_level()));
if(action==FluidAction.EXECUTE) te.tank_level_ -= fs.getAmount();
return fs;
}
}
// ICapabilityProvider ---------------------------------------------------------------------------
@Override
public <T> LazyOptional<T> getCapability(net.minecraftforge.common.capabilities.Capability<T> capability, @Nullable Direction facing)
{
if(!this.removed && (facing != null)) {
if((capability == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY) && (!milk_fluid_.isEmpty())) {
return fluid_handler_.cast();
} else if((capability == CapabilityEnergy.ENERGY) && (energy_consumption>0)) {
return energy_handler_.cast();
}
}
return super.getCapability(capability, facing);
}
// ITickable ------------------------------------------------------------------------------------
private void log(String s)
{} // println("Milker|" + s); may be enabled with config, for dev was println
private static ItemStack milk_filled_container_item(ItemStack stack)
{ return milk_containers_.entrySet().stream().filter(e->e.getKey().isItemEqual(stack)).map(Map.Entry::getValue).findFirst().orElse(ItemStack.EMPTY); }
private void fill_adjacent_inventory_item_containers(Direction block_facing)
{
// Check inventory existence, back to down is preferred, otherwise sort back into same inventory.
IItemHandler src = ItemHandling.itemhandler(world, pos.offset(block_facing), block_facing.getOpposite());
IItemHandler dst = ItemHandling.itemhandler(world, pos.down(), Direction.UP);
if(src==null) { src = dst; } else if(dst==null) { dst = src; }
if((src==null) || (dst==null)) return;
while((tank_level_ >= BUCKET_SIZE)) {
boolean inserted = false;
for(Entry<ItemStack,ItemStack> e:milk_containers_.entrySet()) {
if(ItemHandling.extract(src, e.getKey(), 1, true).isEmpty()) continue;
if(!ItemHandling.insert(dst, e.getValue().copy(), false).isEmpty()) continue;
ItemHandling.extract(src, e.getKey(), 1, false);
tank_level_ -= BUCKET_SIZE;
inserted = true;
}
if(!inserted) break;
}
}
private void release_cow(CowEntity cow)
{
log("release cow");
if(cow != null) {
cow.setNoAI(false);
SingleMoveGoal.abortFor(cow);
}
tracked_cow_ = null;
state_ = MilkingState.IDLE;
tick_timer_ = TICK_INTERVAL;
}
private boolean milking_process()
{
if((tracked_cow_ == null) && (fluid_level() >= MAX_MILKING_TANK_LEVEL)) return false; // nothing to do
final Direction facing = world.getBlockState(getPos()).get(HORIZONTAL_FACING).getOpposite();
final Vec3d target_pos = new Vec3d(getPos().offset(facing)).add(0.5,0,0.5);
CowEntity cow = null;
{
AxisAlignedBB aabb = new AxisAlignedBB(pos.offset(facing, 3)).grow(4, 2, 4);
final List<CowEntity> cows = world.getEntitiesWithinAABB(CowEntity.class, aabb,
e->( ((tracked_cow_==null) && ((!e.isChild()) && (!e.isInLove()) && (!e.isBeingRidden()))) || (e.getUniqueID().equals(tracked_cow_)) )
);
if(cows.size() == 1) {
cow = cows.get(0); // tracked or only one
} else if(cows.size() > 1) {
cow = cows.get(world.rand.nextInt(cows.size()-1)); // pick one
}
}
if((state_ != MilkingState.IDLE) && ((state_timeout_ -= PROCESSING_TICK_INTERVAL) <= 0)) { release_cow(cow); log("Cow motion timeout"); cow = null; }
if((cow == null) || (!cow.isAlive())) { release_cow(cow); cow = null; }
if(tracked_cow_ == null) state_ = MilkingState.IDLE;
if(cow == null) { log("Init: No cow"); return false; } // retry next cycle
tick_timer_ = PROCESSING_TICK_INTERVAL;
state_timer_ -= PROCESSING_TICK_INTERVAL;
if(state_timer_ > 0) return false;
switch(state_) { // Let's do this the old school FSA sequencing way ...
case IDLE: {
final List<LivingEntity> blocking_entities = world.getEntitiesWithinAABB(LivingEntity.class, new AxisAlignedBB(pos.offset(facing)).grow(0.5, 0.5, 0.5));
if(blocking_entities.size() > 0) {
tick_timer_ = TICK_INTERVAL;
log("Idle: Position blocked");
if(blocking_entities.get(0) instanceof CowEntity) {
CowEntity blocker = (CowEntity)blocking_entities.get(0);
BlockPos p = getPos().offset(facing,2);
log("Idle: Shove off");
blocker.setNoAI(false);
SingleMoveGoal.startFor(blocker, p, 2, 1.0, (goal, world, pos)->(pos.distanceSq(goal.getCreature().getPosition())>49));
}
return false;
}
if(cow.getLeashed() || cow.isChild() || cow.isInLove() || (!cow.onGround) || cow.isBeingRidden() || cow.isSprinting()) return false;
tracked_cow_ = cow.getUniqueID();
state_ = MilkingState.PICKED;
state_timeout_ = 200;
tracked_cow_original_position_ = cow.getPosition();
log("Idle: Picked cow " + tracked_cow_);
return false;
}
case PICKED: {
SingleMoveGoal.startFor(
cow, target_pos, 2, 1.0,
(goal, world, pos)->{
if(pos.distanceSq(goal.getCreature().getPosition())>100) return true;
for(int i=0; i<4; ++i) {
if(world.getBlockState(pos.offset(Direction.byHorizontalIndex(i))).getBlock() instanceof BlockDecorMilker) return false;
}
return true;
},
(goal, world, pos)->{
log("move: position reached");
goal.getCreature().setLocationAndAngles(goal.getTargetPosition().getX(), goal.getTargetPosition().getY(), goal.getTargetPosition().getZ(), facing.getHorizontalAngle(), 0);
},
(goal, world, pos)->{
log("move: aborted");
}
);
state_ = MilkingState.COMING;
state_timeout_ = 400; // 15s should be enough
log("Picked: coming to " + target_pos);
return false;
}
case COMING: {
if(target_pos.squareDistanceTo(cow.getPositionVec()) <= 1) {
log("Coming: position reached");
state_ = MilkingState.POSITIONING;
state_timeout_ = 100; // 5s
} else if((!SingleMoveGoal.isActiveFor(cow))) {
release_cow(cow);
log("Coming: aborted");
} else {
state_timeout_ -= 100;
}
return false;
}
case POSITIONING: {
log("Positioning: start milking");
cow.setNoAI(true);
cow.setLocationAndAngles(target_pos.getX(), target_pos.getY(), target_pos.getZ(), facing.getHorizontalAngle(), 0);
world.playSound(null, pos, SoundEvents.ENTITY_COW_MILK, SoundCategory.BLOCKS, 0.5f, 1f);
state_timeout_ = 600;
state_ = MilkingState.MILKING;
state_timer_ = 30;
return false;
}
case MILKING: {
tank_level_ = MathHelper.clamp(tank_level_+BUCKET_SIZE, 0, TANK_CAPACITY);
state_timeout_ = 600;
state_ = MilkingState.LEAVING;
state_timer_ = 20;
cow.setNoAI(false);
cow.getNavigator().clearPath();
log("Milking: done, leave");
return true;
}
case LEAVING: {
BlockPos p = (tracked_cow_original_position_ != null) ? (tracked_cow_original_position_) : getPos().offset(facing,2).offset(facing.rotateYCCW());
SingleMoveGoal.startFor(cow, p, 2, 1.0, (goal, world, pos)->(pos.distanceSq(goal.getCreature().getPosition())>100));
state_timeout_ = 600;
state_timer_ = 500;
tick_timer_ = TICK_INTERVAL;
state_ = MilkingState.WAITING;
log("Leaving: process done");
return true;
}
case WAITING: {
// wait for the timeout to kick in until starting with the next.
tick_timer_ = TICK_INTERVAL;
log("Waiting: ...");
return true;
}
default: {
release_cow(cow);
}
}
return (tracked_cow_ != null);
}
@Override
public void tick()
{
if((world.isRemote) || ((--tick_timer_ > 0))) return;
tick_timer_ = TICK_INTERVAL;
boolean dirty = false;
final BlockState block_state = world.getBlockState(pos);
if(!world.isBlockPowered(pos) || (state_ != MilkingState.IDLE)) {
if(energy_consumption > 0) {
if(energy_stored_ <= 0) return;
energy_stored_ = MathHelper.clamp(energy_stored_-energy_consumption, 0, MAX_ENERGY_BUFFER);
}
// Track and milk cows
if(milking_process()) dirty = true;
// Fluid transfer
if((milk_fluid_.getAmount() > 0) && (fluid_level() >= BUCKET_SIZE)) {
log("Fluid transfer");
for(Direction facing: FLUID_TRANSFER_DIRECTRIONS) {
IFluidHandler fh = FluidUtil.getFluidHandler(world, pos.offset(facing), facing.getOpposite()).orElse(null);
if(fh == null) continue;
FluidStack fs = milk_fluid_.copy();
fs.setAmount(BUCKET_SIZE);
int nfilled = MathHelper.clamp(fh.fill(fs, FluidAction.EXECUTE), 0, BUCKET_SIZE);
if(nfilled <= 0) continue;
tank_level_ -= nfilled;
if(tank_level_ < 0) tank_level_ = 0;
dirty = true;
break;
}
}
// Adjacent inventory update, only done just after milking to prevent waste of server cpu.
if(dirty && (fluid_level() >= BUCKET_SIZE)) {
log("Try item transfer");
fill_adjacent_inventory_item_containers(block_state.get(HORIZONTAL_FACING));
}
}
// State update
BlockState new_state = block_state.with(FILLED, fluid_level()>=FILLED_INDICATION_THRESHOLD).with(ACTIVE, state_==MilkingState.MILKING);
if(block_state != new_state) world.setBlockState(pos, new_state,1|2|16);
if(dirty) markDirty();
}
}
public static class SingleMoveGoal extends net.minecraft.entity.ai.goal.MoveToBlockGoal
{
@FunctionalInterface public interface TargetPositionInValidCheck { boolean test(SingleMoveGoal goal, IWorldReader world, BlockPos pos); }
@FunctionalInterface public interface StrollEvent { void apply(SingleMoveGoal goal, IWorldReader world, Vec3d pos); }
private static void log(String s) {} // println(s);
private static final int motion_timeout = 20*20;
private boolean aborted_;
private boolean in_position_;
private boolean was_aborted_;
private Vec3d target_pos_;
private TargetPositionInValidCheck abort_condition_;
private StrollEvent on_target_position_reached_;
private StrollEvent on_aborted_;
public SingleMoveGoal(CreatureEntity creature, Vec3d pos, double speed, TargetPositionInValidCheck abort_condition, @Nullable StrollEvent on_position_reached, @Nullable StrollEvent on_aborted)
{
super(creature, speed, 32, 32);
abort_condition_ = abort_condition;
on_target_position_reached_ = on_position_reached;
on_aborted_ = on_aborted;
destinationBlock = new BlockPos(pos.getX(), pos.getY(), pos.getZ());
timeoutCounter = 0;
runDelay = 0;
aborted_ = false;
was_aborted_ = false;
target_pos_ = pos;
}
public static void startFor(CreatureEntity entity, BlockPos target_pos, int priority, double speed, TargetPositionInValidCheck abort_condition)
{ startFor(entity, new Vec3d(target_pos.getX(),target_pos.getY(),target_pos.getZ()), priority, speed, abort_condition, null, null); }
public static void startFor(CreatureEntity entity, Vec3d target_pos, int priority, double speed, TargetPositionInValidCheck abort_condition, @Nullable StrollEvent on_position_reached, @Nullable StrollEvent on_aborted)
{ entity.goalSelector.addGoal(priority, new SingleMoveGoal(entity, target_pos, speed, abort_condition, on_position_reached, on_aborted)); }
public static boolean isActiveFor(CreatureEntity entity)
{ return (entity != null) && (entity.goalSelector.getRunningGoals().anyMatch(g->(g.getGoal()) instanceof SingleMoveGoal)); }
public static void abortFor(CreatureEntity entity)
{ entity.goalSelector.getRunningGoals().filter(g->(g.getGoal()) instanceof SingleMoveGoal).forEach(g->((SingleMoveGoal)g.getGoal()).abort()); }
public Vec3d getTargetPosition()
{ return target_pos_; }
public CreatureEntity getCreature()
{ return creature; }
public void abort()
{ aborted_ = true; }
@Override
public void resetTask()
{ runDelay = 0; timeoutCounter = 0; }
@Override
public double getTargetDistanceSq()
{ return 1.2; }
@Override
public boolean shouldMove()
{ return (timeoutCounter & 0x7) == 0; }
@Override
public boolean shouldExecute()
{
if(!shouldMoveTo(creature.world, destinationBlock)) {
aborted_ = true;
return false;
} else if(aborted_) {
// shouldExecute is the point where in GoalSelector.tick() the goal is not in flagGoals and can be removed.
creature.goalSelector.getRunningGoals().filter(g->(g.getGoal()) instanceof SingleMoveGoal).forEach(g->creature.goalSelector.removeGoal(g));
creature.goalSelector.removeGoal(this);
if((!was_aborted_) && (on_aborted_!=null)) on_aborted_.apply(this, creature.world, target_pos_);
was_aborted_ = true;
return false;
} else if(--runDelay > 0) {
return false;
} else {
runDelay = 10;
return true;
}
}
@Override
public void startExecuting()
{
log("startExecuting()");
timeoutCounter = 0;
if(!creature.getNavigator().tryMoveToXYZ(target_pos_.getX(), target_pos_.getY(), target_pos_.getZ(), this.movementSpeed)) abort();
}
public boolean shouldContinueExecuting()
{
if((aborted_) || (creature.getNavigator().noPath()) || (timeoutCounter > motion_timeout) || (!shouldMoveTo(creature.world, destinationBlock))) {
abort();
return false;
}
return true;
}
@Override
protected boolean shouldMoveTo(IWorldReader world, BlockPos pos)
{ if(!abort_condition_.test(this, world, pos)) { return true; } abort(); return false; }
@Override
public void tick()
{
BlockPos testpos = new BlockPos(target_pos_.getX(), creature.getPositionVec().getY(), target_pos_.getZ());
if(!testpos.withinDistance(creature.getPositionVec(), getTargetDistanceSq())) {
if((++timeoutCounter > motion_timeout)) { abort(); return; }
if(shouldMove() && (!creature.getNavigator().tryMoveToXYZ(target_pos_.getX(), target_pos_.getY(), target_pos_.getZ(), movementSpeed))) abort();
} else {
in_position_ = true;
abort();
if(on_target_position_reached_ != null) on_target_position_reached_.apply(this, creature.world, target_pos_);
}
}
}
}

View file

@ -0,0 +1,667 @@
/*
* @file BlockDecorMineralSmelter.java
* @author Stefan Wilhelm (wile)
* @copyright (C) 2019 Stefan Wilhelm
* @license MIT (see https://opensource.org/licenses/MIT)
*
* Small highly insulated stone liquification furnace
* (magmatic phase).
*/
package wile.engineersdecor.blocks;
import wile.engineersdecor.ModContent;
import wile.engineersdecor.ModEngineersDecor;
import net.minecraft.world.IBlockReader;
import net.minecraft.world.World;
import net.minecraft.block.*;
import net.minecraft.tileentity.ITickableTileEntity;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.tileentity.TileEntityType;
import net.minecraft.inventory.ISidedInventory;
import net.minecraft.inventory.ItemStackHelper;
import net.minecraft.item.Item;
import net.minecraft.item.Items;
import net.minecraft.item.ItemStack;
import net.minecraft.item.BlockItemUseContext;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.particles.IParticleData;
import net.minecraft.particles.ParticleTypes;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.util.*;
import net.minecraft.util.math.*;
import net.minecraft.util.text.StringTextComponent;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.state.IntegerProperty;
import net.minecraft.state.StateContainer;
import net.minecraft.fluid.Fluids;
import net.minecraftforge.common.capabilities.ICapabilityProvider;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.energy.CapabilityEnergy;
import net.minecraftforge.energy.IEnergyStorage;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.FluidUtil;
import net.minecraftforge.fluids.capability.CapabilityFluidHandler;
import net.minecraftforge.fluids.capability.IFluidHandler.FluidAction;
import net.minecraftforge.fluids.capability.IFluidHandler;
import net.minecraftforge.items.CapabilityItemHandler;
import net.minecraftforge.items.IItemHandler;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.*;
public class BlockDecorMineralSmelter extends BlockDecorDirectedHorizontal
{
public static final int PHASE_MAX = 3;
public static final IntegerProperty PHASE = IntegerProperty.create("phase", 0, PHASE_MAX);
public BlockDecorMineralSmelter(long config, Block.Properties builder, final AxisAlignedBB unrotatedAABB)
{ super(config, builder, unrotatedAABB); }
@Override
protected void fillStateContainer(StateContainer.Builder<Block, BlockState> builder)
{ super.fillStateContainer(builder); builder.add(PHASE); }
@Override
@Nullable
public BlockState getStateForPlacement(BlockItemUseContext context)
{ return super.getStateForPlacement(context).with(PHASE, 0); }
@Override
@SuppressWarnings("deprecation")
public boolean hasComparatorInputOverride(BlockState state)
{ return true; }
@Override
@SuppressWarnings("deprecation")
public int getComparatorInputOverride(BlockState state, World world, BlockPos pos)
{ return MathHelper.clamp((state.get(PHASE)*5), 0, 15); }
@Override
public boolean hasTileEntity(BlockState state)
{ return true; }
@Override
@Nullable
public TileEntity createTileEntity(BlockState state, IBlockReader world)
{ return new BlockDecorMineralSmelter.BTileEntity(); }
@Override
public void onBlockPlacedBy(World world, BlockPos pos, BlockState state, LivingEntity placer, ItemStack stack)
{}
@Override
public boolean hasDynamicDropList()
{ return true; }
@Override
public List<ItemStack> dropList(BlockState state, World world, BlockPos pos, boolean explosion)
{
final List<ItemStack> stacks = new ArrayList<ItemStack>();
if(world.isRemote) return stacks;
final BTileEntity te = getTe(world, pos);
if(te == null) return stacks;
te.reset_process();
stacks.add(new ItemStack(this, 1));
return stacks;
}
@Override
@SuppressWarnings("deprecation")
public boolean onBlockActivated(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockRayTraceResult rayTraceResult)
{
if(world.isRemote) return true;
if(player.func_225608_bj_()/*isSneaking()*/) return false;
BTileEntity te = getTe(world, pos);
if(te==null) return true;
final ItemStack stack = player.getHeldItem(hand);
boolean dirty = false;
if(te.accepts_lava_container(stack)) {
if(stack.isItemEqualIgnoreDurability(BTileEntity.BUCKET_STACK)) { // check how this works with item capabilities or so
if(te.fluid_level() >= BTileEntity.MAX_BUCKET_EXTRACT_FLUID_LEVEL) {
if(stack.getCount() > 1) {
int target_stack_index = -1;
for(int i=0; i<player.inventory.getSizeInventory(); ++i) {
if(player.inventory.getStackInSlot(i).isEmpty()) {
target_stack_index = i;
break;
}
}
if(target_stack_index >= 0) {
te.reset_process();
stack.shrink(1);
player.setHeldItem(hand, stack);
player.inventory.setInventorySlotContents(target_stack_index, BTileEntity.LAVA_BUCKET_STACK.copy());
world.playSound(null, pos, SoundEvents.ITEM_BUCKET_FILL_LAVA, SoundCategory.BLOCKS, 1f, 1f);
dirty = true;
}
} else {
te.reset_process();
player.setHeldItem(hand, BTileEntity.LAVA_BUCKET_STACK.copy());
world.playSound(null, pos, SoundEvents.ITEM_BUCKET_FILL_LAVA, SoundCategory.BLOCKS, 1f, 1f);
dirty = true;
}
}
}
} else if(stack.isEmpty()) {
final ItemStack istack = te.getStackInSlot(1).copy();
if(te.phase() > BTileEntity.PHASE_WARMUP) player.setFire(1);
if(!istack.isEmpty()) {
istack.setCount(1);
player.setHeldItem(hand, istack);
te.reset_process();
dirty = true;
}
} else if(te.insert(stack.copy(),false)) {
stack.shrink(1);
dirty = true;
}
if(dirty) player.inventory.markDirty();
return true;
}
@Override
@OnlyIn(Dist.CLIENT)
public void animateTick(BlockState state, World world, BlockPos pos, Random rnd)
{
if(state.getBlock()!=this) return;
IParticleData particle = ParticleTypes.SMOKE;
switch(state.get(PHASE)) {
case BTileEntity.PHASE_WARMUP:
return;
case BTileEntity.PHASE_HOT:
if(rnd.nextInt(10) > 4) return;
break;
case BTileEntity.PHASE_MAGMABLOCK:
if(rnd.nextInt(10) > 7) return;
particle = ParticleTypes.LARGE_SMOKE;
break;
case BTileEntity.PHASE_LAVA:
if(rnd.nextInt(10) > 2) return;
particle = ParticleTypes.LAVA;
break;
default:
return;
}
final double x=0.5+pos.getX(), y=0.5+pos.getY(), z=0.5+pos.getZ();
final double xr=rnd.nextDouble()*0.4-0.2, yr=rnd.nextDouble()*0.5, zr=rnd.nextDouble()*0.4-0.2;
world.addParticle(particle, x+xr, y+yr, z+zr, 0.0, 0.0, 0.0);
}
@Nullable
private BTileEntity getTe(World world, BlockPos pos)
{ final TileEntity te=world.getTileEntity(pos); return (!(te instanceof BTileEntity)) ? (null) : ((BTileEntity)te); }
//--------------------------------------------------------------------------------------------------------------------
// Tile entity
//--------------------------------------------------------------------------------------------------------------------
public static class BTileEntity extends TileEntity implements INameable, ITickableTileEntity, ISidedInventory, IEnergyStorage, ICapabilityProvider
{
public static final int TICK_INTERVAL = 20;
public static final int MAX_FLUID_LEVEL = 1000;
public static final int MAX_BUCKET_EXTRACT_FLUID_LEVEL = 900;
public static final int MAX_ENERGY_BUFFER = 32000;
public static final int MAX_ENERGY_TRANSFER = 8192;
public static final int DEFAULT_ENERGY_CONSUMPTION = 92;
public static final int DEFAULT_HEATUP_RATE = 2; // -> 50s for one smelting process
public static final int PHASE_WARMUP = 0;
public static final int PHASE_HOT = 1;
public static final int PHASE_MAGMABLOCK = 2;
public static final int PHASE_LAVA = 3;
private static final ItemStack MAGMA_STACK = new ItemStack(Blocks.MAGMA_BLOCK);
private static final ItemStack BUCKET_STACK = new ItemStack(Items.BUCKET);
private static final ItemStack LAVA_BUCKET_STACK = new ItemStack(Items.LAVA_BUCKET);
private static final FluidStack LAVA_BUCKET_FLUID_STACK = new FluidStack(Fluids.LAVA, 1000);
private static int energy_consumption = DEFAULT_ENERGY_CONSUMPTION;
private static int heatup_rate = DEFAULT_HEATUP_RATE;
private static int cooldown_rate = 1;
private static Set<Item> accepted_minerals = new HashSet<Item>();
private static Set<Item> accepted_lava_contrainers = new HashSet<Item>();
private int tick_timer_;
private int energy_stored_;
private int progress_;
private int fluid_level_;
private boolean force_block_update_;
private NonNullList<ItemStack> stacks_ = NonNullList.<ItemStack>withSize(2, ItemStack.EMPTY);
static {
// Lava containers
accepted_lava_contrainers.add(Items.BUCKET);
}
public static void on_config(int energy_consumption, int heatup_per_second)
{
energy_consumption = MathHelper.clamp(energy_consumption, 32, 4096);
heatup_rate = MathHelper.clamp(heatup_per_second, 1, 5);
cooldown_rate = MathHelper.clamp(heatup_per_second/2, 1, 5);
ModEngineersDecor.logger().info("Config mineal smelter energy consumption:" + energy_consumption + "rf/t, heat-up rate: " + heatup_rate + "%/s.");
}
public BTileEntity()
{ this(ModContent.TET_MINERAL_SMELTER); }
public BTileEntity(TileEntityType<?> te_type)
{ super(te_type); }
public int progress()
{ return progress_; }
public int phase()
{
if(progress_ >= 100) return PHASE_LAVA;
if(progress_ >= 90) return PHASE_MAGMABLOCK;
if(progress_ >= 5) return PHASE_HOT;
return PHASE_WARMUP;
}
public int fluid_level()
{ return fluid_level_; }
public int fluid_level_drain(int amount)
{ amount = MathHelper.clamp(amount, 0, fluid_level_); fluid_level_ -= amount; return amount; }
public int comparator_signal()
{ return phase() * 5; } // -> 0..15
private boolean accepts_lava_container(ItemStack stack)
{ return accepted_lava_contrainers.contains(stack.getItem()); }
private boolean accepts_input(ItemStack stack)
{
if(!stacks_.get(0).isEmpty()) return false;
if(fluid_level() > MAX_BUCKET_EXTRACT_FLUID_LEVEL) {
return accepts_lava_container(stack);
} else {
if(stack.getItem().getTags().contains(new ResourceLocation(ModEngineersDecor.MODID, "accepted_mineral_smelter_input"))) return true;
return accepted_minerals.contains(stack.getItem());
}
}
public boolean insert(final ItemStack stack, boolean simulate)
{
if(stack.isEmpty() || (!accepts_input(stack))) return false;
if(!simulate) {
ItemStack st = stack.copy();
st.setCount(st.getMaxStackSize());
stacks_.set(0, st);
if(!accepts_lava_container(stack)) progress_ = 0;
force_block_update_ = true;
}
return true;
}
public ItemStack extract(boolean simulate)
{
ItemStack stack = stacks_.get(1).copy();
if(stack.isEmpty()) return ItemStack.EMPTY;
if(!simulate) reset_process();
return stack;
}
protected void reset_process()
{
stacks_ = NonNullList.<ItemStack>withSize(2, ItemStack.EMPTY);
force_block_update_ = true;
fluid_level_ = 0;
tick_timer_ = 0;
progress_ = 0;
}
public void readnbt(CompoundNBT nbt)
{
energy_stored_ = nbt.getInt("energy");
progress_ = nbt.getInt("progress");
fluid_level_ = nbt.getInt("fluidlevel");
ItemStackHelper.loadAllItems(nbt, stacks_);
if(stacks_.size() != 2) reset_process();
}
protected void writenbt(CompoundNBT nbt)
{
nbt.putInt("energy", MathHelper.clamp(energy_stored_,0 , MAX_ENERGY_BUFFER));
nbt.putInt("progress", MathHelper.clamp(progress_,0 , 100));
nbt.putInt("fluidlevel", MathHelper.clamp(fluid_level_,0 , MAX_FLUID_LEVEL));
ItemStackHelper.saveAllItems(nbt, stacks_);
}
// TileEntity ------------------------------------------------------------------------------
@Override
public void read(CompoundNBT nbt)
{ super.read(nbt); readnbt(nbt); }
@Override
public CompoundNBT write(CompoundNBT nbt)
{ super.write(nbt); writenbt(nbt); return nbt; }
// INamedContainerProvider / INameable ------------------------------------------------------
@Override
public ITextComponent getName()
{ final Block block=getBlockState().getBlock(); return new StringTextComponent((block!=null) ? block.getTranslationKey() : "Lab furnace"); }
@Override
public boolean hasCustomName()
{ return false; }
@Override
public ITextComponent getCustomName()
{ return getName(); }
// IInventory ------------------------------------------------------------------------------
@Override
public int getSizeInventory()
{ return stacks_.size(); }
@Override
public boolean isEmpty()
{ for(ItemStack stack: stacks_) { if(!stack.isEmpty()) return false; } return true; }
@Override
public ItemStack getStackInSlot(int index)
{ return ((index >= 0) && (index < getSizeInventory())) ? stacks_.get(index) : ItemStack.EMPTY; }
@Override
public ItemStack decrStackSize(int index, int count)
{ return ItemStackHelper.getAndSplit(stacks_, index, count); }
@Override
public ItemStack removeStackFromSlot(int index)
{ return ItemStackHelper.getAndRemove(stacks_, index); }
@Override
public void setInventorySlotContents(int index, ItemStack stack)
{ if(stack.getCount()>getInventoryStackLimit()){stack.setCount(getInventoryStackLimit());} stacks_.set(index, stack); markDirty(); }
@Override
public int getInventoryStackLimit()
{ return 1; }
@Override
public void markDirty()
{ super.markDirty(); }
@Override
public boolean isUsableByPlayer(PlayerEntity player)
{ return ((world.getTileEntity(pos) == this) && (player.getDistanceSq(pos.getX()+0.5d, pos.getY()+0.5d, pos.getZ()+0.5d) <= 64.0d)); }
@Override
public void openInventory(PlayerEntity player)
{}
@Override
public void closeInventory(PlayerEntity player)
{ markDirty(); }
@Override
public boolean isItemValidForSlot(int index, ItemStack stack)
{ return ((index==0) && accepts_input(stack)) || (index==1); }
@Override
public void clear()
{ reset_process(); }
// ISidedInventory ----------------------------------------------------------------------------
private static final int[] SIDED_INV_SLOTS = new int[] {0,1};
@Override
public int[] getSlotsForFace(Direction side)
{ return SIDED_INV_SLOTS; }
@Override
public boolean canInsertItem(int index, ItemStack stack, Direction direction)
{ return (index==0) && isItemValidForSlot(index, stack); }
@Override
public boolean canExtractItem(int index, ItemStack stack, Direction direction)
{ return (index==1) && (!stacks_.get(1).isEmpty()); }
// IItemHandler --------------------------------------------------------------------------------
private LazyOptional<IItemHandler> item_handler_ = LazyOptional.of(() -> (IItemHandler)new BItemHandler(this));
protected static class BItemHandler implements IItemHandler
{
private BTileEntity te;
BItemHandler(BTileEntity te)
{ this.te = te; }
@Override
public int getSlots()
{ return 2; }
@Override
public int getSlotLimit(int index)
{ return te.getInventoryStackLimit(); }
@Override
public boolean isItemValid(int slot, @Nonnull ItemStack stack)
{ return te.isItemValidForSlot(slot, stack); }
@Override
@Nonnull
public ItemStack insertItem(int index, @Nonnull ItemStack stack, boolean simulate)
{
ItemStack rstack = stack.copy();
if((index!=0) || (!te.insert(stack.copy(), simulate))) return rstack;
rstack.shrink(1);
return rstack;
}
@Override
@Nonnull
public ItemStack extractItem(int index, int amount, boolean simulate)
{ return (index!=1) ? ItemStack.EMPTY : te.extract(simulate); }
@Override
@Nonnull
public ItemStack getStackInSlot(int index)
{ return te.getStackInSlot(index); }
}
// IFluidHandler --------------------------------------------------------------------------------
private LazyOptional<IFluidHandler> fluid_handler_ = LazyOptional.of(() -> (IFluidHandler)new BFluidHandler(this));
private static class BFluidHandler implements IFluidHandler
{
private final FluidStack lava;
private final BTileEntity te;
BFluidHandler(BTileEntity te)
{ this.te = te; lava = new net.minecraftforge.fluids.FluidStack(net.minecraft.fluid.Fluids.LAVA, 1); }
@Override public int getTanks() { return 1; }
@Override public FluidStack getFluidInTank(int tank) { return new FluidStack(lava, te.fluid_level()); }
@Override public int getTankCapacity(int tank) { return 1000; }
@Override public boolean isFluidValid(int tank, @Nonnull FluidStack stack) { return (tank==0) && (stack.isFluidEqual(lava)); }
@Override public int fill(FluidStack resource, FluidAction action) { return 0; }
@Override
public FluidStack drain(FluidStack resource, FluidAction action)
{
if(!resource.isFluidEqual(lava) || (te.fluid_level() <= 0)) return FluidStack.EMPTY;
FluidStack stack = new FluidStack(lava, te.fluid_level());
if(action == FluidAction.EXECUTE) te.fluid_level_drain(te.fluid_level());
return stack;
}
@Override
public FluidStack drain(int maxDrain, FluidAction action)
{
if(te.fluid_level() <= 0) return FluidStack.EMPTY;
maxDrain = (action==FluidAction.EXECUTE) ? (te.fluid_level_drain(maxDrain)) : (Math.min(maxDrain, te.fluid_level()));
return new FluidStack(lava, maxDrain);
}
}
// IEnergyStorage ----------------------------------------------------------------------------
protected LazyOptional<IEnergyStorage> energy_handler_ = LazyOptional.of(() -> (IEnergyStorage)this);
@Override
public boolean canExtract()
{ return false; }
@Override
public boolean canReceive()
{ return true; }
@Override
public int getMaxEnergyStored()
{ return MAX_ENERGY_BUFFER; }
@Override
public int getEnergyStored()
{ return energy_stored_; }
@Override
public int extractEnergy(int maxExtract, boolean simulate)
{ return 0; }
@Override
public int receiveEnergy(int maxReceive, boolean simulate)
{
if(energy_stored_ >= MAX_ENERGY_BUFFER) return 0;
int n = Math.min(maxReceive, (MAX_ENERGY_BUFFER - energy_stored_));
if(n > MAX_ENERGY_TRANSFER) n = MAX_ENERGY_TRANSFER;
if(!simulate) {energy_stored_ += n; markDirty(); }
return n;
}
// Capability export ----------------------------------------------------------------------------
@Override
public <T> LazyOptional<T> getCapability(net.minecraftforge.common.capabilities.Capability<T> capability, @Nullable Direction facing)
{
if(!this.removed && (facing != null)) {
if(capability== CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) {
return item_handler_.cast();
} else if(capability == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY) {
return fluid_handler_.cast();
} else if(capability== CapabilityEnergy.ENERGY) {
return energy_handler_.cast();
}
}
return super.getCapability(capability, facing);
}
// ITickable ------------------------------------------------------------------------------------
@Override
public void tick()
{
if(world.isRemote) return;
if(--tick_timer_ > 0) return;
tick_timer_ = TICK_INTERVAL;
boolean dirty = false;
final int last_phase = phase();
final ItemStack istack = stacks_.get(0);
if(istack.isEmpty() && (fluid_level()==0)) {
progress_ = 0;
} else if((energy_stored_ <= 0) || (world.isBlockPowered(pos))) {
progress_ = MathHelper.clamp(progress_-cooldown_rate, 0,100);
} else if(progress_ >= 100) {
progress_ = 100;
energy_stored_ = MathHelper.clamp(energy_stored_-((energy_consumption*TICK_INTERVAL)/20), 0, MAX_ENERGY_BUFFER);
} else {
energy_stored_ = MathHelper.clamp(energy_stored_-(energy_consumption*TICK_INTERVAL), 0, MAX_ENERGY_BUFFER);
progress_ = MathHelper.clamp(progress_+heatup_rate, 0, 100);
}
int new_phase = phase();
boolean is_lava_container = accepts_lava_container(istack);
if(is_lava_container || (new_phase != last_phase)) {
if(is_lava_container) {
// That stays in the slot until its extracted or somone takes it out.
if(istack.isItemEqual(BUCKET_STACK)) {
if(!stacks_.get(1).isItemEqual(LAVA_BUCKET_STACK)) {
if(fluid_level() >= MAX_BUCKET_EXTRACT_FLUID_LEVEL) {
stacks_.set(1, LAVA_BUCKET_STACK);
world.playSound(null, pos, SoundEvents.ITEM_BUCKET_FILL_LAVA, SoundCategory.BLOCKS, 0.2f, 1.3f);
} else {
stacks_.set(1, istack.copy());
}
dirty = true;
}
} else {
stacks_.set(1, istack.copy());
// Out stack -> Somehow the filled container or container with fluid+fluid_level().
}
} else if(new_phase > last_phase) {
switch(new_phase) {
case PHASE_LAVA:
fluid_level_ = MAX_FLUID_LEVEL;
stacks_.set(1, ItemStack.EMPTY);
stacks_.set(0, ItemStack.EMPTY);
world.playSound(null, pos, SoundEvents.BLOCK_LAVA_AMBIENT, SoundCategory.BLOCKS, 0.2f, 1.0f);
dirty = true;
break;
case PHASE_MAGMABLOCK:
stacks_.set(1, MAGMA_STACK.copy());
world.playSound(null, pos, SoundEvents.BLOCK_FIRE_AMBIENT, SoundCategory.BLOCKS, 0.2f, 0.8f);
dirty = true;
break;
case PHASE_HOT:
world.playSound(null, pos, SoundEvents.BLOCK_FIRE_AMBIENT, SoundCategory.BLOCKS, 0.2f, 0.8f);
break;
}
} else {
switch(new_phase) {
case PHASE_MAGMABLOCK:
stacks_.set(0, (fluid_level_ >= MAX_BUCKET_EXTRACT_FLUID_LEVEL) ? (MAGMA_STACK.copy()) : (ItemStack.EMPTY));
stacks_.set(1, stacks_.get(0).copy());
fluid_level_ = 0;
world.playSound(null, pos, SoundEvents.BLOCK_LAVA_EXTINGUISH, SoundCategory.BLOCKS, 0.5f, 1.1f);
dirty = true;
break;
case PHASE_HOT:
if(istack.isItemEqual(MAGMA_STACK)) {
stacks_.set(1, new ItemStack(Blocks.OBSIDIAN));
} else {
stacks_.set(1, new ItemStack(Blocks.COBBLESTONE));
}
world.playSound(null, pos, SoundEvents.BLOCK_LAVA_EXTINGUISH, SoundCategory.BLOCKS, 0.3f, 0.9f);
dirty = true;
break;
case PHASE_WARMUP:
world.playSound(null, pos, SoundEvents.BLOCK_LAVA_EXTINGUISH, SoundCategory.BLOCKS, 0.3f, 0.7f);
break;
}
}
} else if((phase()==PHASE_LAVA) && (fluid_level() >= MAX_BUCKET_EXTRACT_FLUID_LEVEL)) {
// Fluid transfer check
final IFluidHandler fh = FluidUtil.getFluidHandler(world, getPos().down(), Direction.UP).orElse(null);
if(fh != null) {
int n = fh.fill(LAVA_BUCKET_FLUID_STACK.copy(), FluidAction.SIMULATE);
if(n >= LAVA_BUCKET_FLUID_STACK.getAmount()/2) {
n = fh.fill(LAVA_BUCKET_FLUID_STACK.copy(), FluidAction.EXECUTE);
if(n > 0) {
reset_process();
world.playSound(null, pos, SoundEvents.BLOCK_LAVA_EXTINGUISH, SoundCategory.BLOCKS, 0.3f, 0.7f);
}
}
}
}
// Block state
BlockState state = world.getBlockState(pos);
if((state.getBlock() instanceof BlockDecorMineralSmelter) && (force_block_update_ || (state.get(PHASE) != new_phase))) {
state = state.with(PHASE, new_phase);
world.setBlockState(pos, state,3|16);
world.notifyNeighborsOfStateChange(getPos(), state.getBlock());
force_block_update_ = false;
}
if(dirty) markDirty();
}
}
}

View file

@ -0,0 +1,256 @@
/*
* @file BlockDecorPassiveFluidAccumulator.java
* @author Stefan Wilhelm (wile)
* @copyright (C) 2019 Stefan Wilhelm
* @license MIT (see https://opensource.org/licenses/MIT)
*
* A device that collects fluids from adjacent tank outputs
* when a pump drains on the (only) output side. Shall support
* high flow rates, and a vavuum suction delay. Shall not drain
* high amounts of fluid from the adjacent tanks when no fluid
* is requested at the output port. Shall drain balanced from
* the adjacent input sides.
*/
package wile.engineersdecor.blocks;
import wile.engineersdecor.ModContent;
import wile.engineersdecor.detail.ModAuxiliaries;
import net.minecraft.world.World;
import net.minecraft.world.IBlockReader;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.tileentity.TileEntityType;
import net.minecraft.tileentity.ITickableTileEntity;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.util.math.BlockRayTraceResult;
import net.minecraft.util.Hand;
import net.minecraft.util.math.MathHelper;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.util.Direction;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.common.capabilities.ICapabilityProvider;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.capability.CapabilityFluidHandler;
import net.minecraftforge.fluids.capability.IFluidHandler;
import net.minecraftforge.fluids.capability.IFluidHandler.FluidAction;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public class BlockDecorPassiveFluidAccumulator extends BlockDecorDirected
{
public BlockDecorPassiveFluidAccumulator(long config, Block.Properties builder, final AxisAlignedBB unrotatedAABB)
{ super(config, builder, unrotatedAABB); }
@Override
public boolean hasTileEntity(BlockState state)
{ return true; }
@Override
@Nullable
public TileEntity createTileEntity(BlockState state, IBlockReader world)
{ return new BlockDecorPassiveFluidAccumulator.BTileEntity(); }
@Override
@SuppressWarnings("deprecation")
public boolean onBlockActivated(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockRayTraceResult rayTraceResult)
{
if(world.isRemote) return true;
TileEntity te = world.getTileEntity(pos);
if(!(te instanceof BTileEntity)) return true;
((BTileEntity)te).send_device_stats(player);
return true;
}
@Override
@SuppressWarnings("deprecation")
public void neighborChanged(BlockState state, World world, BlockPos pos, Block block, BlockPos fromPos, boolean unused)
{
TileEntity te = world.getTileEntity(pos);
if(te instanceof BlockDecorPipeValve.BTileEntity) ((BTileEntity)te).block_changed();
}
//--------------------------------------------------------------------------------------------------------------------
// Tile entity
//--------------------------------------------------------------------------------------------------------------------
public static class BTileEntity extends TileEntity implements ITickableTileEntity, ICapabilityProvider
{
protected static int tick_idle_interval = 20; // ca 1000ms, simulates suction delay and saves CPU when not drained.
protected static int max_flowrate = 1000;
private Direction block_facing_ = Direction.NORTH;
private FluidStack tank_ = FluidStack.EMPTY;
private int last_drain_request_amount_ = 0;
private int vacuum_ = 0;
private int tick_timer_ = 0;
private int round_robin_ = 0;
private boolean initialized_ = false;
private int total_volume_filled_ = 0;
private int total_volume_drained_ = 0;
public void send_device_stats(PlayerEntity player)
{
int t_vol = tank_.getAmount();
ModAuxiliaries.playerChatMessage(player,"" + t_vol + "mB");
}
public void block_changed()
{ initialized_ = false; tick_timer_ = MathHelper.clamp(tick_timer_ , 0, tick_idle_interval); }
// TileEntity ------------------------------------------------------------------------------
public BTileEntity()
{ this(ModContent.TET_PASSIVE_FLUID_ACCUMULATOR); }
public BTileEntity(TileEntityType<?> te_type)
{ super(te_type); }
@Override
public void read(CompoundNBT nbt)
{
super.read(nbt);
tank_ = (!nbt.contains("tank")) ? (FluidStack.EMPTY) : (FluidStack.loadFluidStackFromNBT(nbt.getCompound("tank")));
}
@Override
public CompoundNBT write(CompoundNBT nbt)
{
super.write(nbt);
if(!tank_.isEmpty()) nbt.put("tank", tank_.writeToNBT(new CompoundNBT()));
return nbt;
}
// Input flow handler ---------------------------------------------------------------------
private static class InputFillHandler implements IFluidHandler
{
private final BTileEntity parent_;
InputFillHandler(BTileEntity parent) { parent_ = parent; }
@Override public int getTanks() { return 0; }
@Override public FluidStack getFluidInTank(int tank) { return FluidStack.EMPTY; }
@Override public int getTankCapacity(int tank) { return max_flowrate; }
@Override public boolean isFluidValid(int tank, @Nonnull FluidStack stack) { return true; }
@Override public int fill(FluidStack resource, FluidAction action) { return 0; }
@Override public FluidStack drain(FluidStack resource, FluidAction action) { return FluidStack.EMPTY; }
@Override public FluidStack drain(int maxDrain, FluidAction action) { return FluidStack.EMPTY; }
}
// Output flow handler ---------------------------------------------------------------------
private static class OutputFlowHandler implements IFluidHandler
{
private final BTileEntity te;
OutputFlowHandler(BTileEntity parent) { te = parent; }
@Override public int getTanks() { return 1; }
@Override public FluidStack getFluidInTank(int tank) { return te.tank_.copy(); }
@Override public int getTankCapacity(int tank) { return max_flowrate; }
@Override public boolean isFluidValid(int tank, @Nonnull FluidStack stack) { return true; }
@Override public int fill(FluidStack resource, FluidAction action) { return 0; }
@Override public FluidStack drain(FluidStack resource, FluidAction action)
{
if((resource==null) || (te.tank_.isEmpty())) return FluidStack.EMPTY;
return (!(te.tank_.isFluidEqual(resource))) ? (FluidStack.EMPTY) : drain(resource.getAmount(), action);
}
@Override public FluidStack drain(int maxDrain, FluidAction action)
{
if(!te.initialized_) return FluidStack.EMPTY;
if((action==FluidAction.EXECUTE) && (maxDrain > 0)) te.last_drain_request_amount_ = maxDrain;
if(te.tank_.isEmpty()) return FluidStack.EMPTY;
maxDrain = MathHelper.clamp(maxDrain ,0 , te.tank_.getAmount());
FluidStack res = te.tank_.copy();
if(action!=FluidAction.EXECUTE) return res;
res.setAmount(maxDrain);
te.tank_.setAmount(te.tank_.getAmount()-maxDrain);
if(te.tank_.getAmount() <= 0) te.tank_ = FluidStack.EMPTY;
te.total_volume_drained_ += res.getAmount();
return res;
}
}
// ICapabilityProvider --------------------------------------------------------------------
private final LazyOptional<IFluidHandler> fluid_handler_ = LazyOptional.of(() -> new OutputFlowHandler(this));
private final LazyOptional<IFluidHandler> fill_handler_ = LazyOptional.of(() -> new InputFillHandler(this));
@Override
public <T> LazyOptional<T> getCapability(net.minecraftforge.common.capabilities.Capability<T> capability, @Nullable Direction facing)
{
if((initialized_) && (!this.removed) && (facing != null)) {
if(capability == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY) {
if(facing == block_facing_) return fluid_handler_.cast();
return fill_handler_.cast();
}
}
return super.getCapability(capability, facing);
}
// ITickable--------------------------------------------------------------------------------
public void tick()
{
if((world.isRemote) || (--tick_timer_ > 0)) return;
tick_timer_ = tick_idle_interval;
if(!initialized_) {
initialized_ = true;
BlockState state = world.getBlockState(pos);
if((state==null) || (!(state.getBlock() instanceof BlockDecorPassiveFluidAccumulator))) return;
block_facing_ = state.get(FACING);
}
int n_requested = last_drain_request_amount_;
last_drain_request_amount_ = 0;
if(n_requested > 0) {
vacuum_ += 2;
if(vacuum_ > 5) vacuum_ = 5;
} else {
if((--vacuum_) <= 0) {
vacuum_ = 0;
if(!tank_.isEmpty()) {
return; // nothing to do, noone's draining.
} else {
n_requested = 10; // drip in
}
}
}
boolean has_refilled = false;
n_requested += (vacuum_ * 50);
int tank_buffer_needed = n_requested;
if(tank_buffer_needed > max_flowrate) tank_buffer_needed = max_flowrate;
for(int i=0; i<6; ++i) {
if(++round_robin_ > 5) round_robin_ = 0;
if(n_requested <= 0) break;
if((tank_.getAmount() >= tank_buffer_needed)) break;
final Direction f = Direction.byIndex(round_robin_);
if(f == block_facing_) continue;
final TileEntity te = world.getTileEntity(pos.offset(f));
if((te==null) || (te instanceof BTileEntity)) continue;
final IFluidHandler fh = te.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, f.getOpposite()).orElse(null);
if(fh==null) continue;
if(tank_.isEmpty()) {
FluidStack res = fh.drain(n_requested, FluidAction.EXECUTE).copy();
if(res.isEmpty()) continue;
total_volume_filled_ += res.getAmount();
tank_ = res.copy();
has_refilled = true;
} else {
if((tank_.getAmount() + n_requested) > max_flowrate) n_requested = (max_flowrate - tank_.getAmount());
FluidStack rq = tank_.copy();
rq.setAmount(n_requested);
FluidStack res = fh.drain(rq, FluidAction.SIMULATE);
if(!res.isFluidEqual(rq)) continue;
res = fh.drain(rq, FluidAction.EXECUTE);
if(res.isEmpty()) continue;
tank_.setAmount(tank_.getAmount()+res.getAmount());
total_volume_filled_ += res.getAmount();
has_refilled = true;
if(tank_.getAmount() >= max_flowrate) break;
}
}
if(has_refilled) tick_timer_ = 0;
}
}
}

View file

@ -0,0 +1,291 @@
/*
* @file BlockDecorPipeValve.java
* @author Stefan Wilhelm (wile)
* @copyright (C) 2019 Stefan Wilhelm
* @license MIT (see https://opensource.org/licenses/MIT)
*
* Basically a piece of pipe that does not connect to
* pipes on the side, and conducts fluids only in one way.
*/
package wile.engineersdecor.blocks;
import wile.engineersdecor.ModContent;
import wile.engineersdecor.ModEngineersDecor;
import net.minecraft.world.IWorld;
import net.minecraft.world.World;
import net.minecraft.world.IBlockReader;
import net.minecraft.state.BooleanProperty;
import net.minecraft.state.StateContainer;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.IWaterLoggable;
import net.minecraft.tileentity.TileEntityType;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.item.BlockItemUseContext;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.entity.LivingEntity;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.Direction;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.shapes.ISelectionContext;
import net.minecraft.util.math.shapes.VoxelShape;
import net.minecraft.util.math.shapes.VoxelShapes;
import net.minecraftforge.common.capabilities.ICapabilityProvider;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.capability.CapabilityFluidHandler;
import net.minecraftforge.fluids.capability.IFluidHandler;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public class BlockDecorPipeValve extends BlockDecorDirected implements IWaterLoggable
{
public static final BooleanProperty RS_CN_N = BooleanProperty.create("rs_n");
public static final BooleanProperty RS_CN_S = BooleanProperty.create("rs_s");
public static final BooleanProperty RS_CN_E = BooleanProperty.create("rs_e");
public static final BooleanProperty RS_CN_W = BooleanProperty.create("rs_w");
public static final BooleanProperty RS_CN_U = BooleanProperty.create("rs_u");
public static final BooleanProperty RS_CN_D = BooleanProperty.create("rs_d");
public static void on_config(int container_size_decl, int redstone_slope)
{
BTileEntity.fluid_maxflow_mb = MathHelper.clamp(container_size_decl, 1, 10000);
BTileEntity.redstone_flow_slope_mb = MathHelper.clamp(redstone_slope, 1, 10000);
ModEngineersDecor.logger().info("Config pipe valve: maxflow:" + BTileEntity.fluid_maxflow_mb + "mb, redstone amp:" + BTileEntity.redstone_flow_slope_mb + "mb/sig");
}
public BlockDecorPipeValve(long config, Block.Properties builder, final AxisAlignedBB unrotatedAABB)
{ super(config|CFG_WATERLOGGABLE, builder, unrotatedAABB); }
private BlockState get_rsconnector_state(BlockState state, IWorld world, BlockPos pos, @Nullable BlockPos fromPos)
{
if((config & (CFG_REDSTONE_CONTROLLED))==0) return state;
Direction.Axis bfa = state.get(FACING).getAxis();
int bfi = state.get(FACING).getIndex();
for(Direction f:Direction.values()) {
boolean cn = (f.getAxis() != bfa);
if(cn) {
BlockPos nbp = pos.offset(f);
if((fromPos != null) && (!nbp.equals(fromPos))) continue; // do not change connectors except form the frompos.
BlockState nbs = world.getBlockState(nbp);
if(!nbs.canProvidePower()) cn = false; // @todo check if there is a direction selective canProvidePower().
}
switch(f) {
case NORTH: state = state.with(RS_CN_N, cn); break;
case SOUTH: state = state.with(RS_CN_S, cn); break;
case EAST: state = state.with(RS_CN_E, cn); break;
case WEST: state = state.with(RS_CN_W, cn); break;
case UP: state = state.with(RS_CN_U, cn); break;
case DOWN: state = state.with(RS_CN_D, cn); break;
}
}
return state;
}
private void update_te(IWorld world, BlockState state, BlockPos pos)
{
TileEntity te = world.getTileEntity(pos);
if(te instanceof BlockDecorPipeValve.BTileEntity) ((BlockDecorPipeValve.BTileEntity)te).block_reconfigure(state.get(FACING), config);
}
@Override
public VoxelShape getCollisionShape(BlockState state, IBlockReader world, BlockPos pos, ISelectionContext selectionContext)
{ return VoxelShapes.fullCube(); }
@Override
protected void fillStateContainer(StateContainer.Builder<Block, BlockState> builder)
{ super.fillStateContainer(builder); builder.add(RS_CN_N, RS_CN_S, RS_CN_E, RS_CN_W, RS_CN_U, RS_CN_D, WATERLOGGED); }
@Override
@Nullable
public BlockState getStateForPlacement(BlockItemUseContext context)
{
return super.getStateForPlacement(context).with(RS_CN_N, false).with(RS_CN_S, false).with(RS_CN_E, false)
.with(RS_CN_W, false).with(RS_CN_U, false).with(RS_CN_D, false);
}
@Override
@SuppressWarnings("deprecation")
public BlockState updatePostPlacement(BlockState state, Direction facing, BlockState facingState, IWorld world, BlockPos pos, BlockPos facingPos)
{
update_te(world, state, pos);
return get_rsconnector_state(state, world, pos, null);
}
@Override
public void onBlockPlacedBy(World world, BlockPos pos, BlockState state, LivingEntity placer, ItemStack stack)
{
update_te(world, state, pos);
world.notifyNeighborsOfStateChange(pos,this);
}
@Override
public boolean hasTileEntity(BlockState state)
{ return true; }
@Override
@Nullable
public TileEntity createTileEntity(BlockState state, IBlockReader world)
{ return new BlockDecorPipeValve.BTileEntity(); }
@Override
public boolean canConnectRedstone(BlockState state, IBlockReader world, BlockPos pos, @Nullable Direction side)
{ return (side!=null) && (side!=state.get(FACING)) && (side!=state.get(FACING).getOpposite()); }
//--------------------------------------------------------------------------------------------------------------------
// Tile entity
//--------------------------------------------------------------------------------------------------------------------
public static class BTileEntity extends TileEntity implements ICapabilityProvider //, IFluidPipe
{
protected static int fluid_maxflow_mb = 1000;
protected static int redstone_flow_slope_mb = 1000/15;
private Direction block_facing_ = null;
private boolean filling_ = false;
private boolean getlocked_ = false;
private long block_config_ = 0;
public BTileEntity()
{ this(ModContent.TET_STRAIGHT_PIPE_VALVE); }
public BTileEntity(TileEntityType<?> te_type)
{ super(te_type); }
public void block_reconfigure(Direction facing, long block_config)
{
block_facing_ = facing;
block_config_ = block_config;
}
private Direction block_facing()
{
if(block_facing_ == null) {
BlockState st = getWorld().getBlockState(getPos());
block_facing_ = (st.getBlock() instanceof BlockDecorPipeValve) ? st.get(FACING) : Direction.NORTH;
}
return block_facing_;
}
// TileEntity ------------------------------------------------------------------------------
@Override
public void read(CompoundNBT nbt)
{
super.read(nbt);
int i = nbt.getInt("facing");
if((i>=0) || (i<6)) block_facing_ = Direction.byIndex(i);
block_config_ = nbt.getLong("conf");
}
@Override
public CompoundNBT write(CompoundNBT nbt)
{
super.write(nbt);
if(block_facing_!=null) nbt.putInt("facing", block_facing_.getIndex());
nbt.putLong("conf", block_config_);
return nbt;
}
// ICapabilityProvider --------------------------------------------------------------------
private LazyOptional<IFluidHandler> back_flow_handler_ = LazyOptional.of(() -> (IFluidHandler)new BackFlowHandler());
private LazyOptional<IFluidHandler> fluid_handler_ = LazyOptional.of(() -> (IFluidHandler)new MainFlowHandler(this));
@Override
public <T> LazyOptional<T> getCapability(net.minecraftforge.common.capabilities.Capability<T> capability, @Nullable Direction facing)
{
if(!this.removed && (facing != null)) {
if(capability == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY) {
if(facing == block_facing()) return back_flow_handler_.cast();
if(facing == block_facing().getOpposite()) return fluid_handler_.cast();
}
}
return super.getCapability(capability, facing);
}
// IFluidHandlers
@Nullable
private IFluidHandler forward_fluid_handler()
{
final TileEntity te = world.getTileEntity(pos.offset(block_facing()));
if(te == null) return null;
return te.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, block_facing().getOpposite()).orElse(null);
}
// Forward flow handler --
private static class MainFlowHandler implements IFluidHandler
{
private BTileEntity te;
public MainFlowHandler(BTileEntity te) { this.te = te; }
@Override public int getTanks() { return 0; }
@Override public FluidStack getFluidInTank(int tank) { return FluidStack.EMPTY; }
@Override public int getTankCapacity(int tank) { return fluid_maxflow_mb; }
@Override public FluidStack drain(FluidStack resource, FluidAction action) { return FluidStack.EMPTY; }
@Override public FluidStack drain(int maxDrain, FluidAction action) { return FluidStack.EMPTY; }
@Override public boolean isFluidValid(int tank, @Nonnull FluidStack stack) { return true; }
@Override public int fill(FluidStack resource, FluidAction action)
{
if(te.filling_) return 0;
final IFluidHandler fh = te.forward_fluid_handler();
if(fh==null) return 0;
if((te.block_config_ & CFG_REDSTONE_CONTROLLED) != 0) {
int rs = te.world.getRedstonePowerFromNeighbors(te.pos);
if(rs <= 0) return 0;
if(((te.block_config_ & CFG_ANALOG) != 0) && (rs < 15)) resource.setAmount(MathHelper.clamp(rs * redstone_flow_slope_mb, 1, resource.getAmount()));
}
FluidStack res = resource.copy();
if(res.getAmount() > fluid_maxflow_mb) res.setAmount(fluid_maxflow_mb);
te.filling_ = true;
// IE fluid pipe not available yet
// if(res.getAmount() > 50) {
// final TileEntity fte = te.world.getTileEntity(te.pos.offset(te.block_facing()));
// if(!(fte instanceof IFluidPipe)) {
// CompoundNBT tag = res.getTag();
// if((tag != null) && (tag.contains("pressurized"))) tag.remove("pressurized"); // remove pressureized tag if no IFluidPipe
// }
// }
int n_filled = fh.fill(res, action);
te.filling_ = false;
return n_filled;
}
}
// Back flow prevention handler --
private static class BackFlowHandler implements IFluidHandler
{
@Override public int getTanks() { return 0; }
@Override public FluidStack getFluidInTank(int tank) { return FluidStack.EMPTY; }
@Override public int getTankCapacity(int tank) { return 0; }
@Override public boolean isFluidValid(int tank, @Nonnull FluidStack stack) { return false; }
@Override public int fill(FluidStack resource, FluidAction action) { return 0; }
@Override public FluidStack drain(FluidStack resource, FluidAction action) { return FluidStack.EMPTY; }
@Override public FluidStack drain(int maxDrain, FluidAction action) { return FluidStack.EMPTY; }
}
// IE IFluidPipe
// @Override
// public boolean hasOutputConnection(Direction side)
// { return (side == block_facing()); }
//
// @Override
// public boolean canOutputPressurized(boolean consumePower)
// {
// if(getlocked_ || (!filling_enabled_)) return false;
// final TileEntity te = world.getTileEntity(pos.offset(block_facing()));
// if(!(te instanceof IFluidPipe)) return false;
// getlocked_ = true; // not sure if IE explicitly pre-detects loops, so let's lock recurion here, too.
// boolean r = ((IFluidPipe)te).canOutputPressurized(consumePower);
// getlocked_ = false;
// return r;
// }
}
}

View file

@ -0,0 +1,755 @@
/*
* @file BlockDecorPlacer.java
* @author Stefan Wilhelm (wile)
* @copyright (C) 2019 Stefan Wilhelm
* @license MIT (see https://opensource.org/licenses/MIT)
*
* Block placer and planter, factory automation suitable.
*/
package wile.engineersdecor.blocks;
import wile.engineersdecor.ModContent;
import wile.engineersdecor.ModEngineersDecor;
import wile.engineersdecor.detail.Networking;
import net.minecraft.block.*;
import net.minecraft.state.StateContainer;
import net.minecraft.world.IBlockReader;
import net.minecraft.world.World;
import net.minecraft.world.server.ServerWorld;
import net.minecraft.tileentity.ITickableTileEntity;
import net.minecraft.tileentity.TileEntityType;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.entity.player.ServerPlayerEntity;
import net.minecraft.entity.item.ItemEntity;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.item.*;
import net.minecraft.inventory.*;
import net.minecraft.inventory.container.INamedContainerProvider;
import net.minecraft.inventory.container.Container;
import net.minecraft.inventory.container.Slot;
import net.minecraft.client.gui.screen.inventory.ContainerScreen;
import net.minecraft.util.*;
import net.minecraft.util.math.*;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.text.StringTextComponent;
import net.minecraft.util.math.shapes.ISelectionContext;
import net.minecraft.util.math.shapes.VoxelShape;
import net.minecraft.util.math.shapes.VoxelShapes;
import net.minecraft.util.SoundEvents;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.common.IPlantable;
import net.minecraftforge.common.util.FakePlayer;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.items.wrapper.SidedInvWrapper;
import net.minecraftforge.items.CapabilityItemHandler;
import net.minecraftforge.items.IItemHandler;
import net.minecraftforge.fml.network.NetworkHooks;
import com.mojang.blaze3d.systems.RenderSystem;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;
public class BlockDecorPlacer extends BlockDecorDirected
{
public BlockDecorPlacer(long config, Block.Properties builder, final AxisAlignedBB unrotatedAABB)
{ super(config, builder, unrotatedAABB); }
@Override
public RenderTypeHint getRenderTypeHint()
{ return RenderTypeHint.SOLID; }
@Override
public VoxelShape getCollisionShape(BlockState state, IBlockReader world, BlockPos pos, ISelectionContext selectionContext)
{ return VoxelShapes.fullCube(); }
@Override
protected void fillStateContainer(StateContainer.Builder<Block, BlockState> builder)
{ super.fillStateContainer(builder); }
@Override
@Nullable
public BlockState getStateForPlacement(BlockItemUseContext context)
{ return super.getStateForPlacement(context); }
@Override
@SuppressWarnings("deprecation")
public boolean hasComparatorInputOverride(BlockState state)
{ return true; }
@Override
@SuppressWarnings("deprecation")
public int getComparatorInputOverride(BlockState blockState, World world, BlockPos pos)
{ return Container.calcRedstone(world.getTileEntity(pos)); }
@Override
public boolean hasTileEntity(BlockState state)
{ return true; }
@Override
@Nullable
public TileEntity createTileEntity(BlockState state, IBlockReader world)
{ return new BTileEntity(); }
@Override
public void onBlockPlacedBy(World world, BlockPos pos, BlockState state, LivingEntity placer, ItemStack stack)
{
if(world.isRemote) return;
if((!stack.hasTag()) || (!stack.getTag().contains("tedata"))) return;
CompoundNBT te_nbt = stack.getTag().getCompound("tedata");
if(te_nbt.isEmpty()) return;
final TileEntity te = world.getTileEntity(pos);
if(!(te instanceof BTileEntity)) return;
((BTileEntity)te).readnbt(te_nbt, false);
((BTileEntity)te).reset_rtstate();
((BTileEntity)te).markDirty();
}
@Override
public boolean hasDynamicDropList()
{ return true; }
@Override
public List<ItemStack> dropList(BlockState state, World world, BlockPos pos, boolean explosion)
{
final List<ItemStack> stacks = new ArrayList<ItemStack>();
if(world.isRemote) return stacks;
final TileEntity te = world.getTileEntity(pos);
if(!(te instanceof BTileEntity)) return stacks;
if(!explosion) {
ItemStack stack = new ItemStack(this, 1);
CompoundNBT te_nbt = ((BTileEntity) te).clear_getnbt();
if(!te_nbt.isEmpty()) {
CompoundNBT nbt = new CompoundNBT();
nbt.put("tedata", te_nbt);
stack.setTag(nbt);
}
stacks.add(stack);
} else {
for(ItemStack stack: ((BTileEntity)te).stacks_) {
if(!stack.isEmpty()) stacks.add(stack);
}
((BTileEntity)te).reset_rtstate();
}
return stacks;
}
@Override
@SuppressWarnings("deprecation")
public boolean onBlockActivated(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockRayTraceResult rayTraceResult)
{
if(world.isRemote) return true;
final TileEntity te = world.getTileEntity(pos);
if(!(te instanceof BTileEntity)) return true;
if((!(player instanceof ServerPlayerEntity) && (!(player instanceof FakePlayer)))) return true;
NetworkHooks.openGui((ServerPlayerEntity)player,(INamedContainerProvider)te);
return true;
}
@Override
@SuppressWarnings("deprecation")
public void neighborChanged(BlockState state, World world, BlockPos pos, Block block, BlockPos fromPos, boolean unused)
{
if(!(world instanceof World) || (((World) world).isRemote)) return;
TileEntity te = world.getTileEntity(pos);
if(!(te instanceof BTileEntity)) return;
((BTileEntity)te).block_updated();
}
@Override
@SuppressWarnings("deprecation")
public boolean canProvidePower(BlockState state)
{ return true; }
@Override
@SuppressWarnings("deprecation")
public int getWeakPower(BlockState blockState, IBlockReader blockAccess, BlockPos pos, Direction side)
{ return 0; }
@Override
@SuppressWarnings("deprecation")
public int getStrongPower(BlockState blockState, IBlockReader blockAccess, BlockPos pos, Direction side)
{ return 0; }
//--------------------------------------------------------------------------------------------------------------------
// Tile entity
//--------------------------------------------------------------------------------------------------------------------
public static class BTileEntity extends TileEntity implements ITickableTileEntity, INameable, IInventory, INamedContainerProvider, ISidedInventory
{
public static final int TICK_INTERVAL = 40;
public static final int NUM_OF_SLOTS = 18;
public static final int NUM_OF_FIELDS = 3;
///
public static final int LOGIC_INVERTED = 0x01;
public static final int LOGIC_CONTINUOUS = 0x02;
///
private boolean block_power_signal_ = false;
private boolean block_power_updated_ = false;
private int logic_ = LOGIC_INVERTED|LOGIC_CONTINUOUS;
private int current_slot_index_ = 0;
private int tick_timer_ = 0;
protected NonNullList<ItemStack> stacks_;
public static void on_config(int cooldown_ticks)
{
// ModEngineersDecor.logger.info("Config factory placer:");
}
public BTileEntity()
{ this(ModContent.TET_FACTORY_PLACER); }
public BTileEntity(TileEntityType<?> te_type)
{
super(te_type);
stacks_ = NonNullList.<ItemStack>withSize(NUM_OF_SLOTS, ItemStack.EMPTY);
reset_rtstate();
}
public CompoundNBT clear_getnbt()
{
CompoundNBT nbt = new CompoundNBT();
writenbt(nbt, false);
for(int i=0; i<stacks_.size(); ++i) stacks_.set(i, ItemStack.EMPTY);
reset_rtstate();
block_power_updated_ = false;
return nbt;
}
public void reset_rtstate()
{
block_power_signal_ = false;
block_power_updated_ = false;
}
public void readnbt(CompoundNBT nbt, boolean update_packet)
{
stacks_ = NonNullList.<ItemStack>withSize(NUM_OF_SLOTS, ItemStack.EMPTY);
ItemStackHelper.loadAllItems(nbt, stacks_);
while(stacks_.size() < NUM_OF_SLOTS) stacks_.add(ItemStack.EMPTY);
block_power_signal_ = nbt.getBoolean("powered");
current_slot_index_ = nbt.getInt("act_slot_index");
logic_ = nbt.getInt("logic");
}
protected void writenbt(CompoundNBT nbt, boolean update_packet)
{
ItemStackHelper.saveAllItems(nbt, stacks_);
nbt.putBoolean("powered", block_power_signal_);
nbt.putInt("act_slot_index", current_slot_index_);
nbt.putInt("logic", logic_);
}
public void block_updated()
{
boolean powered = world.isBlockPowered(pos);
if(block_power_signal_ != powered) block_power_updated_ = true;
block_power_signal_ = powered;
if(block_power_updated_) {
tick_timer_ = 1;
} else if(tick_timer_ > 4) {
tick_timer_ = 4;
}
}
public boolean is_input_slot(int index)
{ return (index >= 0) && (index < NUM_OF_SLOTS); }
// TileEntity ------------------------------------------------------------------------------
@Override
public void read(CompoundNBT nbt)
{ super.read(nbt); readnbt(nbt, false); }
@Override
public CompoundNBT write(CompoundNBT nbt)
{ super.write(nbt); writenbt(nbt, false); return nbt; }
// INamable ----------------------------------------------------------------------------------------------
@Override
public ITextComponent getName()
{ final Block block=getBlockState().getBlock(); return new StringTextComponent((block!=null) ? block.getTranslationKey() : "Factory placer"); }
@Override
public boolean hasCustomName()
{ return false; }
@Override
public ITextComponent getCustomName()
{ return getName(); }
// INamedContainerProvider ------------------------------------------------------------------------------
@Override
public ITextComponent getDisplayName()
{ return INameable.super.getDisplayName(); }
@Override
public Container createMenu(int id, PlayerInventory inventory, PlayerEntity player )
{ return new BContainer(id, inventory, this, IWorldPosCallable.of(world, pos), fields); }
// IInventory -------------------------------------------------------------------------------------------
@Override
public int getSizeInventory()
{ return stacks_.size(); }
@Override
public boolean isEmpty()
{ for(ItemStack stack: stacks_) { if(!stack.isEmpty()) return false; } return true; }
@Override
public ItemStack getStackInSlot(int index)
{ return (index < getSizeInventory()) ? stacks_.get(index) : ItemStack.EMPTY; }
@Override
public ItemStack decrStackSize(int index, int count)
{ return ItemStackHelper.getAndSplit(stacks_, index, count); }
@Override
public ItemStack removeStackFromSlot(int index)
{ return ItemStackHelper.getAndRemove(stacks_, index); }
@Override
public void setInventorySlotContents(int index, ItemStack stack)
{
if((index<0) || (index >= NUM_OF_SLOTS)) return;
stacks_.set(index, stack);
if(stack.getCount() > getInventoryStackLimit()) stack.setCount(getInventoryStackLimit());
if(tick_timer_ > 8) tick_timer_ = 8;
markDirty();
}
@Override
public int getInventoryStackLimit()
{ return 64; }
@Override
public void markDirty()
{ super.markDirty(); }
@Override
public boolean isUsableByPlayer(PlayerEntity player)
{ return getPos().distanceSq(player.getPosition()) < 36; }
@Override
public void openInventory(PlayerEntity player)
{}
@Override
public void closeInventory(PlayerEntity player)
{ markDirty(); }
@Override
public boolean isItemValidForSlot(int index, ItemStack stack)
{ return (index>=0) && (index<NUM_OF_SLOTS); }
@Override
public void clear()
{ for(int i=0; i<stacks_.size(); ++i) stacks_.set(i, ItemStack.EMPTY); } // should search a better vectorizing method here.
// Fields -----------------------------------------------------------------------------------------------
protected final IIntArray fields = new IntArray(BTileEntity.NUM_OF_FIELDS)
{
@Override
public int get(int id)
{
switch(id) {
case 0: return logic_;
case 1: return block_power_signal_ ? 1 : 0;
case 2: return MathHelper.clamp(current_slot_index_, 0, NUM_OF_SLOTS-1);
default: return 0;
}
}
@Override
public void set(int id, int value)
{
switch(id) {
case 0: logic_ = value; return;
case 1: block_power_signal_ = (value != 0); return;
case 2: current_slot_index_ = MathHelper.clamp(value, 0, NUM_OF_SLOTS-1); return;
default: return;
}
}
};
// ISidedInventory --------------------------------------------------------------------------------------
LazyOptional<? extends IItemHandler>[] item_handlers = SidedInvWrapper.create(this, Direction.UP);
private static final int[] SIDED_INV_SLOTS;
static {
SIDED_INV_SLOTS = new int[NUM_OF_SLOTS];
for(int i=0; i<NUM_OF_SLOTS; ++i) SIDED_INV_SLOTS[i] = i;
}
@Override
public int[] getSlotsForFace(Direction side)
{ return SIDED_INV_SLOTS; }
@Override
public boolean canInsertItem(int index, ItemStack stack, Direction direction)
{ return is_input_slot(index) && isItemValidForSlot(index, stack); }
@Override
public boolean canExtractItem(int index, ItemStack stack, Direction direction)
{ return false; }
// Capability export ------------------------------------------------------------------------------------
@Override
public <T> LazyOptional<T> getCapability(net.minecraftforge.common.capabilities.Capability<T> capability, @Nullable Direction facing)
{
if(!this.removed && (facing != null)) {
if(capability==CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) return item_handlers[0].cast();
}
return super.getCapability(capability, facing);
}
// ITickable and aux methods ----------------------------------------------------------------------------
private static int next_slot(int i)
{ return (i<NUM_OF_SLOTS-1) ? (i+1) : 0; }
private boolean spit_out(Direction facing)
{ return spit_out(facing, false); }
private boolean spit_out(Direction facing, boolean all)
{
ItemStack stack = stacks_.get(current_slot_index_);
ItemStack drop = stack.copy();
if(!all) {
stack.shrink(1);
stacks_.set(current_slot_index_, stack);
drop.setCount(1);
} else {
stacks_.set(current_slot_index_, ItemStack.EMPTY);
}
for(int i=0; i<8; ++i) {
BlockPos p = pos.offset(facing, i);
if(!world.isAirBlock(p)) continue;
world.addEntity(new ItemEntity(world, (p.getX()+0.5), (p.getY()+0.5), (p.getZ()+0.5), drop));
world.playSound(null, p, SoundEvents.ENTITY_ITEM_PICKUP, SoundCategory.BLOCKS, 0.7f, 0.8f);
break;
}
return true;
}
private boolean try_place(Direction facing)
{
if(world.isRemote) return false;
BlockPos placement_pos = pos.offset(facing);
if(world.getTileEntity(placement_pos) != null) return false;
ItemStack current_stack = ItemStack.EMPTY;
for(int i=0; i<NUM_OF_SLOTS; ++i) {
if(current_slot_index_ >= NUM_OF_SLOTS) current_slot_index_ = 0;
current_stack = stacks_.get(current_slot_index_);
if(!current_stack.isEmpty()) break;
current_slot_index_ = next_slot(current_slot_index_);
}
if(current_stack.isEmpty()) { current_slot_index_ = 0; return false; }
boolean no_space = false;
final Item item = current_stack.getItem();
Block block = (item instanceof IPlantable) ? (((IPlantable)item).getPlant(world, pos).getBlock()) : Block.getBlockFromItem(item);
if(block == Blocks.AIR) {
if(item != null) {
return spit_out(facing); // Item not accepted
} else {
// try next slot
}
} else if(block instanceof IPlantable) {
if(world.isAirBlock(placement_pos)) {
// plant here, block below has to be valid soil.
BlockState soilstate = world.getBlockState(placement_pos.down());
if(!soilstate.getBlock().canSustainPlant(soilstate, world, pos, Direction.UP, (IPlantable)block)) {
block = Blocks.AIR;
}
} else {
// adjacent block is the soil, plant above if the soil is valid.
BlockState soilstate = world.getBlockState(placement_pos);
if(soilstate.getBlock() == block) {
// The plant is already planted from the case above.
block = Blocks.AIR;
no_space = true;
} else if(!world.isAirBlock(placement_pos.up())) {
// If this is the soil an air block is needed above, if that is blocked we can't plant.
block = Blocks.AIR;
no_space = true;
} else if(!soilstate.getBlock().canSustainPlant(soilstate, world, pos, Direction.UP, (IPlantable)block)) {
// Would be space above, but it's not the right soil for the plant.
block = Blocks.AIR;
} else {
// Ok, plant above.
placement_pos = placement_pos.up();
}
}
} else if(!world.getBlockState(placement_pos).getMaterial().isReplaceable()) {
block = Blocks.AIR;
no_space = true;
}
// println("PLACE " + current_stack + " --> " + block + " at " + placement_pos.subtract(pos) + "( item=" + item + ")");
if(block != Blocks.AIR) {
try {
BlockItemUseContext use_context = null;
{
final FakePlayer placer = net.minecraftforge.common.util.FakePlayerFactory.getMinecraft((ServerWorld)world);
if(placer != null) {
ItemStack placement_stack = current_stack.copy();
placement_stack.setCount(1);
ItemStack held = placer.getHeldItem(Hand.MAIN_HAND);
placer.setHeldItem(Hand.MAIN_HAND, placement_stack);
use_context = new BlockItemUseContext(new ItemUseContext(placer, Hand.MAIN_HAND, new BlockRayTraceResult(new Vec3d(0.5,0,0.5), Direction.DOWN, placement_pos, false)));
placer.setHeldItem(Hand.MAIN_HAND, held);
}
}
final BlockState placement_state = (use_context==null) ? (block.getDefaultState()) : (block.getStateForPlacement(use_context));
if(placement_state == null) {
return spit_out(facing);
} else if(item instanceof BlockItem) {
if(((BlockItem)item).tryPlace(use_context) == ActionResultType.SUCCESS) {
SoundType stype = block.getSoundType(placement_state, world, pos, null);
if(stype != null) world.playSound(null, placement_pos, stype.getPlaceSound(), SoundCategory.BLOCKS, stype.getVolume()*0.6f, stype.getPitch());
} else {
return spit_out(facing);
}
} else {
if(world.setBlockState(placement_pos, placement_state, 1|2|8)) {
SoundType stype = block.getSoundType(placement_state, world, pos, null);
if(stype != null) world.playSound(null, placement_pos, stype.getPlaceSound(), SoundCategory.BLOCKS, stype.getVolume()*0.6f, stype.getPitch());
}
}
current_stack.shrink(1);
stacks_.set(current_slot_index_, current_stack);
return true;
} catch(Throwable e) {
// The block really needs a player or other issues happened during placement.
// A hard crash should not be fired here, instead spit out the item to indicated that this
// block is not compatible.
ModEngineersDecor.logger().error("Exception while trying to place " + ((block==null)?(""):(""+block)) + ", spitting out. Exception is: " + e);
world.removeBlock(placement_pos, false);
return spit_out(facing, true);
}
}
if((!no_space) && (!current_stack.isEmpty())) {
// There is space, but the current plant cannot be planted there, so try next.
for(int i=0; i<NUM_OF_SLOTS; ++i) {
current_slot_index_ = next_slot(current_slot_index_);
if(!stacks_.get(current_slot_index_).isEmpty()) break;
}
}
return false;
}
@Override
public void tick()
{
// Tick cycle pre-conditions
if(world.isRemote) return;
if(--tick_timer_ > 0) return;
tick_timer_ = TICK_INTERVAL;
// Cycle init
boolean dirty = block_power_updated_;
boolean rssignal = ((logic_ & LOGIC_INVERTED)!=0)==(!block_power_signal_);
boolean trigger = (rssignal && ((block_power_updated_) || ((logic_ & LOGIC_CONTINUOUS)!=0)));
final BlockState state = world.getBlockState(pos);
if(state == null) { block_power_signal_= false; return; }
final Direction placer_facing = state.get(FACING);
// Trigger edge detection for next cycle
{
boolean tr = world.isBlockPowered(pos);
block_power_updated_ = (block_power_signal_ != tr);
block_power_signal_ = tr;
if(block_power_updated_) dirty = true;
}
// Placing
if(trigger && try_place(placer_facing)) dirty = true;
if(dirty) markDirty();
if(trigger && (tick_timer_ > TICK_INTERVAL)) tick_timer_ = TICK_INTERVAL;
}
}
//--------------------------------------------------------------------------------------------------------------------
// container
//--------------------------------------------------------------------------------------------------------------------
public static class BContainer extends Container implements Networking.INetworkSynchronisableContainer
{
private static final int PLAYER_INV_START_SLOTNO = BTileEntity.NUM_OF_SLOTS;
private final PlayerEntity player_;
private final IInventory inventory_;
private final IWorldPosCallable wpc_;
private final IIntArray fields_;
public final int field(int index) { return fields_.get(index); }
public BContainer(int cid, PlayerInventory player_inventory)
{ this(cid, player_inventory, new Inventory(BTileEntity.NUM_OF_SLOTS), IWorldPosCallable.DUMMY, new IntArray(BTileEntity.NUM_OF_FIELDS)); }
private BContainer(int cid, PlayerInventory player_inventory, IInventory block_inventory, IWorldPosCallable wpc, IIntArray fields)
{
super(ModContent.CT_FACTORY_PLACER, cid);
fields_ = fields;
wpc_ = wpc;
player_ = player_inventory.player;
inventory_ = block_inventory;
int i=-1;
// device slots (stacks 0 to 17)
for(int y=0; y<3; ++y) {
for(int x=0; x<6; ++x) {
int xpos = 11+x*18, ypos = 9+y*17;
addSlot(new Slot(inventory_, ++i, xpos, ypos));
}
}
// player slots
for(int x=0; x<9; ++x) {
addSlot(new Slot(player_inventory, x, 8+x*18, 129)); // player slots: 0..8
}
for(int y=0; y<3; ++y) {
for(int x=0; x<9; ++x) {
addSlot(new Slot(player_inventory, x+y*9+9, 8+x*18, 71+y*18)); // player slots: 9..35
}
}
this.trackIntArray(fields_); // === Add reference holders
}
@Override
public boolean canInteractWith(PlayerEntity player)
{ return inventory_.isUsableByPlayer(player); }
@Override
public ItemStack transferStackInSlot(PlayerEntity player, int index)
{
Slot slot = getSlot(index);
if((slot==null) || (!slot.getHasStack())) return ItemStack.EMPTY;
ItemStack slot_stack = slot.getStack();
ItemStack transferred = slot_stack.copy();
if((index>=0) && (index<PLAYER_INV_START_SLOTNO)) {
// Device slots
if(!mergeItemStack(slot_stack, PLAYER_INV_START_SLOTNO, PLAYER_INV_START_SLOTNO+36, false)) return ItemStack.EMPTY;
} else if((index >= PLAYER_INV_START_SLOTNO) && (index <= PLAYER_INV_START_SLOTNO+36)) {
// Player slot
if(!mergeItemStack(slot_stack, 0, BTileEntity.NUM_OF_SLOTS, false)) return ItemStack.EMPTY;
} else {
// invalid slot
return ItemStack.EMPTY;
}
if(slot_stack.isEmpty()) {
slot.putStack(ItemStack.EMPTY);
} else {
slot.onSlotChanged();
}
if(slot_stack.getCount() == transferred.getCount()) return ItemStack.EMPTY;
slot.onTake(player, slot_stack);
return transferred;
}
// INetworkSynchronisableContainer ---------------------------------------------------------
@OnlyIn(Dist.CLIENT)
public void onGuiAction(CompoundNBT nbt)
{ Networking.PacketContainerSyncClientToServer.sendToServer(windowId, nbt); }
@OnlyIn(Dist.CLIENT)
public void onGuiAction(String key, int value)
{
CompoundNBT nbt = new CompoundNBT();
nbt.putInt(key, value);
Networking.PacketContainerSyncClientToServer.sendToServer(windowId, nbt);
}
@Override
public void onServerPacketReceived(int windowId, CompoundNBT nbt)
{}
@Override
public void onClientPacketReceived(int windowId, PlayerEntity player, CompoundNBT nbt)
{
if(!(inventory_ instanceof BTileEntity)) return;
BTileEntity te = (BTileEntity)inventory_;
if(nbt.contains("logic")) te.logic_ = nbt.getInt("logic");
if(nbt.contains("manual_trigger") && (nbt.getInt("manual_trigger")!=0)) { te.block_power_signal_=true; te.block_power_updated_=true; te.tick_timer_=1; }
te.markDirty();
}
}
//--------------------------------------------------------------------------------------------------------------------
// GUI
//--------------------------------------------------------------------------------------------------------------------
@OnlyIn(Dist.CLIENT)
public static class BGui extends ContainerScreen<BContainer>
{
protected final PlayerEntity player_;
public BGui(BContainer container, PlayerInventory player_inventory, ITextComponent title)
{ super(container, player_inventory, title); this.player_ = player_inventory.player; }
@Override
public void init()
{ super.init(); }
@Override
public void render(int mouseX, int mouseY, float partialTicks)
{
renderBackground();
super.render(mouseX, mouseY, partialTicks);
renderHoveredToolTip(mouseX, mouseY);
}
@Override
public boolean mouseClicked(double mouseX, double mouseY, int mouseButton)
{
BContainer container = (BContainer)getContainer();
int mx = (int)(mouseX - getGuiLeft() + .5), my = (int)(mouseY - getGuiTop() + .5);
if((!isPointInRegion(126, 1, 49, 60, mouseX, mouseY))) {
return super.mouseClicked(mouseX, mouseY, mouseButton);
} else if(isPointInRegion(133, 49, 9, 9, mouseX, mouseY)) {
container.onGuiAction("manual_trigger", 1);
} else if(isPointInRegion(145, 49, 9, 9, mouseX, mouseY)) {
container.onGuiAction("logic", container.field(0) ^ BTileEntity.LOGIC_INVERTED);
} else if(isPointInRegion(159, 49, 7, 9, mouseX, mouseY)) {
container.onGuiAction("logic", container.field(0) ^ BTileEntity.LOGIC_CONTINUOUS);
}
return true;
}
@Override
protected void drawGuiContainerBackgroundLayer(float partialTicks, int mouseX, int mouseY)
{
RenderSystem.enableBlend();
RenderSystem.color4f(1.0F, 1.0F, 1.0F, 1.0F);
this.minecraft.getTextureManager().bindTexture(new ResourceLocation(ModEngineersDecor.MODID, "textures/gui/factory_placer_gui.png"));
final int x0=getGuiLeft(), y0=getGuiTop(), w=getXSize(), h=getYSize();
blit(x0, y0, 0, 0, w, h);
BContainer container = (BContainer)getContainer();
// active slot
{
int slot_index = container.field(2);
if((slot_index < 0) || (slot_index >= BTileEntity.NUM_OF_SLOTS)) slot_index = 0;
int x = (x0+10+((slot_index % 6) * 18));
int y = (y0+8+((slot_index / 6) * 17));
blit(x, y, 200, 8, 18, 18);
}
// redstone input
{
if(container.field(1) != 0) {
blit(x0+133, y0+49, 217, 49, 9, 9);
}
}
// trigger logic
{
int inverter_offset = ((container.field(0) & BTileEntity.LOGIC_INVERTED) != 0) ? 11 : 0;
blit(x0+145, y0+49, 177+inverter_offset, 49, 9, 9);
int pulse_mode_offset = ((container.field(0) & BTileEntity.LOGIC_CONTINUOUS ) != 0) ? 9 : 0;
blit(x0+159, y0+49, 199+pulse_mode_offset, 49, 9, 9);
}
RenderSystem.disableBlend();
}
}
}

View file

@ -0,0 +1,182 @@
/*
* @file BlockDecorSlab.java
* @author Stefan Wilhelm (wile)
* @copyright (C) 2019 Stefan Wilhelm
* @license MIT (see https://opensource.org/licenses/MIT)
*
* Standard half block horizontal slab characteristics class.
*/
package wile.engineersdecor.blocks;
import net.minecraft.util.math.*;
import wile.engineersdecor.detail.ModAuxiliaries;
import net.minecraft.block.*;
import net.minecraft.client.util.ITooltipFlag;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.state.IntegerProperty;
import net.minecraft.util.*;
import net.minecraft.util.math.shapes.VoxelShapes;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.world.World;
import net.minecraft.entity.EntityType;
import net.minecraft.state.StateContainer;
import net.minecraft.util.math.shapes.ISelectionContext;
import net.minecraft.item.BlockItemUseContext;
import net.minecraft.block.BlockState;
import net.minecraft.world.IBlockReader;
import net.minecraft.util.math.shapes.VoxelShape;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import wile.engineersdecor.detail.ModConfig;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class BlockDecorSlab extends BlockDecor implements IWaterLoggable
{
public static final IntegerProperty PARTS = IntegerProperty.create("parts", 0, 2);
public static final IntegerProperty TEXTURE_VARIANT = IntegerProperty.create("tvariant", 0, 3);
protected static final VoxelShape AABBs[] = {
VoxelShapes.create(new AxisAlignedBB(0, 0./16, 0, 1, 8./16, 1)), // bottom slab
VoxelShapes.create(new AxisAlignedBB(0, 8./16, 0, 1, 16./16, 1)), // top slab
VoxelShapes.create(new AxisAlignedBB(0, 0./16, 0, 1, 16./16, 1)), // both slabs
VoxelShapes.create(new AxisAlignedBB(0, 0./16, 0, 1, 16./16, 1)) // << 2bit fill
};
protected static final int num_slabs_contained_in_parts_[] = { 1,1,2,2 };
protected boolean is_cube(BlockState state)
{ return state.get(PARTS) >= 2; }
public BlockDecorSlab(long config, Block.Properties builder)
{ super(config|CFG_WATERLOGGABLE, builder); }
@Override
public RenderTypeHint getRenderTypeHint()
{ return (((config & CFG_TRANSLUCENT)!=0) ? (RenderTypeHint.TRANSLUCENT) : (RenderTypeHint.CUTOUT)); }
@Override
@OnlyIn(Dist.CLIENT)
public void addInformation(ItemStack stack, @Nullable IBlockReader world, List<ITextComponent> tooltip, ITooltipFlag flag)
{
if(!ModAuxiliaries.Tooltip.addInformation(stack, world, tooltip, flag, true)) return;
if(!ModConfig.without_direct_slab_pickup) ModAuxiliaries.Tooltip.addInformation("engineersdecor.tooltip.slabpickup", "engineersdecor.tooltip.slabpickup", tooltip, flag, true);
}
@Override
@OnlyIn(Dist.CLIENT)
@SuppressWarnings("deprecation")
public boolean isSideInvisible(BlockState state, BlockState adjacentBlockState, Direction side)
{ return (adjacentBlockState==state) ? true : super.isSideInvisible(state, adjacentBlockState, side); }
@Override
public boolean canSpawnInBlock()
{ return false; }
@Override
@SuppressWarnings("deprecation")
public boolean canEntitySpawn(BlockState state, IBlockReader world, BlockPos pos, EntityType<?> entityType)
{ return false; }
@Override
public VoxelShape getShape(BlockState state, IBlockReader source, BlockPos pos, ISelectionContext selectionContext)
{ return AABBs[state.get(PARTS) & 0x3]; }
@Override
public VoxelShape getCollisionShape(BlockState state, IBlockReader world, BlockPos pos, ISelectionContext selectionContext)
{ return getShape(state, world, pos, selectionContext); }
@Override
protected void fillStateContainer(StateContainer.Builder<Block, BlockState> builder)
{ super.fillStateContainer(builder); builder.add(PARTS, TEXTURE_VARIANT, WATERLOGGED); }
@Override
@Nullable
public BlockState getStateForPlacement(BlockItemUseContext context)
{
final Direction facing = context.getFace();
double y = context.getHitVec().getY();
int rnd = MathHelper.clamp((int)(MathHelper.getPositionRandom(context.getPos()) % 4), 0, 3);
return super.getStateForPlacement(context).with(PARTS, ((facing==Direction.UP) || ((facing!=Direction.DOWN) && (y < 0.6))) ? 0 : 1).with(TEXTURE_VARIANT, rnd);
}
@Override
@SuppressWarnings("deprecation")
public BlockState rotate(BlockState state, Rotation rot)
{ return state; }
@Override
@SuppressWarnings("deprecation")
public BlockState mirror(BlockState state, Mirror mirrorIn)
{ return state; }
@Override
public boolean hasDynamicDropList()
{ return true; }
@Override
public List<ItemStack> dropList(BlockState state, World world, BlockPos pos, boolean explosion)
{ return new ArrayList<ItemStack>(Collections.singletonList(new ItemStack(this.asItem(), num_slabs_contained_in_parts_[state.get(PARTS) & 0x3]))); }
@Override
@SuppressWarnings("deprecation")
public boolean onBlockActivated(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockRayTraceResult rayTraceResult)
{
Direction face = rayTraceResult.getFace();
final ItemStack stack = player.getHeldItem(hand);
if(stack.isEmpty() || (Block.getBlockFromItem(stack.getItem()) != this)) return false;
int parts = state.get(PARTS);
if(((face == Direction.UP) && (parts == 0)) || ((face == Direction.DOWN) && (parts == 1))) {
world.setBlockState(pos, state.with(PARTS, 2), 3);
} else {
return false; // "not handled" -> let parent decide if a new slab has to be placed on top/bottom.
}
if(world.isRemote) return true;
if(!player.isCreative()) {
stack.shrink(1);
if(player.inventory != null) player.inventory.markDirty();
}
SoundType st = this.getSoundType(state, world, pos, null);
world.playSound(null, pos, st.getPlaceSound(), SoundCategory.BLOCKS, (st.getVolume()+1f)/2.5f, 0.9f*st.getPitch());
return true;
}
@Override
@SuppressWarnings("deprecation")
public void onBlockClicked(BlockState state, World world, BlockPos pos, PlayerEntity player)
{
if((world.isRemote) || (ModConfig.without_direct_slab_pickup)) return;
final ItemStack stack = player.getHeldItemMainhand();
if(stack.isEmpty() || (Block.getBlockFromItem(stack.getItem()) != this)) return;
if(stack.getCount() >= stack.getMaxStackSize()) return;
Vec3d lv = player.getLookVec();
Direction facing = Direction.getFacingFromVector((float)lv.x, (float)lv.y, (float)lv.z);
if((facing != Direction.UP) && (facing != Direction.DOWN)) return;
if(state.getBlock() != this) return;
int parts = state.get(PARTS);
if(facing == Direction.DOWN) {
if(parts == 2) {
world.setBlockState(pos, state.with(PARTS, 0), 3);
} else {
world.removeBlock(pos, false);
}
} else if(facing == Direction.UP) {
if(parts == 2) {
world.setBlockState(pos, state.with(PARTS, 1), 3);
} else {
world.removeBlock(pos, false);
}
}
if(!player.isCreative()) {
stack.grow(1);
if(player.inventory != null) player.inventory.markDirty();
}
SoundType st = this.getSoundType(state, world, pos, null);
world.playSound(player, pos, st.getPlaceSound(), SoundCategory.BLOCKS, (st.getVolume()+1f)/2.5f, 0.9f*st.getPitch());
}
}

View file

@ -0,0 +1,142 @@
/*
* @file BlockDecorDirected.java
* @author Stefan Wilhelm (wile)
* @copyright (C) 2019 Stefan Wilhelm
* @license MIT (see https://opensource.org/licenses/MIT)
*
* Smaller (cutout) block with a defined facing.
*/
package wile.engineersdecor.blocks;
import net.minecraft.world.LightType;
import wile.engineersdecor.ModContent;
import wile.engineersdecor.ModEngineersDecor;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.tileentity.ITickableTileEntity;
import net.minecraft.tileentity.TileEntityType;
import net.minecraft.util.Direction;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.item.BlockItemUseContext;
import net.minecraft.state.IntegerProperty;
import net.minecraft.state.StateContainer;
import net.minecraft.util.math.MathHelper;
import net.minecraft.world.IBlockReader;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraftforge.energy.CapabilityEnergy;
import net.minecraftforge.energy.IEnergyStorage;
import javax.annotation.Nullable;
public class BlockDecorSolarPanel extends BlockDecor
{
public static final IntegerProperty EXPOSITION = IntegerProperty.create("exposition", 0, 4);
public BlockDecorSolarPanel(long config, Block.Properties builder, final AxisAlignedBB unrotatedAABB)
{
super(config, builder, unrotatedAABB);
setDefaultState(stateContainer.getBaseState().with(EXPOSITION, 1));
}
@Override
protected void fillStateContainer(StateContainer.Builder<Block, BlockState> builder)
{ super.fillStateContainer(builder); builder.add(EXPOSITION); }
@Override
@Nullable
public BlockState getStateForPlacement(BlockItemUseContext context)
{ return super.getStateForPlacement(context); }
@Override
public boolean hasTileEntity(BlockState state)
{ return true; }
@Override
@Nullable
public TileEntity createTileEntity(BlockState state, IBlockReader world)
{ return new BlockDecorSolarPanel.BTileEntity(); }
//--------------------------------------------------------------------------------------------------------------------
// Tile entity
//--------------------------------------------------------------------------------------------------------------------
public static class BTileEntity extends TileEntity implements ITickableTileEntity
{
public static final int DEFAULT_PEAK_POWER = 45;
public static final int TICK_INTERVAL = 8;
public static final int ACCUMULATION_INTERVAL = 4;
private static final Direction transfer_directions_[] = {Direction.DOWN, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.NORTH };
private static int peak_power_per_tick_ = DEFAULT_PEAK_POWER;
private static int max_power_storage_ = 10000;
private int tick_timer_ = 0;
private int recalc_timer_ = 0;
private int accumulated_power_ = 0;
public static void on_config(int peak_power_per_tick)
{
peak_power_per_tick_ = peak_power_per_tick;
ModEngineersDecor.logger().info("Config small solar panel: Peak production:" + peak_power_per_tick_ + "/tick");
}
//------------------------------------------------------------------------------------------------------------------
public BTileEntity()
{ this(ModContent.TET_SMALL_SOLAR_PANEL); }
public BTileEntity(TileEntityType<?> te_type)
{ super(te_type); }
public void readnbt(CompoundNBT nbt, boolean update_packet)
{ accumulated_power_ = nbt.getInt("energy"); }
protected void writenbt(CompoundNBT nbt, boolean update_packet)
{ nbt.putInt("energy", accumulated_power_); }
// TileEntity ------------------------------------------------------------------------------
@Override
public void read(CompoundNBT nbt)
{ super.read(nbt); readnbt(nbt, false); }
@Override
public CompoundNBT write(CompoundNBT nbt)
{ super.write(nbt); writenbt(nbt, false); return nbt; }
@Override
public void tick()
{
if((world.isRemote) || (--tick_timer_ > 0)) return;
tick_timer_ = TICK_INTERVAL;
if(!world.canBlockSeeSky(pos)) { tick_timer_ = TICK_INTERVAL * 5; return; }
if(accumulated_power_ > 0) {
for(int i=0; (i<transfer_directions_.length) && (accumulated_power_>0); ++i) {
final Direction f = transfer_directions_[i];
TileEntity te = world.getTileEntity(pos.offset(f));
if(te==null) continue;
IEnergyStorage es = te.getCapability(CapabilityEnergy.ENERGY, f.getOpposite()).orElse(null);
if((es==null) || (!es.canReceive())) continue;
accumulated_power_ = MathHelper.clamp(accumulated_power_-es.receiveEnergy(accumulated_power_, false),0, accumulated_power_);
}
}
if(--recalc_timer_ > 0) return;
recalc_timer_ = ACCUMULATION_INTERVAL + ((int)(Math.random()+.5));
BlockState state = world.getBlockState(pos);
int theta = ((((int)(world.getCelestialAngleRadians(1f) * (180.0/Math.PI)))+90) % 360);
int e = 2;
if(theta > 340) e = 2;
else if(theta < 45) e = 0;
else if(theta < 80) e = 1;
else if(theta < 100) e = 2;
else if(theta < 135) e = 3;
else if(theta < 190) e = 4;
BlockState nstate = state.with(EXPOSITION, e);
if(nstate != state) world.setBlockState(pos, nstate, 1|2);
final double sb = world.func_226658_a_/*getLight()*/(LightType.SKY, getPos()); //world.getSunBrightness(1f);
double rf = Math.abs(1.0-(((double)Math.abs(MathHelper.clamp(theta, 0, 180)-90))/90));
rf = Math.sqrt(rf) * sb * ((TICK_INTERVAL*ACCUMULATION_INTERVAL)+2) * peak_power_per_tick_;
accumulated_power_ = Math.min(accumulated_power_+(int)rf, max_power_storage_);
}
}
}

View file

@ -0,0 +1,55 @@
/*
* @file BlockDecorStairs.java
* @author Stefan Wilhelm (wile)
* @copyright (C) 2019 Stefan Wilhelm
* @license MIT (see https://opensource.org/licenses/MIT)
*
* Stairs and roof blocks, almost entirely based on vanilla stairs.
*/
package wile.engineersdecor.blocks;
import wile.engineersdecor.detail.ModAuxiliaries;
import net.minecraft.entity.EntityType;
import net.minecraft.util.math.BlockPos;
import net.minecraft.block.*;
import net.minecraft.block.material.PushReaction;
import net.minecraft.block.BlockState;
import net.minecraft.client.util.ITooltipFlag;
import net.minecraft.item.ItemStack;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.world.IBlockReader;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import javax.annotation.Nullable;
import java.util.List;
public class BlockDecorStairs extends StairsBlock implements IDecorBlock
{
public BlockDecorStairs(long config, BlockState state, Block.Properties properties)
{ super(()->state, properties); }
public BlockDecorStairs(long config, java.util.function.Supplier<BlockState> state, Block.Properties properties)
{ super(state, properties); }
@Override
@OnlyIn(Dist.CLIENT)
public void addInformation(ItemStack stack, @Nullable IBlockReader world, List<ITextComponent> tooltip, ITooltipFlag flag)
{ ModAuxiliaries.Tooltip.addInformation(stack, world, tooltip, flag, true); }
@Override
public boolean canSpawnInBlock()
{ return false; }
@Override
@SuppressWarnings("deprecation")
public boolean canEntitySpawn(BlockState state, IBlockReader world, BlockPos pos, EntityType<?> entityType)
{ return false; }
@Override
@SuppressWarnings("deprecation")
public PushReaction getPushReaction(BlockState state)
{ return PushReaction.NORMAL; }
}

View file

@ -0,0 +1,49 @@
/*
* @file BlockDecorStraightPole.java
* @author Stefan Wilhelm (wile)
* @copyright (C) 2019 Stefan Wilhelm
* @license MIT (see https://opensource.org/licenses/MIT)
*
* Smaller (cutout) block with a defined facing.
*/
package wile.engineersdecor.blocks;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.IWaterLoggable;
import net.minecraft.fluid.Fluids;
import net.minecraft.item.BlockItemUseContext;
import net.minecraft.state.StateContainer;
import net.minecraft.world.World;
import net.minecraft.util.Direction;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import javax.annotation.Nullable;
public class BlockDecorStraightPole extends BlockDecorDirected implements IWaterLoggable
{
public BlockDecorStraightPole(long config, Block.Properties builder, final AxisAlignedBB unrotatedAABB)
{ super(config|CFG_WATERLOGGABLE, builder, unrotatedAABB); }
@Override
protected void fillStateContainer(StateContainer.Builder<Block, BlockState> builder)
{ super.fillStateContainer(builder); builder.add(WATERLOGGED); }
@Override
@Nullable
public BlockState getStateForPlacement(BlockItemUseContext context)
{
Direction facing = context.getFace();
final boolean waterlogged = context.getWorld().getFluidState(context.getPos()).getFluid()==Fluids.WATER;
BlockState state = super.getStateForPlacement(context).with(FACING, facing).with(WATERLOGGED, waterlogged);
if((config & CFG_FLIP_PLACEMENT_IF_SAME) != 0) {
World world = context.getWorld();
BlockPos pos = context.getPos();
if(world.getBlockState(pos.offset(facing.getOpposite())).getBlock() instanceof BlockDecorStraightPole) {
state = state.with(FACING, state.get(FACING).getOpposite()).with(WATERLOGGED, waterlogged);
}
}
return state;
}
}

View file

@ -0,0 +1,311 @@
/*
* @file BlockDecorTest.java
* @author Stefan Wilhelm (wile)
* @copyright (C) 2019 Stefan Wilhelm
* @license MIT (see https://opensource.org/licenses/MIT)
*
* Creative mod testing block
*/
package wile.engineersdecor.blocks;
import wile.engineersdecor.ModContent;
import wile.engineersdecor.detail.ModAuxiliaries;
import wile.engineersdecor.detail.ModAuxiliaries.IExperimentalFeature;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.world.IBlockReader;
import net.minecraft.world.World;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.tileentity.TileEntityType;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.tileentity.ITickableTileEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.fluid.Fluids;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.util.Hand;
import net.minecraft.util.Direction;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockRayTraceResult;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.shapes.ISelectionContext;
import net.minecraft.util.math.shapes.VoxelShape;
import net.minecraft.util.math.shapes.VoxelShapes;
import net.minecraftforge.common.capabilities.ICapabilityProvider;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.capability.IFluidHandler.FluidAction;
import net.minecraftforge.fluids.capability.CapabilityFluidHandler;
import net.minecraftforge.fluids.capability.IFluidHandler;
import net.minecraftforge.fluids.capability.IFluidHandlerItem;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;
public class BlockDecorTest extends BlockDecorDirected implements IExperimentalFeature
{
public BlockDecorTest(long config, Block.Properties builder, final AxisAlignedBB unrotatedAABB)
{ super(config, builder, unrotatedAABB); }
@Override
public VoxelShape getCollisionShape(BlockState state, IBlockReader world, BlockPos pos, ISelectionContext selectionContext)
{ return VoxelShapes.fullCube(); }
@Override
public boolean hasTileEntity(BlockState state)
{ return true; }
@Override
@Nullable
public TileEntity createTileEntity(BlockState state, IBlockReader world)
{ return new BTileEntity(); }
@Override
public boolean canConnectRedstone(BlockState state, IBlockReader world, BlockPos pos, @Nullable Direction side)
{ return true; }
@Override
public boolean hasDynamicDropList()
{ return true; }
@Override
public List<ItemStack> dropList(BlockState state, World world, BlockPos pos, boolean explosion)
{
ArrayList<ItemStack> list = new ArrayList<ItemStack>();
list.add(new ItemStack(this, 1));
return list;
}
@Override
@SuppressWarnings("deprecation")
public boolean onBlockActivated(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockRayTraceResult hit)
{
TileEntity te = world.getTileEntity(pos);
if(!(te instanceof BTileEntity)) return false;
((BTileEntity)te).activated(player, hand, hit);
return true;
}
//--------------------------------------------------------------------------------------------------------------------
// Tile entity
//--------------------------------------------------------------------------------------------------------------------
public static class BTileEntity extends TileEntity implements ITickableTileEntity, ICapabilityProvider //, IItemHandler, IEnergyStorage
{
private int tick_interval_ = 10;
private int passive_tank_capacity_ = 32000;
private FluidStack passive_tank_ = FluidStack.EMPTY;
private FluidStack passive_drain_fluidstack_ = new FluidStack(Fluids.WATER, 1000);
private int passive_drain_max_flowrate_ = 1000;
private int passive_fill_max_flowrate_ = 1000;
private int passive_num_drained_general_mb_ = 0;
private int passive_num_drained_specific_mb_ = 0;
private int passive_num_filled_specific_mb_ = 0;
private int passive_num_fh_interactions_ = 0;
private FluidStack active_fill_fluidstack_ = FluidStack.EMPTY;
private int active_num_filled_ = 0;
private int tick_timer_ = 0;
// ------------------------------------------------------------------------------------------
public BTileEntity()
{ this(ModContent.TET_TEST_BLOCK); }
public BTileEntity(TileEntityType<?> te_type)
{ super(te_type); }
// ------------------------------------------------------------------------------------------
private Direction block_facing()
{
BlockState st = getWorld().getBlockState(getPos());
return (st.getBlock() instanceof BlockDecorTest) ? st.get(FACING) : Direction.NORTH;
}
private String dump_fluid_stack(FluidStack fs)
{
String s = "";
if(fs.getFluid().getRegistryName().getNamespace() != "minecraft") s += fs.getFluid().getRegistryName().getNamespace()+":";
s += fs.getFluid().getRegistryName().getPath();
s += " x" + fs.getAmount();
return "[" + s + "]";
}
public void activated(PlayerEntity player, Hand hand, BlockRayTraceResult hit)
{
if(world.isRemote()) return;
final ItemStack held_stack = player.getHeldItem(hand);
// Empty hand -> statistics
{
if(held_stack.isEmpty()) {
String message = "";
if(passive_num_filled_specific_mb_>0 || passive_num_drained_specific_mb_>0 || passive_num_drained_general_mb_>0) {
message += "Fluid handler: filled:" + passive_num_filled_specific_mb_ + ", drained:" + (passive_num_drained_specific_mb_+ passive_num_drained_general_mb_) + ", interactions:" + passive_num_fh_interactions_ + "\n";
}
if(active_num_filled_>0) {
message += "Fluid insertion:" + active_num_filled_ + "mb, (current:" + dump_fluid_stack(active_fill_fluidstack_) + ")\n";
}
if(message.isEmpty()) {
message = "No fluid, energy, or item interactions done yet.";
}
ModAuxiliaries.playerChatMessage(player, message);
return;
}
}
// Fluid container -> set fluid to insert, increase/decrease amount.
{
final IFluidHandlerItem fhi = held_stack.getCapability(CapabilityFluidHandler.FLUID_HANDLER_ITEM_CAPABILITY).orElse(null);
if((fhi != null)) {
int ntanks = fhi.getTanks();
if(ntanks == 0) return;
int capacity = fhi.getTankCapacity(0);
FluidStack fs = fhi.drain(capacity, FluidAction.SIMULATE);
if(!fs.isEmpty()) {
if(active_fill_fluidstack_.isEmpty()) {
active_fill_fluidstack_ = fs.copy();
ModAuxiliaries.playerChatMessage(player, "Fluid insertion fluid set: " + dump_fluid_stack(active_fill_fluidstack_));
} else if(fs.isFluidEqual(active_fill_fluidstack_)) {
active_fill_fluidstack_.grow(fs.getAmount());
ModAuxiliaries.playerChatMessage(player, "Fluid insertion flowrate increased: " + dump_fluid_stack(active_fill_fluidstack_));
} else {
int amount = active_fill_fluidstack_.getAmount();
active_fill_fluidstack_ = fs.copy();
active_fill_fluidstack_.setAmount(amount);
ModAuxiliaries.playerChatMessage(player, "Fluid insertion fluid changed: " + dump_fluid_stack(active_fill_fluidstack_));
}
} else {
if(!active_fill_fluidstack_.isEmpty()) {
active_fill_fluidstack_.shrink(1000);
if(active_fill_fluidstack_.isEmpty()) active_fill_fluidstack_ = FluidStack.EMPTY;
ModAuxiliaries.playerChatMessage(player, "Fluid insertion flowrate decreased: " + dump_fluid_stack(active_fill_fluidstack_));
} else {
ModAuxiliaries.playerChatMessage(player, "Fluid insertion disabled.");
}
}
passive_drain_fluidstack_ = active_fill_fluidstack_.copy(); // currently no difference
return;
}
}
}
// TileEntity ------------------------------------------------------------------------------
@Override
public void read(CompoundNBT nbt)
{
super.read(nbt);
if(nbt.contains("passive_tank")) passive_tank_ = FluidStack.loadFluidStackFromNBT(nbt.getCompound("passive_tank"));
if(nbt.contains("passive_drain")) passive_drain_fluidstack_ = FluidStack.loadFluidStackFromNBT(nbt.getCompound("passive_drain"));
if(nbt.contains("active")) active_fill_fluidstack_ = FluidStack.loadFluidStackFromNBT(nbt.getCompound("active"));
}
@Override
public CompoundNBT write(CompoundNBT nbt)
{
super.write(nbt);
if(!passive_tank_.isEmpty()) nbt.put("passive_tank", passive_tank_.writeToNBT(new CompoundNBT()));
if(!passive_drain_fluidstack_.isEmpty()) nbt.put("passive_drain", passive_drain_fluidstack_.writeToNBT(new CompoundNBT()));
if(!active_fill_fluidstack_.isEmpty()) nbt.put("active", active_fill_fluidstack_.writeToNBT(new CompoundNBT()));
return nbt;
}
// ICapabilityProvider --------------------------------------------------------------------
private LazyOptional<IFluidHandler> fluid_handler_ = LazyOptional.of(() -> (IFluidHandler)new MainFluidHandler(this));
@Override
public <T> LazyOptional<T> getCapability(net.minecraftforge.common.capabilities.Capability<T> capability, @Nullable Direction facing)
{
if(!this.removed && (facing != null)) {
if(capability == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY) {
if(facing != block_facing()) return fluid_handler_.cast();
}
}
return super.getCapability(capability, facing);
}
// IFluidHandler ---------------------------------------------------------------------------
private static class MainFluidHandler implements IFluidHandler
{
private BTileEntity te;
public MainFluidHandler(BTileEntity te)
{ this.te = te; }
@Override public int getTanks()
{ return 1; }
@Override public FluidStack getFluidInTank(int tank)
{ return FluidStack.EMPTY; }
@Override public int getTankCapacity(int tank)
{ return te.passive_tank_capacity_; }
@Override public FluidStack drain(FluidStack resource, FluidAction action)
{
++te.passive_num_fh_interactions_;
if(resource.isEmpty()) return FluidStack.EMPTY;
if(!resource.isFluidEqual(te.passive_drain_fluidstack_)) return FluidStack.EMPTY;
FluidStack st = resource.copy();
st.setAmount(MathHelper.clamp(st.getAmount(), 0, te.passive_drain_max_flowrate_));
if(st.isEmpty()) return FluidStack.EMPTY;
if(action==FluidAction.EXECUTE) te.passive_num_drained_specific_mb_ += st.getAmount();
return st;
}
@Override public FluidStack drain(int maxDrain, FluidAction action)
{
++te.passive_num_fh_interactions_;
maxDrain = MathHelper.clamp(maxDrain, 0, te.passive_drain_max_flowrate_);
if((te.passive_drain_fluidstack_.isEmpty()) || (maxDrain<=0)) return FluidStack.EMPTY;
if(action==FluidAction.EXECUTE) te.passive_num_drained_general_mb_ += maxDrain;
FluidStack st = te.passive_drain_fluidstack_.copy();
st.setAmount(maxDrain);
return st;
}
@Override public boolean isFluidValid(int tank, @Nonnull FluidStack stack)
{ return true; }
@Override public int fill(FluidStack resource, FluidAction action)
{
++te.passive_num_fh_interactions_;
int amount = MathHelper.clamp(resource.getAmount(), 0, te.passive_fill_max_flowrate_);
if(action == FluidAction.EXECUTE) {
te.passive_num_filled_specific_mb_ += amount;
if(te.passive_tank_.isFluidEqual(resource)) {
int level = (int)MathHelper.clamp((long)te.passive_tank_.getAmount() + (long)amount, (long)0, (long)Integer.MAX_VALUE);
te.passive_tank_.setAmount(level);
}
}
return amount;
}
}
// ITickableTileEntity ----------------------------------------------------------------------
private void fluid_insertion()
{
if(active_fill_fluidstack_.isEmpty()) return;
final TileEntity te = world.getTileEntity(pos.offset(block_facing()));
if(te == null) return;
final IFluidHandler fh = te.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, block_facing().getOpposite()).orElse(null);
if(fh == null) return;
int filled = fh.fill(active_fill_fluidstack_.copy(), FluidAction.EXECUTE);
active_num_filled_ += filled;
}
@Override
public void tick()
{
if(world.isRemote) return;
if(--tick_timer_ > 0) return;
tick_interval_ = MathHelper.clamp(tick_interval_ ,1 , 200);
tick_timer_ = tick_interval_;
fluid_insertion();
}
}
}

View file

@ -0,0 +1,207 @@
/*
* @file BlockDecorTreeCutter.java
* @author Stefan Wilhelm (wile)
* @copyright (C) 2019 Stefan Wilhelm
* @license MIT (see https://opensource.org/licenses/MIT)
*
* Small Tree Cutter
*/
package wile.engineersdecor.blocks;
import net.minecraft.item.BlockItemUseContext;
import wile.engineersdecor.ModContent;
import wile.engineersdecor.ModEngineersDecor;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.particles.ParticleTypes;
import net.minecraft.state.BooleanProperty;
import net.minecraft.state.StateContainer;
import net.minecraft.tileentity.ITickableTileEntity;
import net.minecraft.tileentity.TileEntityType;
import net.minecraft.world.IBlockReader;
import net.minecraft.world.World;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.*;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.energy.CapabilityEnergy;
import net.minecraftforge.energy.IEnergyStorage;
import wile.engineersdecor.detail.TreeCutting;
import javax.annotation.Nullable;
import java.util.Random;
public class BlockDecorTreeCutter extends BlockDecorDirectedHorizontal
{
public static final BooleanProperty ACTIVE = BooleanProperty.create("active");
public BlockDecorTreeCutter(long config, Block.Properties builder, final AxisAlignedBB unrotatedAABB)
{ super(config, builder, unrotatedAABB); }
@Override
protected void fillStateContainer(StateContainer.Builder<Block, BlockState> builder)
{ super.fillStateContainer(builder); builder.add(ACTIVE); }
@Override
@Nullable
public BlockState getStateForPlacement(BlockItemUseContext context)
{ return super.getStateForPlacement(context).with(ACTIVE, false); }
@Override
public boolean hasTileEntity(BlockState state)
{ return true; }
@Override
@Nullable
public TileEntity createTileEntity(BlockState state, IBlockReader world)
{ return new BTileEntity(); }
@OnlyIn(Dist.CLIENT)
public void animateTick(BlockState state, World world, BlockPos pos, Random rnd)
{
if((state.getBlock()!=this) || (!state.get(ACTIVE))) return;
final double rv = rnd.nextDouble();
if(rv > 0.8) return;
final double x=0.5+pos.getX(), y=0.5+pos.getY(), z=0.5+pos.getZ();
final double xc=0.52, xr=rnd.nextDouble()*0.4-0.2, yr=(y-0.3+rnd.nextDouble()*0.2);
switch(state.get(HORIZONTAL_FACING)) {
case WEST: world.addParticle(ParticleTypes.SMOKE, x-xc, yr, z+xr, 0.0, 0.0, 0.0); break;
case EAST: world.addParticle(ParticleTypes.SMOKE, x+xc, yr, z+xr, 0.0, 0.0, 0.0); break;
case NORTH: world.addParticle(ParticleTypes.SMOKE, x+xr, yr, z-xc, 0.0, 0.0, 0.0); break;
default: world.addParticle(ParticleTypes.SMOKE, x+xr, yr, z+xc, 0.0, 0.0, 0.0); break;
}
}
//--------------------------------------------------------------------------------------------------------------------
// Tile entity
//--------------------------------------------------------------------------------------------------------------------
public static class BTileEntity extends TileEntity implements ITickableTileEntity, IEnergyStorage
{
public static final int IDLE_TICK_INTERVAL = 40;
public static final int TICK_INTERVAL = 5;
public static final int BOOST_FACTOR = 6;
public static final int DEFAULT_BOOST_ENERGY = 64;
public static final int DEFAULT_CUTTING_TIME_NEEDED = 60; // 60 secs, so that people don't come to the bright idea to carry one with them.
private static int boost_energy_consumption = DEFAULT_BOOST_ENERGY;
private static int cutting_time_needed = 20 * DEFAULT_CUTTING_TIME_NEEDED;
private static boolean requires_power = false;
private int tick_timer_;
private int active_timer_;
private int proc_time_elapsed_;
private int boost_energy_;
public static void on_config(int boost_energy_per_tick, int cutting_time_seconds, boolean power_required)
{
boost_energy_consumption = TICK_INTERVAL * MathHelper.clamp(boost_energy_per_tick, 16, 512);
cutting_time_needed = 20 * MathHelper.clamp(cutting_time_seconds, 10, 240);
requires_power = power_required;
ModEngineersDecor.logger().info("Config tree cutter: Boost energy consumption:" + boost_energy_consumption + "rf/t" + (requires_power?" (power required for operation) ":"") + ", cutting time " + cutting_time_needed + "t." );
}
public BTileEntity()
{ super(ModContent.TET_SMALL_TREE_CUTTER); }
public BTileEntity(TileEntityType<?> te_type)
{ super(te_type); }
// IEnergyStorage ----------------------------------------------------------------------------
protected LazyOptional<IEnergyStorage> energy_handler_ = LazyOptional.of(() -> (IEnergyStorage)this);
@Override
public boolean canExtract()
{ return false; }
@Override
public boolean canReceive()
{ return true; }
@Override
public int getMaxEnergyStored()
{ return boost_energy_consumption; }
@Override
public int getEnergyStored()
{ return boost_energy_; }
@Override
public int extractEnergy(int maxExtract, boolean simulate)
{ return 0; }
@Override
public int receiveEnergy(int maxReceive, boolean simulate)
{ // only speedup support, no buffering, not in nbt -> no markdirty
if((boost_energy_ >= boost_energy_consumption) || (maxReceive < boost_energy_consumption)) return 0;
if(!simulate) boost_energy_ = boost_energy_consumption;
return boost_energy_consumption;
}
// Capability export ----------------------------------------------------------------------------
@Override
public <T> LazyOptional<T> getCapability(net.minecraftforge.common.capabilities.Capability<T> capability, @Nullable Direction facing)
{
if(!this.removed && (facing != null)) {
if(capability== CapabilityEnergy.ENERGY) {
return energy_handler_.cast();
}
}
return super.getCapability(capability, facing);
}
// ITickable ------------------------------------------------------------------------------------
@Override
public void tick()
{
if(--tick_timer_ > 0) return;
if(world.isRemote) {
if(!world.getBlockState(pos).get(ACTIVE)) {
tick_timer_ = TICK_INTERVAL;
} else {
tick_timer_ = 1;
world.playSound(pos.getX(), pos.getY(), pos.getZ(), SoundEvents.BLOCK_WOOD_HIT, SoundCategory.BLOCKS, 0.1f, 1.0f, false);
}
} else {
tick_timer_ = TICK_INTERVAL;
final BlockState device_state = world.getBlockState(pos);
final BlockPos tree_pos = pos.offset(device_state.get(HORIZONTAL_FACING));
final BlockState tree_state = world.getBlockState(tree_pos);
if(!TreeCutting.canChop(tree_state) || (world.isBlockPowered(pos))) {
if(device_state.get(ACTIVE)) world.setBlockState(pos, device_state.with(ACTIVE, false), 1|2);
proc_time_elapsed_ = 0;
active_timer_ = 0;
tick_timer_ = IDLE_TICK_INTERVAL;
return;
}
proc_time_elapsed_ += TICK_INTERVAL;
if(boost_energy_ >= boost_energy_consumption) {
boost_energy_ = 0;
proc_time_elapsed_ += TICK_INTERVAL*BOOST_FACTOR;
active_timer_ = 2;
} else if(!requires_power) {
active_timer_ = 1024;
} else if(active_timer_ > 0) {
--active_timer_;
}
boolean active = (active_timer_ > 0);
if(proc_time_elapsed_ >= cutting_time_needed) {
proc_time_elapsed_ = 0;
TreeCutting.chopTree(world, tree_state, tree_pos, 512, false);
world.playSound(null, pos.getX(), pos.getY(), pos.getZ(), SoundEvents.BLOCK_WOOD_BREAK, SoundCategory.BLOCKS, 1.0f, 1.0f);
active = false;
}
if(device_state.get(ACTIVE) != active) {
world.setBlockState(pos, device_state.with(ACTIVE, active), 1|2);
}
}
}
}
}

View file

@ -0,0 +1,119 @@
/*
* @file BlockDecorWall.java
* @author Stefan Wilhelm (wile)
* @copyright (C) 2019 Stefan Wilhelm
* @license MIT (see https://opensource.org/licenses/MIT)
*
* Wall blocks.
*/
package wile.engineersdecor.blocks;
import net.minecraft.item.BlockItemUseContext;
import net.minecraft.world.*;
import wile.engineersdecor.detail.ModAuxiliaries;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.fluid.IFluidState;
import net.minecraft.entity.EntityType;
import net.minecraft.util.math.shapes.ISelectionContext;
import net.minecraft.state.StateContainer;
import net.minecraft.util.math.MathHelper;
import net.minecraft.block.*;
import net.minecraft.block.material.PushReaction;
import net.minecraft.block.BlockState;
import net.minecraft.client.util.ITooltipFlag;
import net.minecraft.fluid.Fluids;
import net.minecraft.item.ItemStack;
import net.minecraft.state.IntegerProperty;
import net.minecraft.util.Direction;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.shapes.VoxelShape;
import net.minecraft.util.text.ITextComponent;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import javax.annotation.Nullable;
import java.util.List;
public class BlockDecorWall extends WallBlock implements IDecorBlock
{
private final VoxelShape[] shape_voxels;
private final VoxelShape[] collision_shape_voxels;
public static final IntegerProperty TEXTURE_VARIANT = IntegerProperty.create("tvariant", 0, 7);
public BlockDecorWall(long config, Block.Properties builder)
{
super(builder);
this.shape_voxels = buildWallShapes(4.0F, 4.0F, 16.0F, 0.0F, 16.0F);
this.collision_shape_voxels = buildWallShapes(4.0F, 4.0F, 24.0F, 0.0F, 24.0F);
}
@Override
@OnlyIn(Dist.CLIENT)
public void addInformation(ItemStack stack, @Nullable IBlockReader world, List<ITextComponent> tooltip, ITooltipFlag flag)
{ ModAuxiliaries.Tooltip.addInformation(stack, world, tooltip, flag, true); }
protected VoxelShape[] buildWallShapes(float pole_width_x, float pole_width_z, float pole_height, float side_min_y, float side_max_y)
{ return super.makeShapes(pole_width_x, pole_width_z, pole_height, side_min_y, side_max_y); }
@Override
public VoxelShape getShape(BlockState state, IBlockReader world, BlockPos pos, ISelectionContext selectionContext)
{ return shape_voxels[this.getIndex(state)]; }
@Override
public VoxelShape getCollisionShape(BlockState state, IBlockReader world, BlockPos pos, ISelectionContext selectionContext)
{ return collision_shape_voxels[this.getIndex(state)]; }
@Override
protected void fillStateContainer(StateContainer.Builder<Block, BlockState> builder)
{ super.fillStateContainer(builder); builder.add(TEXTURE_VARIANT); }
private boolean attachesTo(BlockState facingState, IWorldReader world, BlockPos facingPos, Direction side)
{
final Block block = facingState.getBlock();
if((block instanceof FenceGateBlock) || (block instanceof WallBlock)) return true;
final BlockState oppositeState = world.getBlockState(facingPos.offset(side, 2));
if(!(oppositeState.getBlock() instanceof BlockDecorWall)) return false;
return facingState.isNormalCube(world, facingPos) && hasSolidSide(facingState, world, facingPos, side);
}
public BlockState getStateForPlacement(BlockItemUseContext context)
{
IWorldReader world = context.getWorld();
BlockPos pos = context.getPos();
IFluidState fs = context.getWorld().getFluidState(context.getPos());
boolean n = attachesTo(world.getBlockState(pos.north()), world, pos.north(), Direction.SOUTH);
boolean e = attachesTo(world.getBlockState(pos.east()), world, pos.east(), Direction.WEST);
boolean s = attachesTo(world.getBlockState(pos.south()), world, pos.south(), Direction.NORTH);
boolean w = attachesTo(world.getBlockState(pos.west()), world, pos.west(), Direction.EAST);
boolean not_straight = (!n || !s || e || w) && (n || s || !e || !w);
return getDefaultState().with(UP, not_straight).with(NORTH, n).with(EAST, e).with(SOUTH, s).with(WEST, w).with(WATERLOGGED, fs.getFluid() == Fluids.WATER);
}
@Override
public BlockState updatePostPlacement(BlockState state, Direction side, BlockState facingState, IWorld world, BlockPos currentPos, BlockPos facingPos)
{
if(state.get(WATERLOGGED)) world.getPendingFluidTicks().scheduleTick(currentPos, Fluids.WATER, Fluids.WATER.getTickRate(world));
if(side == Direction.DOWN) return super.updatePostPlacement(state, side, facingState, world, currentPos, facingPos);
boolean n = (side==Direction.NORTH) ? this.attachesTo(facingState, world, facingPos, side) : state.get(NORTH);
boolean e = (side==Direction.EAST) ? this.attachesTo(facingState, world, facingPos, side) : state.get(EAST);
boolean s = (side==Direction.SOUTH) ? this.attachesTo(facingState, world, facingPos, side) : state.get(SOUTH);
boolean w = (side==Direction.WEST) ? this.attachesTo(facingState, world, facingPos, side) : state.get(WEST);
boolean not_straight = (!n || !s || e || w) && (n || s || !e || !w);
return state.with(UP, not_straight).with(NORTH, n).with(EAST, e).with(SOUTH, s).with(WEST, w).with(TEXTURE_VARIANT, ((int)MathHelper.getPositionRandom(currentPos)) & 0x7);
}
@Override
@SuppressWarnings("deprecation")
public boolean canEntitySpawn(BlockState state, IBlockReader world, BlockPos pos, EntityType<?> entityType)
{ return false; }
@Override
public boolean canSpawnInBlock()
{ return false; }
@Override
@SuppressWarnings("deprecation")
public PushReaction getPushReaction(BlockState state)
{ return PushReaction.NORMAL; }
}

View file

@ -0,0 +1,723 @@
/*
* @file BlockDecorWasteIncinerator.java
* @author Stefan Wilhelm (wile)
* @copyright (C) 2019 Stefan Wilhelm
* @license MIT (see https://opensource.org/licenses/MIT)
*
* Trash/void/nullifier device with internal fifos.
*/
package wile.engineersdecor.blocks;
import wile.engineersdecor.ModContent;
import wile.engineersdecor.ModEngineersDecor;
import net.minecraft.inventory.container.INamedContainerProvider;
import net.minecraft.tileentity.ITickableTileEntity;
import net.minecraft.entity.player.ServerPlayerEntity;
import net.minecraft.inventory.container.Container;
import net.minecraft.inventory.container.Slot;
import net.minecraft.particles.ParticleTypes;
import net.minecraft.state.BooleanProperty;
import net.minecraft.state.StateContainer;
import net.minecraft.tileentity.TileEntityType;
import net.minecraft.util.math.BlockRayTraceResult;
import net.minecraft.util.text.StringTextComponent;
import net.minecraft.world.IBlockReader;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.world.World;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.util.SoundEvents;
import net.minecraft.item.*;
import net.minecraft.inventory.*;
import net.minecraft.client.gui.screen.inventory.ContainerScreen;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.*;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.common.util.FakePlayer;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.fml.network.NetworkHooks;
import net.minecraftforge.energy.CapabilityEnergy;
import net.minecraftforge.energy.IEnergyStorage;
import net.minecraftforge.items.CapabilityItemHandler;
import net.minecraftforge.items.IItemHandler;
import net.minecraftforge.items.ItemHandlerHelper;
import com.mojang.blaze3d.systems.RenderSystem;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class BlockDecorWasteIncinerator extends BlockDecor
{
public static final BooleanProperty LIT = BlockDecorFurnace.LIT;
public BlockDecorWasteIncinerator(long config, Block.Properties builder, final AxisAlignedBB unrotatedAABB)
{ super(config, builder, unrotatedAABB); }
@Override
public RenderTypeHint getRenderTypeHint()
{ return RenderTypeHint.SOLID; }
@Override
protected void fillStateContainer(StateContainer.Builder<Block, BlockState> builder)
{ super.fillStateContainer(builder); builder.add(LIT); }
@Override
@Nullable
public BlockState getStateForPlacement(BlockItemUseContext context)
{ return super.getStateForPlacement(context).with(LIT, false); }
@Override
@SuppressWarnings("deprecation")
public boolean hasComparatorInputOverride(BlockState state)
{ return true; }
@Override
@SuppressWarnings("deprecation")
public int getComparatorInputOverride(BlockState blockState, World world, BlockPos pos)
{ return Container.calcRedstone(world.getTileEntity(pos)); }
@Override
public boolean hasTileEntity(BlockState state)
{ return true; }
@Override
@Nullable
public TileEntity createTileEntity(BlockState state, IBlockReader world)
{ return new BlockDecorWasteIncinerator.BTileEntity(); }
@Override
public void onBlockPlacedBy(World world, BlockPos pos, BlockState state, LivingEntity placer, ItemStack stack)
{
if(world.isRemote) return;
if((!stack.hasTag()) || (!stack.getTag().contains("tedata"))) return;
CompoundNBT te_nbt = stack.getTag().getCompound("tedata");
if(te_nbt.isEmpty()) return;
final TileEntity te = world.getTileEntity(pos);
if(!(te instanceof BlockDecorWasteIncinerator.BTileEntity)) return;
((BlockDecorWasteIncinerator.BTileEntity)te).readnbt(te_nbt);
((BlockDecorWasteIncinerator.BTileEntity)te).markDirty();
}
@Override
public boolean hasDynamicDropList()
{ return true; }
@Override
public List<ItemStack> dropList(BlockState state, World world, BlockPos pos, boolean explosion)
{
final List<ItemStack> stacks = new ArrayList<ItemStack>();
if(world.isRemote) return stacks;
final TileEntity te = world.getTileEntity(pos);
if(!(te instanceof BTileEntity)) return stacks;
if(!explosion) {
ItemStack stack = new ItemStack(this, 1);
CompoundNBT te_nbt = ((BTileEntity) te).reset_getnbt();
if(!te_nbt.isEmpty()) {
CompoundNBT nbt = new CompoundNBT();
nbt.put("tedata", te_nbt);
stack.setTag(nbt);
}
stacks.add(stack);
} else {
for(ItemStack stack: ((BTileEntity)te).stacks_) stacks.add(stack);
((BTileEntity)te).reset_getnbt();
}
return stacks;
}
@Override
@SuppressWarnings("deprecation")
public boolean onBlockActivated(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockRayTraceResult rayTraceResult)
{
if(world.isRemote) return true;
final TileEntity te = world.getTileEntity(pos);
if(!(te instanceof BTileEntity)) return true;
if((!(player instanceof ServerPlayerEntity) && (!(player instanceof FakePlayer)))) return true;
NetworkHooks.openGui((ServerPlayerEntity)player,(INamedContainerProvider)te);
return true;
}
@Override
@OnlyIn(Dist.CLIENT)
public void animateTick(BlockState state, World world, BlockPos pos, Random rnd)
{
if((state.getBlock()!=this) || (!state.get(LIT))) return;
final double rv = rnd.nextDouble();
if(rv > 0.5) return;
final double x=0.5+pos.getX(), y=0.5+pos.getY(), z=0.5+pos.getZ();
final double xr=rnd.nextDouble()*0.4-0.2, yr=rnd.nextDouble()*0.5, zr=rnd.nextDouble()*0.4-0.2;
world.addParticle(ParticleTypes.SMOKE, x+xr, y+yr, z+zr, 0.0, 0.0, 0.0);
}
//--------------------------------------------------------------------------------------------------------------------
// Tile entity
//--------------------------------------------------------------------------------------------------------------------
public static class BTileEntity extends TileEntity implements ITickableTileEntity, INameable, IInventory, INamedContainerProvider, ISidedInventory, IEnergyStorage
{
public static final int NUM_OF_FIELDS = 1;
public static final int TICK_INTERVAL = 20;
public static final int ENERGIZED_TICK_INTERVAL = 5;
public static final int MAX_ENERGY_BUFFER = 16000;
public static final int MAX_ENERGY_TRANSFER = 256;
public static final int DEFAULT_ENERGY_CONSUMPTION = 16;
public static final int NUM_OF_SLOTS = 16;
public static final int INPUT_SLOT_NO = 0;
public static final int BURN_SLOT_NO = NUM_OF_SLOTS-1;
// Config ----------------------------------------------------------------------------------
private static int energy_consumption = DEFAULT_ENERGY_CONSUMPTION;
public static void on_config(int speed_percent, int fuel_efficiency_percent, int boost_energy_per_tick)
{
energy_consumption = MathHelper.clamp(boost_energy_per_tick, 16, 512);
ModEngineersDecor.logger().info("Config waste incinerator boost energy consumption:" + energy_consumption);
}
// BTileEntity -----------------------------------------------------------------------------
private int tick_timer_;
private int check_timer_;
private int energy_stored_;
protected NonNullList<ItemStack> stacks_ = NonNullList.<ItemStack>withSize(NUM_OF_SLOTS, ItemStack.EMPTY);
public BTileEntity()
{ this(ModContent.TET_WASTE_INCINERATOR); }
public BTileEntity(TileEntityType<?> te_type)
{ super(te_type); reset(); }
public CompoundNBT reset_getnbt()
{
CompoundNBT nbt = new CompoundNBT();
writenbt(nbt);
reset();
return nbt;
}
protected void reset()
{
stacks_ = NonNullList.<ItemStack>withSize(NUM_OF_SLOTS, ItemStack.EMPTY);
check_timer_ = 0;
tick_timer_ = 0;
}
public void readnbt(CompoundNBT compound)
{
NonNullList<ItemStack> stacks = NonNullList.<ItemStack>withSize(NUM_OF_SLOTS, ItemStack.EMPTY);
ItemStackHelper.loadAllItems(compound, stacks);
while(stacks.size() < NUM_OF_SLOTS) stacks.add(ItemStack.EMPTY);
stacks_ = stacks;
energy_stored_ = compound.getInt("Energy");
}
protected void writenbt(CompoundNBT compound)
{
compound.putInt("Energy", MathHelper.clamp(energy_stored_,0 , MAX_ENERGY_BUFFER));
ItemStackHelper.saveAllItems(compound, stacks_);
}
// TileEntity ------------------------------------------------------------------------------
@Override
public void read(CompoundNBT compound)
{ super.read(compound); readnbt(compound); }
@Override
public CompoundNBT write(CompoundNBT compound)
{ super.write(compound); writenbt(compound); return compound; }
// INameable ---------------------------------------------------------------------------
@Override
public ITextComponent getName()
{ final Block block=getBlockState().getBlock(); return new StringTextComponent((block!=null) ? block.getTranslationKey() : "Small Waste Incinerator"); }
@Override
public boolean hasCustomName()
{ return false; }
@Override
public ITextComponent getCustomName()
{ return getName(); }
// IContainerProvider ----------------------------------------------------------------------
@Override
public ITextComponent getDisplayName()
{ return INameable.super.getDisplayName(); }
@Override
public Container createMenu(int id, PlayerInventory inventory, PlayerEntity player )
{ return new BlockDecorWasteIncinerator.BContainer(id, inventory, this, IWorldPosCallable.of(world, pos), fields); }
// IInventory ------------------------------------------------------------------------------
@Override
public int getSizeInventory()
{ return stacks_.size(); }
@Override
public boolean isEmpty()
{ for(ItemStack stack: stacks_) { if(!stack.isEmpty()) return false; } return true; }
@Override
public ItemStack getStackInSlot(int index)
{ return ((index >= 0) && (index < getSizeInventory())) ? stacks_.get(index) : ItemStack.EMPTY; }
@Override
public ItemStack decrStackSize(int index, int count)
{ return ItemStackHelper.getAndSplit(stacks_, index, count); }
@Override
public ItemStack removeStackFromSlot(int index)
{ return ItemStackHelper.getAndRemove(stacks_, index); }
@Override
public void setInventorySlotContents(int index, ItemStack stack)
{
if(stack.getCount() > getInventoryStackLimit()) stack.setCount(getInventoryStackLimit());
stacks_.set(index, stack);
markDirty();
}
@Override
public int getInventoryStackLimit()
{ return 64; }
@Override
public void markDirty()
{ super.markDirty(); }
@Override
public boolean isUsableByPlayer(PlayerEntity player)
{ return getPos().distanceSq(player.getPosition()) < 36; }
@Override
public void openInventory(PlayerEntity player)
{}
@Override
public void closeInventory(PlayerEntity player)
{ markDirty(); }
@Override
public boolean isItemValidForSlot(int index, ItemStack stack)
{ return (index==0); }
@Override
public void clear()
{ stacks_.clear(); }
// Fields -----------------------------------------------------------------------------------------------
protected final IIntArray fields = new IntArray(BTileEntity.NUM_OF_FIELDS)
{
@Override
public int get(int id)
{
switch(id) {
default: return 0;
}
}
@Override
public void set(int id, int value)
{
switch(id) {
default: break;
}
}
};
// ISidedInventory ----------------------------------------------------------------------------
private static final int[] SIDED_INV_SLOTS = new int[] { INPUT_SLOT_NO };
@Override
public int[] getSlotsForFace(Direction side)
{ return SIDED_INV_SLOTS; }
@Override
public boolean canInsertItem(int index, ItemStack itemStackIn, Direction direction)
{ return isItemValidForSlot(index, itemStackIn); }
@Override
public boolean canExtractItem(int index, ItemStack stack, Direction direction)
{ return false; }
// IEnergyStorage ----------------------------------------------------------------------------
@Override
public boolean canExtract()
{ return false; }
@Override
public boolean canReceive()
{ return true; }
@Override
public int getMaxEnergyStored()
{ return MAX_ENERGY_BUFFER; }
@Override
public int getEnergyStored()
{ return energy_stored_; }
@Override
public int extractEnergy(int maxExtract, boolean simulate)
{ return 0; }
@Override
public int receiveEnergy(int maxReceive, boolean simulate)
{
if(energy_stored_ >= MAX_ENERGY_BUFFER) return 0;
int n = Math.min(maxReceive, (MAX_ENERGY_BUFFER - energy_stored_));
if(n > MAX_ENERGY_TRANSFER) n = MAX_ENERGY_TRANSFER;
if(!simulate) {energy_stored_ += n; markDirty(); }
return n;
}
// IItemHandler --------------------------------------------------------------------------------
protected static class BItemHandler implements IItemHandler
{
private BTileEntity te;
BItemHandler(BTileEntity te)
{ this.te = te; }
@Override
public int getSlots()
{ return 1; }
@Override
public int getSlotLimit(int index)
{ return te.getInventoryStackLimit(); }
@Override
public boolean isItemValid(int slot, @Nonnull ItemStack stack)
{ return true; }
@Override
@Nonnull
public ItemStack insertItem(int index, @Nonnull ItemStack stack, boolean simulate)
{
if(stack.isEmpty()) return ItemStack.EMPTY;
if(index != 0) return ItemStack.EMPTY;
int slotno = 0;
ItemStack slotstack = getStackInSlot(slotno);
if(!slotstack.isEmpty())
{
if(slotstack.getCount() >= Math.min(slotstack.getMaxStackSize(), getSlotLimit(index))) return stack;
if(!ItemHandlerHelper.canItemStacksStack(stack, slotstack)) return stack;
if(!te.canInsertItem(slotno, stack, Direction.UP) || (!te.isItemValidForSlot(slotno, stack))) return stack;
int n = Math.min(stack.getMaxStackSize(), getSlotLimit(index)) - slotstack.getCount();
if(stack.getCount() <= n) {
if(!simulate) {
ItemStack copy = stack.copy();
copy.grow(slotstack.getCount());
te.setInventorySlotContents(slotno, copy);
}
return ItemStack.EMPTY;
} else {
stack = stack.copy();
if(!simulate) {
ItemStack copy = stack.split(n);
copy.grow(slotstack.getCount());
te.setInventorySlotContents(slotno, copy);
return stack;
} else {
stack.shrink(n);
return stack;
}
}
} else {
if(!te.canInsertItem(slotno, stack, Direction.UP) || (!te.isItemValidForSlot(slotno, stack))) return stack;
int n = Math.min(stack.getMaxStackSize(), getSlotLimit(index));
if(n < stack.getCount()) {
stack = stack.copy();
if(!simulate) {
te.setInventorySlotContents(slotno, stack.split(n));
return stack;
} else {
stack.shrink(n);
return stack;
}
} else {
if(!simulate) te.setInventorySlotContents(slotno, stack);
return ItemStack.EMPTY;
}
}
}
@Override
@Nonnull
public ItemStack extractItem(int index, int amount, boolean simulate)
{ return ItemStack.EMPTY; }
@Override
@Nonnull
public ItemStack getStackInSlot(int index)
{ return te.getStackInSlot(index); }
}
// Capability export ----------------------------------------------------------------------------
protected LazyOptional<IItemHandler> item_handler_ = LazyOptional.of(() -> new BTileEntity.BItemHandler(this));
protected LazyOptional<IEnergyStorage> energy_handler_ = LazyOptional.of(() -> (IEnergyStorage)this);
@Override
public <T> LazyOptional<T> getCapability(net.minecraftforge.common.capabilities.Capability<T> capability, @Nullable Direction facing)
{
if(!this.removed && (facing != null)) {
if(capability==CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) return item_handler_.cast();
if(capability== CapabilityEnergy.ENERGY) return energy_handler_.cast();
}
return super.getCapability(capability, facing);
}
// ITickableTileEntity ---------------------------------------------------------------------------
@Override
public void tick()
{
if(--tick_timer_ > 0) return;
tick_timer_ = TICK_INTERVAL;
if(world.isRemote) return;
boolean dirty = false;
ItemStack processing_stack = stacks_.get(BURN_SLOT_NO);
final boolean was_processing = !processing_stack.isEmpty();
boolean is_processing = was_processing;
boolean new_stack_processing = false;
if((!stacks_.get(0).isEmpty()) && transferItems(0, 1, getInventoryStackLimit())) dirty = true;
ItemStack first_stack = stacks_.get(0);
boolean shift = !first_stack.isEmpty();
if(is_processing) {
processing_stack.shrink(1);
if(processing_stack.getCount() <= 0) {
processing_stack = ItemStack.EMPTY;
is_processing = false;
}
stacks_.set(BURN_SLOT_NO, processing_stack);
if(energy_stored_ >= (energy_consumption * TICK_INTERVAL)) {
energy_stored_ -= (energy_consumption * TICK_INTERVAL);
tick_timer_ = ENERGIZED_TICK_INTERVAL;
}
dirty = true;
}
if(shift) {
int max_shift_slot_no = BURN_SLOT_NO-1;
for(int i=1; i<BURN_SLOT_NO-1; ++i) { if(stacks_.get(i).isEmpty()) { max_shift_slot_no=i; break; } }
if(max_shift_slot_no < (BURN_SLOT_NO-1)) {
// re-stack
boolean stacked = false;
for(int i=1; i<=max_shift_slot_no; ++i) {
if(transferItems(i-1, i, getInventoryStackLimit())) {
dirty = true;
stacked = true;
break;
}
}
if(!stacked) {
shiftStacks(0, max_shift_slot_no);
}
} else if(!is_processing) {
shiftStacks(0, BURN_SLOT_NO);
dirty = true;
}
}
if((was_processing != is_processing) || (new_stack_processing)) {
if(new_stack_processing) world.playSound(null, pos, SoundEvents.BLOCK_LAVA_AMBIENT, SoundCategory.BLOCKS, 0.05f, 2.4f);
final BlockState state = world.getBlockState(pos);
if(state.getBlock() instanceof BlockDecorWasteIncinerator) {
world.setBlockState(pos, state.with(LIT, is_processing), 2|16);
}
}
if(dirty) markDirty();
}
// Aux methods ----------------------------------------------------------------------------------
private ItemStack shiftStacks(final int index_from, final int index_to)
{
if(index_from >= index_to) return ItemStack.EMPTY;
ItemStack out_stack = ItemStack.EMPTY;
ItemStack stack = stacks_.get(index_from);
for(int i=index_from+1; i<=index_to; ++i) {
out_stack = stacks_.get(i);
stacks_.set(i, stack);
stack = out_stack;
}
stacks_.set(index_from, ItemStack.EMPTY);
return out_stack;
}
private boolean transferItems(final int index_from, final int index_to, int count)
{
ItemStack from = stacks_.get(index_from);
if(from.isEmpty()) return false;
ItemStack to = stacks_.get(index_to);
if(from.getCount() < count) count = from.getCount();
if(count <= 0) return false;
boolean changed = true;
if(to.isEmpty()) {
stacks_.set(index_to, from.split(count));
} else if(to.getCount() >= to.getMaxStackSize()) {
changed = false;
} else if((!from.isItemEqual(to)) || (!ItemStack.areItemStackTagsEqual(from, to))) {
changed = false;
} else {
if((to.getCount()+count) >= to.getMaxStackSize()) {
from.shrink(to.getMaxStackSize()-to.getCount());
to.setCount(to.getMaxStackSize());
} else {
from.shrink(count);
to.grow(count);
}
}
if(from.isEmpty() && from!=ItemStack.EMPTY) {
stacks_.set(index_from, ItemStack.EMPTY);
changed = true;
}
return changed;
}
}
//--------------------------------------------------------------------------------------------------------------------
// GUI
//--------------------------------------------------------------------------------------------------------------------
@OnlyIn(Dist.CLIENT)
public static class BGui extends ContainerScreen<BContainer>
{
protected final PlayerEntity player_;
public BGui(BContainer container, PlayerInventory player_inventory, ITextComponent title)
{ super(container, player_inventory, title); this.player_ = player_inventory.player; }
@Override
public void init()
{ super.init(); }
@Override
public void render(int mouseX, int mouseY, float partialTicks)
{
renderBackground();
super.render(mouseX, mouseY, partialTicks);
renderHoveredToolTip(mouseX, mouseY);
}
@Override
protected void drawGuiContainerBackgroundLayer(float partialTicks, int mouseX, int mouseY)
{
RenderSystem.enableBlend();
RenderSystem.color4f(1.0F, 1.0F, 1.0F, 1.0F);
this.minecraft.getTextureManager().bindTexture(new ResourceLocation(ModEngineersDecor.MODID, "textures/gui/small_waste_incinerator_gui.png"));
final int x0=guiLeft, y0=this.guiTop, w=xSize, h=ySize;
blit(x0, y0, 0, 0, w, h);
RenderSystem.disableBlend();
}
}
//--------------------------------------------------------------------------------------------------------------------
// container
//--------------------------------------------------------------------------------------------------------------------
public static class BContainer extends Container
{
private static final int PLAYER_INV_START_SLOTNO = BTileEntity.NUM_OF_SLOTS;
protected final PlayerEntity player_;
protected final IInventory inventory_;
protected final IWorldPosCallable wpc_;
private final IIntArray fields_;
private int proc_time_needed_;
public int field(int index) { return fields_.get(index); }
public PlayerEntity player() { return player_ ; }
public IInventory inventory() { return inventory_ ; }
public World world() { return player_.world; }
public BContainer(int cid, PlayerInventory player_inventory)
{ this(cid, player_inventory, new Inventory(BTileEntity.NUM_OF_SLOTS), IWorldPosCallable.DUMMY, new IntArray(BTileEntity.NUM_OF_FIELDS)); }
private BContainer(int cid, PlayerInventory player_inventory, IInventory block_inventory, IWorldPosCallable wpc, IIntArray fields)
{
super(ModContent.CT_WASTE_INCINERATOR, cid);
player_ = player_inventory.player;
inventory_ = block_inventory;
wpc_ = wpc;
fields_ = fields;
int i=-1;
addSlot(new Slot(inventory_, ++i, 13, 9));
addSlot(new Slot(inventory_, ++i, 37, 12));
addSlot(new Slot(inventory_, ++i, 54, 13));
addSlot(new Slot(inventory_, ++i, 71, 14));
addSlot(new Slot(inventory_, ++i, 88, 15));
addSlot(new Slot(inventory_, ++i, 105, 16));
addSlot(new Slot(inventory_, ++i, 122, 17));
addSlot(new Slot(inventory_, ++i, 139, 18));
addSlot(new Slot(inventory_, ++i, 144, 38));
addSlot(new Slot(inventory_, ++i, 127, 39));
addSlot(new Slot(inventory_, ++i, 110, 40));
addSlot(new Slot(inventory_, ++i, 93, 41));
addSlot(new Slot(inventory_, ++i, 76, 42));
addSlot(new Slot(inventory_, ++i, 59, 43));
addSlot(new Slot(inventory_, ++i, 42, 44));
addSlot(new Slot(inventory_, ++i, 17, 58));
for(int x=0; x<9; ++x) {
addSlot(new Slot(player_inventory, x, 8+x*18, 144)); // player slots: 0..8
}
for(int y=0; y<3; ++y) {
for(int x=0; x<9; ++x) {
addSlot(new Slot(player_inventory, x+y*9+9, 8+x*18, 86+y*18)); // player slots: 9..35
}
}
}
@Override
public boolean canInteractWith(PlayerEntity player)
{ return inventory_.isUsableByPlayer(player); }
@Override
public ItemStack transferStackInSlot(PlayerEntity player, int index)
{
Slot slot = getSlot(index);
if((slot==null) || (!slot.getHasStack())) return ItemStack.EMPTY;
ItemStack slot_stack = slot.getStack();
ItemStack transferred = slot_stack.copy();
if((index>=0) && (index<PLAYER_INV_START_SLOTNO)) {
// Device slots
if(!mergeItemStack(slot_stack, PLAYER_INV_START_SLOTNO, PLAYER_INV_START_SLOTNO+36, true)) return ItemStack.EMPTY;
} else if((index >= PLAYER_INV_START_SLOTNO) && (index <= PLAYER_INV_START_SLOTNO+36)) {
// Player slot
if(!mergeItemStack(slot_stack, 0, PLAYER_INV_START_SLOTNO-1, true)) return ItemStack.EMPTY;
} else {
// invalid slot
return ItemStack.EMPTY;
}
if(slot_stack.isEmpty()) {
slot.putStack(ItemStack.EMPTY);
} else {
slot.onSlotChanged();
}
if(slot_stack.getCount() == transferred.getCount()) return ItemStack.EMPTY;
slot.onTake(player, slot_stack);
return transferred;
}
}
}

View file

@ -0,0 +1,53 @@
/*
* @file BlockDecorWindow.java
* @author Stefan Wilhelm (wile)
* @copyright (C) 2019 Stefan Wilhelm
* @license MIT (see https://opensource.org/licenses/MIT)
*
* Mod windows.
*/
package wile.engineersdecor.blocks;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.IWaterLoggable;
import net.minecraft.item.BlockItemUseContext;
import net.minecraft.state.StateContainer;
import net.minecraft.util.Direction;
import net.minecraft.util.math.AxisAlignedBB;
import javax.annotation.Nullable;
public class BlockDecorWindow extends BlockDecorDirected implements IWaterLoggable
{
public BlockDecorWindow(long config, Block.Properties builder, final AxisAlignedBB unrotatedAABB)
{ super(config|CFG_WATERLOGGABLE, builder, unrotatedAABB); }
@Override
public RenderTypeHint getRenderTypeHint()
{ return RenderTypeHint.TRANSLUCENT; }
@Override
protected void fillStateContainer(StateContainer.Builder<Block, BlockState> builder)
{ super.fillStateContainer(builder); builder.add(WATERLOGGED); }
@Override
@Nullable
public BlockState getStateForPlacement(BlockItemUseContext context)
{
Direction facing = context.getPlacementHorizontalFacing();
if(Math.abs(context.getPlayer().getLookVec().y) > 0.9) {
facing = context.getNearestLookingDirection();
} else {
for(Direction f: Direction.values()) {
BlockState st = context.getWorld().getBlockState(context.getPos().offset(f));
if(st.getBlock() == this) {
facing = st.get(FACING);
break;
}
}
}
return super.getStateForPlacement(context).with(FACING, facing);
}
}

View file

@ -0,0 +1,32 @@
/*
* @file IDecorBlock.java
* @author Stefan Wilhelm (wile)
* @copyright (C) 2019 Stefan Wilhelm
* @license MIT (see https://opensource.org/licenses/MIT)
*
* Interface for tagging and common default behaviour.
*/
package wile.engineersdecor.blocks;
import net.minecraft.block.BlockState;
import net.minecraft.item.ItemStack;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import java.util.Collections;
import java.util.List;
public interface IDecorBlock
{
enum RenderTypeHint { SOLID,CUTOUT,CUTOUT_MIPPED,TRANSLUCENT }
default boolean hasDynamicDropList()
{ return false; }
default List<ItemStack> dropList(BlockState state, World world, BlockPos pos, boolean explosion)
{ return Collections.singletonList((!world.isRemote()) ? (new ItemStack(state.getBlock().asItem())) : (ItemStack.EMPTY)); }
default RenderTypeHint getRenderTypeHint()
{ return RenderTypeHint.SOLID; }
}

View file

@ -0,0 +1,92 @@
/*
* @file ModLootTables.java
* @author Stefan Wilhelm (wile)
* @copyright (C) 2019 Stefan Wilhelm
* @license MIT (see https://opensource.org/licenses/MIT)
*
* Loot table generator.
*/
package wile.engineersdecor.datagen;
import wile.engineersdecor.ModContent;
import wile.engineersdecor.blocks.IDecorBlock;
import wile.engineersdecor.detail.ModAuxiliaries;
import net.minecraft.block.Block;
import net.minecraft.data.*;
import net.minecraft.util.ResourceLocation;
import net.minecraft.world.storage.loot.*;
import net.minecraft.world.storage.loot.functions.CopyName;
import net.minecraft.world.storage.loot.functions.CopyName.Source;
import net.minecraft.world.storage.loot.functions.CopyNbt;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import java.nio.file.Path;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class ModLootTables extends LootTableProvider
{
private static final Logger LOGGER = LogManager.getLogger();
private static final Gson GSON = (new GsonBuilder()).setPrettyPrinting().disableHtmlEscaping().create();
private final DataGenerator generator;
//--------------------------------------------------------------------------------------------------------------------
public ModLootTables(DataGenerator gen)
{ super(gen); generator=gen; }
//-- LootTableProvider -----------------------------------------------------------------------------------------------
@Override
public String getName()
{ return ModAuxiliaries.MODID + " Loot Tables"; }
@Override
public void act(DirectoryCache cache)
{ save(cache, generate()); }
//--------------------------------------------------------------------------------------------------------------------
private Map<ResourceLocation, LootTable> generate()
{
final HashMap<ResourceLocation, LootTable> tables = new HashMap<ResourceLocation, LootTable>();
final List<Block> blocks = ModContent.allBlocks();
blocks.forEach((block)->{
if((!(block instanceof IDecorBlock)) || (!(((IDecorBlock)block).hasDynamicDropList()))) {
tables.put(
block.getLootTable(),
defaultBlockDrops(block.getRegistryName().getPath() + "_dlt", block)
.setParameterSet(LootParameterSets.BLOCK).build());
}
});
return tables;
}
private void save(DirectoryCache cache, Map<ResourceLocation, LootTable> tables)
{
final Path root = generator.getOutputFolder();
tables.forEach((rl,tab)->{
Path fp = root.resolve("data/" + rl.getNamespace() + "/loot_tables/" + rl.getPath() + ".json");
try {
IDataProvider.save(GSON, cache, LootTableManager.toJson(tab), fp);
} catch(Exception e) {
LOGGER.error("Failed to save loottable '"+fp+"', exception: " + e);
}
});
}
private LootTable.Builder defaultBlockDrops(String rl_path, Block block)
{
ItemLootEntry.Builder iltb = ItemLootEntry.builder(block);
iltb.acceptFunction(CopyName.func_215893_a(Source.BLOCK_ENTITY));
if(block.hasTileEntity(block.getDefaultState())) {
iltb.acceptFunction(CopyNbt.func_215881_a(CopyNbt.Source.BLOCK_ENTITY));
}
return LootTable.builder().addLootPool(LootPool.builder().name(rl_path).rolls(ConstantRange.of(1)).addEntry(iltb));
}
}

View file

@ -0,0 +1,24 @@
/*
* @file ExtItems.java
* @author Stefan Wilhelm (wile)
* @copyright (C) 2019 Stefan Wilhelm
* @license MIT (see https://opensource.org/licenses/MIT)
*
* Object holder based item references.
*/
package wile.engineersdecor.detail;
import net.minecraft.item.Item;
import net.minecraftforge.registries.ObjectHolder;
public class ExtItems
{
@ObjectHolder("immersiveengineering:external_heater")
public static final Item IE_EXTERNAL_HEATER = null;
@ObjectHolder("bottledmilk:milk_bottle_drinkable")
public static final Item BOTTLED_MILK_BOTTLE_DRINKLABLE = null;
public static final void onPostInit()
{}
}

View file

@ -0,0 +1,70 @@
package wile.engineersdecor.detail;
import net.minecraft.item.ItemStack;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.Direction;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraft.inventory.IInventory;
import net.minecraft.inventory.ISidedInventory;
import net.minecraftforge.items.CapabilityItemHandler;
import net.minecraftforge.items.IItemHandler;
import net.minecraftforge.items.ItemHandlerHelper;
import net.minecraftforge.items.wrapper.InvWrapper;
import net.minecraftforge.items.wrapper.SidedInvWrapper;
import javax.annotation.Nullable;
public class ItemHandling
{
public static IItemHandler itemhandler(World world, BlockPos pos, @Nullable Direction side)
{
TileEntity te = world.getTileEntity(pos);
if(te==null) return null;
IItemHandler ih = te.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, side).orElse(null);
if(ih!=null) return ih;
if((side!=null) && (te instanceof ISidedInventory)) return new SidedInvWrapper((ISidedInventory)te, side);
if(te instanceof IInventory) return new InvWrapper((IInventory)te);
return null;
}
public static ItemStack insert(IItemHandler inventory, ItemStack stack , boolean simulate)
{ return ItemHandlerHelper.insertItemStacked(inventory, stack, simulate); }
public static ItemStack insert(TileEntity te, @Nullable Direction side, ItemStack stack, boolean simulate)
{
if(te==null) return stack;
IItemHandler hnd = te.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, side).orElse(null);
if(hnd != null) {
hnd = (IItemHandler)te.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, side);
} else if((side!=null) && (te instanceof ISidedInventory)) {
hnd = new SidedInvWrapper((ISidedInventory)te, side);
} else if(te instanceof IInventory) {
hnd = new InvWrapper((IInventory)te);
}
return (hnd==null) ? stack : ItemHandlerHelper.insertItemStacked(hnd, stack, simulate);
}
public static ItemStack extract(IItemHandler inventory, @Nullable ItemStack match, int amount, boolean simulate)
{
if((inventory==null) || (amount<=0)) return ItemStack.EMPTY;
final int max = inventory.getSlots();
ItemStack out_stack = ItemStack.EMPTY;
for(int i=0; i<max; ++i) {
final ItemStack stack = inventory.getStackInSlot(i);
if(stack.isEmpty()) continue;
if(out_stack.isEmpty()) {
if((match!=null) && (!stack.isItemEqual(match))) continue;
out_stack = inventory.extractItem(i, amount, simulate);
} else if(stack.isItemEqual(out_stack)) {
ItemStack es = inventory.extractItem(i, (amount-out_stack.getCount()), simulate);
out_stack.grow(es.getCount());
}
if(out_stack.getCount() >= amount) break;
}
return out_stack;
}
}

View file

@ -0,0 +1,213 @@
/*
* @file ModAuxiliaries.java
* @author Stefan Wilhelm (wile)
* @copyright (C) 2018 Stefan Wilhelm
* @license MIT (see https://opensource.org/licenses/MIT)
*
* General commonly used functionality.
*/
package wile.engineersdecor.detail;
import wile.engineersdecor.ModEngineersDecor;
import net.minecraft.client.util.InputMappings;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.util.Direction;
import net.minecraft.util.SharedConstants;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.text.StringTextComponent;
import net.minecraft.world.IBlockReader;
import net.minecraft.item.ItemStack;
import net.minecraft.client.util.ITooltipFlag;
import net.minecraft.util.text.TranslationTextComponent;
import net.minecraft.util.text.TextFormatting;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraftforge.fml.ModList;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import org.lwjgl.glfw.GLFW;
import javax.annotation.Nullable;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class ModAuxiliaries
{
public static final String MODID = ModEngineersDecor.MODID;
/**
* Text localisation wrapper, implicitly prepends `ModEngineersDecor.MODID` to the
* translation keys. Forces formatting argument, nullable if no special formatting shall be applied..
*/
public static TranslationTextComponent localizable(String modtrkey, @Nullable TextFormatting color, Object... args)
{
TranslationTextComponent tr = new TranslationTextComponent(ModEngineersDecor.MODID+"."+modtrkey, args);
if(color!=null) tr.getStyle().setColor(color);
return tr;
}
public static TranslationTextComponent localizable(String modtrkey)
{ return localizable(modtrkey, null); }
public static TranslationTextComponent localizable_block_key(String blocksubkey)
{ return new TranslationTextComponent("block."+ModEngineersDecor.MODID+"."+blocksubkey); }
@OnlyIn(Dist.CLIENT)
public static String localize(String translationKey, Object... args)
{
TranslationTextComponent tr = new TranslationTextComponent(translationKey, args);
tr.getStyle().setColor(TextFormatting.RESET);
final String ft = tr.getFormattedText();
if(ft.contains("${")) {
// Non-recursive, non-argument lang file entry cross referencing.
Pattern pt = Pattern.compile("\\$\\{([^}]+)\\}");
Matcher mt = pt.matcher(ft);
StringBuffer sb = new StringBuffer();
while(mt.find()) {
String m = mt.group(1);
if(m.contains("?")) {
String[] kv = m.split("\\?", 2);
String key = kv[0].trim();
boolean not = key.startsWith("!");
if(not) key = key.replaceFirst("!", "");
m = kv[1].trim();
if(!ModConfig.getServerConfig().contains(key)) {
m = "";
} else {
boolean r = ModConfig.getServerConfig().getBoolean(key);
if(not) r = !r;
if(!r) m = "";
}
}
mt.appendReplacement(sb, (new TranslationTextComponent(m)).getFormattedText().trim());
}
mt.appendTail(sb);
return sb.toString();
} else {
return ft;
}
}
/**
* Returns true if a given key is translated for the current language.
*/
@OnlyIn(Dist.CLIENT)
public static boolean hasTranslation(String key)
{ return net.minecraft.client.resources.I18n.hasKey(key); }
public static final class Tooltip
{
@OnlyIn(Dist.CLIENT)
public static boolean extendedTipCondition()
{
return (
InputMappings.isKeyDown(ModEngineersDecor.proxy.mc().func_228018_at_()/*getMainWindow()*/.getHandle(), GLFW.GLFW_KEY_LEFT_SHIFT) ||
InputMappings.isKeyDown(ModEngineersDecor.proxy.mc().func_228018_at_()/*getMainWindow()*/.getHandle(), GLFW.GLFW_KEY_RIGHT_SHIFT)
);
}
@OnlyIn(Dist.CLIENT)
public static boolean helpCondition()
{
return extendedTipCondition() && (
InputMappings.isKeyDown(ModEngineersDecor.proxy.mc().func_228018_at_()/*getMainWindow()*/.getHandle(), GLFW.GLFW_KEY_LEFT_CONTROL) ||
InputMappings.isKeyDown(ModEngineersDecor.proxy.mc().func_228018_at_()/*getMainWindow()*/.getHandle(), GLFW.GLFW_KEY_RIGHT_CONTROL)
);
}
/**
* Adds an extended tooltip or help tooltip depending on the key states of CTRL and SHIFT.
* Returns true if the localisable help/tip was added, false if not (either not CTL/SHIFT or
* no translation found).
*/
@OnlyIn(Dist.CLIENT)
public static boolean addInformation(@Nullable String advancedTooltipTranslationKey, @Nullable String helpTranslationKey, List<ITextComponent> tooltip, ITooltipFlag flag, boolean addAdvancedTooltipHints)
{
// Note: intentionally not using keybinding here, this must be `control` or `shift`. MC uses lwjgl Keyboard,
// so using this also here should be ok.
final boolean help_available = (helpTranslationKey != null) && ModAuxiliaries.hasTranslation(helpTranslationKey + ".help");
final boolean tip_available = (advancedTooltipTranslationKey != null) && ModAuxiliaries.hasTranslation(helpTranslationKey + ".tip");
if((!help_available) && (!tip_available)) return false;
if(helpCondition()) {
if(!help_available) return false;
String s = localize(helpTranslationKey + ".help");
if(s.isEmpty()) return false;
tooltip.add(new StringTextComponent(s));
return true;
} else if(extendedTipCondition()) {
if(!tip_available) return false;
String s = localize(advancedTooltipTranslationKey + ".tip");
if(s.isEmpty()) return false;
tooltip.add(new StringTextComponent(s));
return true;
} else if(addAdvancedTooltipHints) {
String s = "";
if(tip_available) s += localize(ModEngineersDecor.MODID + ".tooltip.hint.extended") + (help_available ? " " : "");
if(help_available) s += localize(ModEngineersDecor.MODID + ".tooltip.hint.help");
tooltip.add(new StringTextComponent(s));
}
return false;
}
/**
* Adds an extended tooltip or help tooltip for a given stack depending on the key states of CTRL and SHIFT.
* Format in the lang file is (e.g. for items): "item.MODID.REGISTRYNAME.tip" and "item.MODID.REGISTRYNAME.help".
* Return value see method pattern above.
*/
@OnlyIn(Dist.CLIENT)
public static boolean addInformation(ItemStack stack, @Nullable IBlockReader world, List<ITextComponent> tooltip, ITooltipFlag flag, boolean addAdvancedTooltipHints)
{ return addInformation(stack.getTranslationKey(), stack.getTranslationKey(), tooltip, flag, addAdvancedTooltipHints); }
}
public static final AxisAlignedBB getPixeledAABB(double x0, double y0, double z0, double x1, double y1, double z1)
{ return new AxisAlignedBB(x0/16.0, y0/16.0, z0/16.0, x1/16.0, y1/16.0, z1/16.0); }
public static final AxisAlignedBB getRotatedAABB(AxisAlignedBB bb, Direction new_facing, boolean horizontal_rotation)
{
if(!horizontal_rotation) {
switch(new_facing.getIndex()) {
case 0: return new AxisAlignedBB(1-bb.maxX, 1-bb.maxZ, 1-bb.maxY, 1-bb.minX, 1-bb.minZ, 1-bb.minY); // D
case 1: return new AxisAlignedBB(1-bb.maxX, bb.minZ, bb.minY, 1-bb.minX, bb.maxZ, bb.maxY); // U
case 2: return new AxisAlignedBB(1-bb.maxX, bb.minY, 1-bb.maxZ, 1-bb.minX, bb.maxY, 1-bb.minZ); // N
case 3: return new AxisAlignedBB( bb.minX, bb.minY, bb.minZ, bb.maxX, bb.maxY, bb.maxZ); // S --> bb
case 4: return new AxisAlignedBB(1-bb.maxZ, bb.minY, bb.minX, 1-bb.minZ, bb.maxY, bb.maxX); // W
case 5: return new AxisAlignedBB( bb.minZ, bb.minY, 1-bb.maxX, bb.maxZ, bb.maxY, 1-bb.minX); // E
}
} else {
switch(new_facing.getIndex()) {
case 0: return new AxisAlignedBB( bb.minX, bb.minY, bb.minZ, bb.maxX, bb.maxY, bb.maxZ); // D --> bb
case 1: return new AxisAlignedBB( bb.minX, bb.minY, bb.minZ, bb.maxX, bb.maxY, bb.maxZ); // U --> bb
case 2: return new AxisAlignedBB( bb.minX, bb.minY, bb.minZ, bb.maxX, bb.maxY, bb.maxZ); // N --> bb
case 3: return new AxisAlignedBB(1-bb.maxX, bb.minY, 1-bb.maxZ, 1-bb.minX, bb.maxY, 1-bb.minZ); // S
case 4: return new AxisAlignedBB( bb.minZ, bb.minY, 1-bb.maxX, bb.maxZ, bb.maxY, 1-bb.minX); // W
case 5: return new AxisAlignedBB(1-bb.maxZ, bb.minY, bb.minX, 1-bb.minZ, bb.maxY, bb.maxX); // E
}
}
return bb;
}
public static final boolean isModLoaded(final String registry_name)
{ return ModList.get().isLoaded(registry_name); }
public static final void logInfo(final String msg)
{ ModEngineersDecor.logger().info(msg); }
public static final void logWarn(final String msg)
{ ModEngineersDecor.logger().warn(msg); }
public static final void logError(final String msg)
{ ModEngineersDecor.logger().error(msg); }
@SuppressWarnings("unused")
public static void playerChatMessage(final PlayerEntity player, final String message)
{
String s = message.trim();
if(!s.isEmpty()) player.sendMessage(new TranslationTextComponent(s));
}
public static final boolean isDevelopmentMode()
{ return SharedConstants.developmentMode; }
public interface IExperimentalFeature {}
}

View file

@ -0,0 +1,637 @@
/*
* @file ModConfig.java
* @author Stefan Wilhelm (wile)
* @copyright (C) 2018 Stefan Wilhelm
* @license MIT (see https://opensource.org/licenses/MIT)
*
* Main class for module settings. Handles reading and
* saving the config file.
*/
package wile.engineersdecor.detail;
import wile.engineersdecor.ModContent;
import wile.engineersdecor.ModEngineersDecor;
import wile.engineersdecor.blocks.*;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.block.Block;
import net.minecraft.item.Item;
import net.minecraftforge.common.ForgeConfigSpec;
import org.apache.commons.lang3.tuple.Pair;
import javax.annotation.Nullable;
import java.util.ArrayList;
public class ModConfig
{
//--------------------------------------------------------------------------------------------------------------------
public static final CommonConfig COMMON;
public static final ServerConfig SERVER;
public static final ClientConfig CLIENT;
public static final ForgeConfigSpec COMMON_CONFIG_SPEC;
public static final ForgeConfigSpec SERVER_CONFIG_SPEC;
public static final ForgeConfigSpec CLIENT_CONFIG_SPEC;
static {
final Pair<CommonConfig, ForgeConfigSpec> common_ = (new ForgeConfigSpec.Builder()).configure(CommonConfig::new);
COMMON_CONFIG_SPEC = common_.getRight();
COMMON = common_.getLeft();
final Pair<ServerConfig, ForgeConfigSpec> server_ = (new ForgeConfigSpec.Builder()).configure(ServerConfig::new);
SERVER_CONFIG_SPEC = server_.getRight();
SERVER = server_.getLeft();
final Pair<ClientConfig, ForgeConfigSpec> client_ = (new ForgeConfigSpec.Builder()).configure(ClientConfig::new);
CLIENT_CONFIG_SPEC = client_.getRight();
CLIENT = client_.getLeft();
}
//--------------------------------------------------------------------------------------------------------------------
public static class ClientConfig
{
public final ForgeConfigSpec.BooleanValue without_tooltips;
public final ForgeConfigSpec.BooleanValue without_ters;
ClientConfig(ForgeConfigSpec.Builder builder)
{
builder.comment("Settings not loaded on servers.")
.push("client");
// --- OPTOUTS ------------------------------------------------------------
{
builder.comment("Opt-out settings")
.push("optout");
without_tooltips = builder
.translation(ModEngineersDecor.MODID + ".config.without_tooltips")
.comment("Disable CTRL-SHIFT item tooltip display.")
.define("without_tooltips", false);
without_ters = builder
.translation(ModEngineersDecor.MODID + ".config.without_ters")
.comment("Disable all TERs (tile entity renderers).")
.define("without_ters", false);
}
builder.pop();
}
}
//--------------------------------------------------------------------------------------------------------------------
public static class ServerConfig
{
ServerConfig(ForgeConfigSpec.Builder builder)
{
builder.comment("Settings not loaded on clients.")
.push("server");
builder.pop();
}
}
//--------------------------------------------------------------------------------------------------------------------
public static class CommonConfig
{
// Optout
public final ForgeConfigSpec.ConfigValue<String> pattern_excludes;
public final ForgeConfigSpec.ConfigValue<String> pattern_includes;
public final ForgeConfigSpec.BooleanValue without_clinker_bricks;
public final ForgeConfigSpec.BooleanValue without_slag_bricks;
public final ForgeConfigSpec.BooleanValue without_rebar_concrete;
public final ForgeConfigSpec.BooleanValue without_walls;
public final ForgeConfigSpec.BooleanValue without_stairs;
public final ForgeConfigSpec.BooleanValue without_ie_concrete_wall;
public final ForgeConfigSpec.BooleanValue without_panzer_glass;
public final ForgeConfigSpec.BooleanValue without_ladders;
public final ForgeConfigSpec.BooleanValue without_treated_wood_furniture;
public final ForgeConfigSpec.BooleanValue without_windows;
public final ForgeConfigSpec.BooleanValue without_light_sources;
public final ForgeConfigSpec.BooleanValue without_slabs;
public final ForgeConfigSpec.BooleanValue without_halfslabs;
public final ForgeConfigSpec.BooleanValue without_poles;
public final ForgeConfigSpec.BooleanValue without_hsupports;
public final ForgeConfigSpec.BooleanValue without_sign_plates;
public final ForgeConfigSpec.BooleanValue without_floor_grating;
public final ForgeConfigSpec.BooleanValue without_crafting_table;
public final ForgeConfigSpec.BooleanValue without_lab_furnace;
public final ForgeConfigSpec.BooleanValue without_electrical_furnace;
public final ForgeConfigSpec.BooleanValue without_valves;
public final ForgeConfigSpec.BooleanValue without_passive_fluid_accumulator;
public final ForgeConfigSpec.BooleanValue without_waste_incinerator;
public final ForgeConfigSpec.BooleanValue without_factory_dropper;
public final ForgeConfigSpec.BooleanValue without_factory_hopper;
public final ForgeConfigSpec.BooleanValue without_factory_placer;
public final ForgeConfigSpec.BooleanValue without_block_breaker;
public final ForgeConfigSpec.BooleanValue without_solar_panel;
public final ForgeConfigSpec.BooleanValue without_fluid_funnel;
public final ForgeConfigSpec.BooleanValue without_mineral_smelter;
public final ForgeConfigSpec.BooleanValue without_milking_machine;
public final ForgeConfigSpec.BooleanValue without_chair_sitting;
public final ForgeConfigSpec.BooleanValue without_mob_chair_sitting;
public final ForgeConfigSpec.BooleanValue without_ladder_speed_boost;
public final ForgeConfigSpec.BooleanValue without_crafting_table_history;
public final ForgeConfigSpec.BooleanValue without_direct_slab_pickup;
public final ForgeConfigSpec.BooleanValue with_creative_mode_device_drops;
// Misc
public final ForgeConfigSpec.BooleanValue with_experimental;
public final ForgeConfigSpec.BooleanValue without_recipes;
// Tweaks
public final ForgeConfigSpec.IntValue furnace_smelting_speed_percent;
public final ForgeConfigSpec.IntValue furnace_fuel_efficiency_percent;
public final ForgeConfigSpec.IntValue furnace_boost_energy_consumption;
public final ForgeConfigSpec.IntValue e_furnace_speed_percent;
public final ForgeConfigSpec.IntValue e_furnace_power_consumption;
public final ForgeConfigSpec.IntValue small_solar_panel_peak_production;
public final ForgeConfigSpec.BooleanValue e_furnace_automatic_pulling;
public final ForgeConfigSpec.DoubleValue chair_mob_sitting_probability_percent;
public final ForgeConfigSpec.DoubleValue chair_mob_standup_probability_percent;
public final ForgeConfigSpec.BooleanValue with_crafting_quickmove_buttons;
public final ForgeConfigSpec.IntValue pipevalve_max_flowrate;
public final ForgeConfigSpec.IntValue pipevalve_redstone_gain;
public final ForgeConfigSpec.IntValue block_breaker_power_consumption;
public final ForgeConfigSpec.IntValue block_breaker_reluctance;
public final ForgeConfigSpec.IntValue block_breaker_min_breaking_time;
public final ForgeConfigSpec.BooleanValue block_breaker_requires_power;
public final ForgeConfigSpec.IntValue tree_cuttter_energy_consumption;
public final ForgeConfigSpec.IntValue tree_cuttter_cutting_time_needed;
public final ForgeConfigSpec.BooleanValue tree_cuttter_requires_power;
public final ForgeConfigSpec.IntValue milking_machine_energy_consumption;
CommonConfig(ForgeConfigSpec.Builder builder)
{
builder.comment("Settings affecting the logical server side, but are also configurable in single player.")
.push("server");
// --- OPTOUTS ------------------------------------------------------------
{
builder.comment("Opt-out settings")
.push("optout");
pattern_excludes = builder
.translation(ModEngineersDecor.MODID + ".config.pattern_excludes")
.comment("Opt-out any block by its registry name ('*' wildcard matching, "
+ "comma separated list, whitespaces ignored. You must match the whole name, "
+ "means maybe add '*' also at the begin and end. Example: '*wood*,*steel*' "
+ "excludes everything that has 'wood' or 'steel' in the registry name. "
+ "The matching result is also traced in the log file. ")
.define("pattern_excludes", "");
pattern_includes = builder
.translation(ModEngineersDecor.MODID + ".config.pattern_includes")
.comment("Prevent blocks from being opt'ed by registry name ('*' wildcard matching, "
+ "comma separated list, whitespaces ignored. Evaluated before all other opt-out checks. "
+ "You must match the whole name, means maybe add '*' also at the begin and end. Example: "
+ "'*wood*,*steel*' includes everything that has 'wood' or 'steel' in the registry name."
+ "The matching result is also traced in the log file.")
.define("pattern_includes", "");
without_clinker_bricks = builder
.translation(ModEngineersDecor.MODID + ".config.without_clinker_bricks")
.comment("Disable clinker bricks and derived blocks.")
.define("without_clinker_bricks", false);
without_slag_bricks = builder
.translation(ModEngineersDecor.MODID + ".config.without_slag_bricks")
.comment("Disable slag bricks and derived blocks.")
.define("without_slag_bricks", false);
without_rebar_concrete = builder
.translation(ModEngineersDecor.MODID + ".config.without_rebar_concrete")
.comment("Disable rebar concrete and derived blocks.")
.define("without_rebar_concrete", false);
without_walls = builder
.translation(ModEngineersDecor.MODID + ".config.without_walls")
.comment("Disable all mod wall blocks.")
.define("without_walls", false);
without_stairs = builder
.translation(ModEngineersDecor.MODID + ".config.without_stairs")
.comment("Disable all mod stairs blocks.")
.define("without_stairs", false);
without_ie_concrete_wall = builder
.translation(ModEngineersDecor.MODID + ".config.without_ie_concrete_wall")
.comment("Disable IE concrete wall.")
.define("without_ie_concrete_wall", false);
without_panzer_glass = builder
.translation(ModEngineersDecor.MODID + ".config.without_panzer_glass")
.comment("Disable panzer glass and derived blocks.")
.define("without_panzer_glass", false);
without_crafting_table = builder
.translation(ModEngineersDecor.MODID + ".config.without_crafting_table")
.comment("Disable treated wood crafting table.")
.define("without_crafting_table", false);
without_lab_furnace = builder
.translation(ModEngineersDecor.MODID + ".config.without_lab_furnace")
.comment("Disable small lab furnace.")
.define("without_lab_furnace", false);
without_electrical_furnace = builder
.translation(ModEngineersDecor.MODID + ".config.without_electrical_furnace")
.comment("Disable small electrical pass-through furnace.")
.define("without_electrical_furnace", false);
without_treated_wood_furniture = builder
.translation(ModEngineersDecor.MODID + ".config.without_treated_wood_furniture")
.comment("Disable treated wood table, stool, windowsill, etc.")
.define("without_treated_wood_furniture", false);
without_windows = builder
.translation(ModEngineersDecor.MODID + ".config.without_windows")
.comment("Disable treated wood window, etc.")
.define("without_windows", false);
without_light_sources = builder
.translation(ModEngineersDecor.MODID + ".config.without_light_sources")
.comment("Disable light sources")
.define("without_light_sources", false);
without_ladders = builder
.translation(ModEngineersDecor.MODID + ".config.without_ladders")
.comment("Disable ladders")
.define("without_ladders", false);
without_chair_sitting = builder
.translation(ModEngineersDecor.MODID + ".config.without_chair_sitting")
.comment("Disable possibility to sit on stools and chairs.")
.define("without_chair_sitting", false);
without_mob_chair_sitting = builder
.translation(ModEngineersDecor.MODID + ".config.without_mob_chair_sitting")
.comment("Disable that mobs will sit on chairs and stools.")
.define("without_mob_chair_sitting", false);
without_ladder_speed_boost = builder
.translation(ModEngineersDecor.MODID + ".config.without_ladder_speed_boost")
.comment("Disable the speed boost of ladders in this mod.")
.define("without_ladder_speed_boost", false);
without_crafting_table_history = builder
.translation(ModEngineersDecor.MODID + ".config.without_crafting_table_history")
.comment("Disable history refabrication feature of the treated wood crafting table.")
.define("without_crafting_table_history", false);
without_valves = builder
.translation(ModEngineersDecor.MODID + ".config.without_valves")
.comment("Disable check valve, and redstone controlled valves.")
.define("without_valves", false);
without_passive_fluid_accumulator = builder
.translation(ModEngineersDecor.MODID + ".config.without_passive_fluid_accumulator")
.comment("Disable the passive fluid accumulator.")
.define("without_passive_fluid_accumulator", false);
without_waste_incinerator = builder
.translation(ModEngineersDecor.MODID + ".config.without_waste_incinerator")
.comment("Disable item disposal/trash/void incinerator device.")
.define("without_waste_incinerator", false);
without_sign_plates = builder
.translation(ModEngineersDecor.MODID + ".config.without_sign_plates")
.comment("Disable decorative sign plates (caution, hazards, etc).")
.define("without_sign_plates", false);
without_floor_grating = builder
.translation(ModEngineersDecor.MODID + ".config.without_floor_grating")
.comment("Disable floor gratings.")
.define("without_floor_grating", false);
without_factory_dropper = builder
.translation(ModEngineersDecor.MODID + ".config.without_factory_dropper")
.comment("Disable the factory dropper.")
.define("without_factory_dropper", false);
without_factory_hopper = builder
.translation(ModEngineersDecor.MODID + ".config.without_factory_hopper")
.comment("Disable the factory hopper.")
.define("without_factory_hopper", false);
without_factory_placer = builder
.translation(ModEngineersDecor.MODID + ".config.without_factory_placer")
.comment("Disable the factory placer.")
.define("without_factory_placer", false);
without_block_breaker = builder
.translation(ModEngineersDecor.MODID + ".config.without_block_breaker")
.comment("Disable the small block breaker.")
.define("without_block_breaker", false);
without_solar_panel = builder
.translation(ModEngineersDecor.MODID + ".config.without_solar_panel")
.comment("Disable the small solar panel.")
.define("without_solar_panel", false);
without_fluid_funnel = builder
.translation(ModEngineersDecor.MODID + ".config.without_fluid_funnel")
.comment("Disable the small fluid collection funnel.")
.define("without_fluid_funnel", false);
without_mineral_smelter = builder
.translation(ModEngineersDecor.MODID + ".config.without_mineral_smelter")
.comment("Disable the small mineral smelter.")
.define("without_mineral_smelter", false);
without_milking_machine = builder
.translation(ModEngineersDecor.MODID + ".config.without_milking_machine")
.comment("Disable the small milking machine.")
.define("without_milking_machine", false);
without_slabs = builder
.translation(ModEngineersDecor.MODID + ".config.without_slabs")
.comment("Disable horizontal half-block slab.")
.define("without_slabs", false);
without_halfslabs = builder
.translation(ModEngineersDecor.MODID + ".config.without_halfslabs")
.comment("Disable stackable 1/8 block slices.")
.define("without_halfslabs", false);
without_poles = builder
.translation(ModEngineersDecor.MODID + ".config.without_poles")
.comment("Disable poles of any material.")
.define("without_poles", false);
without_hsupports = builder
.translation(ModEngineersDecor.MODID + ".config.without_hsupports")
.comment("Disable horizontal supports like the double-T support.")
.define("without_hsupports", false);
without_recipes = builder
.translation(ModEngineersDecor.MODID + ".config.without_recipes")
.comment("Disable all internal recipes, allowing to use alternative pack recipes.")
.define("without_recipes", false);
builder.pop();
}
// --- MISC ---------------------------------------------------------------
{
builder.comment("Miscellaneous settings")
.push("miscellaneous");
with_experimental = builder
.translation(ModEngineersDecor.MODID + ".config.with_experimental")
.comment("Enables experimental features. Use at own risk.")
.define("with_experimental", false);
without_direct_slab_pickup = builder
.translation(ModEngineersDecor.MODID + ".config.without_direct_slab_pickup")
.comment("Disable directly picking up layers from slabs and slab " +
" slices by left clicking while looking up/down.")
.define("without_direct_slab_pickup", false);
with_creative_mode_device_drops = builder
.translation(ModEngineersDecor.MODID + ".config.with_creative_mode_device_drops")
.comment("Enable that devices are dropped as item also in creative mode, allowing " +
" to relocate them with contents and settings.")
.define("with_creative_mode_device_drops", false);
builder.pop();
}
// --- TWEAKS -------------------------------------------------------------
{
builder.comment("Tweaks")
.push("tweaks");
furnace_smelting_speed_percent = builder
.translation(ModEngineersDecor.MODID + ".config.furnace_smelting_speed_percent")
.comment("Defines, in percent, how fast the lab furnace smelts compared to " +
"a vanilla furnace. 100% means vanilla furnace speed, 150% means the " +
"lab furnace is faster. The value can be changed on-the-fly for tuning.")
.defineInRange("furnace_smelting_speed_percent", 130, 50, 500);
furnace_fuel_efficiency_percent = builder
.translation(ModEngineersDecor.MODID + ".config.furnace_fuel_efficiency_percent")
.comment("Defines, in percent, how fuel efficient the lab furnace is, compared " +
"to a vanilla furnace. 100% means vanilla furnace consumiton, 200% means " +
"the lab furnace needs about half the fuel of a vanilla furnace, " +
"The value can be changed on-the-fly for tuning.")
.defineInRange("furnace_fuel_efficiency_percent", 100, 50, 250);
furnace_boost_energy_consumption = builder
.translation(ModEngineersDecor.MODID + ".config.furnace_boost_energy_consumption")
.comment("Defines the energy consumption (per tick) for speeding up the smelting process. " +
"If IE is installed, an external heater has to be inserted into an auxiliary slot " +
"of the lab furnace. The power source needs to be able to provide at least 4 times " +
"this consumption (fixed threshold value). The value can be changed on-the-fly for tuning. " +
"The default value corresponds to the IE heater consumption.")
.defineInRange("furnace_boost_energy_consumption", 24, 16, 256);
chair_mob_sitting_probability_percent = builder
.translation(ModEngineersDecor.MODID + ".config.chair_mob_sitting_probability_percent")
.comment("Defines, in percent, how high the probability is that a mob sits on a chair " +
"when colliding with it. Can be changed on-the-fly for tuning.")
.defineInRange("chair_mob_sitting_probability_percent", 10.0, 0.0, 80.0);
chair_mob_standup_probability_percent = builder
.translation(ModEngineersDecor.MODID + ".config.chair_mob_standup_probability_percent")
.comment("Defines, in percent, probable it is that a mob leaves a chair when sitting " +
"on it. The 'dice is rolled' about every 20 ticks. There is also a minimum " +
"Sitting time of about 3s. The config value can be changed on-the-fly for tuning.")
.defineInRange("chair_mob_standup_probability_percent", 1.0, 1e-3, 10.0);
with_crafting_quickmove_buttons = builder
.translation(ModEngineersDecor.MODID + ".config.with_crafting_quickmove_buttons")
.comment("Enables small quick-move arrows from/to player/block storage. " +
"Makes the UI a bit too busy, therefore disabled by default.")
.define("with_crafting_quickmove_buttons", false);
pipevalve_max_flowrate = builder
.translation(ModEngineersDecor.MODID + ".config.pipevalve_max_flowrate")
.comment("Defines how many millibuckets can be transferred (per tick) through the valves. " +
"That is technically the 'storage size' specified for blocks that want to fill " +
"fluids into the valve (the valve has no container and forward that to the output " +
"block), The value can be changed on-the-fly for tuning. ")
.defineInRange("pipevalve_max_flowrate", 1000, 1, 10000);
pipevalve_redstone_gain = builder
.translation(ModEngineersDecor.MODID + ".config.pipevalve_redstone_gain")
.comment("Defines how many millibuckets per redstone signal strength can be transferred per tick " +
"through the analog redstone controlled valves. Note: power 0 is always off, power 15 is always " +
"the max flow rate. Between power 1 and 14 this scaler will result in a flow = 'redstone slope' * 'current redstone power'. " +
"The value can be changed on-the-fly for tuning. ")
.defineInRange("pipevalve_redstone_gain", 20, 1, 10000);
e_furnace_speed_percent = builder
.translation(ModEngineersDecor.MODID + ".config.e_furnace_speed_percent")
.comment("Defines, in percent, how fast the electrical furnace smelts compared to " +
"a vanilla furnace. 100% means vanilla furnace speed, 150% means the " +
"electrical furnace is faster. The value can be changed on-the-fly for tuning.")
.defineInRange("e_furnace_speed_percent", BlockDecorFurnaceElectrical.BTileEntity.DEFAULT_SPEED_PERCENT, 50, 500);
e_furnace_power_consumption = builder
.translation(ModEngineersDecor.MODID + ".config.e_furnace_power_consumption")
.comment("Defines how much RF per tick the the electrical furnace consumed (average) for smelting. " +
"The feeders transferring items from/to adjacent have this consumption/8 for each stack transaction. " +
"The default value is only slightly higher than a furnace with an IE external heater (and no burning fuel inside)." +
"The config value can be changed on-the-fly for tuning.")
.defineInRange("e_furnace_power_consumption", BlockDecorFurnaceElectrical.BTileEntity.DEFAULT_ENERGY_CONSUMPTION, 10, 256);
e_furnace_automatic_pulling = builder
.translation(ModEngineersDecor.MODID + ".config.e_furnace_automatic_pulling")
.comment("Defines if the electrical furnace automatically pulls items from an inventory at the input side." +
"The config value can be changed on-the-fly for tuning.")
.define("e_furnace_automatic_pulling", false);
small_solar_panel_peak_production = builder
.translation(ModEngineersDecor.MODID + ".config.small_solar_panel_peak_production")
.comment("Defines the peak power production (at noon) of the Small Solar Panel. " +
"Note that the agerage power is much less, as no power is produced at all during the night, " +
"and the power curve is nonlinear rising/falling during the day. Bad weather conditions also " +
"decrease the production. The config value can be changed on-the-fly for tuning.")
.defineInRange("small_solar_panel_peak_production", BlockDecorSolarPanel.BTileEntity.DEFAULT_PEAK_POWER, 10, 256);
block_breaker_power_consumption = builder
.translation(ModEngineersDecor.MODID + ".config.block_breaker_power_consumption")
.comment("Defines how much RF power the Small Block Breaker requires to magnificently increase the processing speed. " +
"The config value can be changed on-the-fly for tuning.")
.defineInRange("block_breaker_power_consumption", BlockDecorBreaker.BTileEntity.DEFAULT_BOOST_ENERGY, 16, 512);
block_breaker_reluctance = builder
.translation(ModEngineersDecor.MODID + ".config.block_breaker_reluctance")
.comment("Defines how much time the Small Block Breaker needs per block hardness, " +
"means: 'reluctance' * hardness + min_time, you change the 'reluctance' here." +
"The unit is ticks/hardness. " + "The config value can be changed on-the-fly for tuning.")
.defineInRange("block_breaker_reluctance", BlockDecorBreaker.BTileEntity.DEFAULT_BREAKING_RELUCTANCE, 5, 50);
block_breaker_min_breaking_time = builder
.translation(ModEngineersDecor.MODID + ".config.block_breaker_min_breaking_time")
.comment("Defines how much time the Small Block Breaker needs at least, better said it's an offset: " +
"'reluctance' * hardness + min_time, you change the 'min_time' here, value " +
"in ticks." + "The config value can be changed on-the-fly for tuning.")
.defineInRange("block_breaker_min_breaking_time", BlockDecorBreaker.BTileEntity.DEFAULT_MIN_BREAKING_TIME, 10, 100);
block_breaker_requires_power = builder
.translation(ModEngineersDecor.MODID + ".config.block_breaker_requires_power")
.comment("Defines if the Small Block Breaker does not work without RF power.")
.define("block_breaker_requires_power", false);
tree_cuttter_energy_consumption = builder
.translation(ModEngineersDecor.MODID + ".config.tree_cuttter_energy_consumption")
.comment("Defines how much RF power the Small Tree Cutter requires to magnificently increase the processing speed. " +
"The config value can be changed on-the-fly for tuning.")
.defineInRange("tree_cuttter_energy_consumption", BlockDecorTreeCutter.BTileEntity.DEFAULT_BOOST_ENERGY, 16, 512);
tree_cuttter_cutting_time_needed = builder
.translation(ModEngineersDecor.MODID + ".config.tree_cuttter_cutting_time_needed")
.comment("Defines how much time the Small Tree Cutter needs to cut a tree without RF power. " +
"The value is in seconds. With energy it is 6 times faster. " +
"The config value can be changed on-the-fly for tuning.")
.defineInRange("tree_cuttter_cutting_time_needed", BlockDecorTreeCutter.BTileEntity.DEFAULT_CUTTING_TIME_NEEDED, 10, 240);
tree_cuttter_requires_power = builder
.translation(ModEngineersDecor.MODID + ".config.tree_cuttter_requires_power")
.comment("Defines if the Small Tree Cutter does not work without RF power.")
.define("tree_cuttter_requires_power", false);
milking_machine_energy_consumption = builder
.translation(ModEngineersDecor.MODID + ".config.milking_machine_energy_consumption")
.comment("Defines how much time the Small Milking Machine needs work. " +
"Note this is a permanent standby power, not only when the device does something. " +
"Use zero to disable energy dependency and energy handling of the machine. " +
"The config value can be changed on-the-fly for tuning.")
.defineInRange("milking_machine_energy_consumption", BlockDecorMilker.BTileEntity.DEFAULT_ENERGY_CONSUMPTION, 0, 128);
builder.pop();
}
}
}
//--------------------------------------------------------------------------------------------------------------------
// Optout checks
//--------------------------------------------------------------------------------------------------------------------
public static final boolean isOptedOut(final @Nullable Block block)
{ return isOptedOut(block, false); }
public static final boolean isOptedOut(final @Nullable Block block, boolean with_log_details)
{
if(block == null) return true;
if(block == ModContent.SIGN_MODLOGO) return true;
if(COMMON == null) return false;
try {
if(!COMMON.with_experimental.get()) {
if(block instanceof ModAuxiliaries.IExperimentalFeature) return true;
if(ModContent.isExperimentalBlock(block)) return true;
}
final String rn = block.getRegistryName().getPath();
// Hard IE dependent blocks
if(!immersiveengineering_installed) {
if(block == ModContent.CONCRETE_WALL) return true;
if((block instanceof BlockDecor) && ((((BlockDecor)block).config & BlockDecor.CFG_HARD_IE_DEPENDENT) != 0)) return true;
}
// Force-include/exclude pattern matching
try {
for(String e:includes_) {
if(rn.matches(e)) {
if(with_log_details) ModEngineersDecor.logger().info("Optout force include: " + rn);
return false;
}
}
for(String e:excludes_) {
if(rn.matches(e)) {
if(with_log_details) ModEngineersDecor.logger().info("Optout force exclude: " + rn);
return true;
}
}
} catch(Throwable ex) {
ModEngineersDecor.logger().error("optout include pattern failed, disabling.");
includes_.clear();
excludes_.clear();
}
// Early non-opt out type based evaluation
if(block instanceof BlockDecorCraftingTable) return COMMON.without_crafting_table.get();
if(block instanceof BlockDecorFurnaceElectrical) return COMMON.without_electrical_furnace.get();
if((block instanceof BlockDecorFurnace) && (!(block instanceof BlockDecorFurnaceElectrical))) return COMMON.without_lab_furnace.get();
if(block instanceof BlockDecorPassiveFluidAccumulator) return COMMON.without_passive_fluid_accumulator.get();
if(block instanceof BlockDecorWasteIncinerator) return COMMON.without_waste_incinerator.get();
if(block instanceof BlockDecorDropper) return COMMON.without_factory_dropper.get();
if(block instanceof BlockDecorPlacer) return COMMON.without_factory_placer.get();
if(block instanceof BlockDecorBreaker) return COMMON.without_block_breaker.get();
if(block instanceof BlockDecorHalfSlab) return COMMON.without_halfslabs.get();
if(block instanceof BlockDecorLadder) return COMMON.without_ladders.get();
if(block instanceof BlockDecorWindow) return COMMON.without_windows.get();
if(block instanceof BlockDecorPipeValve) return COMMON.without_valves.get();
if(block instanceof BlockDecorHorizontalSupport) return COMMON.without_hsupports.get();
if(block instanceof BlockDecorFloorGrating) return COMMON.without_floor_grating.get();
if(block instanceof BlockDecorHopper) return COMMON.without_factory_hopper.get();
if(block instanceof BlockDecorFluidFunnel) return COMMON.without_fluid_funnel.get();
if(block instanceof BlockDecorSolarPanel) return COMMON.without_solar_panel.get();
if(block instanceof BlockDecorMineralSmelter) return COMMON.without_mineral_smelter.get();
if(block instanceof BlockDecorMilker) return COMMON.without_milking_machine.get();
// Type based evaluation where later filters may match, too
if(COMMON.without_slabs.get() && (block instanceof BlockDecorSlab)) return true;
if(COMMON.without_stairs.get() && (block instanceof BlockDecorStairs)) return true;
if(COMMON.without_walls.get() && (block instanceof BlockDecorWall)) return true;
if(COMMON.without_poles.get() && (block instanceof BlockDecorStraightPole)) return true;
// String matching based evaluation
if(COMMON.without_clinker_bricks.get() && (rn.startsWith("clinker_brick_"))) return true;
if(COMMON.without_slag_bricks.get() && rn.startsWith("slag_brick_")) return true;
if(COMMON.without_rebar_concrete.get() && rn.startsWith("rebar_concrete")) return true;
if(COMMON.without_ie_concrete_wall.get() && rn.startsWith("concrete_wall")) return true;
if(COMMON.without_panzer_glass.get() && rn.startsWith("panzerglass_")) return true;
if(COMMON.without_light_sources.get() && rn.endsWith("_light")) return true;
if(COMMON.without_sign_plates.get() && rn.startsWith("sign_")) return true;
if(COMMON.without_treated_wood_furniture.get()) {
if(block instanceof BlockDecorChair) return true;
if(rn.equals("treated_wood_table")) return true;
if(rn.equals("treated_wood_stool")) return true;
if(rn.equals("treated_wood_windowsill")) return true;
}
} catch(Exception ex) {
ModEngineersDecor.logger().error("Exception evaluating the optout config: '" + ex.getMessage() + "'");
}
return false;
}
public static final boolean isOptedOut(final @Nullable Item item)
{
if(item == null) return true;
if(SERVER == null) return false;
return false;
}
public static boolean withExperimental()
{ return with_experimental_features_; }
public static boolean withoutRecipes()
{ return without_recipes_; }
//--------------------------------------------------------------------------------------------------------------------
// Cache
//--------------------------------------------------------------------------------------------------------------------
private static final ArrayList<String> includes_ = new ArrayList<String>();
private static final ArrayList<String> excludes_ = new ArrayList<String>();
private static final CompoundNBT server_config_ = new CompoundNBT();
public static boolean without_crafting_table = false;
public static boolean immersiveengineering_installed = false;
public static boolean without_direct_slab_pickup = false;
public static boolean with_creative_mode_device_drops = false;
private static boolean with_experimental_features_ = false;
private static boolean without_recipes_ = false;
public static final CompoundNBT getServerConfig() // config that may be synchronized from server to client via net pkg.
{ return server_config_; }
public static final void apply()
{
BlockDecorFurnace.BTileEntity.on_config(COMMON.furnace_smelting_speed_percent.get(), COMMON.furnace_fuel_efficiency_percent.get(), COMMON.furnace_boost_energy_consumption.get());
BlockDecorChair.on_config(COMMON.without_chair_sitting.get(), COMMON.without_mob_chair_sitting.get(), COMMON.chair_mob_sitting_probability_percent.get(), COMMON.chair_mob_standup_probability_percent.get());
BlockDecorLadder.on_config(COMMON.without_ladder_speed_boost.get());
BlockDecorCraftingTable.on_config(COMMON.without_crafting_table_history.get(), false, COMMON.with_crafting_quickmove_buttons.get());
BlockDecorPipeValve.on_config(COMMON.pipevalve_max_flowrate.get(), COMMON.pipevalve_redstone_gain.get());
BlockDecorFurnaceElectrical.BTileEntity.on_config(COMMON.e_furnace_speed_percent.get(), COMMON.e_furnace_power_consumption.get(), COMMON.e_furnace_automatic_pulling.get());
BlockDecorSolarPanel.BTileEntity.on_config(COMMON.small_solar_panel_peak_production.get());
BlockDecorBreaker.BTileEntity.on_config(COMMON.block_breaker_power_consumption.get(), COMMON.block_breaker_reluctance.get(), COMMON.block_breaker_min_breaking_time.get(), COMMON.block_breaker_requires_power.get());
BlockDecorTreeCutter.BTileEntity.on_config(COMMON.tree_cuttter_energy_consumption.get(), COMMON.tree_cuttter_cutting_time_needed.get(), COMMON.tree_cuttter_requires_power.get());
BlockDecorMilker.BTileEntity.on_config(COMMON.milking_machine_energy_consumption.get());
without_crafting_table = isOptedOut(ModContent.TREATED_WOOD_CRAFTING_TABLE);
immersiveengineering_installed = ModAuxiliaries.isModLoaded("immersiveengineering");
with_experimental_features_ = COMMON.with_experimental.get();
without_recipes_ = COMMON.without_recipes.get();
without_direct_slab_pickup = COMMON.without_direct_slab_pickup.get();
if(with_experimental_features_) {
ModEngineersDecor.logger().info("Config: EXPERIMENTAL FEATURES ENABLED.");
}
{
String inc = COMMON.pattern_includes.get().toLowerCase().replaceAll(ModEngineersDecor.MODID+":", "").replaceAll("[^*_,a-z0-9]", "");
if(COMMON.pattern_includes.get() != inc) COMMON.pattern_includes.set(inc);
if(!inc.isEmpty()) ModEngineersDecor.logger().info("Config pattern includes: '" + inc + "'");
String[] incl = inc.split(",");
includes_.clear();
for(int i=0; i< incl.length; ++i) {
incl[i] = incl[i].replaceAll("[*]", ".*?");
if(!incl[i].isEmpty()) includes_.add(incl[i]);
}
}
{
String exc = COMMON.pattern_includes.get().toLowerCase().replaceAll(ModEngineersDecor.MODID+":", "").replaceAll("[^*_,a-z0-9]", "");
if(!exc.isEmpty()) ModEngineersDecor.logger().info("Config pattern excludes: '" + exc + "'");
String[] excl = exc.split(",");
excludes_.clear();
for(int i=0; i< excl.length; ++i) {
excl[i] = excl[i].replaceAll("[*]", ".*?");
if(!excl[i].isEmpty()) excludes_.add(excl[i]);
}
}
{
// Check if the config is already synchronized or has to be synchronised.
server_config_.putBoolean("tree_cuttter_requires_power", COMMON.tree_cuttter_requires_power.get());
server_config_.putBoolean("block_breaker_requires_power", COMMON.block_breaker_requires_power.get());
}
}
}

View file

@ -0,0 +1,137 @@
/*
* @file ModTesrs.java
* @author Stefan Wilhelm (wile)
* @copyright (C) 2018 Stefan Wilhelm
* @license MIT (see https://opensource.org/licenses/MIT)
*
* Yet unstructured initial experiments with TESRs.
* May be structured after I know what I am doing there.
*/
package wile.engineersdecor.detail;
import wile.engineersdecor.ModEngineersDecor;
import wile.engineersdecor.blocks.BlockDecorChair;
import wile.engineersdecor.blocks.BlockDecorCraftingTable;
import net.minecraft.block.BlockState;
import net.minecraft.client.renderer.*;
import net.minecraft.client.renderer.entity.EntityRenderer;
import net.minecraft.client.renderer.entity.EntityRendererManager;
import net.minecraft.client.renderer.model.ModelManager;
import net.minecraft.client.renderer.model.ModelResourceLocation;
import net.minecraft.client.renderer.texture.AtlasTexture;
import net.minecraft.client.renderer.texture.OverlayTexture;
import net.minecraft.entity.Entity;
import net.minecraft.entity.item.ItemFrameEntity;
import net.minecraft.item.FilledMapItem;
import net.minecraft.util.Direction;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.storage.MapData;
import net.minecraft.client.renderer.tileentity.TileEntityRenderer;
import net.minecraft.client.Minecraft;
import net.minecraft.item.ItemStack;
import net.minecraft.util.math.MathHelper;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import com.mojang.blaze3d.platform.GlStateManager;
import com.mojang.blaze3d.matrix.MatrixStack;
public class ModRenderers
{
//--------------------------------------------------------------------------------------------------------------------
// InvisibleEntityRenderer
//--------------------------------------------------------------------------------------------------------------------
@OnlyIn(Dist.CLIENT)
public static class InvisibleEntityRenderer<T extends Entity> extends EntityRenderer<T>
{
private final Minecraft mc = Minecraft.getInstance();
public InvisibleEntityRenderer(EntityRendererManager renderManagerIn)
{ super(renderManagerIn); }
public void func_225623_a_/*render*/(T p_225623_1_, float p_225623_2_, float p_225623_3_, MatrixStack p_225623_4_, IRenderTypeBuffer p_225623_5_, int p_225623_6_)
{}
public Vec3d func_225627_b_/*likely getOffset*/(T p_225627_1_, float p_225627_2_)
{ return Vec3d.ZERO; }
@SuppressWarnings("deprecation")
public ResourceLocation getEntityTexture(T entity)
{ return AtlasTexture.LOCATION_BLOCKS_TEXTURE; }
protected boolean canRenderName(T entity)
{ return false; }
protected void func_225629_a_/*renderName/renderLabel*/(T p_225629_1_, String p_225629_2_, MatrixStack p_225629_3_, IRenderTypeBuffer p_225629_4_, int p_225629_5_)
{}
}
//--------------------------------------------------------------------------------------------------------------------
// Crafting table
//--------------------------------------------------------------------------------------------------------------------
/*
@OnlyIn(Dist.CLIENT)
public static class TesrDecorCraftingTable extends TileEntityRenderer<BlockDecorCraftingTable.BTileEntity>
{
private static int tesr_error_counter = 4;
private static double scaler = 0.10;
private static double gap = 0.19;
private static double yrotations[] = {0, 90, 180, 270}; // [hdirection] S-W-N-E
private static double offsets[][][] = { // [hdirection][slotindex][xz]
{ {-1,-1},{+0,-1},{+1,-1}, {-1,+0},{+0,+0},{+1,+0}, {-1,+1},{+0,+1},{+1,+1} }, // S
{ {+1,-1},{+1,+0},{+1,+1}, {+0,-1},{+0,+0},{+0,+1}, {-1,-1},{-1,+0},{-1,+1} }, // W
{ {+1,+1},{+0,+1},{-1,+1}, {+1,+0},{+0,+0},{-1,+0}, {+1,-1},{+0,-1},{-1,-1} }, // N
{ {-1,+1},{-1,+0},{-1,-1}, {+0,+1},{+0,+0},{+0,-1}, {+1,+1},{+1,+0},{+1,-1} }, // E
};
@Override
public void func_225616_a_(final BlockDecorCraftingTable.BTileEntity te, float p_225616_2_, MatrixStack p_225616_3_, IRenderTypeBuffer p_225616_4_, int p_225616_5_, int p_225616_6_)
{
render(final BlockDecorCraftingTable.BTileEntity te, double x, double y, double z, float partialTicks, int destroyStage);
}
@SuppressWarnings("deprecation")
public void render(final BlockDecorCraftingTable.BTileEntity te, double x, double y, double z, float partialTicks, int destroyStage)
{
if(tesr_error_counter<=0) return;
try {
int di = MathHelper.clamp(te.getWorld().getBlockState(te.getPos()).get(BlockDecorCraftingTable.FACING).getHorizontalIndex(), 0, 3);
long posrnd = te.getPos().toLong();
posrnd = (posrnd>>16)^(posrnd<<1);
for(int i=0; i<9; ++i) {
final ItemStack stack = te.getStackInSlot(i);
if(stack.isEmpty()) continue;
double prnd = ((double)(((Integer.rotateRight(stack.getItem().hashCode()^(int)posrnd,(stack.getCount()+i)&31)))&1023))/1024.0;
double rndo = gap * ((prnd*0.1)-0.05);
double ox = gap * offsets[di][i][0], oz = gap * offsets[di][i][1];
double oy = 0.5;
double ry = ((yrotations[di]+180) + ((prnd*60)-30)) % 360;
if(stack.isEmpty()) return;
GlStateManager.pushMatrix();
GlStateManager.disableLighting();
RenderHelper.enableStandardItemLighting();
GlStateManager.translated(x+0.5+ox, y+0.5+oy, z+0.5+oz);
GlStateManager.rotated(90, 1, 0, 0);
GlStateManager.rotated(ry, 0, 0, 1);
GlStateManager.translated(rndo, rndo, 0);
GlStateManager.scaled(scaler, scaler, scaler);
Minecraft.getInstance().getItemRenderer().renderItem(stack, net.minecraft.client.renderer.model.ItemCameraTransforms.TransformType.FIXED);
RenderHelper.disableStandardItemLighting();
GlStateManager.enableLighting();
GlStateManager.popMatrix();
}
} catch(Throwable e) {
if(--tesr_error_counter<=0) {
ModEngineersDecor.logger().error("TESR was disabled because broken, exception was: " + e.getMessage());
ModEngineersDecor.logger().error(e.getStackTrace());
}
}
}
}
*/
}

View file

@ -0,0 +1,245 @@
/*
* @file Networking.java
* @author Stefan Wilhelm (wile)
* @copyright (C) 2019 Stefan Wilhelm
* @license MIT (see https://opensource.org/licenses/MIT)
*
* Main client/server message handling.
*/
package wile.engineersdecor.detail;
import wile.engineersdecor.ModEngineersDecor;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.common.util.FakePlayer;
import net.minecraftforge.fml.network.NetworkEvent;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.world.World;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.player.ServerPlayerEntity;
import net.minecraft.util.math.BlockPos;
import net.minecraft.inventory.container.Container;
import net.minecraft.network.PacketBuffer;
import net.minecraftforge.fml.network.NetworkRegistry;
import net.minecraftforge.fml.network.simple.SimpleChannel;
import net.minecraftforge.fml.network.NetworkDirection;
import java.util.function.Supplier;
public class Networking
{
private static final String PROTOCOL = "1";
private static final SimpleChannel DEFAULT_CHANNEL = NetworkRegistry.ChannelBuilder
.named(new ResourceLocation(ModEngineersDecor.MODID, "default_ch"))
.clientAcceptedVersions(PROTOCOL::equals).serverAcceptedVersions(PROTOCOL::equals).networkProtocolVersion(() -> PROTOCOL)
.simpleChannel();
public static void init()
{
int discr = -1;
DEFAULT_CHANNEL.registerMessage(++discr, PacketTileNotifyClientToServer.class, PacketTileNotifyClientToServer::compose, PacketTileNotifyClientToServer::parse, PacketTileNotifyClientToServer.Handler::handle);
DEFAULT_CHANNEL.registerMessage(++discr, PacketTileNotifyServerToClient.class, PacketTileNotifyServerToClient::compose, PacketTileNotifyServerToClient::parse, PacketTileNotifyServerToClient.Handler::handle);
DEFAULT_CHANNEL.registerMessage(++discr, PacketContainerSyncClientToServer.class, PacketContainerSyncClientToServer::compose, PacketContainerSyncClientToServer::parse, PacketContainerSyncClientToServer.Handler::handle);
DEFAULT_CHANNEL.registerMessage(++discr, PacketContainerSyncServerToClient.class, PacketContainerSyncServerToClient::compose, PacketContainerSyncServerToClient::parse, PacketContainerSyncServerToClient.Handler::handle);
}
//--------------------------------------------------------------------------------------------------------------------
// Tile entity notifications
//--------------------------------------------------------------------------------------------------------------------
public interface IPacketTileNotifyReceiver
{
default void onServerPacketReceived(CompoundNBT nbt) {}
default void onClientPacketReceived(PlayerEntity player, CompoundNBT nbt) {}
}
public static class PacketTileNotifyClientToServer
{
CompoundNBT nbt = null;
BlockPos pos = BlockPos.ZERO;
public static void sendToServer(BlockPos pos, CompoundNBT nbt)
{ if((pos!=null) && (nbt!=null)) DEFAULT_CHANNEL.sendToServer(new PacketTileNotifyClientToServer(pos, nbt)); }
public static void sendToServer(TileEntity te, CompoundNBT nbt)
{ if((te!=null) && (nbt!=null)) DEFAULT_CHANNEL.sendToServer(new PacketTileNotifyClientToServer(te, nbt)); }
public PacketTileNotifyClientToServer()
{}
public PacketTileNotifyClientToServer(BlockPos pos, CompoundNBT nbt)
{ this.nbt = nbt; this.pos = pos; }
public PacketTileNotifyClientToServer(TileEntity te, CompoundNBT nbt)
{ this.nbt = nbt; pos = te.getPos(); }
public static PacketTileNotifyClientToServer parse(final PacketBuffer buf)
{ return new PacketTileNotifyClientToServer(buf.readBlockPos(), buf.readCompoundTag()); }
public static void compose(final PacketTileNotifyClientToServer pkt, final PacketBuffer buf)
{ buf.writeBlockPos(pkt.pos); buf.writeCompoundTag(pkt.nbt); }
public static class Handler
{
public static void handle(final PacketTileNotifyClientToServer pkt, final Supplier<NetworkEvent.Context> ctx)
{
ctx.get().enqueueWork(() -> {
PlayerEntity player = ctx.get().getSender();
World world = player.world;
if(world == null) return;
final TileEntity te = world.getTileEntity(pkt.pos);
if(!(te instanceof IPacketTileNotifyReceiver)) return;
((IPacketTileNotifyReceiver)te).onClientPacketReceived(ctx.get().getSender(), pkt.nbt);
});
ctx.get().setPacketHandled(true);
}
}
}
public static class PacketTileNotifyServerToClient
{
CompoundNBT nbt = null;
BlockPos pos = BlockPos.ZERO;
public static void sendToPlayer(PlayerEntity player, TileEntity te, CompoundNBT nbt)
{
if((!(player instanceof ServerPlayerEntity)) || (player instanceof FakePlayer) || (te==null) || (nbt==null)) return;
DEFAULT_CHANNEL.sendTo(new PacketTileNotifyServerToClient(te, nbt), ((ServerPlayerEntity)player).connection.netManager, NetworkDirection.PLAY_TO_CLIENT);
}
public PacketTileNotifyServerToClient()
{}
public PacketTileNotifyServerToClient(BlockPos pos, CompoundNBT nbt)
{ this.nbt=nbt; this.pos=pos; }
public PacketTileNotifyServerToClient(TileEntity te, CompoundNBT nbt)
{ this.nbt=nbt; pos=te.getPos(); }
public static PacketTileNotifyServerToClient parse(final PacketBuffer buf)
{ return new PacketTileNotifyServerToClient(buf.readBlockPos(), buf.readCompoundTag()); }
public static void compose(final PacketTileNotifyServerToClient pkt, final PacketBuffer buf)
{ buf.writeBlockPos(pkt.pos); buf.writeCompoundTag(pkt.nbt); }
public static class Handler
{
public static void handle(final PacketTileNotifyServerToClient pkt, final Supplier<NetworkEvent.Context> ctx)
{
ctx.get().enqueueWork(() -> {
World world = ModEngineersDecor.proxy.getWorldClientSide();
if(world == null) return;
final TileEntity te = world.getTileEntity(pkt.pos);
if(!(te instanceof IPacketTileNotifyReceiver)) return;
((IPacketTileNotifyReceiver)te).onServerPacketReceived(pkt.nbt);
});
ctx.get().setPacketHandled(true);
}
}
}
//--------------------------------------------------------------------------------------------------------------------
// (GUI) Container synchrsonisation
//--------------------------------------------------------------------------------------------------------------------
public interface INetworkSynchronisableContainer
{
void onServerPacketReceived(int windowId, CompoundNBT nbt);
void onClientPacketReceived(int windowId, PlayerEntity player, CompoundNBT nbt);
}
public static class PacketContainerSyncClientToServer
{
int id = -1;
CompoundNBT nbt = null;
public static void sendToServer(int windowId, CompoundNBT nbt)
{ if(nbt!=null) DEFAULT_CHANNEL.sendToServer(new PacketContainerSyncClientToServer(windowId, nbt)); }
public static void sendToServer(Container container, CompoundNBT nbt)
{ if(nbt!=null) DEFAULT_CHANNEL.sendToServer(new PacketContainerSyncClientToServer(container.windowId, nbt)); }
public PacketContainerSyncClientToServer()
{}
public PacketContainerSyncClientToServer(int id, CompoundNBT nbt)
{ this.nbt = nbt; this.id = id; }
public static PacketContainerSyncClientToServer parse(final PacketBuffer buf)
{ return new PacketContainerSyncClientToServer(buf.readInt(), buf.readCompoundTag()); }
public static void compose(final PacketContainerSyncClientToServer pkt, final PacketBuffer buf)
{ buf.writeInt(pkt.id); buf.writeCompoundTag(pkt.nbt); }
public static class Handler
{
public static void handle(final PacketContainerSyncClientToServer pkt, final Supplier<NetworkEvent.Context> ctx)
{
ctx.get().enqueueWork(() -> {
PlayerEntity player = ctx.get().getSender();
if(!(player.openContainer instanceof INetworkSynchronisableContainer)) return;
if(player.openContainer.windowId != pkt.id) return;
((INetworkSynchronisableContainer)player.openContainer).onClientPacketReceived(pkt.id, player,pkt.nbt);
});
ctx.get().setPacketHandled(true);
}
}
}
public static class PacketContainerSyncServerToClient
{
int id = -1;
CompoundNBT nbt = null;
public static void sendToPlayer(PlayerEntity player, int windowId, CompoundNBT nbt)
{
if((!(player instanceof ServerPlayerEntity)) || (player instanceof FakePlayer) || (nbt==null)) return;
DEFAULT_CHANNEL.sendTo(new PacketContainerSyncServerToClient(windowId, nbt), ((ServerPlayerEntity)player).connection.netManager, NetworkDirection.PLAY_TO_CLIENT);
}
public static void sendToPlayer(PlayerEntity player, Container container, CompoundNBT nbt)
{
if((!(player instanceof ServerPlayerEntity)) || (player instanceof FakePlayer) || (nbt==null)) return;
DEFAULT_CHANNEL.sendTo(new PacketContainerSyncServerToClient(container.windowId, nbt), ((ServerPlayerEntity)player).connection.netManager, NetworkDirection.PLAY_TO_CLIENT);
}
// Container listners are private, and add/remove listener overriding seems not too nice, as
// removeListner is client only???
//public static <C extends Container & INetworkSynchronisableContainer> void sendToListeners(C container, CompoundNBT nbt)
//{
// for(IContainerListener listener: container.getListeners()) {
// if(!(listener instanceof ServerPlayerEntity)) continue;
// DEFAULT_CHANNEL.sendTo(new PacketContainerSyncServerToClient(container.windowId, nbt), ((ServerPlayerEntity)listener).connection.netManager, NetworkDirection.PLAY_TO_CLIENT);
// }
//}
public PacketContainerSyncServerToClient()
{}
public PacketContainerSyncServerToClient(int id, CompoundNBT nbt)
{ this.nbt=nbt; this.id=id; }
public static PacketContainerSyncServerToClient parse(final PacketBuffer buf)
{ return new PacketContainerSyncServerToClient(buf.readInt(), buf.readCompoundTag()); }
public static void compose(final PacketContainerSyncServerToClient pkt, final PacketBuffer buf)
{ buf.writeInt(pkt.id); buf.writeCompoundTag(pkt.nbt); }
public static class Handler
{
public static void handle(final PacketContainerSyncServerToClient pkt, final Supplier<NetworkEvent.Context> ctx)
{
ctx.get().enqueueWork(() -> {
PlayerEntity player = ModEngineersDecor.proxy.getPlayerClientSide();
if(!(player.openContainer instanceof INetworkSynchronisableContainer)) return;
if(player.openContainer.windowId != pkt.id) return;
((INetworkSynchronisableContainer)player.openContainer).onServerPacketReceived(pkt.id,pkt.nbt);
});
ctx.get().setPacketHandled(true);
}
}
}
}

View file

@ -0,0 +1,126 @@
/*
* @file OptionalRecipeCondition.java
* @author Stefan Wilhelm (wile)
* @copyright (C) 2018 Stefan Wilhelm
* @license MIT (see https://opensource.org/licenses/MIT)
*
* Recipe condition to enable opt'ing out JSON based recipes.
*/
package wile.engineersdecor.detail;
import wile.engineersdecor.ModEngineersDecor;
import net.minecraft.block.Block;
import net.minecraft.item.Item;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.JSONUtils;
import net.minecraftforge.common.crafting.conditions.ICondition;
import net.minecraftforge.common.crafting.conditions.IConditionSerializer;
import net.minecraftforge.registries.IForgeRegistry;
import net.minecraftforge.registries.ForgeRegistries;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;
public class OptionalRecipeCondition implements ICondition
{
private static final ResourceLocation NAME = new ResourceLocation(ModEngineersDecor.MODID, "optional");
private final List<ResourceLocation> all_required;
private final List<ResourceLocation> any_missing;
private final @Nullable ResourceLocation result;
private final boolean experimental;
public OptionalRecipeCondition(ResourceLocation result, List<ResourceLocation> required, List<ResourceLocation> missing, boolean isexperimental)
{ all_required = required; any_missing = missing; this.result = result; experimental=isexperimental; }
@Override
public ResourceLocation getID()
{ return NAME; }
@Override
public String toString()
{
StringBuilder sb = new StringBuilder();
sb.append("Optional recipe, all-required: [");
for(ResourceLocation e:all_required) sb.append(e.toString()).append(",");
sb.delete(sb.length()-1, sb.length()).append("], any-missing: [");
for(ResourceLocation e:any_missing) sb.append(e.toString()).append(",");
sb.delete(sb.length()-1, sb.length()).append("]");
if(experimental) sb.append(" EXPERIMENTAL");
return sb.toString();
}
@Override
public boolean test()
{
if(ModConfig.withoutRecipes()) return false;
if((experimental) && (!ModConfig.withExperimental())) return false;
final IForgeRegistry<Block> block_registry = ForgeRegistries.BLOCKS;
final IForgeRegistry<Item> item_registry = ForgeRegistries.ITEMS;
if(result != null) {
boolean item_registered = item_registry.containsKey(result);
boolean block_registered = block_registry.containsKey(result);
if((!block_registered) && (!item_registered)) return false; // required result not registered
if(item_registered && ModConfig.isOptedOut(item_registry.getValue(result))) return false;
if(block_registered && ModConfig.isOptedOut(block_registry.getValue(result))) return false;
}
if(!all_required.isEmpty()) {
for(ResourceLocation rl:all_required) {
if((!block_registry.containsKey(rl)) && (!item_registry.containsKey(rl))) return false;
}
}
if(!any_missing.isEmpty()) {
for(ResourceLocation rl:any_missing) {
// At least one item missing, enable this recipe as alternative recipe for another one that check the missing item as required item.
// --> e.g. if IE not installed there is no slag. One recipe requires slag, and another one (for the same result) is used if there
// is no slag.
if((!block_registry.containsKey(rl)) && (!item_registry.containsKey(rl))) return true;
}
return false;
}
return true;
}
public static class Serializer implements IConditionSerializer<OptionalRecipeCondition>
{
public static final Serializer INSTANCE = new Serializer();
@Override
public ResourceLocation getID()
{ return OptionalRecipeCondition.NAME; }
@Override
public void write(JsonObject json, OptionalRecipeCondition condition)
{
JsonArray required = new JsonArray();
JsonArray missing = new JsonArray();
for(ResourceLocation e:condition.all_required) required.add(e.toString());
for(ResourceLocation e:condition.any_missing) missing.add(e.toString());
json.add("required", required);
json.add("missing", missing);
if(condition.result != null) json.addProperty("result", condition.result.toString());
}
@Override
public OptionalRecipeCondition read(JsonObject json)
{
List<ResourceLocation> required = new ArrayList<>();
List<ResourceLocation> missing = new ArrayList<>();
ResourceLocation result = null;
boolean experimental = false;
if(json.has("result")) result = new ResourceLocation(json.get("result").getAsString());
if(json.has("required")) {
for(JsonElement e:JSONUtils.getJsonArray(json, "required")) required.add(new ResourceLocation(e.getAsString()));
}
if(json.has("missing")) {
for(JsonElement e:JSONUtils.getJsonArray(json, "missing")) missing.add(new ResourceLocation(e.getAsString()));
}
if(json.has("experimental")) experimental = json.get("experimental").getAsBoolean();
return new OptionalRecipeCondition(result, required, missing, experimental);
}
}
}

View file

@ -0,0 +1,176 @@
/*
* @file TreeCutting.java
* @author Stefan Wilhelm (wile)
* @copyright (C) 2019 Stefan Wilhelm
* @license MIT (see https://opensource.org/licenses/MIT)
*
* Simple tree cutting algorithm.
*/
package wile.engineersdecor.detail;
import net.minecraft.block.*;
import net.minecraft.util.ResourceLocation;
import wile.engineersdecor.ModEngineersDecor;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3i;
import net.minecraft.world.World;
import com.google.common.collect.ImmutableList;
import java.util.*;
public class TreeCutting
{
private static org.apache.logging.log4j.Logger LOGGER = ModEngineersDecor.logger();
public static boolean canChop(BlockState state)
{ return isLog(state); }
// -------------------------------------------------------------------------------------------------------------------
private static final List<Vec3i> hoffsets = ImmutableList.of(
new Vec3i( 1,0, 0), new Vec3i( 1,0, 1), new Vec3i( 0,0, 1),
new Vec3i(-1,0, 1), new Vec3i(-1,0, 0), new Vec3i(-1,0,-1),
new Vec3i( 0,0,-1), new Vec3i( 1,0,-1)
);
private static boolean isLog(BlockState state)
{ return (state.getBlock() instanceof LogBlock) || (state.getBlock().getTags().contains(new ResourceLocation("minecraft","logs"))); }
private static boolean isSameLog(BlockState a, BlockState b)
{ return (a.getBlock()==b.getBlock()); }
private static boolean isLeaves(BlockState state)
{
if(state.getBlock() instanceof LeavesBlock) return true;
if(state.getBlock().getTags().contains(new ResourceLocation("minecraft","leaves"))) return true;
return false;
}
private static List<BlockPos> findBlocksAround(final World world, final BlockPos centerPos, final BlockState leaf_type_state, final Set<BlockPos> checked, int recursion_left)
{
ArrayList<BlockPos> to_decay = new ArrayList<BlockPos>();
for(int y=-1; y<=1; ++y) {
final BlockPos layer = centerPos.add(0,y,0);
for(Vec3i v:hoffsets) {
BlockPos pos = layer.add(v);
if((!checked.contains(pos)) && (world.getBlockState(pos).getBlock()==leaf_type_state.getBlock())) {
checked.add(pos);
to_decay.add(pos);
if(recursion_left > 0) {
to_decay.addAll(findBlocksAround(world, pos, leaf_type_state, checked, recursion_left-1));
}
}
}
}
return to_decay;
}
private static void breakBlock(World world, BlockPos pos)
{
Block.spawnDrops(world.getBlockState(pos), world, pos);
if(world.setBlockState(pos, world.getFluidState(pos).getBlockState(), 1|2|8)) {} //state.getBlock().onPlayerDestroy(world, pos, state);
}
public static int chopTree(World world, BlockState broken_state, BlockPos startPos, int max_blocks_to_break, boolean without_target_block)
{
if(world.isRemote || !isLog(broken_state)) return 0;
final long ymin = startPos.getY();
final long max_leaf_distance = 6;
Set<BlockPos> checked = new HashSet<BlockPos>();
ArrayList<BlockPos> to_break = new ArrayList<BlockPos>();
ArrayList<BlockPos> to_decay = new ArrayList<BlockPos>();
checked.add(startPos);
// Initial simple layer-up search of same logs. This forms the base corpus, and only leaves and
// leaf-enclosed logs attached to this corpus may be broken/decayed.
{
LinkedList<BlockPos> queue = new LinkedList<BlockPos>();
LinkedList<BlockPos> upqueue = new LinkedList<BlockPos>();
queue.add(startPos);
int cutlevel = 0;
int steps_left = 64;
while(!queue.isEmpty() && (--steps_left >= 0)) {
final BlockPos pos = queue.removeFirst();
// Vertical search
final BlockPos uppos = pos.up();
final BlockState upstate = world.getBlockState(uppos);
if(!checked.contains(uppos)) {
checked.add(uppos);
if(isSameLog(upstate, broken_state)) {
// Up is log
upqueue.add(uppos);
to_break.add(uppos);
steps_left = 64;
} else {
boolean isleaf = isLeaves(upstate);
if(isleaf || world.isAirBlock(uppos) || (upstate.getBlock() instanceof VineBlock)) {
if(isleaf) to_decay.add(uppos);
// Up is air, check adjacent for diagonal up (e.g. Accacia)
for(Vec3i v:hoffsets) {
final BlockPos p = uppos.add(v);
if(checked.contains(p)) continue;
checked.add(p);
final BlockState st = world.getBlockState(p);
final Block bl = st.getBlock();
if(isSameLog(st, broken_state)) {
queue.add(p);
to_break.add(p);
} else if(isLeaves(st)) {
to_decay.add(p);
}
}
}
}
}
// Lateral search
for(Vec3i v:hoffsets) {
final BlockPos p = pos.add(v);
if(checked.contains(p)) continue;
checked.add(p);
if(p.distanceSq(new BlockPos(startPos.getX(), p.getY(), startPos.getZ())) > (3+cutlevel*cutlevel)) continue;
final BlockState st = world.getBlockState(p);
final Block bl = st.getBlock();
if(isSameLog(st, broken_state)) {
queue.add(p);
to_break.add(p);
} else if(isLeaves(st)) {
to_decay.add(p);
}
}
if(queue.isEmpty() && (!upqueue.isEmpty())) {
queue = upqueue;
upqueue = new LinkedList<BlockPos>();
++cutlevel;
}
}
}
{
// Determine lose logs between the leafs
for(BlockPos pos:to_decay) {
int dist = 1;
to_break.addAll(findBlocksAround(world, pos, broken_state, checked, dist));
}
}
if(!to_decay.isEmpty()) {
final BlockState leaf_type_state = world.getBlockState(to_decay.get(0));
final ArrayList<BlockPos> leafs = to_decay;
to_decay = new ArrayList<BlockPos>();
for(BlockPos pos:leafs) {
int dist = 2;
to_decay.add(pos);
to_decay.addAll(findBlocksAround(world, pos, leaf_type_state, checked, dist));
}
}
if(without_target_block) {
checked.remove(startPos);
} else {
to_break.add(startPos);
}
for(BlockPos pos:to_break) breakBlock(world, pos);
for(BlockPos pos:to_decay) breakBlock(world, pos);
{
// And now the bill.
return MathHelper.clamp(((to_break.size()*6/5)+(to_decay.size()/10)-1), 1, 65535);
}
}
}

View file

@ -0,0 +1,66 @@
/*
* @file JEIPlugin.java
* @author Stefan Wilhelm (wile)
* @copyright (C) 2019 Stefan Wilhelm
* @license MIT (see https://opensource.org/licenses/MIT)
*
* JEI plugin (see https://github.com/mezz/JustEnoughItems/wiki/Creating-Plugins)
*/
package wile.engineersdecor.eapi.jei;
public class JEIPlugin {}
/*
import mezz.jei.api.constants.VanillaRecipeCategoryUid;
import mezz.jei.api.registration.IRecipeTransferRegistration;
import wile.engineersdecor.ModEngineersDecor;
import wile.engineersdecor.blocks.BlockDecorCraftingTable;
import wile.engineersdecor.detail.ModConfig;
import wile.engineersdecor.ModContent;
import mezz.jei.api.constants.VanillaTypes;
import mezz.jei.api.runtime.IJeiRuntime;
import net.minecraft.block.Block;
import net.minecraft.item.ItemStack;
import net.minecraft.util.ResourceLocation;
import java.util.ArrayList;
import java.util.List;
@mezz.jei.api.JeiPlugin
public class JEIPlugin implements mezz.jei.api.IModPlugin
{
@Override
public ResourceLocation getPluginUid()
{ return new ResourceLocation(ModEngineersDecor.MODID, "jei_plugin_uid"); }
@Override
public void registerRecipeTransferHandlers(IRecipeTransferRegistration registration)
{
if(!ModConfig.without_crafting_table) {
try {
registration.addRecipeTransferHandler(
BlockDecorCraftingTable.BContainer.class,
VanillaRecipeCategoryUid.CRAFTING,
1, 9, 10, 44
);
} catch(Throwable e) {
ModEngineersDecor.logger().warn("Exception in JEI crafting table handler registration: '" + e.getMessage() + "'.");
}
}
}
@Override
public void onRuntimeAvailable(IJeiRuntime jeiRuntime)
{
List<ItemStack> blacklisted = new ArrayList<>();
for(Block e: ModContent.getRegisteredBlocks()) {
if(ModConfig.isOptedOut(e)) {
blacklisted.add(new ItemStack(e.asItem()));
}
}
try {
jeiRuntime.getIngredientManager().removeIngredientsAtRuntime(VanillaTypes.ITEM, blacklisted);
} catch(Exception e) {
ModEngineersDecor.logger().warn("Exception in JEI opt-out processing: '" + e.getMessage() + "', skipping further JEI optout processing.");
}
}
}
*/

View file

@ -0,0 +1,30 @@
# @file mods.toml
# @spec TOML v0.5.0 (https://github.com/toml-lang/toml)
modLoader="javafml"
loaderVersion="[28,)"
issueTrackerURL="https://github.com/stfwi/engineers-decor/issues/"
[[mods]]
modId="engineersdecor"
version="${file.jarVersion}"
displayName="Engineer's Decor"
description="Adds cosmetic blocks for the engineer's workshop, factory and home."
authors="wilechaote"
credits="BluSunrize, Damien Hazard, malte0811, et al., the Forge Smiths, the Modders of the World."
updateJSONURL="https://raw.githubusercontent.com/stfwi/engineers-decor/develop/meta/update.json"
displayURL="https://github.com/stfwi/engineers-decor/"
logoFile="logo.png"
[[dependencies.engineersdecor]]
modId="forge"
mandatory=true
versionRange="[30,)"
ordering="NONE"
side="BOTH"
[[dependencies.engineersdecor]]
modId="minecraft"
mandatory=true
versionRange="[1.15.1]"
ordering="NONE"
side="BOTH"

View file

@ -0,0 +1,14 @@
{
"variants": {
"": [
{ "model": "engineersdecor:block/brick/clinker_brick_model0" },
{ "model": "engineersdecor:block/brick/clinker_brick_model1" },
{ "model": "engineersdecor:block/brick/clinker_brick_model2" },
{ "model": "engineersdecor:block/brick/clinker_brick_model3" },
{ "model": "engineersdecor:block/brick/clinker_brick_model4" },
{ "model": "engineersdecor:block/brick/clinker_brick_model5" },
{ "model": "engineersdecor:block/brick/clinker_brick_model6" },
{ "model": "engineersdecor:block/brick/clinker_brick_model7" }
]
}
}

View file

@ -0,0 +1,16 @@
{
"variants": {
"parts=0,tvariant=0": { "model": "engineersdecor:block/slab/specific/clinker_brick_slab_s0v0_model" },
"parts=0,tvariant=1": { "model": "engineersdecor:block/slab/specific/clinker_brick_slab_s0v1_model" },
"parts=0,tvariant=2": { "model": "engineersdecor:block/slab/specific/clinker_brick_slab_s0v2_model" },
"parts=0,tvariant=3": { "model": "engineersdecor:block/slab/specific/clinker_brick_slab_s0v3_model" },
"parts=1,tvariant=0": { "model": "engineersdecor:block/slab/specific/clinker_brick_slab_s1v0_model" },
"parts=1,tvariant=1": { "model": "engineersdecor:block/slab/specific/clinker_brick_slab_s1v1_model" },
"parts=1,tvariant=2": { "model": "engineersdecor:block/slab/specific/clinker_brick_slab_s1v2_model" },
"parts=1,tvariant=3": { "model": "engineersdecor:block/slab/specific/clinker_brick_slab_s1v3_model" },
"parts=2,tvariant=0": { "model": "engineersdecor:block/slab/specific/clinker_brick_slab_s2v0_model" },
"parts=2,tvariant=1": { "model": "engineersdecor:block/slab/specific/clinker_brick_slab_s2v1_model" },
"parts=2,tvariant=2": { "model": "engineersdecor:block/slab/specific/clinker_brick_slab_s2v2_model" },
"parts=2,tvariant=3": { "model": "engineersdecor:block/slab/specific/clinker_brick_slab_s2v3_model" }
}
}

View file

@ -0,0 +1,14 @@
{
"variants": {
"": [
{ "model": "engineersdecor:block/brick/clinker_brick_stained_model0" },
{ "model": "engineersdecor:block/brick/clinker_brick_stained_model1" },
{ "model": "engineersdecor:block/brick/clinker_brick_stained_model2" },
{ "model": "engineersdecor:block/brick/clinker_brick_stained_model3" },
{ "model": "engineersdecor:block/brick/clinker_brick_stained_model4" },
{ "model": "engineersdecor:block/brick/clinker_brick_stained_model5" },
{ "model": "engineersdecor:block/brick/clinker_brick_stained_model6" },
{ "model": "engineersdecor:block/brick/clinker_brick_stained_model7" }
]
}
}

View file

@ -0,0 +1,16 @@
{
"variants": {
"parts=0,tvariant=0": { "model": "engineersdecor:block/slab/specific/clinker_brick_stained_slab_s0v0_model" },
"parts=0,tvariant=1": { "model": "engineersdecor:block/slab/specific/clinker_brick_stained_slab_s0v1_model" },
"parts=0,tvariant=2": { "model": "engineersdecor:block/slab/specific/clinker_brick_stained_slab_s0v2_model" },
"parts=0,tvariant=3": { "model": "engineersdecor:block/slab/specific/clinker_brick_stained_slab_s0v3_model" },
"parts=1,tvariant=0": { "model": "engineersdecor:block/slab/specific/clinker_brick_stained_slab_s1v0_model" },
"parts=1,tvariant=1": { "model": "engineersdecor:block/slab/specific/clinker_brick_stained_slab_s1v1_model" },
"parts=1,tvariant=2": { "model": "engineersdecor:block/slab/specific/clinker_brick_stained_slab_s1v2_model" },
"parts=1,tvariant=3": { "model": "engineersdecor:block/slab/specific/clinker_brick_stained_slab_s1v3_model" },
"parts=2,tvariant=0": { "model": "engineersdecor:block/slab/specific/clinker_brick_stained_slab_s2v0_model" },
"parts=2,tvariant=1": { "model": "engineersdecor:block/slab/specific/clinker_brick_stained_slab_s2v1_model" },
"parts=2,tvariant=2": { "model": "engineersdecor:block/slab/specific/clinker_brick_stained_slab_s2v2_model" },
"parts=2,tvariant=3": { "model": "engineersdecor:block/slab/specific/clinker_brick_stained_slab_s2v3_model" }
}
}

View file

@ -0,0 +1,44 @@
{
"variants": {
"facing=east,half=bottom,shape=straight": { "model": "engineersdecor:block/brick/clinker_brick_stained_stairs" },
"facing=west,half=bottom,shape=straight": { "model": "engineersdecor:block/brick/clinker_brick_stained_stairs", "y": 180, "uvlock": true },
"facing=south,half=bottom,shape=straight": { "model": "engineersdecor:block/brick/clinker_brick_stained_stairs", "y": 90, "uvlock": true },
"facing=north,half=bottom,shape=straight": { "model": "engineersdecor:block/brick/clinker_brick_stained_stairs", "y": 270, "uvlock": true },
"facing=east,half=bottom,shape=outer_right": { "model": "engineersdecor:block/brick/clinker_brick_stained_stairs_outer" },
"facing=west,half=bottom,shape=outer_right": { "model": "engineersdecor:block/brick/clinker_brick_stained_stairs_outer", "y": 180, "uvlock": true },
"facing=south,half=bottom,shape=outer_right": { "model": "engineersdecor:block/brick/clinker_brick_stained_stairs_outer", "y": 90, "uvlock": true },
"facing=north,half=bottom,shape=outer_right": { "model": "engineersdecor:block/brick/clinker_brick_stained_stairs_outer", "y": 270, "uvlock": true },
"facing=east,half=bottom,shape=outer_left": { "model": "engineersdecor:block/brick/clinker_brick_stained_stairs_outer", "y": 270, "uvlock": true },
"facing=west,half=bottom,shape=outer_left": { "model": "engineersdecor:block/brick/clinker_brick_stained_stairs_outer", "y": 90, "uvlock": true },
"facing=south,half=bottom,shape=outer_left": { "model": "engineersdecor:block/brick/clinker_brick_stained_stairs_outer" },
"facing=north,half=bottom,shape=outer_left": { "model": "engineersdecor:block/brick/clinker_brick_stained_stairs_outer", "y": 180, "uvlock": true },
"facing=east,half=bottom,shape=inner_right": { "model": "engineersdecor:block/brick/clinker_brick_stained_stairs_inner" },
"facing=west,half=bottom,shape=inner_right": { "model": "engineersdecor:block/brick/clinker_brick_stained_stairs_inner", "y": 180, "uvlock": true },
"facing=south,half=bottom,shape=inner_right": { "model": "engineersdecor:block/brick/clinker_brick_stained_stairs_inner", "y": 90, "uvlock": true },
"facing=north,half=bottom,shape=inner_right": { "model": "engineersdecor:block/brick/clinker_brick_stained_stairs_inner", "y": 270, "uvlock": true },
"facing=east,half=bottom,shape=inner_left": { "model": "engineersdecor:block/brick/clinker_brick_stained_stairs_inner", "y": 270, "uvlock": true },
"facing=west,half=bottom,shape=inner_left": { "model": "engineersdecor:block/brick/clinker_brick_stained_stairs_inner", "y": 90, "uvlock": true },
"facing=south,half=bottom,shape=inner_left": { "model": "engineersdecor:block/brick/clinker_brick_stained_stairs_inner" },
"facing=north,half=bottom,shape=inner_left": { "model": "engineersdecor:block/brick/clinker_brick_stained_stairs_inner", "y": 180, "uvlock": true },
"facing=east,half=top,shape=straight": { "model": "engineersdecor:block/brick/clinker_brick_stained_stairs", "x": 180, "uvlock": true },
"facing=west,half=top,shape=straight": { "model": "engineersdecor:block/brick/clinker_brick_stained_stairs", "x": 180, "y": 180, "uvlock": true },
"facing=south,half=top,shape=straight": { "model": "engineersdecor:block/brick/clinker_brick_stained_stairs", "x": 180, "y": 90, "uvlock": true },
"facing=north,half=top,shape=straight": { "model": "engineersdecor:block/brick/clinker_brick_stained_stairs", "x": 180, "y": 270, "uvlock": true },
"facing=east,half=top,shape=outer_right": { "model": "engineersdecor:block/brick/clinker_brick_stained_stairs_outer", "x": 180, "y": 90, "uvlock": true },
"facing=west,half=top,shape=outer_right": { "model": "engineersdecor:block/brick/clinker_brick_stained_stairs_outer", "x": 180, "y": 270, "uvlock": true },
"facing=south,half=top,shape=outer_right": { "model": "engineersdecor:block/brick/clinker_brick_stained_stairs_outer", "x": 180, "y": 180, "uvlock": true },
"facing=north,half=top,shape=outer_right": { "model": "engineersdecor:block/brick/clinker_brick_stained_stairs_outer", "x": 180, "uvlock": true },
"facing=east,half=top,shape=outer_left": { "model": "engineersdecor:block/brick/clinker_brick_stained_stairs_outer", "x": 180, "uvlock": true },
"facing=west,half=top,shape=outer_left": { "model": "engineersdecor:block/brick/clinker_brick_stained_stairs_outer", "x": 180, "y": 180, "uvlock": true },
"facing=south,half=top,shape=outer_left": { "model": "engineersdecor:block/brick/clinker_brick_stained_stairs_outer", "x": 180, "y": 90, "uvlock": true },
"facing=north,half=top,shape=outer_left": { "model": "engineersdecor:block/brick/clinker_brick_stained_stairs_outer", "x": 180, "y": 270, "uvlock": true },
"facing=east,half=top,shape=inner_right": { "model": "engineersdecor:block/brick/clinker_brick_stained_stairs_inner", "x": 180, "y": 90, "uvlock": true },
"facing=west,half=top,shape=inner_right": { "model": "engineersdecor:block/brick/clinker_brick_stained_stairs_inner", "x": 180, "y": 270, "uvlock": true },
"facing=south,half=top,shape=inner_right": { "model": "engineersdecor:block/brick/clinker_brick_stained_stairs_inner", "x": 180, "y": 180, "uvlock": true },
"facing=north,half=top,shape=inner_right": { "model": "engineersdecor:block/brick/clinker_brick_stained_stairs_inner", "x": 180, "uvlock": true },
"facing=east,half=top,shape=inner_left": { "model": "engineersdecor:block/brick/clinker_brick_stained_stairs_inner", "x": 180, "uvlock": true },
"facing=west,half=top,shape=inner_left": { "model": "engineersdecor:block/brick/clinker_brick_stained_stairs_inner", "x": 180, "y": 180, "uvlock": true },
"facing=south,half=top,shape=inner_left": { "model": "engineersdecor:block/brick/clinker_brick_stained_stairs_inner", "x": 180, "y": 90, "uvlock": true },
"facing=north,half=top,shape=inner_left": { "model": "engineersdecor:block/brick/clinker_brick_stained_stairs_inner", "x": 180, "y": 270, "uvlock": true }
}
}

View file

@ -0,0 +1,44 @@
{
"variants": {
"facing=east,half=bottom,shape=straight": { "model": "engineersdecor:block/brick/clinker_brick_stairs" },
"facing=west,half=bottom,shape=straight": { "model": "engineersdecor:block/brick/clinker_brick_stairs", "y": 180, "uvlock": true },
"facing=south,half=bottom,shape=straight": { "model": "engineersdecor:block/brick/clinker_brick_stairs", "y": 90, "uvlock": true },
"facing=north,half=bottom,shape=straight": { "model": "engineersdecor:block/brick/clinker_brick_stairs", "y": 270, "uvlock": true },
"facing=east,half=bottom,shape=outer_right": { "model": "engineersdecor:block/brick/clinker_brick_stairs_outer" },
"facing=west,half=bottom,shape=outer_right": { "model": "engineersdecor:block/brick/clinker_brick_stairs_outer", "y": 180, "uvlock": true },
"facing=south,half=bottom,shape=outer_right": { "model": "engineersdecor:block/brick/clinker_brick_stairs_outer", "y": 90, "uvlock": true },
"facing=north,half=bottom,shape=outer_right": { "model": "engineersdecor:block/brick/clinker_brick_stairs_outer", "y": 270, "uvlock": true },
"facing=east,half=bottom,shape=outer_left": { "model": "engineersdecor:block/brick/clinker_brick_stairs_outer", "y": 270, "uvlock": true },
"facing=west,half=bottom,shape=outer_left": { "model": "engineersdecor:block/brick/clinker_brick_stairs_outer", "y": 90, "uvlock": true },
"facing=south,half=bottom,shape=outer_left": { "model": "engineersdecor:block/brick/clinker_brick_stairs_outer" },
"facing=north,half=bottom,shape=outer_left": { "model": "engineersdecor:block/brick/clinker_brick_stairs_outer", "y": 180, "uvlock": true },
"facing=east,half=bottom,shape=inner_right": { "model": "engineersdecor:block/brick/clinker_brick_stairs_inner" },
"facing=west,half=bottom,shape=inner_right": { "model": "engineersdecor:block/brick/clinker_brick_stairs_inner", "y": 180, "uvlock": true },
"facing=south,half=bottom,shape=inner_right": { "model": "engineersdecor:block/brick/clinker_brick_stairs_inner", "y": 90, "uvlock": true },
"facing=north,half=bottom,shape=inner_right": { "model": "engineersdecor:block/brick/clinker_brick_stairs_inner", "y": 270, "uvlock": true },
"facing=east,half=bottom,shape=inner_left": { "model": "engineersdecor:block/brick/clinker_brick_stairs_inner", "y": 270, "uvlock": true },
"facing=west,half=bottom,shape=inner_left": { "model": "engineersdecor:block/brick/clinker_brick_stairs_inner", "y": 90, "uvlock": true },
"facing=south,half=bottom,shape=inner_left": { "model": "engineersdecor:block/brick/clinker_brick_stairs_inner" },
"facing=north,half=bottom,shape=inner_left": { "model": "engineersdecor:block/brick/clinker_brick_stairs_inner", "y": 180, "uvlock": true },
"facing=east,half=top,shape=straight": { "model": "engineersdecor:block/brick/clinker_brick_stairs", "x": 180, "uvlock": true },
"facing=west,half=top,shape=straight": { "model": "engineersdecor:block/brick/clinker_brick_stairs", "x": 180, "y": 180, "uvlock": true },
"facing=south,half=top,shape=straight": { "model": "engineersdecor:block/brick/clinker_brick_stairs", "x": 180, "y": 90, "uvlock": true },
"facing=north,half=top,shape=straight": { "model": "engineersdecor:block/brick/clinker_brick_stairs", "x": 180, "y": 270, "uvlock": true },
"facing=east,half=top,shape=outer_right": { "model": "engineersdecor:block/brick/clinker_brick_stairs_outer", "x": 180, "y": 90, "uvlock": true },
"facing=west,half=top,shape=outer_right": { "model": "engineersdecor:block/brick/clinker_brick_stairs_outer", "x": 180, "y": 270, "uvlock": true },
"facing=south,half=top,shape=outer_right": { "model": "engineersdecor:block/brick/clinker_brick_stairs_outer", "x": 180, "y": 180, "uvlock": true },
"facing=north,half=top,shape=outer_right": { "model": "engineersdecor:block/brick/clinker_brick_stairs_outer", "x": 180, "uvlock": true },
"facing=east,half=top,shape=outer_left": { "model": "engineersdecor:block/brick/clinker_brick_stairs_outer", "x": 180, "uvlock": true },
"facing=west,half=top,shape=outer_left": { "model": "engineersdecor:block/brick/clinker_brick_stairs_outer", "x": 180, "y": 180, "uvlock": true },
"facing=south,half=top,shape=outer_left": { "model": "engineersdecor:block/brick/clinker_brick_stairs_outer", "x": 180, "y": 90, "uvlock": true },
"facing=north,half=top,shape=outer_left": { "model": "engineersdecor:block/brick/clinker_brick_stairs_outer", "x": 180, "y": 270, "uvlock": true },
"facing=east,half=top,shape=inner_right": { "model": "engineersdecor:block/brick/clinker_brick_stairs_inner", "x": 180, "y": 90, "uvlock": true },
"facing=west,half=top,shape=inner_right": { "model": "engineersdecor:block/brick/clinker_brick_stairs_inner", "x": 180, "y": 270, "uvlock": true },
"facing=south,half=top,shape=inner_right": { "model": "engineersdecor:block/brick/clinker_brick_stairs_inner", "x": 180, "y": 180, "uvlock": true },
"facing=north,half=top,shape=inner_right": { "model": "engineersdecor:block/brick/clinker_brick_stairs_inner", "x": 180, "uvlock": true },
"facing=east,half=top,shape=inner_left": { "model": "engineersdecor:block/brick/clinker_brick_stairs_inner", "x": 180, "uvlock": true },
"facing=west,half=top,shape=inner_left": { "model": "engineersdecor:block/brick/clinker_brick_stairs_inner", "x": 180, "y": 180, "uvlock": true },
"facing=south,half=top,shape=inner_left": { "model": "engineersdecor:block/brick/clinker_brick_stairs_inner", "x": 180, "y": 90, "uvlock": true },
"facing=north,half=top,shape=inner_left": { "model": "engineersdecor:block/brick/clinker_brick_stairs_inner", "x": 180, "y": 270, "uvlock": true }
}
}

View file

@ -0,0 +1,9 @@
{
"multipart": [
{ "when": { "up": "true" }, "apply": { "model": "engineersdecor:block/brick/clinker_brick_wall_post" } },
{ "when": { "north": "true" }, "apply": { "model": "engineersdecor:block/brick/clinker_brick_wall_side", "uvlock": true } },
{ "when": { "east": "true" }, "apply": { "model": "engineersdecor:block/brick/clinker_brick_wall_side", "y": 90, "uvlock": true } },
{ "when": { "south": "true" }, "apply": { "model": "engineersdecor:block/brick/clinker_brick_wall_side", "y": 180, "uvlock": true } },
{ "when": { "west": "true" }, "apply": { "model": "engineersdecor:block/brick/clinker_brick_wall_side", "y": 270, "uvlock": true } }
]
}

View file

@ -0,0 +1,9 @@
{
"multipart": [
{ "when": { "up": "true" }, "apply": { "model": "engineersdecor:block/concrete/concrete_wall_post" } },
{ "when": { "north": "true" }, "apply": { "model": "engineersdecor:block/concrete/concrete_wall_side", "uvlock": true } },
{ "when": { "east": "true" }, "apply": { "model": "engineersdecor:block/concrete/concrete_wall_side", "y": 90, "uvlock": true } },
{ "when": { "south": "true" }, "apply": { "model": "engineersdecor:block/concrete/concrete_wall_side", "y": 180, "uvlock": true } },
{ "when": { "west": "true" }, "apply": { "model": "engineersdecor:block/concrete/concrete_wall_side", "y": 270, "uvlock": true } }
]
}

View file

@ -0,0 +1,16 @@
{
"variants": {
"facing=north,open=false": { "model": "engineersdecor:block/device/factory_dropper_model" },
"facing=south,open=false": { "model": "engineersdecor:block/device/factory_dropper_model", "y":180 },
"facing=west,open=false": { "model": "engineersdecor:block/device/factory_dropper_model", "y":270 },
"facing=east,open=false": { "model": "engineersdecor:block/device/factory_dropper_model", "y":90 },
"facing=up,open=false": { "model": "engineersdecor:block/device/factory_dropper_model", "x":270 },
"facing=down,open=false": { "model": "engineersdecor:block/device/factory_dropper_model", "x":90 },
"facing=north,open=true": { "model": "engineersdecor:block/device/factory_dropper_model_open" },
"facing=south,open=true": { "model": "engineersdecor:block/device/factory_dropper_model_open", "y":180 },
"facing=west,open=true": { "model": "engineersdecor:block/device/factory_dropper_model_open", "y":270 },
"facing=east,open=true": { "model": "engineersdecor:block/device/factory_dropper_model_open", "y":90 },
"facing=up,open=true": { "model": "engineersdecor:block/device/factory_dropper_model_open", "x":270 },
"facing=down,open=true": { "model": "engineersdecor:block/device/factory_dropper_model_open", "x":90 }
}
}

View file

@ -0,0 +1,10 @@
{
"variants": {
"facing=north": { "model": "engineersdecor:block/device/factory_hopper_model" },
"facing=south": { "model": "engineersdecor:block/device/factory_hopper_model", "y":180 },
"facing=west": { "model": "engineersdecor:block/device/factory_hopper_model", "y":270 },
"facing=east": { "model": "engineersdecor:block/device/factory_hopper_model", "y":90 },
"facing=up": { "model": "engineersdecor:block/device/factory_hopper_model_up" },
"facing=down": { "model": "engineersdecor:block/device/factory_hopper_model_down" }
}
}

View file

@ -0,0 +1,10 @@
{
"variants": {
"facing=north": { "model": "engineersdecor:block/device/factory_placer_model" },
"facing=south": { "model": "engineersdecor:block/device/factory_placer_model", "y":180 },
"facing=west": { "model": "engineersdecor:block/device/factory_placer_model", "y":270 },
"facing=east": { "model": "engineersdecor:block/device/factory_placer_model", "y":90 },
"facing=up": { "model": "engineersdecor:block/device/factory_placer_model", "x":270 },
"facing=down": { "model": "engineersdecor:block/device/factory_placer_model", "x":90 }
}
}

View file

@ -0,0 +1,14 @@
{
"variants": {
"": [
{ "model": "engineersdecor:block/concrete/gas_concrete_model0" },
{ "model": "engineersdecor:block/concrete/gas_concrete_model1" },
{ "model": "engineersdecor:block/concrete/gas_concrete_model2" },
{ "model": "engineersdecor:block/concrete/gas_concrete_model3" },
{ "model": "engineersdecor:block/concrete/gas_concrete_model4" },
{ "model": "engineersdecor:block/concrete/gas_concrete_model5" },
{ "model": "engineersdecor:block/concrete/gas_concrete_model6" },
{ "model": "engineersdecor:block/concrete/gas_concrete_model7" }
]
}
}

View file

@ -0,0 +1,16 @@
{
"variants": {
"parts=0,tvariant=0": { "model": "engineersdecor:block/slab/specific/gas_concrete_slab_s0v0_model" },
"parts=0,tvariant=1": { "model": "engineersdecor:block/slab/specific/gas_concrete_slab_s0v1_model" },
"parts=0,tvariant=2": { "model": "engineersdecor:block/slab/specific/gas_concrete_slab_s0v2_model" },
"parts=0,tvariant=3": { "model": "engineersdecor:block/slab/specific/gas_concrete_slab_s0v3_model" },
"parts=1,tvariant=0": { "model": "engineersdecor:block/slab/specific/gas_concrete_slab_s1v0_model" },
"parts=1,tvariant=1": { "model": "engineersdecor:block/slab/specific/gas_concrete_slab_s1v1_model" },
"parts=1,tvariant=2": { "model": "engineersdecor:block/slab/specific/gas_concrete_slab_s1v2_model" },
"parts=1,tvariant=3": { "model": "engineersdecor:block/slab/specific/gas_concrete_slab_s1v3_model" },
"parts=2,tvariant=0": { "model": "engineersdecor:block/slab/specific/gas_concrete_slab_s2v0_model" },
"parts=2,tvariant=1": { "model": "engineersdecor:block/slab/specific/gas_concrete_slab_s2v1_model" },
"parts=2,tvariant=2": { "model": "engineersdecor:block/slab/specific/gas_concrete_slab_s2v2_model" },
"parts=2,tvariant=3": { "model": "engineersdecor:block/slab/specific/gas_concrete_slab_s2v3_model" }
}
}

View file

@ -0,0 +1,44 @@
{
"variants": {
"facing=east,half=bottom,shape=straight": { "model": "engineersdecor:block/concrete/gas_concrete_stairs" },
"facing=west,half=bottom,shape=straight": { "model": "engineersdecor:block/concrete/gas_concrete_stairs", "y": 180, "uvlock": true },
"facing=south,half=bottom,shape=straight": { "model": "engineersdecor:block/concrete/gas_concrete_stairs", "y": 90, "uvlock": true },
"facing=north,half=bottom,shape=straight": { "model": "engineersdecor:block/concrete/gas_concrete_stairs", "y": 270, "uvlock": true },
"facing=east,half=bottom,shape=outer_right": { "model": "engineersdecor:block/concrete/gas_concrete_stairs_outer" },
"facing=west,half=bottom,shape=outer_right": { "model": "engineersdecor:block/concrete/gas_concrete_stairs_outer", "y": 180, "uvlock": true },
"facing=south,half=bottom,shape=outer_right": { "model": "engineersdecor:block/concrete/gas_concrete_stairs_outer", "y": 90, "uvlock": true },
"facing=north,half=bottom,shape=outer_right": { "model": "engineersdecor:block/concrete/gas_concrete_stairs_outer", "y": 270, "uvlock": true },
"facing=east,half=bottom,shape=outer_left": { "model": "engineersdecor:block/concrete/gas_concrete_stairs_outer", "y": 270, "uvlock": true },
"facing=west,half=bottom,shape=outer_left": { "model": "engineersdecor:block/concrete/gas_concrete_stairs_outer", "y": 90, "uvlock": true },
"facing=south,half=bottom,shape=outer_left": { "model": "engineersdecor:block/concrete/gas_concrete_stairs_outer" },
"facing=north,half=bottom,shape=outer_left": { "model": "engineersdecor:block/concrete/gas_concrete_stairs_outer", "y": 180, "uvlock": true },
"facing=east,half=bottom,shape=inner_right": { "model": "engineersdecor:block/concrete/gas_concrete_stairs_inner" },
"facing=west,half=bottom,shape=inner_right": { "model": "engineersdecor:block/concrete/gas_concrete_stairs_inner", "y": 180, "uvlock": true },
"facing=south,half=bottom,shape=inner_right": { "model": "engineersdecor:block/concrete/gas_concrete_stairs_inner", "y": 90, "uvlock": true },
"facing=north,half=bottom,shape=inner_right": { "model": "engineersdecor:block/concrete/gas_concrete_stairs_inner", "y": 270, "uvlock": true },
"facing=east,half=bottom,shape=inner_left": { "model": "engineersdecor:block/concrete/gas_concrete_stairs_inner", "y": 270, "uvlock": true },
"facing=west,half=bottom,shape=inner_left": { "model": "engineersdecor:block/concrete/gas_concrete_stairs_inner", "y": 90, "uvlock": true },
"facing=south,half=bottom,shape=inner_left": { "model": "engineersdecor:block/concrete/gas_concrete_stairs_inner" },
"facing=north,half=bottom,shape=inner_left": { "model": "engineersdecor:block/concrete/gas_concrete_stairs_inner", "y": 180, "uvlock": true },
"facing=east,half=top,shape=straight": { "model": "engineersdecor:block/concrete/gas_concrete_stairs", "x": 180, "uvlock": true },
"facing=west,half=top,shape=straight": { "model": "engineersdecor:block/concrete/gas_concrete_stairs", "x": 180, "y": 180, "uvlock": true },
"facing=south,half=top,shape=straight": { "model": "engineersdecor:block/concrete/gas_concrete_stairs", "x": 180, "y": 90, "uvlock": true },
"facing=north,half=top,shape=straight": { "model": "engineersdecor:block/concrete/gas_concrete_stairs", "x": 180, "y": 270, "uvlock": true },
"facing=east,half=top,shape=outer_right": { "model": "engineersdecor:block/concrete/gas_concrete_stairs_outer", "x": 180, "y": 90, "uvlock": true },
"facing=west,half=top,shape=outer_right": { "model": "engineersdecor:block/concrete/gas_concrete_stairs_outer", "x": 180, "y": 270, "uvlock": true },
"facing=south,half=top,shape=outer_right": { "model": "engineersdecor:block/concrete/gas_concrete_stairs_outer", "x": 180, "y": 180, "uvlock": true },
"facing=north,half=top,shape=outer_right": { "model": "engineersdecor:block/concrete/gas_concrete_stairs_outer", "x": 180, "uvlock": true },
"facing=east,half=top,shape=outer_left": { "model": "engineersdecor:block/concrete/gas_concrete_stairs_outer", "x": 180, "uvlock": true },
"facing=west,half=top,shape=outer_left": { "model": "engineersdecor:block/concrete/gas_concrete_stairs_outer", "x": 180, "y": 180, "uvlock": true },
"facing=south,half=top,shape=outer_left": { "model": "engineersdecor:block/concrete/gas_concrete_stairs_outer", "x": 180, "y": 90, "uvlock": true },
"facing=north,half=top,shape=outer_left": { "model": "engineersdecor:block/concrete/gas_concrete_stairs_outer", "x": 180, "y": 270, "uvlock": true },
"facing=east,half=top,shape=inner_right": { "model": "engineersdecor:block/concrete/gas_concrete_stairs_inner", "x": 180, "y": 90, "uvlock": true },
"facing=west,half=top,shape=inner_right": { "model": "engineersdecor:block/concrete/gas_concrete_stairs_inner", "x": 180, "y": 270, "uvlock": true },
"facing=south,half=top,shape=inner_right": { "model": "engineersdecor:block/concrete/gas_concrete_stairs_inner", "x": 180, "y": 180, "uvlock": true },
"facing=north,half=top,shape=inner_right": { "model": "engineersdecor:block/concrete/gas_concrete_stairs_inner", "x": 180, "uvlock": true },
"facing=east,half=top,shape=inner_left": { "model": "engineersdecor:block/concrete/gas_concrete_stairs_inner", "x": 180, "uvlock": true },
"facing=west,half=top,shape=inner_left": { "model": "engineersdecor:block/concrete/gas_concrete_stairs_inner", "x": 180, "y": 180, "uvlock": true },
"facing=south,half=top,shape=inner_left": { "model": "engineersdecor:block/concrete/gas_concrete_stairs_inner", "x": 180, "y": 90, "uvlock": true },
"facing=north,half=top,shape=inner_left": { "model": "engineersdecor:block/concrete/gas_concrete_stairs_inner", "x": 180, "y": 270, "uvlock": true }
}
}

View file

@ -0,0 +1,9 @@
{
"multipart": [
{ "when": { "up": "true" }, "apply": { "model": "engineersdecor:block/concrete/gas_concrete_wall_post" } },
{ "when": { "north": "true" }, "apply": { "model": "engineersdecor:block/concrete/gas_concrete_wall_side", "uvlock": true } },
{ "when": { "east": "true" }, "apply": { "model": "engineersdecor:block/concrete/gas_concrete_wall_side", "y": 90, "uvlock": true } },
{ "when": { "south": "true" }, "apply": { "model": "engineersdecor:block/concrete/gas_concrete_wall_side", "y": 180, "uvlock": true } },
{ "when": { "west": "true" }, "apply": { "model": "engineersdecor:block/concrete/gas_concrete_wall_side", "y": 270, "uvlock": true } }
]
}

View file

@ -0,0 +1,19 @@
{
"variants": {
"parts=0": { "model": "engineersdecor:block/slab/specific/halfslab_clinker_brick_s0_model" },
"parts=1": { "model": "engineersdecor:block/slab/specific/halfslab_clinker_brick_s1_model" },
"parts=2": { "model": "engineersdecor:block/slab/specific/halfslab_clinker_brick_s2_model" },
"parts=3": { "model": "engineersdecor:block/slab/specific/halfslab_clinker_brick_s3_model" },
"parts=4": { "model": "engineersdecor:block/slab/specific/halfslab_clinker_brick_s4_model" },
"parts=5": { "model": "engineersdecor:block/slab/specific/halfslab_clinker_brick_s5_model" },
"parts=6": { "model": "engineersdecor:block/slab/specific/halfslab_clinker_brick_s6_model" },
"parts=7": { "model": "engineersdecor:block/slab/specific/halfslab_clinker_brick_s7_model" },
"parts=8": { "model": "engineersdecor:block/slab/specific/halfslab_clinker_brick_s8_model" },
"parts=9": { "model": "engineersdecor:block/slab/specific/halfslab_clinker_brick_s9_model" },
"parts=10": { "model": "engineersdecor:block/slab/specific/halfslab_clinker_brick_sa_model" },
"parts=11": { "model": "engineersdecor:block/slab/specific/halfslab_clinker_brick_sb_model" },
"parts=12": { "model": "engineersdecor:block/slab/specific/halfslab_clinker_brick_sc_model" },
"parts=13": { "model": "engineersdecor:block/slab/specific/halfslab_clinker_brick_sd_model" },
"parts=14": { "model": "engineersdecor:block/slab/specific/halfslab_clinker_brick_se_model" }
}
}

View file

@ -0,0 +1,19 @@
{
"variants": {
"parts=0": { "model": "engineersdecor:block/slab/specific/halfslab_concrete_s0_model" },
"parts=1": { "model": "engineersdecor:block/slab/specific/halfslab_concrete_s1_model" },
"parts=2": { "model": "engineersdecor:block/slab/specific/halfslab_concrete_s2_model" },
"parts=3": { "model": "engineersdecor:block/slab/specific/halfslab_concrete_s3_model" },
"parts=4": { "model": "engineersdecor:block/slab/specific/halfslab_concrete_s4_model" },
"parts=5": { "model": "engineersdecor:block/slab/specific/halfslab_concrete_s5_model" },
"parts=6": { "model": "engineersdecor:block/slab/specific/halfslab_concrete_s6_model" },
"parts=7": { "model": "engineersdecor:block/slab/specific/halfslab_concrete_s7_model" },
"parts=8": { "model": "engineersdecor:block/slab/specific/halfslab_concrete_s8_model" },
"parts=9": { "model": "engineersdecor:block/slab/specific/halfslab_concrete_s9_model" },
"parts=10": { "model": "engineersdecor:block/slab/specific/halfslab_concrete_sa_model" },
"parts=11": { "model": "engineersdecor:block/slab/specific/halfslab_concrete_sb_model" },
"parts=12": { "model": "engineersdecor:block/slab/specific/halfslab_concrete_sc_model" },
"parts=13": { "model": "engineersdecor:block/slab/specific/halfslab_concrete_sd_model" },
"parts=14": { "model": "engineersdecor:block/slab/specific/halfslab_concrete_se_model" }
}
}

View file

@ -0,0 +1,19 @@
{
"variants": {
"parts=0": { "model": "engineersdecor:block/slab/specific/halfslab_gas_concrete_s0_model" },
"parts=1": { "model": "engineersdecor:block/slab/specific/halfslab_gas_concrete_s1_model" },
"parts=2": { "model": "engineersdecor:block/slab/specific/halfslab_gas_concrete_s2_model" },
"parts=3": { "model": "engineersdecor:block/slab/specific/halfslab_gas_concrete_s3_model" },
"parts=4": { "model": "engineersdecor:block/slab/specific/halfslab_gas_concrete_s4_model" },
"parts=5": { "model": "engineersdecor:block/slab/specific/halfslab_gas_concrete_s5_model" },
"parts=6": { "model": "engineersdecor:block/slab/specific/halfslab_gas_concrete_s6_model" },
"parts=7": { "model": "engineersdecor:block/slab/specific/halfslab_gas_concrete_s7_model" },
"parts=8": { "model": "engineersdecor:block/slab/specific/halfslab_gas_concrete_s8_model" },
"parts=9": { "model": "engineersdecor:block/slab/specific/halfslab_gas_concrete_s9_model" },
"parts=10": { "model": "engineersdecor:block/slab/specific/halfslab_gas_concrete_sa_model" },
"parts=11": { "model": "engineersdecor:block/slab/specific/halfslab_gas_concrete_sb_model" },
"parts=12": { "model": "engineersdecor:block/slab/specific/halfslab_gas_concrete_sc_model" },
"parts=13": { "model": "engineersdecor:block/slab/specific/halfslab_gas_concrete_sd_model" },
"parts=14": { "model": "engineersdecor:block/slab/specific/halfslab_gas_concrete_se_model" }
}
}

View file

@ -0,0 +1,19 @@
{
"variants": {
"parts=0": { "model": "engineersdecor:block/slab/specific/halfslab_rebar_concrete_s0_model" },
"parts=1": { "model": "engineersdecor:block/slab/specific/halfslab_rebar_concrete_s1_model" },
"parts=2": { "model": "engineersdecor:block/slab/specific/halfslab_rebar_concrete_s2_model" },
"parts=3": { "model": "engineersdecor:block/slab/specific/halfslab_rebar_concrete_s3_model" },
"parts=4": { "model": "engineersdecor:block/slab/specific/halfslab_rebar_concrete_s4_model" },
"parts=5": { "model": "engineersdecor:block/slab/specific/halfslab_rebar_concrete_s5_model" },
"parts=6": { "model": "engineersdecor:block/slab/specific/halfslab_rebar_concrete_s6_model" },
"parts=7": { "model": "engineersdecor:block/slab/specific/halfslab_rebar_concrete_s7_model" },
"parts=8": { "model": "engineersdecor:block/slab/specific/halfslab_rebar_concrete_s8_model" },
"parts=9": { "model": "engineersdecor:block/slab/specific/halfslab_rebar_concrete_s9_model" },
"parts=10": { "model": "engineersdecor:block/slab/specific/halfslab_rebar_concrete_sa_model" },
"parts=11": { "model": "engineersdecor:block/slab/specific/halfslab_rebar_concrete_sb_model" },
"parts=12": { "model": "engineersdecor:block/slab/specific/halfslab_rebar_concrete_sc_model" },
"parts=13": { "model": "engineersdecor:block/slab/specific/halfslab_rebar_concrete_sd_model" },
"parts=14": { "model": "engineersdecor:block/slab/specific/halfslab_rebar_concrete_se_model" }
}
}

View file

@ -0,0 +1,19 @@
{
"variants": {
"parts=0": { "model": "engineersdecor:block/slab/specific/halfslab_sheetmetal_aluminum_s0_model" },
"parts=1": { "model": "engineersdecor:block/slab/specific/halfslab_sheetmetal_aluminum_s1_model" },
"parts=2": { "model": "engineersdecor:block/slab/specific/halfslab_sheetmetal_aluminum_s2_model" },
"parts=3": { "model": "engineersdecor:block/slab/specific/halfslab_sheetmetal_aluminum_s3_model" },
"parts=4": { "model": "engineersdecor:block/slab/specific/halfslab_sheetmetal_aluminum_s4_model" },
"parts=5": { "model": "engineersdecor:block/slab/specific/halfslab_sheetmetal_aluminum_s5_model" },
"parts=6": { "model": "engineersdecor:block/slab/specific/halfslab_sheetmetal_aluminum_s6_model" },
"parts=7": { "model": "engineersdecor:block/slab/specific/halfslab_sheetmetal_aluminum_s7_model" },
"parts=8": { "model": "engineersdecor:block/slab/specific/halfslab_sheetmetal_aluminum_s8_model" },
"parts=9": { "model": "engineersdecor:block/slab/specific/halfslab_sheetmetal_aluminum_s9_model" },
"parts=10": { "model": "engineersdecor:block/slab/specific/halfslab_sheetmetal_aluminum_sa_model" },
"parts=11": { "model": "engineersdecor:block/slab/specific/halfslab_sheetmetal_aluminum_sb_model" },
"parts=12": { "model": "engineersdecor:block/slab/specific/halfslab_sheetmetal_aluminum_sc_model" },
"parts=13": { "model": "engineersdecor:block/slab/specific/halfslab_sheetmetal_aluminum_sd_model" },
"parts=14": { "model": "engineersdecor:block/slab/specific/halfslab_sheetmetal_aluminum_se_model" }
}
}

View file

@ -0,0 +1,19 @@
{
"variants": {
"parts=0": { "model": "engineersdecor:block/slab/specific/halfslab_sheetmetal_copper_s0_model" },
"parts=1": { "model": "engineersdecor:block/slab/specific/halfslab_sheetmetal_copper_s1_model" },
"parts=2": { "model": "engineersdecor:block/slab/specific/halfslab_sheetmetal_copper_s2_model" },
"parts=3": { "model": "engineersdecor:block/slab/specific/halfslab_sheetmetal_copper_s3_model" },
"parts=4": { "model": "engineersdecor:block/slab/specific/halfslab_sheetmetal_copper_s4_model" },
"parts=5": { "model": "engineersdecor:block/slab/specific/halfslab_sheetmetal_copper_s5_model" },
"parts=6": { "model": "engineersdecor:block/slab/specific/halfslab_sheetmetal_copper_s6_model" },
"parts=7": { "model": "engineersdecor:block/slab/specific/halfslab_sheetmetal_copper_s7_model" },
"parts=8": { "model": "engineersdecor:block/slab/specific/halfslab_sheetmetal_copper_s8_model" },
"parts=9": { "model": "engineersdecor:block/slab/specific/halfslab_sheetmetal_copper_s9_model" },
"parts=10": { "model": "engineersdecor:block/slab/specific/halfslab_sheetmetal_copper_sa_model" },
"parts=11": { "model": "engineersdecor:block/slab/specific/halfslab_sheetmetal_copper_sb_model" },
"parts=12": { "model": "engineersdecor:block/slab/specific/halfslab_sheetmetal_copper_sc_model" },
"parts=13": { "model": "engineersdecor:block/slab/specific/halfslab_sheetmetal_copper_sd_model" },
"parts=14": { "model": "engineersdecor:block/slab/specific/halfslab_sheetmetal_copper_se_model" }
}
}

View file

@ -0,0 +1,19 @@
{
"variants": {
"parts=0": { "model": "engineersdecor:block/slab/specific/halfslab_sheetmetal_gold_s0_model" },
"parts=1": { "model": "engineersdecor:block/slab/specific/halfslab_sheetmetal_gold_s1_model" },
"parts=2": { "model": "engineersdecor:block/slab/specific/halfslab_sheetmetal_gold_s2_model" },
"parts=3": { "model": "engineersdecor:block/slab/specific/halfslab_sheetmetal_gold_s3_model" },
"parts=4": { "model": "engineersdecor:block/slab/specific/halfslab_sheetmetal_gold_s4_model" },
"parts=5": { "model": "engineersdecor:block/slab/specific/halfslab_sheetmetal_gold_s5_model" },
"parts=6": { "model": "engineersdecor:block/slab/specific/halfslab_sheetmetal_gold_s6_model" },
"parts=7": { "model": "engineersdecor:block/slab/specific/halfslab_sheetmetal_gold_s7_model" },
"parts=8": { "model": "engineersdecor:block/slab/specific/halfslab_sheetmetal_gold_s8_model" },
"parts=9": { "model": "engineersdecor:block/slab/specific/halfslab_sheetmetal_gold_s9_model" },
"parts=10": { "model": "engineersdecor:block/slab/specific/halfslab_sheetmetal_gold_sa_model" },
"parts=11": { "model": "engineersdecor:block/slab/specific/halfslab_sheetmetal_gold_sb_model" },
"parts=12": { "model": "engineersdecor:block/slab/specific/halfslab_sheetmetal_gold_sc_model" },
"parts=13": { "model": "engineersdecor:block/slab/specific/halfslab_sheetmetal_gold_sd_model" },
"parts=14": { "model": "engineersdecor:block/slab/specific/halfslab_sheetmetal_gold_se_model" }
}
}

View file

@ -0,0 +1,19 @@
{
"variants": {
"parts=0": { "model": "engineersdecor:block/slab/specific/halfslab_sheetmetal_iron_s0_model" },
"parts=1": { "model": "engineersdecor:block/slab/specific/halfslab_sheetmetal_iron_s1_model" },
"parts=2": { "model": "engineersdecor:block/slab/specific/halfslab_sheetmetal_iron_s2_model" },
"parts=3": { "model": "engineersdecor:block/slab/specific/halfslab_sheetmetal_iron_s3_model" },
"parts=4": { "model": "engineersdecor:block/slab/specific/halfslab_sheetmetal_iron_s4_model" },
"parts=5": { "model": "engineersdecor:block/slab/specific/halfslab_sheetmetal_iron_s5_model" },
"parts=6": { "model": "engineersdecor:block/slab/specific/halfslab_sheetmetal_iron_s6_model" },
"parts=7": { "model": "engineersdecor:block/slab/specific/halfslab_sheetmetal_iron_s7_model" },
"parts=8": { "model": "engineersdecor:block/slab/specific/halfslab_sheetmetal_iron_s8_model" },
"parts=9": { "model": "engineersdecor:block/slab/specific/halfslab_sheetmetal_iron_s9_model" },
"parts=10": { "model": "engineersdecor:block/slab/specific/halfslab_sheetmetal_iron_sa_model" },
"parts=11": { "model": "engineersdecor:block/slab/specific/halfslab_sheetmetal_iron_sb_model" },
"parts=12": { "model": "engineersdecor:block/slab/specific/halfslab_sheetmetal_iron_sc_model" },
"parts=13": { "model": "engineersdecor:block/slab/specific/halfslab_sheetmetal_iron_sd_model" },
"parts=14": { "model": "engineersdecor:block/slab/specific/halfslab_sheetmetal_iron_se_model" }
}
}

View file

@ -0,0 +1,19 @@
{
"variants": {
"parts=0": { "model": "engineersdecor:block/slab/specific/halfslab_sheetmetal_steel_s0_model" },
"parts=1": { "model": "engineersdecor:block/slab/specific/halfslab_sheetmetal_steel_s1_model" },
"parts=2": { "model": "engineersdecor:block/slab/specific/halfslab_sheetmetal_steel_s2_model" },
"parts=3": { "model": "engineersdecor:block/slab/specific/halfslab_sheetmetal_steel_s3_model" },
"parts=4": { "model": "engineersdecor:block/slab/specific/halfslab_sheetmetal_steel_s4_model" },
"parts=5": { "model": "engineersdecor:block/slab/specific/halfslab_sheetmetal_steel_s5_model" },
"parts=6": { "model": "engineersdecor:block/slab/specific/halfslab_sheetmetal_steel_s6_model" },
"parts=7": { "model": "engineersdecor:block/slab/specific/halfslab_sheetmetal_steel_s7_model" },
"parts=8": { "model": "engineersdecor:block/slab/specific/halfslab_sheetmetal_steel_s8_model" },
"parts=9": { "model": "engineersdecor:block/slab/specific/halfslab_sheetmetal_steel_s9_model" },
"parts=10": { "model": "engineersdecor:block/slab/specific/halfslab_sheetmetal_steel_sa_model" },
"parts=11": { "model": "engineersdecor:block/slab/specific/halfslab_sheetmetal_steel_sb_model" },
"parts=12": { "model": "engineersdecor:block/slab/specific/halfslab_sheetmetal_steel_sc_model" },
"parts=13": { "model": "engineersdecor:block/slab/specific/halfslab_sheetmetal_steel_sd_model" },
"parts=14": { "model": "engineersdecor:block/slab/specific/halfslab_sheetmetal_steel_se_model" }
}
}

View file

@ -0,0 +1,19 @@
{
"variants": {
"parts=0": { "model": "engineersdecor:block/slab/specific/halfslab_treated_wood_s0_model" },
"parts=1": { "model": "engineersdecor:block/slab/specific/halfslab_treated_wood_s1_model" },
"parts=2": { "model": "engineersdecor:block/slab/specific/halfslab_treated_wood_s2_model" },
"parts=3": { "model": "engineersdecor:block/slab/specific/halfslab_treated_wood_s3_model" },
"parts=4": { "model": "engineersdecor:block/slab/specific/halfslab_treated_wood_s4_model" },
"parts=5": { "model": "engineersdecor:block/slab/specific/halfslab_treated_wood_s5_model" },
"parts=6": { "model": "engineersdecor:block/slab/specific/halfslab_treated_wood_s6_model" },
"parts=7": { "model": "engineersdecor:block/slab/specific/halfslab_treated_wood_s7_model" },
"parts=8": { "model": "engineersdecor:block/slab/specific/halfslab_treated_wood_s8_model" },
"parts=9": { "model": "engineersdecor:block/slab/specific/halfslab_treated_wood_s9_model" },
"parts=10": { "model": "engineersdecor:block/slab/specific/halfslab_treated_wood_sa_model" },
"parts=11": { "model": "engineersdecor:block/slab/specific/halfslab_treated_wood_sb_model" },
"parts=12": { "model": "engineersdecor:block/slab/specific/halfslab_treated_wood_sc_model" },
"parts=13": { "model": "engineersdecor:block/slab/specific/halfslab_treated_wood_sd_model" },
"parts=14": { "model": "engineersdecor:block/slab/specific/halfslab_treated_wood_se_model" }
}
}

View file

@ -0,0 +1,10 @@
{
"variants": {
"facing=north": { "model": "engineersdecor:block/light/floor_edge_light_model" },
"facing=south": { "model": "engineersdecor:block/light/floor_edge_light_model", "y":180 },
"facing=west": { "model": "engineersdecor:block/light/floor_edge_light_model", "y":270 },
"facing=east": { "model": "engineersdecor:block/light/floor_edge_light_model", "y":90 },
"facing=up": { "model": "engineersdecor:block/light/floor_edge_light_model", "x":270 },
"facing=down": { "model": "engineersdecor:block/light/floor_edge_light_model", "x":90 }
}
}

View file

@ -0,0 +1,10 @@
{
"variants": {
"facing=north": { "model": "engineersdecor:block/light/inset_light_model" },
"facing=south": { "model": "engineersdecor:block/light/inset_light_model", "y":180 },
"facing=west": { "model": "engineersdecor:block/light/inset_light_model", "y":270 },
"facing=east": { "model": "engineersdecor:block/light/inset_light_model", "y":90 },
"facing=up": { "model": "engineersdecor:block/light/inset_light_model", "x":270 },
"facing=down": { "model": "engineersdecor:block/light/inset_light_model", "x":90 }
}
}

View file

@ -0,0 +1,8 @@
{
"variants": {
"facing=north": { "model": "engineersdecor:block/ladder/metal_rung_ladder_model" },
"facing=south": { "model": "engineersdecor:block/ladder/metal_rung_ladder_model", "y":180 },
"facing=west": { "model": "engineersdecor:block/ladder/metal_rung_ladder_model", "y":270 },
"facing=east": { "model": "engineersdecor:block/ladder/metal_rung_ladder_model", "y":90 }
}
}

View file

@ -0,0 +1,8 @@
{
"variants": {
"facing=north": { "model": "engineersdecor:block/ladder/metal_rung_steps_model" },
"facing=south": { "model": "engineersdecor:block/ladder/metal_rung_steps_model", "y":180 },
"facing=west": { "model": "engineersdecor:block/ladder/metal_rung_steps_model", "y":270 },
"facing=east": { "model": "engineersdecor:block/ladder/metal_rung_steps_model", "y":90 }
}
}

View file

@ -0,0 +1,10 @@
{
"variants": {
"": [
{ "model": "engineersdecor:block/glass/panzerglass_block_model", "textures": { "all": "engineersdecor:block/glass/panzerglass_block_texture0" }},
{ "model": "engineersdecor:block/glass/panzerglass_block_model", "textures": { "all": "engineersdecor:block/glass/panzerglass_block_texture1" }},
{ "model": "engineersdecor:block/glass/panzerglass_block_model", "textures": { "all": "engineersdecor:block/glass/panzerglass_block_texture2" }},
{ "model": "engineersdecor:block/glass/panzerglass_block_model", "textures": { "all": "engineersdecor:block/glass/panzerglass_block_texture3" }}
]
}
}

View file

@ -0,0 +1,16 @@
{
"variants": {
"parts=0,tvariant=0": { "model": "engineersdecor:block/slab/specific/panzerglass_slab_s0v0_model" },
"parts=0,tvariant=1": { "model": "engineersdecor:block/slab/specific/panzerglass_slab_s0v1_model" },
"parts=0,tvariant=2": { "model": "engineersdecor:block/slab/specific/panzerglass_slab_s0v2_model" },
"parts=0,tvariant=3": { "model": "engineersdecor:block/slab/specific/panzerglass_slab_s0v3_model" },
"parts=1,tvariant=0": { "model": "engineersdecor:block/slab/specific/panzerglass_slab_s1v0_model" },
"parts=1,tvariant=1": { "model": "engineersdecor:block/slab/specific/panzerglass_slab_s1v1_model" },
"parts=1,tvariant=2": { "model": "engineersdecor:block/slab/specific/panzerglass_slab_s1v2_model" },
"parts=1,tvariant=3": { "model": "engineersdecor:block/slab/specific/panzerglass_slab_s1v3_model" },
"parts=2,tvariant=0": { "model": "engineersdecor:block/slab/specific/panzerglass_slab_s2v0_model" },
"parts=2,tvariant=1": { "model": "engineersdecor:block/slab/specific/panzerglass_slab_s2v1_model" },
"parts=2,tvariant=2": { "model": "engineersdecor:block/slab/specific/panzerglass_slab_s2v2_model" },
"parts=2,tvariant=3": { "model": "engineersdecor:block/slab/specific/panzerglass_slab_s2v3_model" }
}
}

View file

@ -0,0 +1,10 @@
{
"variants": {
"facing=north": { "model": "engineersdecor:block/pipe/passive_fluid_accumulator_model" },
"facing=south": { "model": "engineersdecor:block/pipe/passive_fluid_accumulator_model", "y":180 },
"facing=west": { "model": "engineersdecor:block/pipe/passive_fluid_accumulator_model", "y":270 },
"facing=east": { "model": "engineersdecor:block/pipe/passive_fluid_accumulator_model", "y":90 },
"facing=up": { "model": "engineersdecor:block/pipe/passive_fluid_accumulator_model", "x":270 },
"facing=down": { "model": "engineersdecor:block/pipe/passive_fluid_accumulator_model", "x":90 }
}
}

View file

@ -0,0 +1,14 @@
{
"variants": {
"": [
{ "model": "engineersdecor:block/concrete/rebar_concrete_model0" },
{ "model": "engineersdecor:block/concrete/rebar_concrete_model1" },
{ "model": "engineersdecor:block/concrete/rebar_concrete_model2" },
{ "model": "engineersdecor:block/concrete/rebar_concrete_model3" },
{ "model": "engineersdecor:block/concrete/rebar_concrete_model4" },
{ "model": "engineersdecor:block/concrete/rebar_concrete_model5" },
{ "model": "engineersdecor:block/concrete/rebar_concrete_model6" },
{ "model": "engineersdecor:block/concrete/rebar_concrete_model7" }
]
}
}

View file

@ -0,0 +1,16 @@
{
"variants": {
"parts=0,tvariant=0": { "model": "engineersdecor:block/slab/specific/rebar_concrete_slab_s0v0_model" },
"parts=0,tvariant=1": { "model": "engineersdecor:block/slab/specific/rebar_concrete_slab_s0v1_model" },
"parts=0,tvariant=2": { "model": "engineersdecor:block/slab/specific/rebar_concrete_slab_s0v2_model" },
"parts=0,tvariant=3": { "model": "engineersdecor:block/slab/specific/rebar_concrete_slab_s0v3_model" },
"parts=1,tvariant=0": { "model": "engineersdecor:block/slab/specific/rebar_concrete_slab_s1v0_model" },
"parts=1,tvariant=1": { "model": "engineersdecor:block/slab/specific/rebar_concrete_slab_s1v1_model" },
"parts=1,tvariant=2": { "model": "engineersdecor:block/slab/specific/rebar_concrete_slab_s1v2_model" },
"parts=1,tvariant=3": { "model": "engineersdecor:block/slab/specific/rebar_concrete_slab_s1v3_model" },
"parts=2,tvariant=0": { "model": "engineersdecor:block/slab/specific/rebar_concrete_slab_s2v0_model" },
"parts=2,tvariant=1": { "model": "engineersdecor:block/slab/specific/rebar_concrete_slab_s2v1_model" },
"parts=2,tvariant=2": { "model": "engineersdecor:block/slab/specific/rebar_concrete_slab_s2v2_model" },
"parts=2,tvariant=3": { "model": "engineersdecor:block/slab/specific/rebar_concrete_slab_s2v3_model" }
}
}

View file

@ -0,0 +1,44 @@
{
"variants": {
"facing=east,half=bottom,shape=straight": { "model": "engineersdecor:block/concrete/rebar_concrete_stairs" },
"facing=west,half=bottom,shape=straight": { "model": "engineersdecor:block/concrete/rebar_concrete_stairs", "y": 180, "uvlock": true },
"facing=south,half=bottom,shape=straight": { "model": "engineersdecor:block/concrete/rebar_concrete_stairs", "y": 90, "uvlock": true },
"facing=north,half=bottom,shape=straight": { "model": "engineersdecor:block/concrete/rebar_concrete_stairs", "y": 270, "uvlock": true },
"facing=east,half=bottom,shape=outer_right": { "model": "engineersdecor:block/concrete/rebar_concrete_stairs_outer" },
"facing=west,half=bottom,shape=outer_right": { "model": "engineersdecor:block/concrete/rebar_concrete_stairs_outer", "y": 180, "uvlock": true },
"facing=south,half=bottom,shape=outer_right": { "model": "engineersdecor:block/concrete/rebar_concrete_stairs_outer", "y": 90, "uvlock": true },
"facing=north,half=bottom,shape=outer_right": { "model": "engineersdecor:block/concrete/rebar_concrete_stairs_outer", "y": 270, "uvlock": true },
"facing=east,half=bottom,shape=outer_left": { "model": "engineersdecor:block/concrete/rebar_concrete_stairs_outer", "y": 270, "uvlock": true },
"facing=west,half=bottom,shape=outer_left": { "model": "engineersdecor:block/concrete/rebar_concrete_stairs_outer", "y": 90, "uvlock": true },
"facing=south,half=bottom,shape=outer_left": { "model": "engineersdecor:block/concrete/rebar_concrete_stairs_outer" },
"facing=north,half=bottom,shape=outer_left": { "model": "engineersdecor:block/concrete/rebar_concrete_stairs_outer", "y": 180, "uvlock": true },
"facing=east,half=bottom,shape=inner_right": { "model": "engineersdecor:block/concrete/rebar_concrete_stairs_inner" },
"facing=west,half=bottom,shape=inner_right": { "model": "engineersdecor:block/concrete/rebar_concrete_stairs_inner", "y": 180, "uvlock": true },
"facing=south,half=bottom,shape=inner_right": { "model": "engineersdecor:block/concrete/rebar_concrete_stairs_inner", "y": 90, "uvlock": true },
"facing=north,half=bottom,shape=inner_right": { "model": "engineersdecor:block/concrete/rebar_concrete_stairs_inner", "y": 270, "uvlock": true },
"facing=east,half=bottom,shape=inner_left": { "model": "engineersdecor:block/concrete/rebar_concrete_stairs_inner", "y": 270, "uvlock": true },
"facing=west,half=bottom,shape=inner_left": { "model": "engineersdecor:block/concrete/rebar_concrete_stairs_inner", "y": 90, "uvlock": true },
"facing=south,half=bottom,shape=inner_left": { "model": "engineersdecor:block/concrete/rebar_concrete_stairs_inner" },
"facing=north,half=bottom,shape=inner_left": { "model": "engineersdecor:block/concrete/rebar_concrete_stairs_inner", "y": 180, "uvlock": true },
"facing=east,half=top,shape=straight": { "model": "engineersdecor:block/concrete/rebar_concrete_stairs", "x": 180, "uvlock": true },
"facing=west,half=top,shape=straight": { "model": "engineersdecor:block/concrete/rebar_concrete_stairs", "x": 180, "y": 180, "uvlock": true },
"facing=south,half=top,shape=straight": { "model": "engineersdecor:block/concrete/rebar_concrete_stairs", "x": 180, "y": 90, "uvlock": true },
"facing=north,half=top,shape=straight": { "model": "engineersdecor:block/concrete/rebar_concrete_stairs", "x": 180, "y": 270, "uvlock": true },
"facing=east,half=top,shape=outer_right": { "model": "engineersdecor:block/concrete/rebar_concrete_stairs_outer", "x": 180, "y": 90, "uvlock": true },
"facing=west,half=top,shape=outer_right": { "model": "engineersdecor:block/concrete/rebar_concrete_stairs_outer", "x": 180, "y": 270, "uvlock": true },
"facing=south,half=top,shape=outer_right": { "model": "engineersdecor:block/concrete/rebar_concrete_stairs_outer", "x": 180, "y": 180, "uvlock": true },
"facing=north,half=top,shape=outer_right": { "model": "engineersdecor:block/concrete/rebar_concrete_stairs_outer", "x": 180, "uvlock": true },
"facing=east,half=top,shape=outer_left": { "model": "engineersdecor:block/concrete/rebar_concrete_stairs_outer", "x": 180, "uvlock": true },
"facing=west,half=top,shape=outer_left": { "model": "engineersdecor:block/concrete/rebar_concrete_stairs_outer", "x": 180, "y": 180, "uvlock": true },
"facing=south,half=top,shape=outer_left": { "model": "engineersdecor:block/concrete/rebar_concrete_stairs_outer", "x": 180, "y": 90, "uvlock": true },
"facing=north,half=top,shape=outer_left": { "model": "engineersdecor:block/concrete/rebar_concrete_stairs_outer", "x": 180, "y": 270, "uvlock": true },
"facing=east,half=top,shape=inner_right": { "model": "engineersdecor:block/concrete/rebar_concrete_stairs_inner", "x": 180, "y": 90, "uvlock": true },
"facing=west,half=top,shape=inner_right": { "model": "engineersdecor:block/concrete/rebar_concrete_stairs_inner", "x": 180, "y": 270, "uvlock": true },
"facing=south,half=top,shape=inner_right": { "model": "engineersdecor:block/concrete/rebar_concrete_stairs_inner", "x": 180, "y": 180, "uvlock": true },
"facing=north,half=top,shape=inner_right": { "model": "engineersdecor:block/concrete/rebar_concrete_stairs_inner", "x": 180, "uvlock": true },
"facing=east,half=top,shape=inner_left": { "model": "engineersdecor:block/concrete/rebar_concrete_stairs_inner", "x": 180, "uvlock": true },
"facing=west,half=top,shape=inner_left": { "model": "engineersdecor:block/concrete/rebar_concrete_stairs_inner", "x": 180, "y": 180, "uvlock": true },
"facing=south,half=top,shape=inner_left": { "model": "engineersdecor:block/concrete/rebar_concrete_stairs_inner", "x": 180, "y": 90, "uvlock": true },
"facing=north,half=top,shape=inner_left": { "model": "engineersdecor:block/concrete/rebar_concrete_stairs_inner", "x": 180, "y": 270, "uvlock": true }
}
}

View file

@ -0,0 +1,14 @@
{
"variants": {
"": [
{ "model": "engineersdecor:block/concrete/rebar_concrete_tile_model0" },
{ "model": "engineersdecor:block/concrete/rebar_concrete_tile_model1" },
{ "model": "engineersdecor:block/concrete/rebar_concrete_tile_model2" },
{ "model": "engineersdecor:block/concrete/rebar_concrete_tile_model3" },
{ "model": "engineersdecor:block/concrete/rebar_concrete_tile_model4" },
{ "model": "engineersdecor:block/concrete/rebar_concrete_tile_model5" },
{ "model": "engineersdecor:block/concrete/rebar_concrete_tile_model6" },
{ "model": "engineersdecor:block/concrete/rebar_concrete_tile_model7" }
]
}
}

View file

@ -0,0 +1,16 @@
{
"variants": {
"parts=0,tvariant=0": { "model": "engineersdecor:block/slab/specific/rebar_concrete_tile_slab_s0v0_model" },
"parts=0,tvariant=1": { "model": "engineersdecor:block/slab/specific/rebar_concrete_tile_slab_s0v1_model" },
"parts=0,tvariant=2": { "model": "engineersdecor:block/slab/specific/rebar_concrete_tile_slab_s0v2_model" },
"parts=0,tvariant=3": { "model": "engineersdecor:block/slab/specific/rebar_concrete_tile_slab_s0v3_model" },
"parts=1,tvariant=0": { "model": "engineersdecor:block/slab/specific/rebar_concrete_tile_slab_s1v0_model" },
"parts=1,tvariant=1": { "model": "engineersdecor:block/slab/specific/rebar_concrete_tile_slab_s1v1_model" },
"parts=1,tvariant=2": { "model": "engineersdecor:block/slab/specific/rebar_concrete_tile_slab_s1v2_model" },
"parts=1,tvariant=3": { "model": "engineersdecor:block/slab/specific/rebar_concrete_tile_slab_s1v3_model" },
"parts=2,tvariant=0": { "model": "engineersdecor:block/slab/specific/rebar_concrete_tile_slab_s2v0_model" },
"parts=2,tvariant=1": { "model": "engineersdecor:block/slab/specific/rebar_concrete_tile_slab_s2v1_model" },
"parts=2,tvariant=2": { "model": "engineersdecor:block/slab/specific/rebar_concrete_tile_slab_s2v2_model" },
"parts=2,tvariant=3": { "model": "engineersdecor:block/slab/specific/rebar_concrete_tile_slab_s2v3_model" }
}
}

View file

@ -0,0 +1,44 @@
{
"variants": {
"facing=east,half=bottom,shape=straight": { "model": "engineersdecor:block/concrete/rebar_concrete_tile_stairs" },
"facing=west,half=bottom,shape=straight": { "model": "engineersdecor:block/concrete/rebar_concrete_tile_stairs", "y": 180, "uvlock": true },
"facing=south,half=bottom,shape=straight": { "model": "engineersdecor:block/concrete/rebar_concrete_tile_stairs", "y": 90, "uvlock": true },
"facing=north,half=bottom,shape=straight": { "model": "engineersdecor:block/concrete/rebar_concrete_tile_stairs", "y": 270, "uvlock": true },
"facing=east,half=bottom,shape=outer_right": { "model": "engineersdecor:block/concrete/rebar_concrete_tile_stairs_outer" },
"facing=west,half=bottom,shape=outer_right": { "model": "engineersdecor:block/concrete/rebar_concrete_tile_stairs_outer", "y": 180, "uvlock": true },
"facing=south,half=bottom,shape=outer_right": { "model": "engineersdecor:block/concrete/rebar_concrete_tile_stairs_outer", "y": 90, "uvlock": true },
"facing=north,half=bottom,shape=outer_right": { "model": "engineersdecor:block/concrete/rebar_concrete_tile_stairs_outer", "y": 270, "uvlock": true },
"facing=east,half=bottom,shape=outer_left": { "model": "engineersdecor:block/concrete/rebar_concrete_tile_stairs_outer", "y": 270, "uvlock": true },
"facing=west,half=bottom,shape=outer_left": { "model": "engineersdecor:block/concrete/rebar_concrete_tile_stairs_outer", "y": 90, "uvlock": true },
"facing=south,half=bottom,shape=outer_left": { "model": "engineersdecor:block/concrete/rebar_concrete_tile_stairs_outer" },
"facing=north,half=bottom,shape=outer_left": { "model": "engineersdecor:block/concrete/rebar_concrete_tile_stairs_outer", "y": 180, "uvlock": true },
"facing=east,half=bottom,shape=inner_right": { "model": "engineersdecor:block/concrete/rebar_concrete_tile_stairs_inner" },
"facing=west,half=bottom,shape=inner_right": { "model": "engineersdecor:block/concrete/rebar_concrete_tile_stairs_inner", "y": 180, "uvlock": true },
"facing=south,half=bottom,shape=inner_right": { "model": "engineersdecor:block/concrete/rebar_concrete_tile_stairs_inner", "y": 90, "uvlock": true },
"facing=north,half=bottom,shape=inner_right": { "model": "engineersdecor:block/concrete/rebar_concrete_tile_stairs_inner", "y": 270, "uvlock": true },
"facing=east,half=bottom,shape=inner_left": { "model": "engineersdecor:block/concrete/rebar_concrete_tile_stairs_inner", "y": 270, "uvlock": true },
"facing=west,half=bottom,shape=inner_left": { "model": "engineersdecor:block/concrete/rebar_concrete_tile_stairs_inner", "y": 90, "uvlock": true },
"facing=south,half=bottom,shape=inner_left": { "model": "engineersdecor:block/concrete/rebar_concrete_tile_stairs_inner" },
"facing=north,half=bottom,shape=inner_left": { "model": "engineersdecor:block/concrete/rebar_concrete_tile_stairs_inner", "y": 180, "uvlock": true },
"facing=east,half=top,shape=straight": { "model": "engineersdecor:block/concrete/rebar_concrete_tile_stairs", "x": 180, "uvlock": true },
"facing=west,half=top,shape=straight": { "model": "engineersdecor:block/concrete/rebar_concrete_tile_stairs", "x": 180, "y": 180, "uvlock": true },
"facing=south,half=top,shape=straight": { "model": "engineersdecor:block/concrete/rebar_concrete_tile_stairs", "x": 180, "y": 90, "uvlock": true },
"facing=north,half=top,shape=straight": { "model": "engineersdecor:block/concrete/rebar_concrete_tile_stairs", "x": 180, "y": 270, "uvlock": true },
"facing=east,half=top,shape=outer_right": { "model": "engineersdecor:block/concrete/rebar_concrete_tile_stairs_outer", "x": 180, "y": 90, "uvlock": true },
"facing=west,half=top,shape=outer_right": { "model": "engineersdecor:block/concrete/rebar_concrete_tile_stairs_outer", "x": 180, "y": 270, "uvlock": true },
"facing=south,half=top,shape=outer_right": { "model": "engineersdecor:block/concrete/rebar_concrete_tile_stairs_outer", "x": 180, "y": 180, "uvlock": true },
"facing=north,half=top,shape=outer_right": { "model": "engineersdecor:block/concrete/rebar_concrete_tile_stairs_outer", "x": 180, "uvlock": true },
"facing=east,half=top,shape=outer_left": { "model": "engineersdecor:block/concrete/rebar_concrete_tile_stairs_outer", "x": 180, "uvlock": true },
"facing=west,half=top,shape=outer_left": { "model": "engineersdecor:block/concrete/rebar_concrete_tile_stairs_outer", "x": 180, "y": 180, "uvlock": true },
"facing=south,half=top,shape=outer_left": { "model": "engineersdecor:block/concrete/rebar_concrete_tile_stairs_outer", "x": 180, "y": 90, "uvlock": true },
"facing=north,half=top,shape=outer_left": { "model": "engineersdecor:block/concrete/rebar_concrete_tile_stairs_outer", "x": 180, "y": 270, "uvlock": true },
"facing=east,half=top,shape=inner_right": { "model": "engineersdecor:block/concrete/rebar_concrete_tile_stairs_inner", "x": 180, "y": 90, "uvlock": true },
"facing=west,half=top,shape=inner_right": { "model": "engineersdecor:block/concrete/rebar_concrete_tile_stairs_inner", "x": 180, "y": 270, "uvlock": true },
"facing=south,half=top,shape=inner_right": { "model": "engineersdecor:block/concrete/rebar_concrete_tile_stairs_inner", "x": 180, "y": 180, "uvlock": true },
"facing=north,half=top,shape=inner_right": { "model": "engineersdecor:block/concrete/rebar_concrete_tile_stairs_inner", "x": 180, "uvlock": true },
"facing=east,half=top,shape=inner_left": { "model": "engineersdecor:block/concrete/rebar_concrete_tile_stairs_inner", "x": 180, "uvlock": true },
"facing=west,half=top,shape=inner_left": { "model": "engineersdecor:block/concrete/rebar_concrete_tile_stairs_inner", "x": 180, "y": 180, "uvlock": true },
"facing=south,half=top,shape=inner_left": { "model": "engineersdecor:block/concrete/rebar_concrete_tile_stairs_inner", "x": 180, "y": 90, "uvlock": true },
"facing=north,half=top,shape=inner_left": { "model": "engineersdecor:block/concrete/rebar_concrete_tile_stairs_inner", "x": 180, "y": 270, "uvlock": true }
}
}

Some files were not shown because too many files have changed in this diff Show more